From c76485756144743b1a1976852b9242cc4eb0b7a6 Mon Sep 17 00:00:00 2001 From: nub31 Date: Wed, 29 Oct 2025 18:41:52 +0100 Subject: [PATCH] ... --- compiler/NubLang/Ast/Node.cs | 85 ++++++++++----------- compiler/NubLang/Ast/NubType.cs | 96 ++++++++++++++++++++++-- compiler/NubLang/Ast/TypeChecker.cs | 24 ++---- compiler/NubLang/Ast/TypeResolver.cs | 4 +- compiler/NubLang/Generation/Generator.cs | 2 +- compiler/NubLang/Syntax/Parser.cs | 13 ++-- compiler/NubLang/Syntax/Syntax.cs | 6 +- compiler/NubLang/Syntax/Token.cs | 1 + compiler/NubLang/Syntax/Tokenizer.cs | 1 + compiler/NubLang/Syntax/TypedModule.cs | 2 +- 10 files changed, 154 insertions(+), 80 deletions(-) diff --git a/compiler/NubLang/Ast/Node.cs b/compiler/NubLang/Ast/Node.cs index 4c3a7d6..6dd7656 100644 --- a/compiler/NubLang/Ast/Node.cs +++ b/compiler/NubLang/Ast/Node.cs @@ -112,9 +112,10 @@ public class StructFieldNode(List tokens, IdentifierToken nameToken, NubT } } -public class StructNode(List tokens, IdentifierToken name, NubStructType structType, List fields) : DefinitionNode(tokens, name) +public class StructNode(List tokens, IdentifierToken name, NubStructType structType, bool packed, List fields) : DefinitionNode(tokens, name) { public NubStructType StructType { get; } = structType; + public bool Packed { get; } = packed; public List Fields { get; } = fields; public override IEnumerable Children() @@ -132,8 +133,6 @@ public class StructNode(List tokens, IdentifierToken name, NubStructType public abstract class StatementNode(List tokens) : Node(tokens); -public abstract class TerminalStatementNode(List tokens) : StatementNode(tokens); - public class BlockNode(List tokens, List statements) : StatementNode(tokens) { public List Statements { get; } = statements; @@ -154,7 +153,7 @@ public class StatementFuncCallNode(List tokens, FuncCallNode funcCall) : } } -public class ReturnNode(List tokens, ExpressionNode? value) : TerminalStatementNode(tokens) +public class ReturnNode(List tokens, ExpressionNode? value) : StatementNode(tokens) { public ExpressionNode? Value { get; } = value; @@ -164,9 +163,9 @@ public class ReturnNode(List tokens, ExpressionNode? value) : TerminalSta } } -public class AssignmentNode(List tokens, LValueExpressionNode target, ExpressionNode value) : StatementNode(tokens) +public class AssignmentNode(List tokens, ExpressionNode target, ExpressionNode value) : StatementNode(tokens) { - public LValueExpressionNode Target { get; } = target; + public ExpressionNode Target { get; } = target; public ExpressionNode Value { get; } = value; public override IEnumerable Children() @@ -205,7 +204,7 @@ public class VariableDeclarationNode(List tokens, IdentifierToken nameTok } } -public class ContinueNode(List tokens) : TerminalStatementNode(tokens) +public class ContinueNode(List tokens) : StatementNode(tokens) { public override IEnumerable Children() { @@ -213,7 +212,7 @@ public class ContinueNode(List tokens) : TerminalStatementNode(tokens) } } -public class BreakNode(List tokens) : TerminalStatementNode(tokens) +public class BreakNode(List tokens) : StatementNode(tokens) { public override IEnumerable Children() { @@ -308,13 +307,7 @@ public abstract class ExpressionNode(List tokens, NubType type) : Node(to public NubType Type { get; } = type; } -public abstract class LValueExpressionNode(List tokens, NubType type) : ExpressionNode(tokens, type); - -public abstract class RValueExpressionNode(List tokens, NubType type) : ExpressionNode(tokens, type); - -public abstract class IntermediateExpression(List tokens) : ExpressionNode(tokens, new NubVoidType()); - -public class StringLiteralNode(List tokens, string value) : RValueExpressionNode(tokens, new NubStringType()) +public class StringLiteralNode(List tokens, string value) : ExpressionNode(tokens, new NubStringType()) { public string Value { get; } = value; @@ -324,7 +317,7 @@ public class StringLiteralNode(List tokens, string value) : RValueExpress } } -public class CStringLiteralNode(List tokens, string value) : RValueExpressionNode(tokens, new NubPointerType(new NubIntType(true, 8))) +public class CStringLiteralNode(List tokens, string value) : ExpressionNode(tokens, new NubPointerType(new NubIntType(true, 8))) { public string Value { get; } = value; @@ -334,7 +327,7 @@ public class CStringLiteralNode(List tokens, string value) : RValueExpres } } -public class I8LiteralNode(List tokens, sbyte value) : RValueExpressionNode(tokens, new NubIntType(true, 8)) +public class I8LiteralNode(List tokens, sbyte value) : ExpressionNode(tokens, new NubIntType(true, 8)) { public sbyte Value { get; } = value; @@ -344,7 +337,7 @@ public class I8LiteralNode(List tokens, sbyte value) : RValueExpressionNo } } -public class I16LiteralNode(List tokens, short value) : RValueExpressionNode(tokens, new NubIntType(true, 16)) +public class I16LiteralNode(List tokens, short value) : ExpressionNode(tokens, new NubIntType(true, 16)) { public short Value { get; } = value; @@ -354,7 +347,7 @@ public class I16LiteralNode(List tokens, short value) : RValueExpressionN } } -public class I32LiteralNode(List tokens, int value) : RValueExpressionNode(tokens, new NubIntType(true, 32)) +public class I32LiteralNode(List tokens, int value) : ExpressionNode(tokens, new NubIntType(true, 32)) { public int Value { get; } = value; @@ -364,7 +357,7 @@ public class I32LiteralNode(List tokens, int value) : RValueExpressionNod } } -public class I64LiteralNode(List tokens, long value) : RValueExpressionNode(tokens, new NubIntType(true, 64)) +public class I64LiteralNode(List tokens, long value) : ExpressionNode(tokens, new NubIntType(true, 64)) { public long Value { get; } = value; @@ -374,7 +367,7 @@ public class I64LiteralNode(List tokens, long value) : RValueExpressionNo } } -public class U8LiteralNode(List tokens, byte value) : RValueExpressionNode(tokens, new NubIntType(false, 8)) +public class U8LiteralNode(List tokens, byte value) : ExpressionNode(tokens, new NubIntType(false, 8)) { public byte Value { get; } = value; @@ -384,7 +377,7 @@ public class U8LiteralNode(List tokens, byte value) : RValueExpressionNod } } -public class U16LiteralNode(List tokens, ushort value) : RValueExpressionNode(tokens, new NubIntType(false, 16)) +public class U16LiteralNode(List tokens, ushort value) : ExpressionNode(tokens, new NubIntType(false, 16)) { public ushort Value { get; } = value; @@ -394,7 +387,7 @@ public class U16LiteralNode(List tokens, ushort value) : RValueExpression } } -public class U32LiteralNode(List tokens, uint value) : RValueExpressionNode(tokens, new NubIntType(false, 32)) +public class U32LiteralNode(List tokens, uint value) : ExpressionNode(tokens, new NubIntType(false, 32)) { public uint Value { get; } = value; @@ -404,7 +397,7 @@ public class U32LiteralNode(List tokens, uint value) : RValueExpressionNo } } -public class U64LiteralNode(List tokens, ulong value) : RValueExpressionNode(tokens, new NubIntType(false, 64)) +public class U64LiteralNode(List tokens, ulong value) : ExpressionNode(tokens, new NubIntType(false, 64)) { public ulong Value { get; } = value; @@ -414,7 +407,7 @@ public class U64LiteralNode(List tokens, ulong value) : RValueExpressionN } } -public class Float32LiteralNode(List tokens, float value) : RValueExpressionNode(tokens, new NubFloatType(32)) +public class Float32LiteralNode(List tokens, float value) : ExpressionNode(tokens, new NubFloatType(32)) { public float Value { get; } = value; @@ -424,7 +417,7 @@ public class Float32LiteralNode(List tokens, float value) : RValueExpress } } -public class Float64LiteralNode(List tokens, double value) : RValueExpressionNode(tokens, new NubFloatType(64)) +public class Float64LiteralNode(List tokens, double value) : ExpressionNode(tokens, new NubFloatType(64)) { public double Value { get; } = value; @@ -434,7 +427,7 @@ public class Float64LiteralNode(List tokens, double value) : RValueExpres } } -public class BoolLiteralNode(List tokens, bool value) : RValueExpressionNode(tokens, new NubBoolType()) +public class BoolLiteralNode(List tokens, bool value) : ExpressionNode(tokens, new NubBoolType()) { public bool Value { get; } = value; @@ -444,7 +437,7 @@ public class BoolLiteralNode(List tokens, bool value) : RValueExpressionN } } -public class BinaryExpressionNode(List tokens, NubType type, ExpressionNode left, BinaryOperator @operator, ExpressionNode right) : RValueExpressionNode(tokens, type) +public class BinaryExpressionNode(List tokens, NubType type, ExpressionNode left, BinaryOperator @operator, ExpressionNode right) : ExpressionNode(tokens, type) { public ExpressionNode Left { get; } = left; public BinaryOperator Operator { get; } = @operator; @@ -457,7 +450,7 @@ public class BinaryExpressionNode(List tokens, NubType type, ExpressionNo } } -public class UnaryExpressionNode(List tokens, NubType type, UnaryOperator @operator, ExpressionNode operand) : RValueExpressionNode(tokens, type) +public class UnaryExpressionNode(List tokens, NubType type, UnaryOperator @operator, ExpressionNode operand) : ExpressionNode(tokens, type) { public UnaryOperator Operator { get; } = @operator; public ExpressionNode Operand { get; } = operand; @@ -468,7 +461,7 @@ public class UnaryExpressionNode(List tokens, NubType type, UnaryOperator } } -public class FuncCallNode(List tokens, NubType type, ExpressionNode expression, List parameters) : RValueExpressionNode(tokens, type) +public class FuncCallNode(List tokens, NubType type, ExpressionNode expression, List parameters) : ExpressionNode(tokens, type) { public ExpressionNode Expression { get; } = expression; public List Parameters { get; } = parameters; @@ -483,7 +476,7 @@ public class FuncCallNode(List tokens, NubType type, ExpressionNode expre } } -public class VariableIdentifierNode(List tokens, NubType type, IdentifierToken nameToken) : LValueExpressionNode(tokens, type) +public class VariableIdentifierNode(List tokens, NubType type, IdentifierToken nameToken) : ExpressionNode(tokens, type) { public IdentifierToken NameToken { get; } = nameToken; @@ -493,7 +486,7 @@ public class VariableIdentifierNode(List tokens, NubType type, Identifier } } -public class FuncIdentifierNode(List tokens, NubType type, IdentifierToken moduleToken, IdentifierToken nameToken, StringLiteralToken? externSymbolToken) : RValueExpressionNode(tokens, type) +public class FuncIdentifierNode(List tokens, NubType type, IdentifierToken moduleToken, IdentifierToken nameToken, StringLiteralToken? externSymbolToken) : ExpressionNode(tokens, type) { public IdentifierToken ModuleToken { get; } = moduleToken; public IdentifierToken NameToken { get; } = nameToken; @@ -505,7 +498,7 @@ public class FuncIdentifierNode(List tokens, NubType type, IdentifierToke } } -public class ArrayInitializerNode(List tokens, NubType type, List values) : RValueExpressionNode(tokens, type) +public class ArrayInitializerNode(List tokens, NubType type, List values) : ExpressionNode(tokens, type) { public List Values { get; } = values; @@ -515,7 +508,7 @@ public class ArrayInitializerNode(List tokens, NubType type, List tokens, NubType type, List values) : RValueExpressionNode(tokens, type) +public class ConstArrayInitializerNode(List tokens, NubType type, List values) : ExpressionNode(tokens, type) { public List Values { get; } = values; @@ -525,7 +518,7 @@ public class ConstArrayInitializerNode(List tokens, NubType type, List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type) +public class ArrayIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : ExpressionNode(tokens, type) { public ExpressionNode Target { get; } = target; public ExpressionNode Index { get; } = index; @@ -537,7 +530,7 @@ public class ArrayIndexAccessNode(List tokens, NubType type, ExpressionNo } } -public class ConstArrayIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type) +public class ConstArrayIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : ExpressionNode(tokens, type) { public ExpressionNode Target { get; } = target; public ExpressionNode Index { get; } = index; @@ -549,7 +542,7 @@ public class ConstArrayIndexAccessNode(List tokens, NubType type, Express } } -public class SliceIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : LValueExpressionNode(tokens, type) +public class SliceIndexAccessNode(List tokens, NubType type, ExpressionNode target, ExpressionNode index) : ExpressionNode(tokens, type) { public ExpressionNode Target { get; } = target; public ExpressionNode Index { get; } = index; @@ -561,17 +554,17 @@ public class SliceIndexAccessNode(List tokens, NubType type, ExpressionNo } } -public class AddressOfNode(List tokens, NubType type, LValueExpressionNode lValue) : RValueExpressionNode(tokens, type) +public class AddressOfNode(List tokens, NubType type, ExpressionNode target) : ExpressionNode(tokens, type) { - public LValueExpressionNode LValue { get; } = lValue; + public ExpressionNode Target { get; } = target; public override IEnumerable Children() { - yield return LValue; + yield return Target; } } -public class StructFieldAccessNode(List tokens, NubType type, ExpressionNode target, IdentifierToken fieldToken) : LValueExpressionNode(tokens, type) +public class StructFieldAccessNode(List tokens, NubType type, ExpressionNode target, IdentifierToken fieldToken) : ExpressionNode(tokens, type) { public ExpressionNode Target { get; } = target; public IdentifierToken FieldToken { get; } = fieldToken; @@ -582,7 +575,7 @@ public class StructFieldAccessNode(List tokens, NubType type, ExpressionN } } -public class StructInitializerNode(List tokens, NubType type, Dictionary initializers) : RValueExpressionNode(tokens, type) +public class StructInitializerNode(List tokens, NubType type, Dictionary initializers) : ExpressionNode(tokens, type) { public Dictionary Initializers { get; } = initializers; @@ -595,7 +588,7 @@ public class StructInitializerNode(List tokens, NubType type, Dictionary< } } -public class DereferenceNode(List tokens, NubType type, ExpressionNode target) : LValueExpressionNode(tokens, type) +public class DereferenceNode(List tokens, NubType type, ExpressionNode target) : ExpressionNode(tokens, type) { public ExpressionNode Target { get; } = target; @@ -605,7 +598,7 @@ public class DereferenceNode(List tokens, NubType type, ExpressionNode ta } } -public class SizeNode(List tokens, NubType TargetType) : RValueExpressionNode(tokens, new NubIntType(false, 64)) +public class SizeNode(List tokens, NubType TargetType) : ExpressionNode(tokens, new NubIntType(false, 64)) { public NubType TargetType { get; } = TargetType; @@ -615,7 +608,7 @@ public class SizeNode(List tokens, NubType TargetType) : RValueExpression } } -public class CastNode(List tokens, NubType type, ExpressionNode value) : RValueExpressionNode(tokens, type) +public class CastNode(List tokens, NubType type, ExpressionNode value) : ExpressionNode(tokens, type) { public ExpressionNode Value { get; } = value; @@ -625,6 +618,8 @@ public class CastNode(List tokens, NubType type, ExpressionNode value) : } } +public abstract class IntermediateExpression(List tokens) : ExpressionNode(tokens, new NubVoidType()); + public class EnumReferenceIntermediateNode(List tokens, IdentifierToken moduleToken, IdentifierToken nameToken) : IntermediateExpression(tokens) { public IdentifierToken ModuleToken { get; } = moduleToken; diff --git a/compiler/NubLang/Ast/NubType.cs b/compiler/NubLang/Ast/NubType.cs index 887babd..173be29 100644 --- a/compiler/NubLang/Ast/NubType.cs +++ b/compiler/NubLang/Ast/NubType.cs @@ -5,6 +5,9 @@ namespace NubLang.Ast; public abstract class NubType : IEquatable { + public abstract ulong GetSize(); + public abstract ulong GetAlignment(); + public override bool Equals(object? obj) => obj is NubType other && Equals(other); public abstract bool Equals(NubType? other); @@ -17,24 +20,33 @@ public abstract class NubType : IEquatable public class NubVoidType : NubType { + public override ulong GetSize() => 8; + public override ulong GetAlignment() => 8; + public override string ToString() => "void"; public override bool Equals(NubType? other) => other is NubVoidType; public override int GetHashCode() => HashCode.Combine(typeof(NubVoidType)); } -public sealed class NubIntType(bool signed, int width) : NubType +public sealed class NubIntType(bool signed, ulong width) : NubType { public bool Signed { get; } = signed; - public int Width { get; } = width; + public ulong Width { get; } = width; + + public override ulong GetSize() => Width / 8; + public override ulong GetAlignment() => Width / 8; public override string ToString() => $"{(Signed ? "i" : "u")}{Width}"; public override bool Equals(NubType? other) => other is NubIntType @int && @int.Width == Width && @int.Signed == Signed; public override int GetHashCode() => HashCode.Combine(typeof(NubIntType), Signed, Width); } -public sealed class NubFloatType(int width) : NubType +public sealed class NubFloatType(ulong width) : NubType { - public int Width { get; } = width; + public ulong Width { get; } = width; + + public override ulong GetSize() => Width / 8; + public override ulong GetAlignment() => Width / 8; public override string ToString() => $"f{Width}"; public override bool Equals(NubType? other) => other is NubFloatType @float && @float.Width == Width; @@ -43,6 +55,9 @@ public sealed class NubFloatType(int width) : NubType public class NubBoolType : NubType { + public override ulong GetSize() => 1; + public override ulong GetAlignment() => 1; + public override string ToString() => "bool"; public override bool Equals(NubType? other) => other is NubBoolType; public override int GetHashCode() => HashCode.Combine(typeof(NubBoolType)); @@ -52,6 +67,9 @@ public sealed class NubPointerType(NubType baseType) : NubType { public NubType BaseType { get; } = baseType; + public override ulong GetSize() => 8; + public override ulong GetAlignment() => 8; + public override string ToString() => "^" + BaseType; public override bool Equals(NubType? other) => other is NubPointerType pointer && BaseType.Equals(pointer.BaseType); public override int GetHashCode() => HashCode.Combine(typeof(NubPointerType), BaseType); @@ -62,6 +80,9 @@ public class NubFuncType(List parameters, NubType returnType) : NubType public List Parameters { get; } = parameters; public NubType ReturnType { get; } = returnType; + public override ulong GetSize() => 8; + public override ulong GetAlignment() => 8; + public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}"; public override bool Equals(NubType? other) => other is NubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters); @@ -79,12 +100,63 @@ public class NubFuncType(List parameters, NubType returnType) : NubType } } -public class NubStructType(string module, string name, List fields) : NubType +public class NubStructType(string module, string name, bool packed, List fields) : NubType { public string Module { get; } = module; public string Name { get; } = name; + public bool Packed { get; } = packed; public List Fields { get; set; } = fields; + public Dictionary GetFieldOffsets() + { + var offsets = new Dictionary(); + ulong offset = 0; + + foreach (var field in Fields) + { + var alignment = Packed ? 1 : field.Type.GetAlignment(); + if (!Packed) + { + var padding = (alignment - offset % alignment) % alignment; + offset += padding; + } + + offsets[field] = offset; + offset += field.Type.GetSize(); + } + + return offsets; + } + + public override ulong GetSize() + { + var offsets = GetFieldOffsets(); + if (Fields.Count == 0) + { + return 0; + } + + var lastField = Fields.Last(); + var size = offsets[lastField] + lastField.Type.GetSize(); + + if (!Packed) + { + var structAlignment = GetAlignment(); + var padding = (structAlignment - size % structAlignment) % structAlignment; + size += padding; + } + + return size; + } + + public override ulong GetAlignment() + { + if (Fields.Count == 0) + return 1; + + return Packed ? 1 : Fields.Max(f => f.Type.GetAlignment()); + } + public override string ToString() => $"{Module}::{Name}"; public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module; public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name); @@ -101,6 +173,10 @@ public class NubSliceType(NubType elementType) : NubType { public NubType ElementType { get; } = elementType; + // note(nub31): Fat pointer + public override ulong GetSize() => 16; + public override ulong GetAlignment() => 8; + public override string ToString() => "[]" + ElementType; public override bool Equals(NubType? other) => other is NubSliceType slice && ElementType.Equals(slice.ElementType); public override int GetHashCode() => HashCode.Combine(typeof(NubSliceType), ElementType); @@ -111,6 +187,9 @@ public class NubConstArrayType(NubType elementType, ulong size) : NubType public NubType ElementType { get; } = elementType; public ulong Size { get; } = size; + public override ulong GetSize() => ElementType.GetSize() * Size; + public override ulong GetAlignment() => ElementType.GetAlignment(); + public override string ToString() => $"[{Size}]{ElementType}"; public override bool Equals(NubType? other) => other is NubConstArrayType array && ElementType.Equals(array.ElementType) && Size == array.Size; public override int GetHashCode() => HashCode.Combine(typeof(NubConstArrayType), ElementType, Size); @@ -120,6 +199,9 @@ public class NubArrayType(NubType elementType) : NubType { public NubType ElementType { get; } = elementType; + public override ulong GetSize() => 8; + public override ulong GetAlignment() => 8; + public override string ToString() => $"[?]{ElementType}"; public override bool Equals(NubType? other) => other is NubArrayType array && ElementType.Equals(array.ElementType); public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType); @@ -127,6 +209,10 @@ public class NubArrayType(NubType elementType) : NubType public class NubStringType : NubType { + // note(nub31): Fat pointer + public override ulong GetSize() => 16; + public override ulong GetAlignment() => 8; + public override string ToString() => "string"; public override bool Equals(NubType? other) => other is NubStringType; public override int GetHashCode() => HashCode.Combine(typeof(NubStringType)); diff --git a/compiler/NubLang/Ast/TypeChecker.cs b/compiler/NubLang/Ast/TypeChecker.cs index bf36e49..bbd31da 100644 --- a/compiler/NubLang/Ast/TypeChecker.cs +++ b/compiler/NubLang/Ast/TypeChecker.cs @@ -221,30 +221,25 @@ public sealed class TypeChecker } var currentModule = GetCurrentModule(); - var type = new NubStructType(currentModule.Name.Value, structSyntax.NameToken.Value, fields.Select(x => new NubStructFieldType(x.NameToken.Value, x.Type, x.Value != null)).ToList()); + var type = new NubStructType(currentModule.Name.Value, structSyntax.NameToken.Value, structSyntax.Packed, fields.Select(x => new NubStructFieldType(x.NameToken.Value, x.Type, x.Value != null)).ToList()); - return new StructNode(structSyntax.Tokens, structSyntax.NameToken, type, fields); + return new StructNode(structSyntax.Tokens, structSyntax.NameToken, type, structSyntax.Packed, fields); } private AssignmentNode CheckAssignment(AssignmentSyntax statement) { var target = CheckExpression(statement.Target); - if (target is not LValueExpressionNode lValue) - { - throw new CompileException(Diagnostic.Error("Cannot assign to an rvalue").At(statement).Build()); - } + var value = CheckExpression(statement.Value, target.Type); - var value = CheckExpression(statement.Value, lValue.Type); - - if (value.Type != lValue.Type) + if (value.Type != target.Type) { throw new CompileException(Diagnostic - .Error($"Cannot assign {value.Type} to {lValue.Type}") + .Error($"Cannot assign {value.Type} to {target.Type}") .At(statement.Value) .Build()); } - return new AssignmentNode(statement.Tokens, lValue, value); + return new AssignmentNode(statement.Tokens, target, value); } private IfNode CheckIf(IfSyntax statement) @@ -499,13 +494,8 @@ public sealed class TypeChecker private AddressOfNode CheckAddressOf(AddressOfSyntax expression, NubType? expectedType) { var target = CheckExpression(expression.Target, (expectedType as NubPointerType)?.BaseType); - if (target is not LValueExpressionNode lvalue) - { - throw new CompileException(Diagnostic.Error("Cannot take address of an rvalue").At(expression).Build()); - } - var type = new NubPointerType(target.Type); - return new AddressOfNode(expression.Tokens, type, lvalue); + return new AddressOfNode(expression.Tokens, type, target); } private ExpressionNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression, NubType? _) diff --git a/compiler/NubLang/Ast/TypeResolver.cs b/compiler/NubLang/Ast/TypeResolver.cs index 06a921d..1734341 100644 --- a/compiler/NubLang/Ast/TypeResolver.cs +++ b/compiler/NubLang/Ast/TypeResolver.cs @@ -55,14 +55,14 @@ public class TypeResolver if (!_resolvingTypes.Add(key)) { - var placeholder = new NubStructType(customType.ModuleToken?.Value ?? currentModule, customType.NameToken.Value, []); + var placeholder = new NubStructType(customType.ModuleToken?.Value ?? currentModule, customType.NameToken.Value, structDef.Packed, []); _typeCache[key] = placeholder; return placeholder; } try { - var result = new NubStructType(customType.ModuleToken?.Value ?? currentModule, structDef.NameToken.Value, []); + var result = new NubStructType(customType.ModuleToken?.Value ?? currentModule, structDef.NameToken.Value, structDef.Packed, []); _typeCache[key] = result; var fields = structDef.Fields diff --git a/compiler/NubLang/Generation/Generator.cs b/compiler/NubLang/Generation/Generator.cs index 975b09c..e2f3e0a 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -499,7 +499,7 @@ public class Generator private string EmitAddressOf(AddressOfNode addressOfNode) { - var value = EmitExpression(addressOfNode.LValue); + var value = EmitExpression(addressOfNode.Target); return $"&{value}"; } diff --git a/compiler/NubLang/Syntax/Parser.cs b/compiler/NubLang/Syntax/Parser.cs index 9a3d338..ba29e39 100644 --- a/compiler/NubLang/Syntax/Parser.cs +++ b/compiler/NubLang/Syntax/Parser.cs @@ -28,6 +28,7 @@ public sealed class Parser var startIndex = _tokenIndex; var exported = TryExpectSymbol(Symbol.Export); + var packed = TryExpectSymbol(Symbol.Packed); if (TryExpectSymbol(Symbol.Extern)) { @@ -43,7 +44,7 @@ public sealed class Parser Symbol.Module => ParseModule(startIndex), Symbol.Import => ParseImport(startIndex), Symbol.Func => ParseFunc(startIndex, exported, null), - Symbol.Struct => ParseStruct(startIndex, exported), + Symbol.Struct => ParseStruct(startIndex, exported, packed), Symbol.Enum => ParseEnum(startIndex, exported), _ => throw new CompileException(Diagnostic .Error($"Expected 'func', 'struct', 'enum', 'import' or 'module' but found '{keyword.Symbol}'") @@ -126,7 +127,7 @@ public sealed class Parser return new FuncSyntax(GetTokens(startIndex), prototype, body); } - private StructSyntax ParseStruct(int startIndex, bool exported) + private StructSyntax ParseStruct(int startIndex, bool exported, bool packed) { var name = ExpectIdentifier(); @@ -152,7 +153,7 @@ public sealed class Parser fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue)); } - return new StructSyntax(GetTokens(startIndex), name, exported, fields); + return new StructSyntax(GetTokens(startIndex), name, exported, packed, fields); } private EnumSyntax ParseEnum(int startIndex, bool exported) @@ -650,7 +651,7 @@ public sealed class Parser var startIndex = _tokenIndex; if (TryExpectIdentifier(out var name)) { - if (name.Value[0] == 'u' && int.TryParse(name.Value[1..], out var size)) + if (name.Value[0] == 'u' && ulong.TryParse(name.Value[1..], out var size)) { if (size is not 8 and not 16 and not 32 and not 64) { @@ -664,7 +665,7 @@ public sealed class Parser return new IntTypeSyntax(GetTokens(startIndex), false, size); } - if (name.Value[0] == 'i' && int.TryParse(name.Value[1..], out size)) + if (name.Value[0] == 'i' && ulong.TryParse(name.Value[1..], out size)) { if (size is not 8 and not 16 and not 32 and not 64) { @@ -678,7 +679,7 @@ public sealed class Parser return new IntTypeSyntax(GetTokens(startIndex), true, size); } - if (name.Value[0] == 'f' && int.TryParse(name.Value[1..], out size)) + if (name.Value[0] == 'f' && ulong.TryParse(name.Value[1..], out size)) { if (size is not 32 and not 64) { diff --git a/compiler/NubLang/Syntax/Syntax.cs b/compiler/NubLang/Syntax/Syntax.cs index 8fb9c3a..4c1f233 100644 --- a/compiler/NubLang/Syntax/Syntax.cs +++ b/compiler/NubLang/Syntax/Syntax.cs @@ -20,7 +20,7 @@ public record FuncSyntax(List Tokens, FuncPrototypeSyntax Prototype, Bloc public record StructFieldSyntax(List Tokens, IdentifierToken NameToken, TypeSyntax Type, ExpressionSyntax? Value) : SyntaxNode(Tokens); -public record StructSyntax(List Tokens, IdentifierToken NameToken, bool Exported, List Fields) : DefinitionSyntax(Tokens, NameToken, Exported); +public record StructSyntax(List Tokens, IdentifierToken NameToken, bool Exported, bool Packed, List Fields) : DefinitionSyntax(Tokens, NameToken, Exported); public record EnumFieldSyntax(List Tokens, IdentifierToken NameToken, IntLiteralToken? ValueToken) : SyntaxNode(Tokens); @@ -134,9 +134,9 @@ public record PointerTypeSyntax(List Tokens, TypeSyntax BaseType) : TypeS public record VoidTypeSyntax(List Tokens) : TypeSyntax(Tokens); -public record IntTypeSyntax(List Tokens, bool Signed, int Width) : TypeSyntax(Tokens); +public record IntTypeSyntax(List Tokens, bool Signed, ulong Width) : TypeSyntax(Tokens); -public record FloatTypeSyntax(List Tokens, int Width) : TypeSyntax(Tokens); +public record FloatTypeSyntax(List Tokens, ulong Width) : TypeSyntax(Tokens); public record BoolTypeSyntax(List Tokens) : TypeSyntax(Tokens); diff --git a/compiler/NubLang/Syntax/Token.cs b/compiler/NubLang/Syntax/Token.cs index 444ffc1..31673d2 100644 --- a/compiler/NubLang/Syntax/Token.cs +++ b/compiler/NubLang/Syntax/Token.cs @@ -85,6 +85,7 @@ public enum Symbol // Modifier Extern, + Packed, Export, Colon, diff --git a/compiler/NubLang/Syntax/Tokenizer.cs b/compiler/NubLang/Syntax/Tokenizer.cs index 1734c91..896aa23 100644 --- a/compiler/NubLang/Syntax/Tokenizer.cs +++ b/compiler/NubLang/Syntax/Tokenizer.cs @@ -248,6 +248,7 @@ public sealed class Tokenizer "return" => Symbol.Return, "struct" => Symbol.Struct, "extern" => Symbol.Extern, + "packed" => Symbol.Packed, "module" => Symbol.Module, "export" => Symbol.Export, "import" => Symbol.Import, diff --git a/compiler/NubLang/Syntax/TypedModule.cs b/compiler/NubLang/Syntax/TypedModule.cs index 01b4b30..55d7337 100644 --- a/compiler/NubLang/Syntax/TypedModule.cs +++ b/compiler/NubLang/Syntax/TypedModule.cs @@ -33,7 +33,7 @@ public sealed class TypedModule fields.Add(new NubStructFieldType(field.NameToken.Value, typeResolver.ResolveType(field.Type, name), field.Value != null)); } - structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, fields)); + structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, structSyntax.Packed, fields)); } return new TypedModule(functionPrototypes, structTypes, module.Imports());