pointers kinda works
This commit is contained in:
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
```nub
|
||||||
|
import c
|
||||||
|
|
||||||
|
global func main(argc: i64, argv: i64) {
|
||||||
|
printf("args: %d, starts at %p\n", argc, argv)
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import c
|
import c
|
||||||
|
|
||||||
global func main(argc: i64, argv: i64) {
|
global func main(argc: i64, argv: i64) {
|
||||||
printf("args: %d, starts at %p\n", argc, argv)
|
x = "TEST"
|
||||||
|
printf("%s\n", ^&x)
|
||||||
|
|
||||||
printf("%s\n", list.text)
|
|
||||||
}
|
}
|
||||||
@@ -73,6 +73,7 @@ public class Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NubStructType:
|
case NubStructType:
|
||||||
|
case NubPointerType:
|
||||||
{
|
{
|
||||||
return "l";
|
return "l";
|
||||||
}
|
}
|
||||||
@@ -118,6 +119,10 @@ public class Generator
|
|||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
return ":" + nubCustomType.Name;
|
||||||
}
|
}
|
||||||
|
case NubPointerType:
|
||||||
|
{
|
||||||
|
return "l";
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -163,6 +168,10 @@ public class Generator
|
|||||||
{
|
{
|
||||||
return ":" + nubCustomType.Name;
|
return ":" + nubCustomType.Name;
|
||||||
}
|
}
|
||||||
|
case NubPointerType:
|
||||||
|
{
|
||||||
|
return "l";
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -208,6 +217,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
throw new Exception($"Cannot determine size of non-existent type {nubCustomType}");
|
throw new Exception($"Cannot determine size of non-existent type {nubCustomType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
|
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -490,6 +500,8 @@ public class Generator
|
|||||||
return GenerateLiteral(literal);
|
return GenerateLiteral(literal);
|
||||||
case StructInitializerNode structInitializer:
|
case StructInitializerNode structInitializer:
|
||||||
return GenerateStructInitializer(structInitializer);
|
return GenerateStructInitializer(structInitializer);
|
||||||
|
case UnaryExpressionNode unaryExpression:
|
||||||
|
return GenerateUnaryExpression(unaryExpression);
|
||||||
case StructFieldAccessorNode structMemberAccessor:
|
case StructFieldAccessorNode structMemberAccessor:
|
||||||
return GenerateStructFieldAccessor(structMemberAccessor);
|
return GenerateStructFieldAccessor(structMemberAccessor);
|
||||||
default:
|
default:
|
||||||
@@ -1239,6 +1251,99 @@ public class Generator
|
|||||||
return $"%{structVar}";
|
return $"%{structVar}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GenerateUnaryExpression(UnaryExpressionNode unaryExpression)
|
||||||
|
{
|
||||||
|
var operand = GenerateExpression(unaryExpression.Operand);
|
||||||
|
var outputLabel = GenName();
|
||||||
|
|
||||||
|
switch (unaryExpression.Operator)
|
||||||
|
{
|
||||||
|
case UnaryExpressionOperator.Negate:
|
||||||
|
{
|
||||||
|
switch (unaryExpression.Operand.Type)
|
||||||
|
{
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =l neg {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =w neg {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =d neg {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =s neg {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.Invert:
|
||||||
|
{
|
||||||
|
switch (unaryExpression.Operand.Type)
|
||||||
|
{
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =w xor {operand}, 1");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.AddressOf:
|
||||||
|
{
|
||||||
|
switch (unaryExpression.Operand.Type)
|
||||||
|
{
|
||||||
|
case NubPointerType:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.String }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U64 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =l alloc8 8");
|
||||||
|
_builder.AppendLine($" storel {operand}, %{outputLabel}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U32 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I16 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U16 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I8 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.U8 }:
|
||||||
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
||||||
|
_builder.AppendLine($" %{outputLabel} =l alloc8 4");
|
||||||
|
_builder.AppendLine($" storew {operand}, %{outputLabel}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.Dereference:
|
||||||
|
{
|
||||||
|
// Handle dereference operator (assuming operand is a pointer)
|
||||||
|
// This would load the value from the address stored in the operand
|
||||||
|
if (unaryExpression.Type is NubPrimitiveType primitiveType)
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" %{outputLabel} ={SQT(primitiveType)} load{SQT(primitiveType)} {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unaryExpression.Type is NubStructType structType)
|
||||||
|
{
|
||||||
|
// For struct types, we'd need to handle differently
|
||||||
|
// This is a simplified version
|
||||||
|
_builder.AppendLine($" %{outputLabel} =l copy {operand}");
|
||||||
|
return $"%{outputLabel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported");
|
||||||
|
}
|
||||||
|
|
||||||
private string GenerateStructFieldAccessor(StructFieldAccessorNode structFieldAccessor)
|
private string GenerateStructFieldAccessor(StructFieldAccessorNode structFieldAccessor)
|
||||||
{
|
{
|
||||||
var structType = structFieldAccessor.Struct.Type;
|
var structType = structFieldAccessor.Struct.Type;
|
||||||
|
|||||||
@@ -359,6 +359,26 @@ public class Parser
|
|||||||
|
|
||||||
return new StructInitializerNode(type, initializers);
|
return new StructInitializerNode(type, initializers);
|
||||||
}
|
}
|
||||||
|
case Symbol.Caret:
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionNode(UnaryExpressionOperator.Dereference, expression);
|
||||||
|
}
|
||||||
|
case Symbol.Ampersand:
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionNode(UnaryExpressionOperator.AddressOf, expression);
|
||||||
|
}
|
||||||
|
case Symbol.Minus:
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionNode(UnaryExpressionOperator.Negate, expression);
|
||||||
|
}
|
||||||
|
case Symbol.Bang:
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionNode(UnaryExpressionOperator.Invert, expression);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Nub.Lang.Frontend.Parsing;
|
||||||
|
|
||||||
|
public class UnaryExpressionNode(UnaryExpressionOperator @operator, ExpressionNode operand) : ExpressionNode
|
||||||
|
{
|
||||||
|
public UnaryExpressionOperator Operator { get; } = @operator;
|
||||||
|
public ExpressionNode Operand { get; } = operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UnaryExpressionOperator
|
||||||
|
{
|
||||||
|
AddressOf,
|
||||||
|
Dereference,
|
||||||
|
Negate,
|
||||||
|
Invert
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@ namespace Nub.Lang.Frontend.Typing;
|
|||||||
|
|
||||||
public class TypeCheckingException : Exception
|
public class TypeCheckingException : Exception
|
||||||
{
|
{
|
||||||
public TypeCheckingException(string message) : base(message) { }
|
public TypeCheckingException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TypeChecker
|
public class TypeChecker
|
||||||
@@ -119,6 +121,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{explicitType}'");
|
throw new TypeCheckingException($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{explicitType}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
_variables[varAssign.Name] = explicitType;
|
_variables[varAssign.Name] = explicitType;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -248,6 +251,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Variable '{identifier.Identifier}' is not defined");
|
throw new TypeCheckingException($"Variable '{identifier.Identifier}' is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
resultType = varType;
|
resultType = varType;
|
||||||
break;
|
break;
|
||||||
case BinaryExpressionNode binaryExpr:
|
case BinaryExpressionNode binaryExpr:
|
||||||
@@ -262,6 +266,9 @@ public class TypeChecker
|
|||||||
case StructInitializerNode structInit:
|
case StructInitializerNode structInit:
|
||||||
resultType = TypeCheckStructInitializer(structInit);
|
resultType = TypeCheckStructInitializer(structInit);
|
||||||
break;
|
break;
|
||||||
|
case UnaryExpressionNode unaryExpression:
|
||||||
|
resultType = TypeCheckUnaryExpression(unaryExpression);
|
||||||
|
break;
|
||||||
case StructFieldAccessorNode fieldAccess:
|
case StructFieldAccessorNode fieldAccess:
|
||||||
resultType = TypeCheckStructFieldAccess(fieldAccess);
|
resultType = TypeCheckStructFieldAccess(fieldAccess);
|
||||||
break;
|
break;
|
||||||
@@ -296,6 +303,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Comparison operators require numeric operands, got '{leftType}' and '{rightType}'");
|
throw new TypeCheckingException($"Comparison operators require numeric operands, got '{leftType}' and '{rightType}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return NubPrimitiveType.Bool;
|
return NubPrimitiveType.Bool;
|
||||||
case BinaryExpressionOperator.Plus:
|
case BinaryExpressionOperator.Plus:
|
||||||
case BinaryExpressionOperator.Minus:
|
case BinaryExpressionOperator.Minus:
|
||||||
@@ -305,6 +313,7 @@ public class TypeChecker
|
|||||||
{
|
{
|
||||||
throw new TypeCheckingException($"Arithmetic operators require numeric operands, got '{leftType}' and '{rightType}'");
|
throw new TypeCheckingException($"Arithmetic operators require numeric operands, got '{leftType}' and '{rightType}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return leftType;
|
return leftType;
|
||||||
default:
|
default:
|
||||||
throw new TypeCheckingException($"Unsupported binary operator: {binaryExpr.Operator}");
|
throw new TypeCheckingException($"Unsupported binary operator: {binaryExpr.Operator}");
|
||||||
@@ -367,6 +376,60 @@ public class TypeChecker
|
|||||||
return structType;
|
return structType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private NubType TypeCheckUnaryExpression(UnaryExpressionNode unaryExpression)
|
||||||
|
{
|
||||||
|
var operandType = TypeCheckExpression(unaryExpression.Operand);
|
||||||
|
|
||||||
|
switch (unaryExpression.Operator)
|
||||||
|
{
|
||||||
|
case UnaryExpressionOperator.AddressOf:
|
||||||
|
{
|
||||||
|
if (unaryExpression.Operand is not (IdentifierNode or StructFieldAccessorNode))
|
||||||
|
{
|
||||||
|
throw new TypeCheckingException($"Cannot take the address of {unaryExpression.Operand.GetType().Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NubPointerType(operandType);
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.Dereference:
|
||||||
|
{
|
||||||
|
if (operandType is not NubPointerType nubPointerType)
|
||||||
|
{
|
||||||
|
throw new TypeCheckingException($"Cannot dereference a non-pointer type {operandType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return nubPointerType.BaseType;
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.Negate:
|
||||||
|
{
|
||||||
|
if (operandType.Equals(NubPrimitiveType.I8) ||
|
||||||
|
operandType.Equals(NubPrimitiveType.I16) ||
|
||||||
|
operandType.Equals(NubPrimitiveType.I32) ||
|
||||||
|
operandType.Equals(NubPrimitiveType.I64) ||
|
||||||
|
operandType.Equals(NubPrimitiveType.F32) ||
|
||||||
|
operandType.Equals(NubPrimitiveType.F64))
|
||||||
|
{
|
||||||
|
return operandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeCheckingException($"Cannot negate non-numeric type {operandType}");
|
||||||
|
}
|
||||||
|
case UnaryExpressionOperator.Invert:
|
||||||
|
{
|
||||||
|
if (!operandType.Equals(NubPrimitiveType.Bool))
|
||||||
|
{
|
||||||
|
throw new TypeCheckingException($"Cannot invert non-boolean type {operandType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return operandType;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private NubType TypeCheckStructFieldAccess(StructFieldAccessorNode fieldAccess)
|
private NubType TypeCheckStructFieldAccess(StructFieldAccessorNode fieldAccess)
|
||||||
{
|
{
|
||||||
var structType = TypeCheckExpression(fieldAccess.Struct);
|
var structType = TypeCheckExpression(fieldAccess.Struct);
|
||||||
|
|||||||
@@ -28,6 +28,22 @@ public abstract class NubType
|
|||||||
|
|
||||||
public class NubStructType(string name) : NubType(name);
|
public class NubStructType(string name) : NubType(name);
|
||||||
|
|
||||||
|
public class NubPointerType(NubType baseType) : NubType("^" + baseType)
|
||||||
|
{
|
||||||
|
public NubType BaseType { get; } = baseType;
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is NubPointerType other)
|
||||||
|
{
|
||||||
|
return BaseType.Equals(other.BaseType);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => BaseType.GetHashCode() * 31;
|
||||||
|
}
|
||||||
|
|
||||||
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType(KindToString(kind))
|
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType(KindToString(kind))
|
||||||
{
|
{
|
||||||
public PrimitiveTypeKind Kind { get; } = kind;
|
public PrimitiveTypeKind Kind { get; } = kind;
|
||||||
|
|||||||
Reference in New Issue
Block a user