This commit is contained in:
nub31
2025-09-29 16:57:25 +02:00
parent 428d69d242
commit 0de84375d3
6 changed files with 127 additions and 120 deletions

View File

@@ -249,13 +249,14 @@ public class Diagnostic
{ {
return ConsoleColors.Colorize(tokenText, ConsoleColors.BrightWhite); 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); return ConsoleColors.Colorize(tokenText, ConsoleColors.Magenta);
} }
case SymbolToken symbolToken: case SymbolToken symbolToken:

View File

@@ -39,11 +39,11 @@ public sealed class Parser
{ {
while (TryExpectSymbol(Symbol.Import)) while (TryExpectSymbol(Symbol.Import))
{ {
imports.Add(ExpectLiteral(LiteralKind.String).Value); imports.Add(ExpectStringLiteral().Value);
} }
ExpectSymbol(Symbol.Module); ExpectSymbol(Symbol.Module);
_moduleName = ExpectLiteral(LiteralKind.String).Value; _moduleName = ExpectStringLiteral().Value;
} }
catch (ParseException e) catch (ParseException e)
{ {
@@ -75,9 +75,9 @@ public sealed class Parser
if (TryExpectSymbol(Symbol.Extern)) if (TryExpectSymbol(Symbol.Extern))
{ {
var externSymbol = ExpectLiteral(LiteralKind.String).Value; var externSymbol = ExpectStringLiteral();
ExpectSymbol(Symbol.Func); ExpectSymbol(Symbol.Func);
definitions.Add(ParseFunc(startIndex, exported, externSymbol)); definitions.Add(ParseFunc(startIndex, exported, externSymbol.Value));
continue; continue;
} }
@@ -464,7 +464,10 @@ public sealed class Parser
var token = ExpectToken(); var token = ExpectToken();
var expr = token switch 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), IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
SymbolToken symbolToken => symbolToken.Symbol switch SymbolToken symbolToken => symbolToken.Symbol switch
{ {
@@ -920,14 +923,14 @@ public sealed class Parser
return identifier; return identifier;
} }
private LiteralToken ExpectLiteral() private IntLiteralToken ExpectIntLiteral()
{ {
var token = ExpectToken(); var token = ExpectToken();
if (token is not LiteralToken identifier) if (token is not IntLiteralToken identifier)
{ {
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error($"Expected literal, but found {token.GetType().Name}") .Error($"Expected int literal, but found {token.GetType().Name}")
.WithHelp("Provide a valid literal name here") .WithHelp("Provide a valid int literal")
.At(token) .At(token)
.Build()); .Build());
} }
@@ -935,19 +938,49 @@ public sealed class Parser
return identifier; return identifier;
} }
private LiteralToken ExpectLiteral(LiteralKind kind) private FloatLiteralToken ExpectFloatLiteral()
{ {
var literal = ExpectLiteral(); var token = ExpectToken();
if (literal.Kind != kind) if (token is not FloatLiteralToken identifier)
{ {
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error($"Expected {kind} literal, but found {literal.Kind}") .Error($"Expected float literal, but found {token.GetType().Name}")
.WithHelp($"Provide a {kind} literal name here") .WithHelp("Provide a valid float literal")
.At(literal) .At(token)
.Build()); .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() private void Next()

View File

@@ -50,7 +50,13 @@ public record ArrayIndexAccessSyntax(List<Token> Tokens, ExpressionSyntax Target
public record AddressOfSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens); public record AddressOfSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record LiteralSyntax(List<Token> Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens); public record IntLiteralSyntax(List<Token> Tokens, string Value, int Base) : ExpressionSyntax(Tokens);
public record StringLiteralSyntax(List<Token> Tokens, string Value) : ExpressionSyntax(Tokens);
public record BoolLiteralSyntax(List<Token> Tokens, bool Value) : ExpressionSyntax(Tokens);
public record FloatLiteralSyntax(List<Token> Tokens, string Value) : ExpressionSyntax(Tokens);
public record MemberAccessSyntax(List<Token> Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens); public record MemberAccessSyntax(List<Token> Tokens, ExpressionSyntax Target, string Member) : ExpressionSyntax(Tokens);

View File

@@ -2,16 +2,6 @@
namespace NubLang.Tokenization; namespace NubLang.Tokenization;
public enum LiteralKind
{
Integer,
Hex,
Binary,
Float,
String,
Bool
}
public enum Symbol public enum Symbol
{ {
Func, 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 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); public record SymbolToken(string FileName, SourceSpan Span, Symbol Symbol) : Token(FileName, Span);

View File

@@ -148,7 +148,7 @@ public sealed class Tokenizer
if (buffer is "true" or "false") 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); return new IdentifierToken(_fileName, CreateSpan(lineStart, columnStart), buffer);
@@ -156,7 +156,6 @@ public sealed class Tokenizer
if (char.IsDigit(current)) if (char.IsDigit(current))
{ {
var isFloat = false;
var buffer = string.Empty; var buffer = string.Empty;
if (current == '0' && Peek(1) is 'x') if (current == '0' && Peek(1) is 'x')
@@ -178,7 +177,7 @@ public sealed class Tokenizer
.Build()); .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') if (current == '0' && Peek(1) is 'b')
@@ -200,10 +199,10 @@ public sealed class Tokenizer
.Build()); .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) while (Peek() != null)
{ {
var next = Peek()!.Value; var next = Peek()!.Value;
@@ -232,12 +231,14 @@ public sealed class Tokenizer
} }
} }
return new LiteralToken( if (isFloat)
_fileName, {
CreateSpan(lineStart, columnStart), return new FloatLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer);
isFloat ? LiteralKind.Float : LiteralKind.Integer, }
buffer else
); {
return new IntLiteralToken(_fileName, CreateSpan(lineStart, columnStart), buffer, 10);
}
} }
if (current == '"') if (current == '"')
@@ -272,7 +273,7 @@ public sealed class Tokenizer
Next(); 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) foreach (var (pattern, symbol) in OrderedSymbols)

View File

@@ -1,9 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using NubLang.Diagnostics; using NubLang.Diagnostics;
using NubLang.Modules; using NubLang.Modules;
using NubLang.Parsing.Syntax; using NubLang.Parsing.Syntax;
using NubLang.Tokenization;
using NubLang.TypeChecking.Node; using NubLang.TypeChecking.Node;
namespace NubLang.TypeChecking; namespace NubLang.TypeChecking;
@@ -339,7 +337,10 @@ public sealed class TypeChecker
FuncCallSyntax expression => CheckFuncCall(expression), FuncCallSyntax expression => CheckFuncCall(expression),
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression), LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
ModuleIdentifierSyntax expression => CheckModuleIdentifier(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), MemberAccessSyntax expression => CheckMemberAccess(expression),
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType), StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) }, InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
@@ -766,81 +767,50 @@ public sealed class TypeChecker
.Build()); .Build());
} }
private ExpressionNode CheckLiteral(LiteralSyntax expression, NubType? expectedType) private ExpressionNode CheckStringLiteral(StringLiteralSyntax expression, NubType? expectedType)
{ {
switch (expression.Kind) return expectedType switch
{ {
case LiteralKind.Integer: NubCStringType => new CStringLiteralNode(expectedType, expression.Value),
{ NubStringType => new StringLiteralNode(expectedType, expression.Value),
if (expectedType is NubIntType intType) _ => new CStringLiteralNode(new NubCStringType(), expression.Value)
{ };
return intType.Signed }
? new IntLiteralNode(intType, long.Parse(expression.Value))
: new UIntLiteralNode(intType, ulong.Parse(expression.Value));
}
if (expectedType is NubFloatType floatType) private ExpressionNode CheckIntLiteral(IntLiteralSyntax expression, NubType? expectedType)
{ {
return floatType.Width switch if (expectedType is NubIntType intType)
{ {
32 => new Float32LiteralNode(floatType, float.Parse(expression.Value, CultureInfo.InvariantCulture)), return intType.Signed
64 => new Float64LiteralNode(floatType, double.Parse(expression.Value, CultureInfo.InvariantCulture)), ? new IntLiteralNode(intType, Convert.ToInt64(expression.Value, expression.Base))
_ => throw new ArgumentOutOfRangeException() : new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value, expression.Base));
};
}
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}");
}
} }
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) private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression)