pointers kinda works

This commit is contained in:
nub31
2025-05-17 18:22:23 +02:00
parent 942b38992b
commit 97611317f7
7 changed files with 240 additions and 16 deletions

7
README.md Normal file
View File

@@ -0,0 +1,7 @@
```nub
import c
global func main(argc: i64, argv: i64) {
printf("args: %d, starts at %p\n", argc, argv)
}
```

View File

@@ -1,8 +1,6 @@
import c
global func main(argc: i64, argv: i64) {
printf("args: %d, starts at %p\n", argc, argv)
printf("%s\n", list.text)
x = "TEST"
printf("%s\n", ^&x)
}

View File

@@ -73,6 +73,7 @@ public class Generator
}
}
case NubStructType:
case NubPointerType:
{
return "l";
}
@@ -118,6 +119,10 @@ public class Generator
{
return ":" + nubCustomType.Name;
}
case NubPointerType:
{
return "l";
}
default:
{
throw new NotImplementedException();
@@ -163,6 +168,10 @@ public class Generator
{
return ":" + nubCustomType.Name;
}
case NubPointerType:
{
return "l";
}
default:
{
throw new NotImplementedException();
@@ -208,6 +217,7 @@ public class Generator
{
throw new Exception($"Cannot determine size of non-existent type {nubCustomType}");
}
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
}
default:
@@ -490,6 +500,8 @@ public class Generator
return GenerateLiteral(literal);
case StructInitializerNode structInitializer:
return GenerateStructInitializer(structInitializer);
case UnaryExpressionNode unaryExpression:
return GenerateUnaryExpression(unaryExpression);
case StructFieldAccessorNode structMemberAccessor:
return GenerateStructFieldAccessor(structMemberAccessor);
default:
@@ -1239,6 +1251,99 @@ public class Generator
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)
{
var structType = structFieldAccessor.Struct.Type;

View File

@@ -359,6 +359,26 @@ public class Parser
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:
{
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");

View File

@@ -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
}

View File

@@ -4,7 +4,9 @@ namespace Nub.Lang.Frontend.Typing;
public class TypeCheckingException : Exception
{
public TypeCheckingException(string message) : base(message) { }
public TypeCheckingException(string message) : base(message)
{
}
}
public class TypeChecker
@@ -25,7 +27,7 @@ public class TypeChecker
{
TypeCheckStructDef(structDef);
}
foreach (var funcDef in _definitions.OfType<LocalFuncDefinitionNode>())
{
TypeCheckFuncDef(funcDef);
@@ -49,7 +51,7 @@ public class TypeChecker
throw new TypeCheckingException("Default field initializer does not match the defined type");
}
}
fields[field.Name] = field.Type;
}
}
@@ -111,7 +113,7 @@ public class TypeChecker
private void TypeCheckVariableAssignment(VariableAssignmentNode varAssign)
{
var valueType = TypeCheckExpression(varAssign.Value);
if (varAssign.ExplicitType.HasValue)
{
var explicitType = varAssign.ExplicitType.Value;
@@ -119,6 +121,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{explicitType}'");
}
_variables[varAssign.Name] = explicitType;
}
else
@@ -144,7 +147,7 @@ public class TypeChecker
parameters = externFuncDef.Parameters;
returnType = externFuncDef.ReturnType;
}
else
{
throw new TypeCheckingException($"Function '{funcCall.Name}' is not defined");
@@ -154,7 +157,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Function '{funcCall.Name}' has multiple variadic parameters");
}
for (var i = 0; i < funcCall.Parameters.Count; i++)
{
var argType = TypeCheckExpression(funcCall.Parameters[i]);
@@ -172,7 +175,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Function '{funcCall.Name}' does not take {funcCall.Parameters.Count} parameters");
}
if (!AreTypesCompatible(argType, paramType))
{
throw new TypeCheckingException($"Parameter {i} of function '{funcCall.Name}' expects type '{paramType}', but got '{argType}'");
@@ -217,12 +220,12 @@ public class TypeChecker
if (returnNode.Value.HasValue)
{
var returnType = TypeCheckExpression(returnNode.Value.Value);
if (_currentFunctionReturnType == null)
{
throw new TypeCheckingException("Cannot return a value from a function with no return type");
}
if (!AreTypesCompatible(returnType, _currentFunctionReturnType))
{
throw new TypeCheckingException($"Return value of type '{returnType}' is not compatible with function return type '{_currentFunctionReturnType}'");
@@ -248,6 +251,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Variable '{identifier.Identifier}' is not defined");
}
resultType = varType;
break;
case BinaryExpressionNode binaryExpr:
@@ -262,6 +266,9 @@ public class TypeChecker
case StructInitializerNode structInit:
resultType = TypeCheckStructInitializer(structInit);
break;
case UnaryExpressionNode unaryExpression:
resultType = TypeCheckUnaryExpression(unaryExpression);
break;
case StructFieldAccessorNode fieldAccess:
resultType = TypeCheckStructFieldAccess(fieldAccess);
break;
@@ -296,6 +303,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Comparison operators require numeric operands, got '{leftType}' and '{rightType}'");
}
return NubPrimitiveType.Bool;
case BinaryExpressionOperator.Plus:
case BinaryExpressionOperator.Minus:
@@ -305,6 +313,7 @@ public class TypeChecker
{
throw new TypeCheckingException($"Arithmetic operators require numeric operands, got '{leftType}' and '{rightType}'");
}
return leftType;
default:
throw new TypeCheckingException($"Unsupported binary operator: {binaryExpr.Operator}");
@@ -321,7 +330,7 @@ public class TypeChecker
private NubType TypeCheckStructInitializer(StructInitializerNode structInit)
{
var initialized = new HashSet<string>();
var structType = structInit.StructType;
if (structType is not NubStructType customType)
{
@@ -347,10 +356,10 @@ public class TypeChecker
{
throw new TypeCheckingException($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'");
}
initialized.Add(initializer.Key);
}
foreach (var field in definition.Fields.Where(f => f.Value.HasValue))
{
initialized.Add(field.Name);
@@ -367,6 +376,60 @@ public class TypeChecker
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)
{
var structType = TypeCheckExpression(fieldAccess.Struct);

View File

@@ -28,6 +28,22 @@ public abstract class NubType
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 PrimitiveTypeKind Kind { get; } = kind;