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)
private string GenerateCast(CastNode cast)
{
return _variables[identifier.Identifier].Identifier;
}
var input = GenerateExpression(cast.Expression);
var outputType = cast.TargetType;
var inputType = cast.Expression.Type;
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)
{
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

@@ -322,6 +322,23 @@ public class Parser
{
case Symbol.OpenParen:
{
// This is ugly
var nextToken = Peek();
if (nextToken is { Value: IdentifierToken })
{
var startIndex = _index;
var identifierToken = ExpectIdentifier();
var type = NubType.Parse(identifierToken.Value);
if (TryExpectSymbol(Symbol.CloseParen))
{
var expressionToCast = ParsePrimaryExpression();
return new CastNode(type, expressionToCast);
}
_index = startIndex;
}
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return expression;

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;