From 1371e95b76c150b905f9c467e8f5b85b14308fc8 Mon Sep 17 00:00:00 2001 From: nub31 Date: Fri, 16 May 2025 23:39:57 +0200 Subject: [PATCH] casting --- src/compiler/Nub.Lang/Backend/Generator.cs | 150 +++++++++--------- .../Nub.Lang/Frontend/Parsing/CastNode.cs | 7 + .../Nub.Lang/Frontend/Parsing/Parser.cs | 81 ++++++---- .../Nub.Lang/Frontend/Typing/TypeChecker.cs | 16 +- 4 files changed, 144 insertions(+), 110 deletions(-) create mode 100644 src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs diff --git a/src/compiler/Nub.Lang/Backend/Generator.cs b/src/compiler/Nub.Lang/Backend/Generator.cs index 1885ef3..3b335a7 100644 --- a/src/compiler/Nub.Lang/Backend/Generator.cs +++ b/src/compiler/Nub.Lang/Backend/Generator.cs @@ -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() - .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() @@ -1149,6 +1117,44 @@ public class Generator return $"%{structVar}"; } + private string GenerateStructFieldAccessor(StructFieldAccessorNode structFieldAccessor) + { + var structType = structFieldAccessor.Struct.Type; + var structDefinition = _definitions + .OfType() + .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(); diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs b/src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs new file mode 100644 index 0000000..df0e14e --- /dev/null +++ b/src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs @@ -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; +} \ No newline at end of file diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs index 952efed..ce52b19 100644 --- a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs @@ -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 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 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) { diff --git a/src/compiler/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/compiler/Nub.Lang/Frontend/Typing/TypeChecker.cs index 9dad729..47791e1 100644 --- a/src/compiler/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/compiler/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -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;