Better type mapping

This commit is contained in:
nub31
2025-10-17 13:32:00 +02:00
parent bc1252ea1f
commit 610e259503
7 changed files with 198 additions and 153 deletions

View File

@@ -5,78 +5,10 @@ using NubLang.Generation;
using NubLang.Modules; using NubLang.Modules;
using NubLang.Syntax; using NubLang.Syntax;
List<string> files = [];
List<string> headerFiles = [];
for (var i = 0; i < args.Length; i++)
{
if (args[i] == "-h")
{
i += 1;
if (i > args.Length - 1)
{
Console.Error.WriteLine("Expected argument after -h");
}
headerFiles.Add(args[i]);
}
else
{
files.Add(args[i]);
}
}
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var syntaxTrees = new List<SyntaxTree>(); var syntaxTrees = new List<SyntaxTree>();
foreach (var headerFile in headerFiles) foreach (var file in args)
{
using var bindingsGenerateProc = new Process();
// todo(nub31): Embed python file to remove absolute path
bindingsGenerateProc.StartInfo = new ProcessStartInfo("python3", ["/home/oliste/repos/nub-lang/bindings/generate.py", headerFile])
{
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
UseShellExecute = false,
};
bindingsGenerateProc.Start();
var output = await bindingsGenerateProc.StandardOutput.ReadToEndAsync();
var error = await bindingsGenerateProc.StandardError.ReadToEndAsync();
await bindingsGenerateProc.WaitForExitAsync();
if (bindingsGenerateProc.ExitCode != 0)
{
Console.Error.WriteLine($"Failed to automatically generate bindings for header file {headerFile}\n{error}");
return 1;
}
var tokenizer = new Tokenizer(headerFile, output);
tokenizer.Tokenize();
diagnostics.AddRange(tokenizer.Diagnostics);
if (tokenizer.Diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
{
Console.Error.WriteLine($"Binding generator produced invalid syntax for header file {headerFile}");
return 1;
}
var parser = new Parser();
var syntaxTree = parser.Parse(tokenizer.Tokens);
if (parser.Diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
{
Console.Error.WriteLine($"Binding generator produced invalid syntax tree for header file {headerFile}");
return 1;
}
syntaxTrees.Add(syntaxTree);
}
foreach (var file in files)
{ {
var tokenizer = new Tokenizer(file, File.ReadAllText(file)); var tokenizer = new Tokenizer(file, File.ReadAllText(file));
tokenizer.Tokenize(); tokenizer.Tokenize();

View File

@@ -141,6 +141,19 @@ public class NubArrayType(NubType elementType) : NubType
public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType); public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType);
} }
public class NubConstArrayType(NubType elementType, int size) : NubType
{
public override bool IsValueType => false;
public override bool IsScalar => true;
public NubType ElementType { get; } = elementType;
public int 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 NubCStringType : NubType public class NubCStringType : NubType
{ {
public override bool IsValueType => false; public override bool IsValueType => false;

View File

@@ -329,7 +329,7 @@ public sealed class TypeChecker
AddressOfSyntax expression => CheckAddressOf(expression), AddressOfSyntax expression => CheckAddressOf(expression),
ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression), ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression),
ArrayInitializerSyntax expression => CheckArrayInitializer(expression), ArrayInitializerSyntax expression => CheckArrayInitializer(expression),
BinaryExpressionSyntax expression => CheckBinaryExpression(expression), BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType), UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
DereferenceSyntax expression => CheckDereference(expression), DereferenceSyntax expression => CheckDereference(expression),
MemberFuncCallSyntax expression => CheckMemberFuncCall(expression), MemberFuncCallSyntax expression => CheckMemberFuncCall(expression),
@@ -427,7 +427,7 @@ public sealed class TypeChecker
return new ArrayInitializerNode(type, capacity, elementType); return new ArrayInitializerNode(type, capacity, elementType);
} }
private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression) private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression, NubType? expectedType)
{ {
var op = expression.Operator switch var op = expression.Operator switch
{ {
@@ -457,6 +457,7 @@ public sealed class TypeChecker
case BinaryOperatorSyntax.Equal: case BinaryOperatorSyntax.Equal:
case BinaryOperatorSyntax.NotEqual: case BinaryOperatorSyntax.NotEqual:
{ {
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left);
if (left.Type is not NubIntType and not NubFloatType and not NubBoolType) if (left.Type is not NubIntType and not NubFloatType and not NubBoolType)
{ {
@@ -475,6 +476,7 @@ public sealed class TypeChecker
case BinaryOperatorSyntax.LessThan: case BinaryOperatorSyntax.LessThan:
case BinaryOperatorSyntax.LessThanOrEqual: case BinaryOperatorSyntax.LessThanOrEqual:
{ {
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left);
if (left.Type is not NubIntType and not NubFloatType) if (left.Type is not NubIntType and not NubFloatType)
{ {
@@ -491,6 +493,7 @@ public sealed class TypeChecker
case BinaryOperatorSyntax.LogicalAnd: case BinaryOperatorSyntax.LogicalAnd:
case BinaryOperatorSyntax.LogicalOr: case BinaryOperatorSyntax.LogicalOr:
{ {
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left);
if (left.Type is not NubBoolType) if (left.Type is not NubBoolType)
{ {
@@ -506,7 +509,7 @@ public sealed class TypeChecker
} }
case BinaryOperatorSyntax.Plus: case BinaryOperatorSyntax.Plus:
{ {
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left, expectedType);
if (left.Type is NubIntType or NubFloatType or NubStringType or NubCStringType) if (left.Type is NubIntType or NubFloatType or NubStringType or NubCStringType)
{ {
var right = CheckExpression(expression.Right, left.Type); var right = CheckExpression(expression.Right, left.Type);
@@ -523,7 +526,7 @@ public sealed class TypeChecker
case BinaryOperatorSyntax.Divide: case BinaryOperatorSyntax.Divide:
case BinaryOperatorSyntax.Modulo: case BinaryOperatorSyntax.Modulo:
{ {
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left, expectedType);
if (left.Type is not NubIntType and not NubFloatType) if (left.Type is not NubIntType and not NubFloatType)
{ {
throw new TypeCheckerException(Diagnostic throw new TypeCheckerException(Diagnostic
@@ -542,7 +545,7 @@ public sealed class TypeChecker
case BinaryOperatorSyntax.BitwiseXor: case BinaryOperatorSyntax.BitwiseXor:
case BinaryOperatorSyntax.BitwiseOr: case BinaryOperatorSyntax.BitwiseOr:
{ {
var left = CheckExpression(expression.Left); var left = CheckExpression(expression.Left, expectedType);
if (left.Type is not NubIntType) if (left.Type is not NubIntType)
{ {
throw new TypeCheckerException(Diagnostic throw new TypeCheckerException(Diagnostic
@@ -988,6 +991,7 @@ public sealed class TypeChecker
FloatTypeSyntax f => new NubFloatType(f.Width), FloatTypeSyntax f => new NubFloatType(f.Width),
FuncTypeSyntax func => new NubFuncType(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)), FuncTypeSyntax func => new NubFuncType(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)),
ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType)), ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType)),
ConstArrayTypeSyntax arr => new NubConstArrayType(ResolveType(arr.BaseType), arr.Size),
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)), PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
StringTypeSyntax => new NubStringType(), StringTypeSyntax => new NubStringType(),
CustomTypeSyntax c => ResolveCustomType(c), CustomTypeSyntax c => ResolveCustomType(c),

View File

@@ -193,7 +193,7 @@ public class Diagnostic
return sb.ToString(); return sb.ToString();
} }
catch (Exception e) catch (Exception)
{ {
return ConsoleColors.Colorize("Failed to generate error message", ConsoleColors.Red); return ConsoleColors.Colorize("Failed to generate error message", ConsoleColors.Red);
} }

View File

@@ -8,7 +8,9 @@ public class Generator
private readonly HashSet<NubStructType> _structTypes; private readonly HashSet<NubStructType> _structTypes;
private readonly IndentedTextWriter _writer; private readonly IndentedTextWriter _writer;
private readonly Stack<List<DeferNode>> _deferStack = []; private readonly Stack<List<DeferNode>> _deferStack = [];
private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = [];
private int _tmpIndex; private int _tmpIndex;
private int _funcDefIndex;
public Generator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes) public Generator(List<DefinitionNode> definitions, HashSet<NubStructType> structTypes)
{ {
@@ -23,47 +25,69 @@ public class Generator
return $"_t{++_tmpIndex}"; return $"_t{++_tmpIndex}";
} }
private static string MapType(NubType nubType) private string MapType(NubType nubType)
{ {
return nubType switch return nubType switch
{ {
NubArrayType => "uintptr_t", NubArrayType arrayType => MapType(arrayType.ElementType),
NubConstArrayType arrayType => MapType(arrayType.ElementType),
NubBoolType => "bool", NubBoolType => "bool",
NubCStringType => "char*", NubCStringType => "char",
NubFloatType floatType => floatType.Width switch NubFloatType floatType => floatType.Width switch
{ {
32 => "f32", 32 => "f32",
64 => "f64", 64 => "f64",
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}, },
NubFuncType => "uintptr_t", NubFuncType funcType => MapFuncType(funcType),
NubIntType intType => intType.Signed switch NubIntType intType => (intType.Signed, intType.Width) switch
{ {
true => intType.Width switch (false, 8) => "u8",
{ (false, 16) => "u16",
8 => "i8", (false, 32) => "u32",
16 => "i16", (false, 64) => "u64",
32 => "i32", (true, 8) => "i8",
64 => "i64", (true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}, },
false => intType.Width switch NubPointerType pointerType => MapType(pointerType.BaseType),
{ NubStringType => throw new NotImplementedException(),
8 => "u8",
16 => "u16",
32 => "u32",
64 => "u64",
_ => throw new ArgumentOutOfRangeException()
},
},
NubPointerType => "uintptr_t",
NubStringType => "uintptr_t",
NubStructType structType => StructName(structType.Module, structType.Name), NubStructType structType => StructName(structType.Module, structType.Name),
NubVoidType => "void", NubVoidType => "void",
_ => throw new ArgumentOutOfRangeException(nameof(nubType)) _ => throw new ArgumentOutOfRangeException(nameof(nubType))
}; };
} }
private string MapFuncType(NubFuncType funcType)
{
var name = $"_func_type_def{++_funcDefIndex}";
_funcDefs.Push((name, funcType));
return name;
}
private string MapNameWithType(NubType nubType, string name)
{
var prefix = "";
var postfix = "";
switch (nubType)
{
case NubCStringType or NubPointerType:
prefix = "*";
break;
case NubArrayType:
postfix = "[]";
break;
case NubConstArrayType constArrayType:
postfix = $"[{constArrayType.Size}]";
break;
}
return $"{MapType(nubType)} {prefix}{name}{postfix}";
}
private static string FuncName(string module, string name, string? externSymbol) private static string FuncName(string module, string name, string? externSymbol)
{ {
return externSymbol ?? $"{module}_{name}"; return externSymbol ?? $"{module}_{name}";
@@ -81,7 +105,7 @@ public class Generator
public string Emit() public string Emit()
{ {
_writer.WriteLine(""" var header = """
typedef __builtin_va_list va_list; typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last) #define va_start(ap, last) __builtin_va_start(ap, last)
@@ -119,8 +143,7 @@ public class Generator
#define I64_C(x) x##LL #define I64_C(x) x##LL
#define U64_C(x) x##ULL #define U64_C(x) x##ULL
"""); """;
_writer.WriteLine();
foreach (var structType in _structTypes) foreach (var structType in _structTypes)
{ {
@@ -130,7 +153,7 @@ public class Generator
{ {
foreach (var field in structType.Fields) foreach (var field in structType.Fields)
{ {
_writer.WriteLine($"{MapType(field.Type)} {field.Name};"); _writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};");
} }
} }
@@ -144,11 +167,11 @@ public class Generator
{ {
appendNewLine = true; appendNewLine = true;
var parameters = funcNode.Signature.Parameters.Count != 0 var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}")) ? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void"; : "void";
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol); var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapType(funcNode.Signature.ReturnType)} {name}({parameters});"); _writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters});");
} }
if (appendNewLine) if (appendNewLine)
@@ -161,11 +184,11 @@ public class Generator
foreach (var structFuncNode in structNode.Functions) foreach (var structFuncNode in structNode.Functions)
{ {
var parameters = structFuncNode.Signature.Parameters.Count != 0 var parameters = structFuncNode.Signature.Parameters.Count != 0
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}")) ? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void"; : "void";
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name); var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name);
_writer.WriteLine($"{MapType(structFuncNode.Signature.ReturnType)} {name}({parameters})"); _writer.WriteLine($"{MapNameWithType(structFuncNode.Signature.ReturnType, name)}({parameters})");
EmitBlock(structFuncNode.Body); EmitBlock(structFuncNode.Body);
_writer.WriteLine(); _writer.WriteLine();
} }
@@ -176,7 +199,7 @@ public class Generator
if (funcNode.Body == null) continue; if (funcNode.Body == null) continue;
var parameters = funcNode.Signature.Parameters.Count != 0 var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => $"{MapType(x.Type)} {x.Name}")) ? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void"; : "void";
if (funcNode.ExternSymbol == null) if (funcNode.ExternSymbol == null)
@@ -185,12 +208,26 @@ public class Generator
} }
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol); var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapType(funcNode.Signature.ReturnType)} {name}({parameters})"); _writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters})");
EmitBlock(funcNode.Body); EmitBlock(funcNode.Body);
_writer.WriteLine(); _writer.WriteLine();
} }
return _writer.ToString(); List<string> typedefs = [];
while (_funcDefs.TryPop(out var funcTypeDef))
{
var returnType = MapType(funcTypeDef.FuncType.ReturnType);
var paramList = string.Join(", ", funcTypeDef.FuncType.Parameters.Select((type, i) => MapNameWithType(type, $"arg{i}")));
if (funcTypeDef.FuncType.Parameters.Count == 0)
{
paramList = "void";
}
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});");
}
return header + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer;
} }
private void EmitStatement(StatementNode statementNode) private void EmitStatement(StatementNode statementNode)
@@ -296,7 +333,7 @@ public class Generator
if (_deferStack.Peek().Count != 0) if (_deferStack.Peek().Count != 0)
{ {
var tmp = NewTmp(); var tmp = NewTmp();
_writer.WriteLine($"{MapType(returnNode.Value.Type)} {tmp} = {returnValue};"); _writer.WriteLine($"{MapNameWithType(returnNode.Value.Type, tmp)} = {returnValue};");
var blockDefers = _deferStack.Peek(); var blockDefers = _deferStack.Peek();
for (var i = blockDefers.Count - 1; i >= 0; i--) for (var i = blockDefers.Count - 1; i >= 0; i--)
@@ -330,11 +367,11 @@ public class Generator
if (variableDeclarationNode.Assignment != null) if (variableDeclarationNode.Assignment != null)
{ {
var value = EmitExpression(variableDeclarationNode.Assignment); var value = EmitExpression(variableDeclarationNode.Assignment);
_writer.WriteLine($"{MapType(variableDeclarationNode.Type)} {variableDeclarationNode.Name} = {value};"); _writer.WriteLine($"{MapNameWithType(variableDeclarationNode.Type, variableDeclarationNode.Name)} = {value};");
} }
else else
{ {
_writer.WriteLine($"{MapType(variableDeclarationNode.Type)} {variableDeclarationNode.Name};"); _writer.WriteLine($"{MapNameWithType(variableDeclarationNode.Type, variableDeclarationNode.Name)};");
} }
} }
@@ -383,14 +420,12 @@ public class Generator
{ {
var array = EmitExpression(arrayIndexAccessNode.Target); var array = EmitExpression(arrayIndexAccessNode.Target);
var index = EmitExpression(arrayIndexAccessNode.Index); var index = EmitExpression(arrayIndexAccessNode.Index);
return $"(({MapType(arrayIndexAccessNode.Type)}*){array})[{index}]"; return $"{array}[{index}]";
} }
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode) private string EmitArrayInitializer(ArrayInitializerNode arrayInitializerNode)
{ {
var capacity = EmitExpression(arrayInitializerNode.Capacity); throw new NotImplementedException();
var elementType = MapType(arrayInitializerNode.ElementType);
return $"({elementType}[{capacity}]){{0}}";
} }
private string EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode) private string EmitBinaryExpression(BinaryExpressionNode binaryExpressionNode)
@@ -432,13 +467,32 @@ public class Generator
private string EmitConvertFloat(ConvertFloatNode convertFloatNode) private string EmitConvertFloat(ConvertFloatNode convertFloatNode)
{ {
var value = EmitExpression(convertFloatNode.Value); var value = EmitExpression(convertFloatNode.Value);
return $"({MapType(convertFloatNode.Type)}){value}"; var targetCast = convertFloatNode.TargetType.Width switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetCast}){value}";
} }
private string EmitConvertInt(ConvertIntNode convertIntNode) private string EmitConvertInt(ConvertIntNode convertIntNode)
{ {
var value = EmitExpression(convertIntNode.Value); var value = EmitExpression(convertIntNode.Value);
return $"({MapType(convertIntNode.Type)}){value}"; var targetType = (convertIntNode.TargetType.Signed, convertIntNode.TargetType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetType}){value}";
} }
private string EmitCStringLiteral(CStringLiteralNode cStringLiteralNode) private string EmitCStringLiteral(CStringLiteralNode cStringLiteralNode)
@@ -449,7 +503,7 @@ public class Generator
private string EmitDereference(DereferenceNode dereferenceNode) private string EmitDereference(DereferenceNode dereferenceNode)
{ {
var pointer = EmitExpression(dereferenceNode.Target); var pointer = EmitExpression(dereferenceNode.Target);
return $"*({MapType(dereferenceNode.Type)}*){pointer}"; return $"*{pointer}";
} }
private string EmitFloat32Literal(Float32LiteralNode float32LiteralNode) private string EmitFloat32Literal(Float32LiteralNode float32LiteralNode)
@@ -477,7 +531,19 @@ public class Generator
private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode) private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode)
{ {
var value = EmitExpression(floatToIntBuiltinNode.Value); var value = EmitExpression(floatToIntBuiltinNode.Value);
return $"({MapType(floatToIntBuiltinNode.Type)}){value}"; var targetType = (floatToIntBuiltinNode.TargetType.Signed, floatToIntBuiltinNode.TargetType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetType}){value}";
} }
private string EmitFuncCall(FuncCallNode funcCallNode) private string EmitFuncCall(FuncCallNode funcCallNode)
@@ -508,7 +574,7 @@ public class Generator
private string EmitAddressOf(AddressOfNode addressOfNode) private string EmitAddressOf(AddressOfNode addressOfNode)
{ {
var value = EmitExpression(addressOfNode.LValue); var value = EmitExpression(addressOfNode.LValue);
return $"(uintptr_t)&{value}"; return $"&{value}";
} }
private string EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode) private string EmitLValueIdentifier(LValueIdentifierNode lValueIdentifierNode)
@@ -523,6 +589,11 @@ public class Generator
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode) private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
{ {
if (sizeBuiltinNode.TargetType is NubConstArrayType constArrayType)
{
return $"sizeof({MapType(constArrayType.ElementType)}) * {constArrayType.Size}";
}
return $"sizeof({MapType(sizeBuiltinNode.TargetType)})"; return $"sizeof({MapType(sizeBuiltinNode.TargetType)})";
} }
@@ -539,9 +610,10 @@ public class Generator
private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode) private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode)
{ {
var thisParameter = EmitExpression(structFuncCallNode.StructExpression);
var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName); var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName);
var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList(); var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList();
return $"{name}({string.Join(", ", parameterNames)})"; return $"{name}({thisParameter}, {string.Join(", ", parameterNames)})";
} }
private string EmitStructInitializer(StructInitializerNode structInitializerNode) private string EmitStructInitializer(StructInitializerNode structInitializerNode)
@@ -557,7 +629,7 @@ public class Generator
? "0" ? "0"
: string.Join(", ", initValues); : string.Join(", ", initValues);
return $"({MapType(structInitializerNode.Type)}){{{initString}}}"; return $"({StructName(structInitializerNode.StructType.Module, structInitializerNode.StructType.Name)}){{{initString}}}";
} }
private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode) private string EmitUIntLiteral(UIntLiteralNode uIntLiteralNode)

View File

@@ -806,11 +806,20 @@ public sealed class Parser
} }
if (TryExpectSymbol(Symbol.OpenBracket)) if (TryExpectSymbol(Symbol.OpenBracket))
{
if (TryExpectIntLiteral(out var intLiteral))
{
ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType();
return new ConstArrayTypeSyntax(GetTokens(startIndex), baseType, int.Parse(intLiteral.Value));
}
else
{ {
ExpectSymbol(Symbol.CloseBracket); ExpectSymbol(Symbol.CloseBracket);
var baseType = ParseType(); var baseType = ParseType();
return new ArrayTypeSyntax(GetTokens(startIndex), baseType); return new ArrayTypeSyntax(GetTokens(startIndex), baseType);
} }
}
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error("Invalid type syntax") .Error("Invalid type syntax")
@@ -930,6 +939,19 @@ public sealed class Parser
return identifier; return identifier;
} }
private bool TryExpectIntLiteral([NotNullWhen(true)] out IntLiteralToken? stringLiteral)
{
if (CurrentToken is IntLiteralToken token)
{
stringLiteral = token;
Next();
return true;
}
stringLiteral = null;
return false;
}
private FloatLiteralToken ExpectFloatLiteral() private FloatLiteralToken ExpectFloatLiteral()
{ {
var token = ExpectToken(); var token = ExpectToken();

View File

@@ -144,6 +144,8 @@ public record CStringTypeSyntax(List<Token> Tokens) : TypeSyntax(Tokens);
public record ArrayTypeSyntax(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 CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens); public record CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens);
public record StructTemplateTypeSyntax(List<Token> Tokens, List<TypeSyntax> TemplateParameters, string Module, string Name) : TypeSyntax(Tokens); public record StructTemplateTypeSyntax(List<Token> Tokens, List<TypeSyntax> TemplateParameters, string Module, string Name) : TypeSyntax(Tokens);