This commit is contained in:
nub31
2025-10-20 20:15:29 +02:00
parent 7697f7b7cc
commit 7a3a461519
10 changed files with 125 additions and 70 deletions

View File

@@ -45,6 +45,10 @@ def map_type(clang_type: Type):
size = canonical.get_array_size()
return f"[{size}]{map_type(element_type)}"
if kind == TypeKind.INCOMPLETEARRAY:
element_type = canonical.get_array_element_type()
return f"[?]{map_type(element_type)}"
if kind == TypeKind.FUNCTIONPROTO or kind == TypeKind.FUNCTIONNOPROTO:
arg_types = []

View File

@@ -103,10 +103,11 @@ if (modules.TryGetValue("main", out var mainModule))
.text
.globl _start
_start:
mov rdi, rsp # Pass stack pointer to main (length + cstring pointers)
mov rdi, [rsp] # argc
mov rsi, [rsp + 8] # argv
call {mainFunction.Prototype.ExternSymbol}
mov rdi, rax # Move return value into rdi
mov rax, 60 # syscall: exit
mov rdi, rax # Move return value into rdi
mov rax, 60 # syscall: exit
syscall
""";

View File

@@ -108,8 +108,14 @@ public record FuncIdentifierNode(List<Token> Tokens, NubType Type, string Module
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, ExpressionNode Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
public record ConstArrayInitializerNode(List<Token> Tokens, NubType Type, long Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record SliceIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type);
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type);

View File

@@ -5,9 +5,6 @@ namespace NubLang.Ast;
public abstract class NubType : IEquatable<NubType>
{
public abstract bool IsValueType { get; }
public abstract bool IsScalar { get; }
public override bool Equals(object? obj) => obj is NubType other && Equals(other);
public abstract bool Equals(NubType? other);
@@ -20,9 +17,6 @@ public abstract class NubType : IEquatable<NubType>
public class NubVoidType : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => "void";
public override bool Equals(NubType? other) => other is NubVoidType;
public override int GetHashCode() => HashCode.Combine(typeof(NubVoidType));
@@ -30,9 +24,6 @@ public class NubVoidType : NubType
public sealed class NubIntType(bool signed, int width) : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public bool Signed { get; } = signed;
public int Width { get; } = width;
@@ -43,9 +34,6 @@ public sealed class NubIntType(bool signed, int width) : NubType
public sealed class NubFloatType(int width) : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public int Width { get; } = width;
public override string ToString() => $"f{Width}";
@@ -55,9 +43,6 @@ public sealed class NubFloatType(int width) : NubType
public class NubBoolType : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public override string ToString() => "bool";
public override bool Equals(NubType? other) => other is NubBoolType;
public override int GetHashCode() => HashCode.Combine(typeof(NubBoolType));
@@ -65,9 +50,6 @@ public class NubBoolType : NubType
public sealed class NubPointerType(NubType baseType) : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public NubType BaseType { get; } = baseType;
public override string ToString() => "^" + BaseType;
@@ -77,9 +59,6 @@ public sealed class NubPointerType(NubType baseType) : NubType
public class NubFuncType(List<NubType> parameters, NubType returnType) : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => true;
public List<NubType> Parameters { get; } = parameters;
public NubType ReturnType { get; } = returnType;
@@ -102,9 +81,6 @@ public class NubFuncType(List<NubType> parameters, NubType returnType) : NubType
public class NubStructType(string module, string name, List<NubStructFieldType> fields) : NubType
{
public override bool IsValueType => true;
public override bool IsScalar => false;
public string Module { get; } = module;
public string Name { get; } = name;
public List<NubStructFieldType> Fields { get; set; } = fields;
@@ -121,43 +97,36 @@ public class NubStructFieldType(string name, NubType type, bool hasDefaultValue)
public bool HasDefaultValue { get; } = hasDefaultValue;
}
public class NubStructFuncType(string name, List<NubType> parameters, NubType returnType)
public class NubSliceType(NubType elementType) : NubType
{
public string Name { get; } = name;
public List<NubType> Parameters { get; } = parameters;
public NubType ReturnType { get; } = returnType;
}
public class NubArrayType(NubType elementType) : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => true;
public NubType ElementType { get; } = elementType;
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);
public override bool Equals(NubType? other) => other is NubSliceType slice && ElementType.Equals(slice.ElementType);
public override int GetHashCode() => HashCode.Combine(typeof(NubSliceType), ElementType);
}
public class NubConstArrayType(NubType elementType, int size) : NubType
public class NubConstArrayType(NubType elementType, long size) : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => true;
public NubType ElementType { get; } = elementType;
public int Size { get; } = size;
public long Size { get; } = size;
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);
}
public class NubArrayType(NubType elementType) : NubType
{
public NubType ElementType { get; } = elementType;
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);
}
public class NubCStringType : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => "cstring";
public override bool Equals(NubType? other) => other is NubCStringType;
public override int GetHashCode() => HashCode.Combine(typeof(NubCStringType));
@@ -165,9 +134,6 @@ public class NubCStringType : NubType
public class NubStringType : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => false;
public override string ToString() => "string";
public override bool Equals(NubType? other) => other is NubStringType;
public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
@@ -190,7 +156,7 @@ public static class NameMangler
NubCStringType => "CS",
NubStringType => "S",
NubPointerType p => "P" + EncodeType(p.BaseType),
NubArrayType a => "A" + EncodeType(a.ElementType),
NubSliceType a => "A" + EncodeType(a.ElementType),
NubFuncType fn => "FN(" + string.Join(",", fn.Parameters.Select(EncodeType)) + ")" + EncodeType(fn.ReturnType),
NubStructType st => "ST(" + st.Module + "." + st.Name + ")",
_ => throw new NotSupportedException($"Cannot encode type: {node}")

View File

@@ -248,6 +248,7 @@ public sealed class TypeChecker
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression),
BoolLiteralSyntax expression => CheckBoolLiteral(expression),
ConstArrayInitializerSyntax expression => CheckConstArrayInitializer(expression),
StringLiteralSyntax expression => CheckStringLiteral(expression, expectedType),
IntLiteralSyntax expression => CheckIntLiteral(expression, expectedType),
FloatLiteralSyntax expression => CheckFloatLiteral(expression, expectedType),
@@ -264,6 +265,11 @@ public sealed class TypeChecker
return result;
}
if (result.Type is NubConstArrayType && expectedType is NubArrayType)
{
return result;
}
if (result.Type is NubIntType sourceIntType && expectedType is NubIntType targetIntType)
{
if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width)
@@ -283,6 +289,13 @@ public sealed class TypeChecker
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {result.Type} to {expectedType}").At(node).Build());
}
private ConstArrayInitializerNode CheckConstArrayInitializer(ConstArrayInitializerSyntax expression)
{
var elementType = ResolveType(expression.ElementType);
var type = new NubConstArrayType(elementType, expression.Capacity);
return new ConstArrayInitializerNode(expression.Tokens, type, expression.Capacity, elementType);
}
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression)
{
var value = CheckExpression(expression.Value);
@@ -318,16 +331,18 @@ public sealed class TypeChecker
return new AddressOfNode(expression.Tokens, type, lvalue);
}
private ArrayIndexAccessNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression)
private ExpressionNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression)
{
var index = CheckExpression(expression.Index, new NubIntType(false, 64));
var target = CheckExpression(expression.Target);
if (target.Type is not NubArrayType arrayType)
{
throw new TypeCheckerException(Diagnostic.Error($"Cannot use array indexer on type {target.Type}").At(expression).Build());
}
return new ArrayIndexAccessNode(expression.Tokens, arrayType.ElementType, target, index);
return target.Type switch
{
NubArrayType arrayType => new ArrayIndexAccessNode(expression.Tokens, arrayType.ElementType, target, index),
NubConstArrayType constArrayType => new ConstArrayIndexAccessNode(expression.Tokens, constArrayType.ElementType, target, index),
NubSliceType sliceType => new SliceIndexAccessNode(expression.Tokens, sliceType.ElementType, target, index),
_ => throw new TypeCheckerException(Diagnostic.Error($"Cannot use array indexer on type {target.Type}").At(expression).Build())
};
}
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression)
@@ -808,12 +823,13 @@ public sealed class TypeChecker
{
return type switch
{
ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType)),
BoolTypeSyntax => new NubBoolType(),
CStringTypeSyntax => new NubCStringType(),
IntTypeSyntax i => new NubIntType(i.Signed, i.Width),
FloatTypeSyntax f => new NubFloatType(f.Width),
FuncTypeSyntax func => new NubFuncType(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)),
ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType)),
SliceTypeSyntax slice => new NubSliceType(ResolveType(slice.BaseType)),
ConstArrayTypeSyntax arr => new NubConstArrayType(ResolveType(arr.BaseType), arr.Size),
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
StringTypeSyntax => new NubStringType(),

View File

@@ -22,7 +22,7 @@ public class Generator
return $"_t{++_tmpIndex}";
}
private string MapNameWithType(NubType nubType, string name)
private static string MapNameWithType(NubType nubType, string name)
{
var prefix = "";
var postfix = "";
@@ -46,8 +46,9 @@ public class Generator
{
return type switch
{
NubSliceType sliceType => throw new NotImplementedException(),
NubConstArrayType constArrayType => MapBaseType(constArrayType.ElementType),
NubArrayType arrayType => MapBaseType(arrayType.ElementType),
NubConstArrayType arrayType => MapBaseType(arrayType.ElementType),
NubBoolType => "bool",
NubCStringType => "char",
NubFloatType floatType => floatType.Width switch
@@ -121,6 +122,22 @@ public class Generator
_writer.WriteLine();
// note(nub31): declare extern functions
foreach (var funcNode in _compilationUnit.Functions)
{
if (funcNode.Body != null) continue;
EmitLine(funcNode.Tokens.FirstOrDefault());
var parameters = funcNode.Prototype.Parameters.Count != 0
? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters});");
}
_writer.WriteLine();
// note(nub31): Normal functions
foreach (var funcNode in _compilationUnit.Functions)
{
@@ -317,7 +334,7 @@ public class Generator
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
{
if (variableDeclarationNode.Assignment != null)
if (variableDeclarationNode.Assignment is { Type: not NubArrayType and not NubConstArrayType })
{
var value = EmitExpression(variableDeclarationNode.Assignment);
_writer.WriteLine($"{MapNameWithType(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};");
@@ -343,6 +360,8 @@ public class Generator
ArrayInitializerNode arrayInitializerNode => EmitArrayInitializer(arrayInitializerNode),
BinaryExpressionNode binaryExpressionNode => EmitBinaryExpression(binaryExpressionNode),
BoolLiteralNode boolLiteralNode => EmitBoolLiteral(boolLiteralNode),
ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode),
ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode),
ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode),
ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode),
CStringLiteralNode cStringLiteralNode => EmitCStringLiteral(cStringLiteralNode),
@@ -357,6 +376,7 @@ public class Generator
LValueIdentifierNode lValueIdentifierNode => EmitLValueIdentifier(lValueIdentifierNode),
RValueIdentifierNode rValueIdentifierNode => EmitRValueIdentifier(rValueIdentifierNode),
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
SliceIndexAccessNode sliceIndexAccessNode => EmitSliceArrayIndexAccess(sliceIndexAccessNode),
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
@@ -416,6 +436,19 @@ public class Generator
return boolLiteralNode.Value ? "true" : "false";
}
private string EmitConstArrayIndexAccess(ConstArrayIndexAccessNode constArrayIndexAccessNode)
{
var array = EmitExpression(constArrayIndexAccessNode.Target);
var index = EmitExpression(constArrayIndexAccessNode.Index);
// todo(nub31): We can emit bounds checking here
return $"{array}[{index}]";
}
private string EmitConstArrayInitializer(ConstArrayInitializerNode constArrayInitializerNode)
{
return string.Empty;
}
private string EmitConvertFloat(ConvertFloatNode convertFloatNode)
{
var value = EmitExpression(convertFloatNode.Value);
@@ -544,6 +577,14 @@ public class Generator
throw new NotImplementedException();
}
private string EmitSliceArrayIndexAccess(SliceIndexAccessNode sliceIndexAccessNode)
{
var value = EmitExpression(sliceIndexAccessNode.Target);
var index = EmitExpression(sliceIndexAccessNode.Index);
// todo(nub31): We can emit bounds checking here
return $"{value}.data[{index}]";
}
private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
{
throw new NotImplementedException();

View File

@@ -530,12 +530,21 @@ public sealed class Parser
return expr;
}
private ArrayInitializerSyntax ParseArrayInitializer(int startIndex)
private ExpressionSyntax ParseArrayInitializer(int startIndex)
{
var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
return new ArrayInitializerSyntax(GetTokens(startIndex), capacity, type);
if (TryExpectIntLiteral(out var intLiteral))
{
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
return new ConstArrayInitializerSyntax(GetTokens(startIndex), Convert.ToInt64(intLiteral.Value, intLiteral.Base), type);
}
else
{
var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket);
var type = ParseType();
return new ArrayInitializerSyntax(GetTokens(startIndex), capacity, type);
}
}
private StructInitializerSyntax ParseStructInitializer(int startIndex)
@@ -707,13 +716,19 @@ public sealed class Parser
{
ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType();
return new ConstArrayTypeSyntax(GetTokens(startIndex), baseType, int.Parse(intLiteral.Value));
return new ConstArrayTypeSyntax(GetTokens(startIndex), baseType, Convert.ToInt64(intLiteral.Value, intLiteral.Base));
}
else if (TryExpectSymbol(Symbol.QuestionMark))
{
ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType();
return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
}
else
{
ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType();
return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
return new SliceTypeSyntax(GetTokens(startIndex), baseType);
}
}

View File

@@ -88,6 +88,8 @@ public record ModuleIdentifierSyntax(List<Token> Tokens, string Module, string N
public record ArrayInitializerSyntax(List<Token> Tokens, ExpressionSyntax Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens);
public record ConstArrayInitializerSyntax(List<Token> Tokens, long Capacity, TypeSyntax ElementType) : ExpressionSyntax(Tokens);
public record ArrayIndexAccessSyntax(List<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens);
public record AddressOfSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
@@ -134,9 +136,11 @@ public record StringTypeSyntax(List<Token> Tokens) : TypeSyntax(Tokens);
public record CStringTypeSyntax(List<Token> Tokens) : TypeSyntax(Tokens);
public record SliceTypeSyntax(List<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens);
public record ArrayTypeSyntax(List<Token> Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens);
public record ConstArrayTypeSyntax(List<Token> Tokens, TypeSyntax BaseType, int Size) : TypeSyntax(Tokens);
public record ConstArrayTypeSyntax(List<Token> Tokens, TypeSyntax BaseType, long Size) : TypeSyntax(Tokens);
public record CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens);

View File

@@ -56,6 +56,7 @@ public enum Symbol
Module,
Import,
At,
QuestionMark
}
public abstract record Token(SourceSpan Span);

View File

@@ -56,6 +56,7 @@ public sealed class Tokenizer
[['%']] = Symbol.Percent,
[['|']] = Symbol.Pipe,
[['@']] = Symbol.At,
[['?']] = Symbol.QuestionMark,
};
private static readonly (char[] Pattern, Symbol Symbol)[] OrderedSymbols = Symbols