...
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user