This commit is contained in:
nub31
2025-05-16 23:39:57 +02:00
parent 5a6c56c5c2
commit 1371e95b76
4 changed files with 144 additions and 110 deletions

View File

@@ -478,6 +478,8 @@ public class Generator
{
case BinaryExpressionNode binaryExpression:
return GenerateBinaryExpression(binaryExpression);
case CastNode cast:
return GenerateCast(cast);
case FuncCallExpressionNode funcCallExpression:
return GenerateExpressionFuncCall(funcCallExpression);
case IdentifierNode identifier:
@@ -493,44 +495,6 @@ public class Generator
}
}
private string GenerateStructFieldAccessor(StructFieldAccessorNode structFieldAccessor)
{
var structType = structFieldAccessor.Struct.Type;
var structDefinition = _definitions
.OfType<StructDefinitionNode>()
.FirstOrDefault(s => s.Name == structType.Name);
if (structDefinition == null)
{
throw new Exception($"Struct {structType.Name} is not defined");
}
var @struct = GenerateExpression(structFieldAccessor.Struct);
var fieldIndex = -1;
for (var i = 0; i < structDefinition.Fields.Count; i++)
{
if (structDefinition.Fields[i].Name == structFieldAccessor.Field)
{
fieldIndex = i;
break;
}
}
if (fieldIndex == -1)
{
throw new Exception($"Field {structFieldAccessor.Field} is not defined in struct {structType.Name}");
}
var offsetLabel = GenName("offset");
_builder.AppendLine($" %{offsetLabel} =l add {@struct}, {fieldIndex * QbeTypeSize(structFieldAccessor.Type)}");
var outputLabel = GenName("field");
_builder.AppendLine($" %{outputLabel} ={SQT(structFieldAccessor.Type)} load{SQT(structFieldAccessor.Type)} %{offsetLabel}");
return $"%{outputLabel}";
}
private string GenerateBinaryExpression(BinaryExpressionNode binaryExpression)
{
var left = GenerateExpression(binaryExpression.Left);
@@ -757,41 +721,12 @@ public class Generator
throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types left: {binaryExpression.Left.Type}, right: {binaryExpression.Right.Type} not supported");
}
private string GenerateIdentifier(IdentifierNode identifier)
{
return _variables[identifier.Identifier].Identifier;
}
private string GenerateLiteral(LiteralNode literal)
{
if (literal.LiteralType.Equals(NubPrimitiveType.String))
{
_strings.Add(literal.Literal);
return $"$str{_strings.Count}";
}
if (literal.LiteralType.Equals(NubPrimitiveType.I64))
{
return literal.Literal;
}
if (literal.LiteralType.Equals(NubPrimitiveType.F64))
{
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
var bits = BitConverter.DoubleToInt64Bits(value);
return bits.ToString();
}
if (literal.LiteralType.Equals(NubPrimitiveType.Bool))
{
return bool.Parse(literal.Literal) ? "1" : "0";
}
throw new NotSupportedException($"Literal {literal.LiteralType} is not supported");
}
private string GenerateTypeConversion(string input, NubType inputType, NubType outputType)
private string GenerateCast(CastNode cast)
{
var input = GenerateExpression(cast.Expression);
var outputType = cast.TargetType;
var inputType = cast.Expression.Type;
if (inputType.Equals(outputType) || outputType.Equals(NubPrimitiveType.Any))
{
return input;
@@ -1107,6 +1042,39 @@ public class Generator
}
}
private string GenerateIdentifier(IdentifierNode identifier)
{
return _variables[identifier.Identifier].Identifier;
}
private string GenerateLiteral(LiteralNode literal)
{
if (literal.LiteralType.Equals(NubPrimitiveType.String))
{
_strings.Add(literal.Literal);
return $"$str{_strings.Count}";
}
if (literal.LiteralType.Equals(NubPrimitiveType.I64))
{
return literal.Literal;
}
if (literal.LiteralType.Equals(NubPrimitiveType.F64))
{
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
var bits = BitConverter.DoubleToInt64Bits(value);
return bits.ToString();
}
if (literal.LiteralType.Equals(NubPrimitiveType.Bool))
{
return bool.Parse(literal.Literal) ? "1" : "0";
}
throw new NotSupportedException($"Literal {literal.LiteralType} is not supported");
}
private string GenerateStructInitializer(StructInitializerNode structInitializer)
{
var structDefinition = _definitions.OfType<StructDefinitionNode>()
@@ -1149,6 +1117,44 @@ public class Generator
return $"%{structVar}";
}
private string GenerateStructFieldAccessor(StructFieldAccessorNode structFieldAccessor)
{
var structType = structFieldAccessor.Struct.Type;
var structDefinition = _definitions
.OfType<StructDefinitionNode>()
.FirstOrDefault(s => s.Name == structType.Name);
if (structDefinition == null)
{
throw new Exception($"Struct {structType.Name} is not defined");
}
var @struct = GenerateExpression(structFieldAccessor.Struct);
var fieldIndex = -1;
for (var i = 0; i < structDefinition.Fields.Count; i++)
{
if (structDefinition.Fields[i].Name == structFieldAccessor.Field)
{
fieldIndex = i;
break;
}
}
if (fieldIndex == -1)
{
throw new Exception($"Field {structFieldAccessor.Field} is not defined in struct {structType.Name}");
}
var offsetLabel = GenName("offset");
_builder.AppendLine($" %{offsetLabel} =l add {@struct}, {fieldIndex * QbeTypeSize(structFieldAccessor.Type)}");
var outputLabel = GenName("field");
_builder.AppendLine($" %{outputLabel} ={SQT(structFieldAccessor.Type)} load{SQT(structFieldAccessor.Type)} %{offsetLabel}");
return $"%{outputLabel}";
}
private string GenerateExpressionFuncCall(FuncCallExpressionNode funcCall)
{
var outputLabel = GenName();

View File

@@ -0,0 +1,7 @@
namespace Nub.Lang.Frontend.Parsing;
public class CastNode(NubType targetType, ExpressionNode expression) : ExpressionNode
{
public NubType TargetType { get; } = targetType;
public ExpressionNode Expression { get; } = expression;
}

View File

@@ -304,53 +304,70 @@ public class Parser
}
private ExpressionNode ParsePrimaryExpression()
{
var token = ExpectToken();
switch (token)
{
var token = ExpectToken();
switch (token)
case LiteralToken literal:
{
case LiteralToken literal:
return new LiteralNode(literal.Value, literal.Type);
}
case IdentifierToken identifier:
{
return ParseExpressionIdentifier(identifier);
}
case SymbolToken symbolToken:
{
switch (symbolToken.Symbol)
{
return new LiteralNode(literal.Value, literal.Type);
}
case IdentifierToken identifier:
{
return ParseExpressionIdentifier(identifier);
}
case SymbolToken symbolToken:
{
switch (symbolToken.Symbol)
case Symbol.OpenParen:
{
case Symbol.OpenParen:
// This is ugly
var nextToken = Peek();
if (nextToken is { Value: IdentifierToken })
{
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;
}
case Symbol.New:
{
var type = ParseType();
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
var startIndex = _index;
var identifierToken = ExpectIdentifier();
var type = NubType.Parse(identifierToken.Value);
if (TryExpectSymbol(Symbol.CloseParen))
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
var expressionToCast = ParsePrimaryExpression();
return new CastNode(type, expressionToCast);
}
return new StructInitializerNode(type, initializers);
_index = startIndex;
}
default:
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;
}
case Symbol.New:
{
var type = ParseType();
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
}
return new StructInitializerNode(type, initializers);
}
default:
{
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
}
}
default:
throw new Exception($"Unexpected token type {token.GetType().Name}");
}
default:
throw new Exception($"Unexpected token type {token.GetType().Name}");
}
}
private ExpressionNode ParseExpressionIdentifier(IdentifierToken identifier)
{

View File

@@ -245,7 +245,6 @@ public class TypeChecker
case LiteralNode literal:
resultType = literal.LiteralType;
break;
case IdentifierNode identifier:
if (!_variables.TryGetValue(identifier.Identifier, out var varType))
{
@@ -253,23 +252,21 @@ public class TypeChecker
}
resultType = varType;
break;
case BinaryExpressionNode binaryExpr:
resultType = TypeCheckBinaryExpression(binaryExpr);
break;
case CastNode cast:
resultType = TypeCheckCast(cast);
break;
case FuncCallExpressionNode funcCallExpr:
resultType = TypeCheckFuncCall(funcCallExpr.FuncCall);
break;
case StructInitializerNode structInit:
resultType = TypeCheckStructInitializer(structInit);
break;
case StructFieldAccessorNode fieldAccess:
resultType = TypeCheckStructFieldAccess(fieldAccess);
break;
default:
throw new TypeCheckingException($"Unsupported expression type: {expression.GetType().Name}");
}
@@ -316,6 +313,13 @@ public class TypeChecker
}
}
private NubType TypeCheckCast(CastNode cast)
{
TypeCheckExpression(cast.Expression);
// TODO: Check if castable
return cast.TargetType;
}
private NubType TypeCheckStructInitializer(StructInitializerNode structInit)
{
var structType = structInit.StructType;