casting
This commit is contained in:
@@ -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();
|
||||
|
||||
7
src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs
Normal file
7
src/compiler/Nub.Lang/Frontend/Parsing/CastNode.cs
Normal 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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user