From 0de84375d3f581a175352daaf04f8304222ebd08 Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 29 Sep 2025 16:57:25 +0200 Subject: [PATCH] ... --- compiler/NubLang/Diagnostics/Diagnostic.cs | 13 +- compiler/NubLang/Parsing/Parser.cs | 65 +++++++--- .../Parsing/Syntax/ExpressionSyntax.cs | 8 +- compiler/NubLang/Tokenization/Token.cs | 18 ++- compiler/NubLang/Tokenization/Tokenizer.cs | 25 ++-- compiler/NubLang/TypeChecking/TypeChecker.cs | 118 +++++++----------- 6 files changed, 127 insertions(+), 120 deletions(-) diff --git a/compiler/NubLang/Diagnostics/Diagnostic.cs b/compiler/NubLang/Diagnostics/Diagnostic.cs index a1b5e52..41803b6 100644 --- a/compiler/NubLang/Diagnostics/Diagnostic.cs +++ b/compiler/NubLang/Diagnostics/Diagnostic.cs @@ -249,13 +249,14 @@ public class Diagnostic { return ConsoleColors.Colorize(tokenText, ConsoleColors.BrightWhite); } - case LiteralToken literal: + case StringLiteralToken: + { + return ConsoleColors.Colorize(tokenText, ConsoleColors.Green); + } + case IntLiteralToken: + case FloatLiteralToken: + case BoolLiteralToken: { - if (literal.Kind == LiteralKind.String) - { - return ConsoleColors.Colorize(tokenText, ConsoleColors.Green); - } - return ConsoleColors.Colorize(tokenText, ConsoleColors.Magenta); } case SymbolToken symbolToken: diff --git a/compiler/NubLang/Parsing/Parser.cs b/compiler/NubLang/Parsing/Parser.cs index b909566..0c577ce 100644 --- a/compiler/NubLang/Parsing/Parser.cs +++ b/compiler/NubLang/Parsing/Parser.cs @@ -39,11 +39,11 @@ public sealed class Parser { while (TryExpectSymbol(Symbol.Import)) { - imports.Add(ExpectLiteral(LiteralKind.String).Value); + imports.Add(ExpectStringLiteral().Value); } ExpectSymbol(Symbol.Module); - _moduleName = ExpectLiteral(LiteralKind.String).Value; + _moduleName = ExpectStringLiteral().Value; } catch (ParseException e) { @@ -75,9 +75,9 @@ public sealed class Parser if (TryExpectSymbol(Symbol.Extern)) { - var externSymbol = ExpectLiteral(LiteralKind.String).Value; + var externSymbol = ExpectStringLiteral(); ExpectSymbol(Symbol.Func); - definitions.Add(ParseFunc(startIndex, exported, externSymbol)); + definitions.Add(ParseFunc(startIndex, exported, externSymbol.Value)); continue; } @@ -464,7 +464,10 @@ public sealed class Parser var token = ExpectToken(); var expr = token switch { - LiteralToken literal => new LiteralSyntax(GetTokens(startIndex), literal.Value, literal.Kind), + BoolLiteralToken boolLiteral => new BoolLiteralSyntax(GetTokens(startIndex), boolLiteral.Value), + StringLiteralToken stringLiteral => new StringLiteralSyntax(GetTokens(startIndex), stringLiteral.Value), + FloatLiteralToken floatLiteral => new FloatLiteralSyntax(GetTokens(startIndex), floatLiteral.Value), + IntLiteralToken intLiteral => new IntLiteralSyntax(GetTokens(startIndex), intLiteral.Value, intLiteral.Base), IdentifierToken identifier => ParseIdentifier(startIndex, identifier), SymbolToken symbolToken => symbolToken.Symbol switch { @@ -920,14 +923,14 @@ public sealed class Parser return identifier; } - private LiteralToken ExpectLiteral() + private IntLiteralToken ExpectIntLiteral() { var token = ExpectToken(); - if (token is not LiteralToken identifier) + if (token is not IntLiteralToken identifier) { throw new ParseException(Diagnostic - .Error($"Expected literal, but found {token.GetType().Name}") - .WithHelp("Provide a valid literal name here") + .Error($"Expected int literal, but found {token.GetType().Name}") + .WithHelp("Provide a valid int literal") .At(token) .Build()); } @@ -935,19 +938,49 @@ public sealed class Parser return identifier; } - private LiteralToken ExpectLiteral(LiteralKind kind) + private FloatLiteralToken ExpectFloatLiteral() { - var literal = ExpectLiteral(); - if (literal.Kind != kind) + var token = ExpectToken(); + if (token is not FloatLiteralToken identifier) { throw new ParseException(Diagnostic - .Error($"Expected {kind} literal, but found {literal.Kind}") - .WithHelp($"Provide a {kind} literal name here") - .At(literal) + .Error($"Expected float literal, but found {token.GetType().Name}") + .WithHelp("Provide a valid float literal") + .At(token) .Build()); } - return literal; + return identifier; + } + + private BoolLiteralToken ExpectBoolLiteral() + { + var token = ExpectToken(); + if (token is not BoolLiteralToken identifier) + { + throw new ParseException(Diagnostic + .Error($"Expected bool literal, but found {token.GetType().Name}") + .WithHelp("Provide a valid bool literal") + .At(token) + .Build()); + } + + return identifier; + } + + private StringLiteralToken ExpectStringLiteral() + { + var token = ExpectToken(); + if (token is not StringLiteralToken identifier) + { + throw new ParseException(Diagnostic + .Error($"Expected string literal, but found {token.GetType().Name}") + .WithHelp("Provide a valid string literal") + .At(token) + .Build()); + } + + return identifier; } private void Next() diff --git a/compiler/NubLang/Parsing/Syntax/ExpressionSyntax.cs b/compiler/NubLang/Parsing/Syntax/ExpressionSyntax.cs index 9acc77b..3d5bbfe 100644 --- a/compiler/NubLang/Parsing/Syntax/ExpressionSyntax.cs +++ b/compiler/NubLang/Parsing/Syntax/ExpressionSyntax.cs @@ -50,7 +50,13 @@ public record ArrayIndexAccessSyntax(List Tokens, ExpressionSyntax Target public record AddressOfSyntax(List Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens); -public record LiteralSyntax(List Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens); +public record IntLiteralSyntax(List Tokens, string Value, int Base) : ExpressionSyntax(Tokens); + +public record StringLiteralSyntax(List Tokens, string Value) : ExpressionSyntax(Tokens); + +public record BoolLiteralSyntax(List Tokens, bool Value) : ExpressionSyntax(Tokens); + +public record FloatLiteralSyntax(List Tokens, string Value) : ExpressionSyntax(Tokens); public record MemberAccessSyntax(List Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens); diff --git a/compiler/NubLang/Tokenization/Token.cs b/compiler/NubLang/Tokenization/Token.cs index 2c16999..86d7fd5 100644 --- a/compiler/NubLang/Tokenization/Token.cs +++ b/compiler/NubLang/Tokenization/Token.cs @@ -2,16 +2,6 @@ namespace NubLang.Tokenization; -public enum LiteralKind -{ - Integer, - Hex, - Binary, - Float, - String, - Bool -} - public enum Symbol { Func, @@ -69,6 +59,12 @@ public abstract record Token(string FileName, SourceSpan Span); public record IdentifierToken(string FileName, SourceSpan Span, string Value) : Token(FileName, Span); -public record LiteralToken(string FileName, SourceSpan Span, LiteralKind Kind, string Value) : Token(FileName, Span); +public record IntLiteralToken(string FileName, SourceSpan Span, string Value, int Base) : Token(FileName, Span); + +public record StringLiteralToken(string FileName, SourceSpan Span, string Value) : Token(FileName, Span); + +public record BoolLiteralToken(string FileName, SourceSpan Span, bool Value) : Token(FileName, Span); + +public record FloatLiteralToken(string FileName, SourceSpan Span, string Value) : Token(FileName, Span); public record SymbolToken(string FileName, SourceSpan Span, Symbol Symbol) : Token(FileName, Span); \ No newline at end of file diff --git a/compiler/NubLang/Tokenization/Tokenizer.cs b/compiler/NubLang/Tokenization/Tokenizer.cs index 354ec74..c7801ec 100644 --- a/compiler/NubLang/Tokenization/Tokenizer.cs +++ b/compiler/NubLang/Tokenization/Tokenizer.cs @@ -148,7 +148,7 @@ public sealed class Tokenizer if (buffer is "true" or "false") { - return new LiteralToken(_fileName, CreateSpan(lineStart, columnStart), LiteralKind.Bool, buffer); + return new BoolLiteralToken(_fileName, CreateSpan(lineStart, columnStart), Convert.ToBoolean(buffer)); } return new IdentifierToken(_fileName, CreateSpan(lineStart, columnStart), buffer); @@ -156,7 +156,6 @@ public sealed class Tokenizer if (char.IsDigit(current)) { - var isFloat = false; var buffer = string.Empty; if (current == '0' && Peek(1) is 'x') @@ -178,7 +177,7 @@ public sealed class Tokenizer .Build()); } - return new LiteralToken(_fileName, CreateSpan(lineStart, columnStart), LiteralKind.Hex, buffer); + return new IntLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer, 16); } if (current == '0' && Peek(1) is 'b') @@ -200,10 +199,10 @@ public sealed class Tokenizer .Build()); } - return new LiteralToken(_fileName, CreateSpan(lineStart, columnStart), LiteralKind.Binary, buffer); + return new IntLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer, 2); } - buffer += current; + var isFloat = false; while (Peek() != null) { var next = Peek()!.Value; @@ -232,12 +231,14 @@ public sealed class Tokenizer } } - return new LiteralToken( - _fileName, - CreateSpan(lineStart, columnStart), - isFloat ? LiteralKind.Float : LiteralKind.Integer, - buffer - ); + if (isFloat) + { + return new FloatLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer); + } + else + { + return new IntLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer, 10); + } } if (current == '"') @@ -272,7 +273,7 @@ public sealed class Tokenizer Next(); } - return new LiteralToken(_fileName, CreateSpan(lineStart, columnStart), LiteralKind.String, buffer); + return new StringLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer); } foreach (var (pattern, symbol) in OrderedSymbols) diff --git a/compiler/NubLang/TypeChecking/TypeChecker.cs b/compiler/NubLang/TypeChecking/TypeChecker.cs index 37c9d76..bb760f4 100644 --- a/compiler/NubLang/TypeChecking/TypeChecker.cs +++ b/compiler/NubLang/TypeChecking/TypeChecker.cs @@ -1,9 +1,7 @@ using System.Diagnostics; -using System.Globalization; using NubLang.Diagnostics; using NubLang.Modules; using NubLang.Parsing.Syntax; -using NubLang.Tokenization; using NubLang.TypeChecking.Node; namespace NubLang.TypeChecking; @@ -339,7 +337,10 @@ public sealed class TypeChecker FuncCallSyntax expression => CheckFuncCall(expression), LocalIdentifierSyntax expression => CheckLocalIdentifier(expression), ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression), - LiteralSyntax expression => CheckLiteral(expression, expectedType), + BoolLiteralSyntax expression => CheckBoolLiteral(expression), + StringLiteralSyntax expression => CheckStringLiteral(expression, expectedType), + IntLiteralSyntax expression => CheckIntLiteral(expression, expectedType), + FloatLiteralSyntax expression => CheckFloatLiteral(expression, expectedType), MemberAccessSyntax expression => CheckMemberAccess(expression), StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType), InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) }, @@ -766,81 +767,50 @@ public sealed class TypeChecker .Build()); } - private ExpressionNode CheckLiteral(LiteralSyntax expression, NubType? expectedType) + private ExpressionNode CheckStringLiteral(StringLiteralSyntax expression, NubType? expectedType) { - switch (expression.Kind) + return expectedType switch { - case LiteralKind.Integer: - { - if (expectedType is NubIntType intType) - { - return intType.Signed - ? new IntLiteralNode(intType, long.Parse(expression.Value)) - : new UIntLiteralNode(intType, ulong.Parse(expression.Value)); - } + NubCStringType => new CStringLiteralNode(expectedType, expression.Value), + NubStringType => new StringLiteralNode(expectedType, expression.Value), + _ => new CStringLiteralNode(new NubCStringType(), expression.Value) + }; + } - if (expectedType is NubFloatType floatType) - { - return floatType.Width switch - { - 32 => new Float32LiteralNode(floatType, float.Parse(expression.Value, CultureInfo.InvariantCulture)), - 64 => new Float64LiteralNode(floatType, double.Parse(expression.Value, CultureInfo.InvariantCulture)), - _ => throw new ArgumentOutOfRangeException() - }; - } - - var type = new NubIntType(true, 64); - return new IntLiteralNode(type, long.Parse(expression.Value)); - } - case LiteralKind.Float: - { - var type = expectedType as NubFloatType ?? new NubFloatType(64); - return type.Width == 32 - ? new Float32LiteralNode(type, float.Parse(expression.Value, CultureInfo.InvariantCulture)) - : new Float64LiteralNode(type, double.Parse(expression.Value, CultureInfo.InvariantCulture)); - } - case LiteralKind.Hex: - { - if (expectedType is NubIntType intType) - { - return intType.Signed - ? new IntLiteralNode(intType, Convert.ToInt64(expression.Value, 16)) - : new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value, 16)); - } - - var type = new NubIntType(true, 64); - return new IntLiteralNode(type, Convert.ToInt64(expression.Value, 16)); - } - case LiteralKind.Binary: - { - if (expectedType is NubIntType intType) - { - return intType.Signed - ? new IntLiteralNode(intType, Convert.ToInt64(expression.Value[2..], 2)) - : new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value[2..], 2)); - } - - var type = new NubIntType(true, 64); - return new IntLiteralNode(type, Convert.ToInt64(expression.Value.Substring(2), 2)); - } - case LiteralKind.String: - { - return expectedType switch - { - NubCStringType => new CStringLiteralNode(expectedType, expression.Value), - NubStringType => new StringLiteralNode(expectedType, expression.Value), - _ => new CStringLiteralNode(new NubCStringType(), expression.Value) - }; - } - case LiteralKind.Bool: - { - return new BoolLiteralNode(new NubBoolType(), bool.Parse(expression.Value)); - } - default: - { - throw new ArgumentOutOfRangeException(nameof(expression.Kind), $"Unknown literal kind: {expression.Kind}"); - } + private ExpressionNode CheckIntLiteral(IntLiteralSyntax expression, NubType? expectedType) + { + if (expectedType is NubIntType intType) + { + return intType.Signed + ? new IntLiteralNode(intType, Convert.ToInt64(expression.Value, expression.Base)) + : new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value, expression.Base)); } + + if (expectedType is NubFloatType floatType) + { + return floatType.Width switch + { + 32 => new Float32LiteralNode(floatType, Convert.ToSingle(Convert.ToInt64(expression.Value, expression.Base))), + 64 => new Float64LiteralNode(floatType, Convert.ToDouble(Convert.ToInt64(expression.Value, expression.Base))), + _ => throw new ArgumentOutOfRangeException() + }; + } + + var type = new NubIntType(true, 64); + return new IntLiteralNode(type, Convert.ToInt64(expression.Value, expression.Base)); + } + + private ExpressionNode CheckFloatLiteral(FloatLiteralSyntax expression, NubType? expectedType) + { + var type = expectedType as NubFloatType ?? new NubFloatType(64); + return type.Width == 32 + ? new Float32LiteralNode(type, Convert.ToSingle(expression.Value)) + : new Float64LiteralNode(type, Convert.ToDouble(expression.Value)); + } + + private BoolLiteralNode CheckBoolLiteral(BoolLiteralSyntax expression) + { + return new BoolLiteralNode(new NubBoolType(), expression.Value); } private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression)