This commit is contained in:
nub31
2025-10-26 22:28:48 +01:00
parent 27bc4da4fd
commit 560e6428ff
18 changed files with 663 additions and 483 deletions

View File

@@ -45,7 +45,7 @@ public sealed class Parser
Symbol.Func => ParseFunc(startIndex, exported, null),
Symbol.Struct => ParseStruct(startIndex, exported),
Symbol.Enum => ParseEnum(startIndex, exported),
_ => throw new ParseException(Diagnostic
_ => throw new CompileException(Diagnostic
.Error($"Expected 'func', 'struct', 'enum', 'import' or 'module' but found '{keyword.Symbol}'")
.WithHelp("Valid top level statements are 'func', 'struct', 'enum', 'import' and 'module'")
.At(keyword)
@@ -54,7 +54,7 @@ public sealed class Parser
topLevelSyntaxNodes.Add(definition);
}
catch (ParseException e)
catch (CompileException e)
{
Diagnostics.Add(e.Diagnostic);
while (HasToken)
@@ -180,7 +180,7 @@ public sealed class Parser
{
if (!TryExpectIntLiteral(out var intLiteralToken))
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Value of enum field must be an integer literal")
.At(CurrentToken)
.Build());
@@ -451,13 +451,13 @@ public sealed class Parser
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
Symbol.Struct => ParseStructInitializer(startIndex),
Symbol.At => ParseBuiltinFunction(startIndex),
_ => throw new ParseException(Diagnostic
_ => throw new CompileException(Diagnostic
.Error($"Unexpected symbol '{symbolToken.Symbol}' in expression")
.WithHelp("Expected '(', '-', '!', '[' or '{'")
.At(symbolToken)
.Build())
},
_ => throw new ParseException(Diagnostic
_ => throw new CompileException(Diagnostic
.Error($"Unexpected token '{token.GetType().Name}' in expression")
.WithHelp("Expected literal, identifier, or parenthesized expression")
.At(token)
@@ -488,7 +488,7 @@ public sealed class Parser
}
default:
{
throw new ParseException(Diagnostic.Error($"Unknown builtin {name.Value}").At(name).Build());
throw new CompileException(Diagnostic.Error($"Unknown builtin {name.Value}").At(name).Build());
}
}
}
@@ -628,7 +628,7 @@ public sealed class Parser
{
statements.Add(ParseStatement());
}
catch (ParseException ex)
catch (CompileException ex)
{
Diagnostics.Add(ex.Diagnostic);
if (HasToken)
@@ -654,7 +654,7 @@ public sealed class Parser
{
if (size is not 8 and not 16 and not 32 and not 64)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Arbitrary uint size is not supported")
.WithHelp("Use u8, u16, u32 or u64")
.At(name)
@@ -668,7 +668,7 @@ public sealed class Parser
{
if (size is not 8 and not 16 and not 32 and not 64)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Arbitrary int size is not supported")
.WithHelp("Use i8, i16, i32 or i64")
.At(name)
@@ -682,7 +682,7 @@ public sealed class Parser
{
if (size is not 32 and not 64)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Arbitrary float size is not supported")
.WithHelp("Use f32 or f64")
.At(name)
@@ -772,7 +772,7 @@ public sealed class Parser
}
}
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Invalid type syntax")
.WithHelp("Expected type name, '^' for pointer, or '[]' for array")
.At(CurrentToken)
@@ -783,7 +783,7 @@ public sealed class Parser
{
if (!HasToken)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error("Unexpected end of file")
.WithHelp("Expected more tokens to complete the syntax")
.At(_tokens[^1])
@@ -800,7 +800,7 @@ public sealed class Parser
var token = ExpectToken();
if (token is not SymbolToken symbol)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error($"Expected symbol, but found {token.GetType().Name}")
.WithHelp("This position requires a symbol like '(', ')', '{', '}', etc.")
.At(token)
@@ -815,7 +815,7 @@ public sealed class Parser
var token = ExpectSymbol();
if (token.Symbol != expectedSymbol)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error($"Expected '{expectedSymbol}', but found '{token.Symbol}'")
.WithHelp($"Insert '{expectedSymbol}' here")
.At(token)
@@ -865,7 +865,7 @@ public sealed class Parser
var token = ExpectToken();
if (token is not IdentifierToken identifier)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error($"Expected identifier, but found {token.GetType().Name}")
.WithHelp("Provide a valid identifier name here")
.At(token)
@@ -893,7 +893,7 @@ public sealed class Parser
var token = ExpectToken();
if (token is not StringLiteralToken identifier)
{
throw new ParseException(Diagnostic
throw new CompileException(Diagnostic
.Error($"Expected string literal, but found {token.GetType().Name}")
.WithHelp("Provide a valid string literal")
.At(token)
@@ -914,14 +914,4 @@ public sealed class Parser
}
}
public record SyntaxTree(List<TopLevelSyntaxNode> TopLevelSyntaxNodes);
public class ParseException : Exception
{
public Diagnostic Diagnostic { get; }
public ParseException(Diagnostic diagnostic) : base(diagnostic.Message)
{
Diagnostic = diagnostic;
}
}
public record SyntaxTree(List<TopLevelSyntaxNode> TopLevelSyntaxNodes);

View File

@@ -58,7 +58,7 @@ public sealed class Tokenizer
Tokens.Add(ParseToken(current, _line, _column));
}
catch (TokenizerException e)
catch (CompileException e)
{
Diagnostics.Add(e.Diagnostic);
Next();
@@ -95,7 +95,7 @@ public sealed class Tokenizer
return ParseIdentifier(lineStart, columnStart);
}
throw new TokenizerException(Diagnostic.Error($"Unknown token '{current}'").Build());
throw new CompileException(Diagnostic.Error($"Unknown token '{current}'").Build());
}
private Token ParseNumber(int lineStart, int columnStart)
@@ -116,7 +116,7 @@ public sealed class Tokenizer
if (_index == digitStart)
{
throw new TokenizerException(Diagnostic
throw new CompileException(Diagnostic
.Error("Invalid hex literal, no digits found")
.At(_fileName, _line, _column)
.Build());
@@ -141,7 +141,7 @@ public sealed class Tokenizer
if (_index == digitStart)
{
throw new TokenizerException(Diagnostic
throw new CompileException(Diagnostic
.Error("Invalid binary literal, no digits found")
.At(_fileName, _line, _column)
.Build());
@@ -163,7 +163,7 @@ public sealed class Tokenizer
{
if (isFloat)
{
throw new TokenizerException(Diagnostic
throw new CompileException(Diagnostic
.Error("More than one period found in float literal")
.At(_fileName, _line, _column)
.Build());
@@ -198,7 +198,7 @@ public sealed class Tokenizer
{
if (_index >= _content.Length)
{
throw new TokenizerException(Diagnostic
throw new CompileException(Diagnostic
.Error("Unclosed string literal")
.At(_fileName, _line, _column)
.Build());
@@ -208,7 +208,7 @@ public sealed class Tokenizer
if (next == '\n')
{
throw new TokenizerException(Diagnostic
throw new CompileException(Diagnostic
.Error("Unclosed string literal (newline found)")
.At(_fileName, _line, _column)
.Build());
@@ -375,14 +375,4 @@ public sealed class Tokenizer
_index += count;
_column += count;
}
}
public class TokenizerException : Exception
{
public Diagnostic Diagnostic { get; }
public TokenizerException(Diagnostic diagnostic) : base(diagnostic.Message)
{
Diagnostic = diagnostic;
}
}

View File

@@ -0,0 +1,50 @@
using NubLang.Ast;
namespace NubLang.Syntax;
public sealed class TypedModule
{
public static TypedModule FromModule(string name, Module module, Dictionary<string, Module> modules)
{
var typeResolver = new TypeResolver(modules);
var functionPrototypes = new List<FuncPrototypeNode>();
foreach (var funcSyntax in module.Functions(true))
{
var parameters = new List<FuncParameterNode>();
foreach (var parameter in funcSyntax.Prototype.Parameters)
{
parameters.Add(new FuncParameterNode(parameter.Tokens, parameter.NameToken, typeResolver.ResolveType(parameter.Type, name)));
}
var returnType = typeResolver.ResolveType(funcSyntax.Prototype.ReturnType, name);
functionPrototypes.Add(new FuncPrototypeNode(funcSyntax.Tokens, funcSyntax.Prototype.NameToken, funcSyntax.Prototype.ExternSymbolToken, parameters, returnType));
}
var structTypes = new List<NubStructType>();
foreach (var structSyntax in module.Structs(true))
{
var fields = new List<NubStructFieldType>();
foreach (var field in structSyntax.Fields)
{
fields.Add(new NubStructFieldType(field.NameToken.Value, typeResolver.ResolveType(field.Type, name), field.Value != null));
}
structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, fields));
}
return new TypedModule(functionPrototypes, structTypes);
}
public TypedModule(List<FuncPrototypeNode> functionPrototypes, List<NubStructType> structTypes)
{
FunctionPrototypes = functionPrototypes;
StructTypes = structTypes;
}
public List<FuncPrototypeNode> FunctionPrototypes { get; set; }
public List<NubStructType> StructTypes { get; set; }
}