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);
}
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:

View File

@@ -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()

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 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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)