This commit is contained in:
nub31
2025-05-16 23:39:57 +02:00
parent 5214cec822
commit bc971f7033
4 changed files with 144 additions and 110 deletions

View File

@@ -478,6 +478,8 @@ public class Generator
{ {
case BinaryExpressionNode binaryExpression: case BinaryExpressionNode binaryExpression:
return GenerateBinaryExpression(binaryExpression); return GenerateBinaryExpression(binaryExpression);
case CastNode cast:
return GenerateCast(cast);
case FuncCallExpressionNode funcCallExpression: case FuncCallExpressionNode funcCallExpression:
return GenerateExpressionFuncCall(funcCallExpression); return GenerateExpressionFuncCall(funcCallExpression);
case IdentifierNode identifier: 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) private string GenerateBinaryExpression(BinaryExpressionNode binaryExpression)
{ {
var left = GenerateExpression(binaryExpression.Left); 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"); 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;
}
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)
{ {
var input = GenerateExpression(cast.Expression);
var outputType = cast.TargetType;
var inputType = cast.Expression.Type;
if (inputType.Equals(outputType) || outputType.Equals(NubPrimitiveType.Any)) if (inputType.Equals(outputType) || outputType.Equals(NubPrimitiveType.Any))
{ {
return input; 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) private string GenerateStructInitializer(StructInitializerNode structInitializer)
{ {
var structDefinition = _definitions.OfType<StructDefinitionNode>() var structDefinition = _definitions.OfType<StructDefinitionNode>()
@@ -1149,6 +1117,44 @@ public class Generator
return $"%{structVar}"; 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) private string GenerateExpressionFuncCall(FuncCallExpressionNode funcCall)
{ {
var outputLabel = GenName(); 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() private ExpressionNode ParsePrimaryExpression()
{
var token = ExpectToken();
switch (token)
{ {
var token = ExpectToken(); case LiteralToken literal:
switch (token)
{ {
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 Symbol.OpenParen:
}
case IdentifierToken identifier:
{
return ParseExpressionIdentifier(identifier);
}
case SymbolToken symbolToken:
{
switch (symbolToken.Symbol)
{ {
case Symbol.OpenParen: // This is ugly
var nextToken = Peek();
if (nextToken is { Value: IdentifierToken })
{ {
var expression = ParseExpression(); var startIndex = _index;
ExpectSymbol(Symbol.CloseParen); var identifierToken = ExpectIdentifier();
return expression; var type = NubType.Parse(identifierToken.Value);
}
case Symbol.New: if (TryExpectSymbol(Symbol.CloseParen))
{
var type = ParseType();
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{ {
var name = ExpectIdentifier().Value; var expressionToCast = ParsePrimaryExpression();
ExpectSymbol(Symbol.Assign); return new CastNode(type, expressionToCast);
var value = ParseExpression();
initializers.Add(name, value);
} }
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) private ExpressionNode ParseExpressionIdentifier(IdentifierToken identifier)
{ {

View File

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