This commit is contained in:
nub31
2025-05-24 20:37:26 +02:00
parent 010df49dc4
commit 757e3490f5
9 changed files with 132 additions and 69 deletions

View File

@@ -1,9 +1,14 @@
import c
// Test
// Test2
// Test3
// Test4
global func main(args: []string) {
i = 0
printf("%d\n", args.count)
while i < args.count {
// Test
printf("%s\n", args[i])
i = i + 1
}

View File

@@ -0,0 +1,6 @@
namespace Nub.Lang.Frontend.Lexing;
public class CommentToken(string comment) : Token
{
public string Comment { get; } = comment;
}

View File

@@ -63,26 +63,44 @@ public class Lexer
_index = 0;
List<Token> tokens = [];
while (Peek().HasValue)
while (Peek().TryGetValue(out var character))
{
tokens.Add(ParseToken());
if (char.IsWhiteSpace(character))
{
Next();
continue;
}
tokens.Add(ParseToken(character));
}
return tokens;
}
private Token ParseToken()
private Token ParseToken(char current)
{
var current = Peek();
if (current == '/' && Peek(1) is { Value: '/' })
{
Next();
Next();
var buffer = string.Empty;
while (Peek() is not { Value: '\n' })
{
buffer += Peek().Value;
Next();
}
if (char.IsLetter(current.Value) || current.Value == '_')
Next();
return new CommentToken(buffer);
}
if (char.IsLetter(current) || current == '_')
{
var buffer = string.Empty;
while (current.HasValue && (char.IsLetterOrDigit(current.Value) || current.Value == '_'))
while (Peek().TryGetValue(out var next) && (char.IsLetterOrDigit(next) || next == '_'))
{
buffer += current.Value;
buffer += next;
Next();
current = Peek();
}
if (Keywords.TryGetValue(buffer, out var keywordSymbol))
@@ -103,31 +121,30 @@ public class Lexer
return new IdentifierToken(buffer);
}
if (char.IsDigit(current.Value))
if (char.IsDigit(current))
{
var isFloat = false;
var buffer = string.Empty;
while (current.HasValue)
while (Peek().TryGetValue(out var next))
{
if (current.Value == '.')
if (next == '.')
{
if (isFloat)
{
throw new Exception("More than one period found in float literal");
}
isFloat = true;
buffer += current.Value;
buffer += next;
Next();
current = Peek();
}
else if (char.IsDigit(current.Value))
else if (char.IsDigit(next))
{
buffer += current.Value;
buffer += next;
Next();
current = Peek();
}
else if (current.Value == 'f')
else if (next == 'f')
{
isFloat = true;
Next();
@@ -145,7 +162,7 @@ public class Lexer
// TODO: Revisit this
foreach (var chain in Chians)
{
if (current.Value != chain.Key[0]) continue;
if (current != chain.Key[0]) continue;
for (var i = 1; i < chain.Key.Length; i++)
{
@@ -164,36 +181,38 @@ public class Lexer
}
}
if (Chars.TryGetValue(current.Value, out var charSymbol))
if (Chars.TryGetValue(current, out var charSymbol))
{
Next();
return new SymbolToken(charSymbol);
}
if (current.Value == '"')
if (current == '"')
{
Next();
var buffer = string.Empty;
while (true)
{
current = Peek();
if (!Peek().TryGetValue(out var next))
{
throw new Exception("Unclosed string literal");
}
if (next == '"')
{
Next();
break;
}
buffer += next;
Next();
if (!current.HasValue) throw new Exception("Unclosed string literal");
if (current.Value == '"') break;
buffer += current.Value;
}
return new LiteralToken(NubPrimitiveType.String, buffer);
}
if (char.IsWhiteSpace(current.Value))
{
Next();
return new SymbolToken(Symbol.Whitespace);
}
throw new Exception($"Unknown character {current.Value}");
throw new Exception($"Unknown character {current}");
}
private Optional<char> Peek(int offset = 0)

View File

@@ -7,7 +7,6 @@ public class SymbolToken(Symbol symbol) : Token
public enum Symbol
{
Whitespace,
Import,
Func,
Return,

View File

@@ -1,10 +1,11 @@
namespace Nub.Lang.Frontend.Parsing;
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<NubType> returnType, Optional<string> documentation) : DefinitionNode
{
public string Name { get; } = name;
public List<FuncParameter> Parameters { get; } = parameters;
public Optional<NubType> ReturnType { get; } = returnType;
public Optional<string> Documentation { get; set; } = documentation;
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
}

View File

@@ -1,12 +1,13 @@
namespace Nub.Lang.Frontend.Parsing;
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool global) : DefinitionNode
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool global, Optional<string> documentation) : DefinitionNode
{
public string Name { get; } = name;
public List<FuncParameter> Parameters { get; } = parameters;
public BlockNode Body { get; } = body;
public Optional<NubType> ReturnType { get; } = returnType;
public bool Global { get; } = global;
public Optional<string> Documentation { get; set; } = documentation;
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
}

View File

@@ -36,6 +36,15 @@ public class Parser
{
List<Modifier> modifiers = [];
List<string> documentationParts = [];
while (_index < _tokens.Count && _tokens[_index] is CommentToken commentToken)
{
documentationParts.Add(commentToken.Comment);
_index++;
}
var documentation = documentationParts.Count == 0 ? null : string.Join('\n', documentationParts);
while (TryExpectModifier(out var modifier))
{
modifiers.Add(modifier);
@@ -44,13 +53,13 @@ public class Parser
var keyword = ExpectSymbol();
return keyword.Symbol switch
{
Symbol.Func => ParseFuncDefinition(modifiers),
Symbol.Struct => ParseStruct(modifiers),
Symbol.Func => ParseFuncDefinition(modifiers, Optional.OfNullable(documentation)),
Symbol.Struct => ParseStruct(modifiers, Optional.OfNullable(documentation)),
_ => throw new Exception("Unexpected symbol: " + keyword.Symbol)
};
}
private DefinitionNode ParseFuncDefinition(List<Modifier> modifiers)
private DefinitionNode ParseFuncDefinition(List<Modifier> modifiers, Optional<string> documentation)
{
var name = ExpectIdentifier();
List<FuncParameter> parameters = [];
@@ -77,7 +86,7 @@ public class Parser
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for an extern function");
}
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
return new ExternFuncDefinitionNode(name.Value, parameters, returnType, documentation);
}
var body = ParseBlock();
@@ -88,10 +97,10 @@ public class Parser
throw new Exception($"Modifiers: {string.Join(", ", modifiers)} is not valid for a local function");
}
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, global);
return new LocalFuncDefinitionNode(name.Value, parameters, body, returnType, global, documentation);
}
private StructDefinitionNode ParseStruct(List<Modifier> _)
private StructDefinitionNode ParseStruct(List<Modifier> _, Optional<string> documentation)
{
var name = ExpectIdentifier().Value;
@@ -115,7 +124,7 @@ public class Parser
variables.Add(new StructField(variableName, variableType, variableValue));
}
return new StructDefinitionNode(name, variables);
return new StructDefinitionNode(name, variables, documentation);
}
private FuncParameter ParseFuncParameter()
@@ -341,6 +350,7 @@ public class Parser
break;
}
}
break;
}
case SymbolToken symbolToken:
@@ -403,6 +413,7 @@ public class Parser
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
}
}
break;
}
default:
@@ -558,14 +569,15 @@ public class Parser
private Optional<Token> Peek()
{
while (_index < _tokens.Count && _tokens.ElementAt(_index) is SymbolToken { Symbol: Symbol.Whitespace })
var peekIndex = _index;
while (peekIndex < _tokens.Count && _tokens[peekIndex] is CommentToken)
{
Next();
peekIndex++;
}
if (_index < _tokens.Count)
if (peekIndex < _tokens.Count)
{
return _tokens.ElementAt(_index);
return _tokens[peekIndex];
}
return Optional<Token>.Empty();
@@ -573,6 +585,11 @@ public class Parser
private void Next()
{
while (_index < _tokens.Count && _tokens[_index] is CommentToken)
{
_index++;
}
_index++;
}
}

View File

@@ -1,7 +1,8 @@
namespace Nub.Lang.Frontend.Parsing;
public class StructDefinitionNode(string name, List<StructField> fields) : DefinitionNode
public class StructDefinitionNode(string name, List<StructField> fields, Optional<string> documentation) : DefinitionNode
{
public string Name { get; } = name;
public List<StructField> Fields { get; } = fields;
public Optional<string> Documentation { get; set; } = documentation;
}

View File

@@ -44,5 +44,19 @@ public readonly struct Optional<TValue>
[MemberNotNullWhen(true, nameof(Value))]
public bool HasValue { get; }
[MemberNotNullWhen(true, nameof(Value))]
public bool TryGetValue([NotNullWhen(true)] out TValue? value)
{
if (HasValue)
{
value = Value;
return true;
}
value = default;
return false;
}
public static implicit operator Optional<TValue>(TValue value) => new(value);
}