From 8d6f2f925a64a379420171ee76952232a5613d75 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sat, 7 Jun 2025 20:34:10 +0200 Subject: [PATCH] Add literal conversion based on context at compile time --- example/main.nub | 16 +- .../Nub.Lang/Frontend/Generation/Generator.cs | 952 +++++++++--------- src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs | 6 - .../Parsing/Definitions/FuncDefinitionNode.cs | 31 - .../Frontend/Parsing/Expressions/CastNode.cs | 20 +- .../Parsing/Expressions/FuncCallNode.cs | 2 +- .../Parsing/Expressions/LiteralNode.cs | 1 - src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 20 +- src/lang/Nub.Lang/Frontend/Typing/NubType.cs | 24 + .../Nub.Lang/Frontend/Typing/TypeChecker.cs | 146 ++- 10 files changed, 618 insertions(+), 600 deletions(-) diff --git a/example/main.nub b/example/main.nub index 41ff5e3..3e28a06 100644 --- a/example/main.nub +++ b/example/main.nub @@ -1,5 +1,17 @@ namespace main +struct Human { + age: ^u64 +} + export func main(args: []^string) { - sys::call(60, 0) -} \ No newline at end of file + let x = [3]f64 + + x[0] = 1 + x[1.2] = 2 + x[2] = 3 + + c::printf("%d\n", x[0]) + c::printf("%d\n", x[1]) + c::printf("%d\n", x[2]) +} diff --git a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs index 8f3a573..f6a0f14 100644 --- a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs +++ b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs @@ -44,8 +44,6 @@ public class Generator _builder.AppendLine(); } - var localFuncIndex = 0; - foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType()) { switch (funcSignature) @@ -60,7 +58,7 @@ public class Generator } else { - _funcNames[funcSignature] = $"$func{++localFuncIndex}"; + _funcNames[funcSignature] = "$" + localFuncDefinitionNode.Namespace + "_" + localFuncDefinitionNode.Name; } break; @@ -80,7 +78,7 @@ public class Generator for (var i = 0; i < _strings.Count; i++) { var str = _strings[i]; - _builder.AppendLine($"data $str{i + 1} = {{ b \"{str}\", b 0 }}"); + _builder.AppendLine($"data $string{i + 1} = {{ b \"{str}\", b 0 }}"); } return _builder.ToString(); @@ -352,11 +350,18 @@ public class Generator break; } - var pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {SizeOf(parameter.Type)}"); - _builder.AppendLine($" storel %{parameterName}, {pointerName}"); + if (IsLargeType(parameter.Type)) + { + _variables[parameter.Name] = parameterName; + } + else + { + var pointerName = GenVarName(); + _builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(parameter.Type)}"); + _builder.AppendLine($" {QBEStore(parameter.Type)} %{parameterName}, {pointerName}"); - _variables[parameter.Name] = pointerName; + _variables[parameter.Name] = pointerName; + } } _builder.AppendLine(); @@ -643,14 +648,14 @@ public class Generator else { pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}"); + _builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}"); _builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}"); } } else { pointerName = GenVarName(); - _builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}"); + _builder.AppendLine($" {pointerName} =l alloc8 {SizeOf(type)}"); if (IsLargeType(type)) { _builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})"); @@ -693,7 +698,7 @@ public class Generator ArrayIndexAccessNode arrayIndex => GenerateArrayIndex(arrayIndex), ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), - CastNode cast => GenerateCast(cast), + // CastNode cast => GenerateCast(cast), DereferenceNode dereference => GenerateDereference(dereference), FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer), FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression), @@ -1067,448 +1072,448 @@ public class Generator throw new NotSupportedException($"Binary operator {binaryExpression.Operator} for types {binaryExpression.Left.Type} and {binaryExpression.Right.Type} not supported"); } - private string GenerateCast(CastNode cast) - { - var input = GenerateExpression(cast.Expression); - var outputType = cast.TargetType; - var inputType = cast.Expression.Type; - - if (inputType.Equals(outputType)) - { - return input; - } - - if (outputType is not NubPrimitiveType primitiveOutputType || inputType is not NubPrimitiveType primitiveInputType) - { - throw new NotSupportedException("Casting is only supported for primitive types"); - } - - var outputName = GenVarName(); - - switch (primitiveInputType.Kind) - { - case PrimitiveTypeKind.I64: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.Any: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - _builder.AppendLine($" {outputName} =d sltof {input}"); - return outputName; - case PrimitiveTypeKind.F32: - _builder.AppendLine($" {outputName} =s sltof {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_i64_to_string(l {input})"); - return outputName; - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.I32: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extsw {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extsw {input}"); - _builder.AppendLine($" {outputName} =d sltof {extName}"); - return outputName; - case PrimitiveTypeKind.F32: - _builder.AppendLine($" {outputName} =s swtof {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {input})"); - return outputName; - case PrimitiveTypeKind.Any: - var extAnyName = GenVarName(); - _builder.AppendLine($" {extAnyName} =l extsw {input}"); - return extAnyName; - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.I16: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extsh {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - _builder.AppendLine($" {outputName} =w extsh {input}"); - return outputName; - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extsh {input}"); - _builder.AppendLine($" {outputName} =d sltof {extName}"); - return outputName; - } - case PrimitiveTypeKind.F32: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extsh {input}"); - _builder.AppendLine($" {outputName} =s swtof {extName}"); - return outputName; - } - case PrimitiveTypeKind.String: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extsh {input}"); - _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); - return outputName; - } - case PrimitiveTypeKind.Any: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extsh {input}"); - return extName; - } - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.I8: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extsb {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - _builder.AppendLine($" {outputName} =w extsb {input}"); - return outputName; - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extsb {input}"); - _builder.AppendLine($" {outputName} =d sltof {extName}"); - return outputName; - } - case PrimitiveTypeKind.F32: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extsb {input}"); - _builder.AppendLine($" {outputName} =s swtof {extName}"); - return outputName; - } - case PrimitiveTypeKind.String: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extsb {input}"); - _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); - return outputName; - } - case PrimitiveTypeKind.Any: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extsb {input}"); - return extName; - } - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.U64: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - _builder.AppendLine($" {outputName} =d ultof {input}"); - return outputName; - case PrimitiveTypeKind.F32: - _builder.AppendLine($" {outputName} =s ultof {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_u64_to_string(l {input})"); - return outputName; - case PrimitiveTypeKind.Any: - return input; - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.U32: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extuw {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extuw {input}"); - _builder.AppendLine($" {outputName} =d ultof {extName}"); - return outputName; - case PrimitiveTypeKind.F32: - _builder.AppendLine($" {outputName} =s uwtof {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {input})"); - return outputName; - case PrimitiveTypeKind.Any: - var extAnyName = GenVarName(); - _builder.AppendLine($" {extAnyName} =l extuw {input}"); - return extAnyName; - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.U16: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extuh {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - _builder.AppendLine($" {outputName} =w extuh {input}"); - return outputName; - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extuh {input}"); - _builder.AppendLine($" {outputName} =d ultof {extName}"); - return outputName; - } - case PrimitiveTypeKind.F32: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extuh {input}"); - _builder.AppendLine($" {outputName} =s uwtof {extName}"); - return outputName; - } - case PrimitiveTypeKind.String: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extuh {input}"); - _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); - return outputName; - } - case PrimitiveTypeKind.Any: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extuh {input}"); - return extName; - } - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.U8: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l extub {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.U16: - _builder.AppendLine($" {outputName} =w extub {input}"); - return outputName; - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U8: - return input; - case PrimitiveTypeKind.F64: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extub {input}"); - _builder.AppendLine($" {outputName} =d ultof {extName}"); - return outputName; - } - case PrimitiveTypeKind.F32: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extub {input}"); - _builder.AppendLine($" {outputName} =s uwtof {extName}"); - return outputName; - } - case PrimitiveTypeKind.String: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =w extub {input}"); - _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); - return outputName; - } - case PrimitiveTypeKind.Any: - { - var extName = GenVarName(); - _builder.AppendLine($" {extName} =l extub {input}"); - return extName; - } - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.F64: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.F64: - case PrimitiveTypeKind.Any: - return input; - case PrimitiveTypeKind.F32: - _builder.AppendLine($" {outputName} =s dtos {input}"); - return outputName; - case PrimitiveTypeKind.I64: - _builder.AppendLine($" {outputName} =l dtosi {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.I8: - _builder.AppendLine($" {outputName} =w dtosi {input}"); - return outputName; - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l dtoui {input}"); - return outputName; - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.U8: - _builder.AppendLine($" {outputName} =w dtoui {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_f64_to_string(d {input})"); - return outputName; - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.F32: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.F64: - _builder.AppendLine($" {outputName} =d stod {input}"); - return outputName; - case PrimitiveTypeKind.F32: - return input; - case PrimitiveTypeKind.I64: - _builder.AppendLine($" {outputName} =l stosi {input}"); - return outputName; - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.I8: - _builder.AppendLine($" {outputName} =w stosi {input}"); - return outputName; - case PrimitiveTypeKind.U64: - _builder.AppendLine($" {outputName} =l stoui {input}"); - return outputName; - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.U8: - _builder.AppendLine($" {outputName} =w stoui {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_f32_to_string(s {input})"); - return outputName; - case PrimitiveTypeKind.Any: - throw new NotImplementedException(); - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.Bool: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.Bool: - return input; - case PrimitiveTypeKind.Any: - _builder.AppendLine($" {outputName} =l extsw {input}"); - return outputName; - case PrimitiveTypeKind.String: - _builder.AppendLine($" {outputName} =l call $nub_bool_to_string(s {input})"); - return outputName; - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U64: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.U8: - case PrimitiveTypeKind.F64: - case PrimitiveTypeKind.F32: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.String: - switch (primitiveOutputType.Kind) - { - case PrimitiveTypeKind.String: - case PrimitiveTypeKind.Any: - return input; - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.U64: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.U8: - case PrimitiveTypeKind.F64: - case PrimitiveTypeKind.F32: - case PrimitiveTypeKind.Bool: - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - case PrimitiveTypeKind.Any: - return input; - default: - throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); - } - } + // private string GenerateCast(CastNode cast) + // { + // var input = GenerateExpression(cast.Expression); + // var outputType = cast.TargetType; + // var inputType = cast.Expression.Type; + // + // if (inputType.Equals(outputType)) + // { + // return input; + // } + // + // if (outputType is not NubPrimitiveType primitiveOutputType || inputType is not NubPrimitiveType primitiveInputType) + // { + // throw new NotSupportedException("Casting is only supported for primitive types"); + // } + // + // var outputName = GenVarName(); + // + // switch (primitiveInputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.Any: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // _builder.AppendLine($" {outputName} =d sltof {input}"); + // return outputName; + // case PrimitiveTypeKind.F32: + // _builder.AppendLine($" {outputName} =s sltof {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_i64_to_string(l {input})"); + // return outputName; + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.I32: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extsw {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extsw {input}"); + // _builder.AppendLine($" {outputName} =d sltof {extName}"); + // return outputName; + // case PrimitiveTypeKind.F32: + // _builder.AppendLine($" {outputName} =s swtof {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {input})"); + // return outputName; + // case PrimitiveTypeKind.Any: + // var extAnyName = GenVarName(); + // _builder.AppendLine($" {extAnyName} =l extsw {input}"); + // return extAnyName; + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.I16: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extsh {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // _builder.AppendLine($" {outputName} =w extsh {input}"); + // return outputName; + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extsh {input}"); + // _builder.AppendLine($" {outputName} =d sltof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.F32: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extsh {input}"); + // _builder.AppendLine($" {outputName} =s swtof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.String: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extsh {input}"); + // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); + // return outputName; + // } + // case PrimitiveTypeKind.Any: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extsh {input}"); + // return extName; + // } + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.I8: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extsb {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // _builder.AppendLine($" {outputName} =w extsb {input}"); + // return outputName; + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extsb {input}"); + // _builder.AppendLine($" {outputName} =d sltof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.F32: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extsb {input}"); + // _builder.AppendLine($" {outputName} =s swtof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.String: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extsb {input}"); + // _builder.AppendLine($" {outputName} =l call $nub_i32_to_string(w {extName})"); + // return outputName; + // } + // case PrimitiveTypeKind.Any: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extsb {input}"); + // return extName; + // } + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.U64: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // _builder.AppendLine($" {outputName} =d ultof {input}"); + // return outputName; + // case PrimitiveTypeKind.F32: + // _builder.AppendLine($" {outputName} =s ultof {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_u64_to_string(l {input})"); + // return outputName; + // case PrimitiveTypeKind.Any: + // return input; + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.U32: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extuw {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extuw {input}"); + // _builder.AppendLine($" {outputName} =d ultof {extName}"); + // return outputName; + // case PrimitiveTypeKind.F32: + // _builder.AppendLine($" {outputName} =s uwtof {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {input})"); + // return outputName; + // case PrimitiveTypeKind.Any: + // var extAnyName = GenVarName(); + // _builder.AppendLine($" {extAnyName} =l extuw {input}"); + // return extAnyName; + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.U16: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extuh {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // _builder.AppendLine($" {outputName} =w extuh {input}"); + // return outputName; + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extuh {input}"); + // _builder.AppendLine($" {outputName} =d ultof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.F32: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extuh {input}"); + // _builder.AppendLine($" {outputName} =s uwtof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.String: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extuh {input}"); + // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); + // return outputName; + // } + // case PrimitiveTypeKind.Any: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extuh {input}"); + // return extName; + // } + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.U8: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l extub {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.U16: + // _builder.AppendLine($" {outputName} =w extub {input}"); + // return outputName; + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U8: + // return input; + // case PrimitiveTypeKind.F64: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extub {input}"); + // _builder.AppendLine($" {outputName} =d ultof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.F32: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extub {input}"); + // _builder.AppendLine($" {outputName} =s uwtof {extName}"); + // return outputName; + // } + // case PrimitiveTypeKind.String: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =w extub {input}"); + // _builder.AppendLine($" {outputName} =l call $nub_u32_to_string(w {extName})"); + // return outputName; + // } + // case PrimitiveTypeKind.Any: + // { + // var extName = GenVarName(); + // _builder.AppendLine($" {extName} =l extub {input}"); + // return extName; + // } + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.F64: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.F64: + // case PrimitiveTypeKind.Any: + // return input; + // case PrimitiveTypeKind.F32: + // _builder.AppendLine($" {outputName} =s dtos {input}"); + // return outputName; + // case PrimitiveTypeKind.I64: + // _builder.AppendLine($" {outputName} =l dtosi {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.I8: + // _builder.AppendLine($" {outputName} =w dtosi {input}"); + // return outputName; + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l dtoui {input}"); + // return outputName; + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.U8: + // _builder.AppendLine($" {outputName} =w dtoui {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_f64_to_string(d {input})"); + // return outputName; + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.F32: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.F64: + // _builder.AppendLine($" {outputName} =d stod {input}"); + // return outputName; + // case PrimitiveTypeKind.F32: + // return input; + // case PrimitiveTypeKind.I64: + // _builder.AppendLine($" {outputName} =l stosi {input}"); + // return outputName; + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.I8: + // _builder.AppendLine($" {outputName} =w stosi {input}"); + // return outputName; + // case PrimitiveTypeKind.U64: + // _builder.AppendLine($" {outputName} =l stoui {input}"); + // return outputName; + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.U8: + // _builder.AppendLine($" {outputName} =w stoui {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_f32_to_string(s {input})"); + // return outputName; + // case PrimitiveTypeKind.Any: + // throw new NotImplementedException(); + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.Bool: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.Bool: + // return input; + // case PrimitiveTypeKind.Any: + // _builder.AppendLine($" {outputName} =l extsw {input}"); + // return outputName; + // case PrimitiveTypeKind.String: + // _builder.AppendLine($" {outputName} =l call $nub_bool_to_string(s {input})"); + // return outputName; + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U64: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.U8: + // case PrimitiveTypeKind.F64: + // case PrimitiveTypeKind.F32: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.String: + // switch (primitiveOutputType.Kind) + // { + // case PrimitiveTypeKind.String: + // case PrimitiveTypeKind.Any: + // return input; + // case PrimitiveTypeKind.I64: + // case PrimitiveTypeKind.I32: + // case PrimitiveTypeKind.I16: + // case PrimitiveTypeKind.I8: + // case PrimitiveTypeKind.U64: + // case PrimitiveTypeKind.U32: + // case PrimitiveTypeKind.U16: + // case PrimitiveTypeKind.U8: + // case PrimitiveTypeKind.F64: + // case PrimitiveTypeKind.F32: + // case PrimitiveTypeKind.Bool: + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // case PrimitiveTypeKind.Any: + // return input; + // default: + // throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + // } + // } private string GenerateIdentifier(IdentifierNode identifier) { @@ -1527,17 +1532,38 @@ public class Generator private string GenerateLiteral(LiteralNode literal) { + if (literal.Type.IsInteger) + { + switch (literal.Kind) + { + case LiteralKind.Integer: + return literal.Literal; + case LiteralKind.Float: + return literal.Literal.Split(".").First(); + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (literal.Type.IsFloat64) + { + var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.DoubleToInt64Bits(value); + return bits.ToString(); + } + + if (literal.Type.IsFloat32) + { + var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.SingleToInt32Bits(value); + return bits.ToString(); + } + switch (literal.Kind) { - case LiteralKind.Integer: - return literal.Literal; - case LiteralKind.Float: - var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture); - var bits = BitConverter.DoubleToInt64Bits(value); - return bits.ToString(); case LiteralKind.String: _strings.Add(literal.Literal); - return $"$str{_strings.Count}"; + return $"$string{_strings.Count}"; case LiteralKind.Bool: return bool.Parse(literal.Literal) ? "1" : "0"; default: @@ -1703,7 +1729,7 @@ public class Generator private string GenerateFuncCall(FuncCallNode funcCall) { - var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); + var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name); if (funcDefinition == null) { throw new Exception($"Unknown function {funcCall}"); @@ -1750,13 +1776,13 @@ public class Generator return $"@l{++_labelIndex}"; } - private IFuncSignature LookupFuncSignature(string @namespace, string name, List parameters) + private IFuncSignature LookupFuncSignature(string @namespace, string name) { return _sourceFiles .Where(f => f.Namespace == @namespace) .SelectMany(f => f.Definitions) .OfType() - .Single(f => f.SignatureMatches(name, parameters)); + .Single(f => f.Name == name); } private StructDefinitionNode LookupStructDefinition(string @namespace, string name) diff --git a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs index dc1c768..a02551b 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -171,12 +171,6 @@ public class Lexer buffer += next; Next(); } - else if (next == 'f') - { - isFloat = true; - Next(); - break; - } else { break; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs index 9f03f68..ae6b63f 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Definitions/FuncDefinitionNode.cs @@ -20,37 +20,6 @@ public interface IFuncSignature public List Parameters { get; } public Optional ReturnType { get; } - public bool SignatureMatches(string name, List parameters) - { - if (Name != name) return false; - if (Parameters.Count == 0 && parameters.Count == 0) return true; - if (Parameters.Count > parameters.Count) return false; - - for (var i = 0; i < parameters.Count; i++) - { - if (i >= Parameters.Count) - { - if (Parameters.Count > 0 && Parameters[^1].Variadic) - { - if (!NubType.IsCompatibleWith(parameters[i], Parameters[^1].Type)) - { - return false; - } - } - else - { - return false; - } - } - else if (!NubType.IsCompatibleWith(parameters[i], Parameters[i].Type)) - { - return false; - } - } - - return true; - } - public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}"; } diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs index 9b25a05..5fc33b8 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/CastNode.cs @@ -1,10 +1,10 @@ -using Nub.Lang.Frontend.Lexing; -using Nub.Lang.Frontend.Typing; - -namespace Nub.Lang.Frontend.Parsing.Expressions; - -public class CastNode(IReadOnlyList tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens) -{ - public NubType TargetType { get; } = targetType; - public ExpressionNode Expression { get; } = expression; -} \ No newline at end of file +// using Nub.Lang.Frontend.Lexing; +// using Nub.Lang.Frontend.Typing; +// +// namespace Nub.Lang.Frontend.Parsing.Expressions; +// +// public class CastNode(IReadOnlyList tokens, NubType targetType, ExpressionNode expression) : ExpressionNode(tokens) +// { +// public NubType TargetType { get; } = targetType; +// public ExpressionNode Expression { get; } = expression; +// } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs index 837d31d..30aca4c 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/FuncCallNode.cs @@ -8,5 +8,5 @@ public class FuncCallNode(IReadOnlyList tokens, string @namespace, string public string Name { get; } = name; public List Parameters { get; } = parameters; - public override string ToString() => $"{Name}()"; + public override string ToString() => $"{Name}::{Name}()"; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs index a91f02a..1f52d00 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/LiteralNode.cs @@ -1,5 +1,4 @@ using Nub.Lang.Frontend.Lexing; -using Nub.Lang.Frontend.Typing; namespace Nub.Lang.Frontend.Parsing.Expressions; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index 091ee59..c4bc676 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -499,16 +499,16 @@ public class Parser expr = expression; break; } - case Symbol.LessThan: - { - var type = ParseType(); - ExpectSymbol(Symbol.GreaterThan); - ExpectSymbol(Symbol.OpenParen); - var expressionToCast = ParseExpression(); - ExpectSymbol(Symbol.CloseParen); - expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast); - break; - } + // case Symbol.LessThan: + // { + // var type = ParseType(); + // ExpectSymbol(Symbol.GreaterThan); + // ExpectSymbol(Symbol.OpenParen); + // var expressionToCast = ParseExpression(); + // ExpectSymbol(Symbol.CloseParen); + // expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast); + // break; + // } case Symbol.Ampersand: { var expression = ParsePrimaryExpression(); diff --git a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs index 542170b..4a24de0 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs @@ -24,6 +24,30 @@ public abstract class NubType return false; } + public bool IsInteger => this is NubPrimitiveType + { + Kind: PrimitiveTypeKind.I8 + or PrimitiveTypeKind.I16 + or PrimitiveTypeKind.I32 + or PrimitiveTypeKind.I64 + or PrimitiveTypeKind.U8 + or PrimitiveTypeKind.U16 + or PrimitiveTypeKind.U32 + or PrimitiveTypeKind.U64 + }; + + public bool IsFloat32 => this is NubPrimitiveType + { + Kind: PrimitiveTypeKind.F32 + }; + + public bool IsFloat64 => this is NubPrimitiveType + { + Kind: PrimitiveTypeKind.F64 + }; + + public bool IsNumber => IsFloat32 || IsFloat64 || IsInteger; + public abstract override bool Equals(object? obj); public abstract override int GetHashCode(); public abstract override string ToString(); diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index 3cb97f6..ef56792 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -71,7 +71,7 @@ public class TypeChecker if (field.Value.HasValue) { - var fieldType = TypeCheckExpression(field.Value.Value); + var fieldType = TypeCheckExpression(field.Value.Value, field.Type); if (fieldType != null && !fieldType.Equals(field.Type)) { ReportError("Default field initializer does not match the defined type", field.Value.Value); @@ -153,7 +153,7 @@ public class TypeChecker { var memberType = TypeCheckExpression(memberAssignment.MemberAccess); if (memberType == null) return; - var valueType = TypeCheckExpression(memberAssignment.Value); + var valueType = TypeCheckExpression(memberAssignment.Value, memberType); if (valueType == null) return; if (!NubType.IsCompatibleWith(memberType, valueType)) @@ -166,7 +166,7 @@ public class TypeChecker { var itemType = TypeCheckExpression(arrayIndexAssignment.ArrayIndexAccess); if (itemType == null) return; - var valueType = TypeCheckExpression(arrayIndexAssignment.Value); + var valueType = TypeCheckExpression(arrayIndexAssignment.Value, itemType); if (valueType == null) return; if (!NubType.IsCompatibleWith(itemType, valueType)) @@ -177,19 +177,18 @@ public class TypeChecker private void TypeCheckVariableAssignment(VariableAssignmentNode variableAssignment) { - var valueType = TypeCheckExpression(variableAssignment.Value); - if (valueType == null) return; - - if (!_variables.TryGetValue(variableAssignment.Identifier.Identifier, out var existingVariable)) + if (!_variables.TryGetValue(variableAssignment.Identifier.Identifier, out var variable)) { ReportError($"Variable '{variableAssignment.Identifier}' is not declared", variableAssignment); return; } + + var valueType = TypeCheckExpression(variableAssignment.Value, variable); + if (valueType == null) return; - if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, existingVariable)) + if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, variable)) { - ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{existingVariable}'", - variableAssignment); + ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{variable}'", variableAssignment); } } @@ -197,14 +196,14 @@ public class TypeChecker { NubType? type = null; - if (_variables.TryGetValue(variableDeclaration.Name, out var existingVariable)) + if (_variables.TryGetValue(variableDeclaration.Name, out var variable)) { - ReportError($"Cannot redeclare variable '{existingVariable}'", variableDeclaration); + ReportError($"Cannot redeclare variable '{variable}'", variableDeclaration); } if (variableDeclaration.Value.HasValue) { - var valueType = TypeCheckExpression(variableDeclaration.Value.Value); + var valueType = TypeCheckExpression(variableDeclaration.Value.Value, variableDeclaration.ExplicitType.Value); if (valueType == null) return; type = valueType; } @@ -254,31 +253,21 @@ public class TypeChecker private NubType? TypeCheckFuncCall(FuncCallNode funcCall, Node node) { - List parameterTypes = []; - foreach (var funcCallParameter in funcCall.Parameters) - { - var parameterType = TypeCheckExpression(funcCallParameter); - if (parameterType == null) return null; - parameterTypes.Add(parameterType); - } - - var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, parameterTypes); + var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name); if (funcDefinition == null) { - ReportError($"Function '{funcCall.Name}' is not defined", node); + ReportError($"Function '{funcCall}' is not defined", node); return null; } if (funcDefinition.Parameters.Take(funcDefinition.Parameters.Count - 1).Any(x => x.Variadic)) { - ReportError($"Function '{funcCall.Name}' has multiple variadic parameters", node); + ReportError($"Function '{funcCall}' has multiple variadic parameters", node); return null; } - + for (var i = 0; i < funcCall.Parameters.Count; i++) { - var argType = funcCall.Parameters[i].Type; - NubType paramType; if (i < funcDefinition.Parameters.Count) { @@ -290,13 +279,16 @@ public class TypeChecker } else { - ReportError($"Function '{funcCall.Name}' does not take {funcCall.Parameters.Count} parameters", node); + ReportError($"Function '{funcCall}' does not take {funcCall.Parameters.Count} parameters", node); continue; } + + var argType = TypeCheckExpression(funcCall.Parameters[i], paramType); + if (argType == null) return null; if (!NubType.IsCompatibleWith(argType, paramType)) { - ReportError($"Parameter {i + 1} of function '{funcCall.Name}' expects type '{paramType}', but got '{argType}'", funcCall.Parameters[i]); + ReportError($"Parameter {i + 1} of function '{funcCall}' expects type '{paramType}', but got '{argType}'", funcCall.Parameters[i]); } } @@ -305,7 +297,7 @@ public class TypeChecker private void TypeCheckIf(IfNode ifNode) { - var conditionType = TypeCheckExpression(ifNode.Condition); + var conditionType = TypeCheckExpression(ifNode.Condition, NubPrimitiveType.Bool); if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool)) { ReportError($"If condition must be a boolean expression, got '{conditionType}'", ifNode.Condition); @@ -322,7 +314,7 @@ public class TypeChecker private void TypeCheckWhile(WhileNode whileNode) { - var conditionType = TypeCheckExpression(whileNode.Condition); + var conditionType = TypeCheckExpression(whileNode.Condition, NubPrimitiveType.Bool); if (conditionType != null && !conditionType.Equals(NubPrimitiveType.Bool)) { ReportError($"While condition must be a boolean expression, got '{conditionType}'", whileNode.Condition); @@ -337,7 +329,7 @@ public class TypeChecker if (returnNode.Value.HasValue) { - var returnType = TypeCheckExpression(returnNode.Value.Value); + var returnType = TypeCheckExpression(returnNode.Value.Value, _currentFunctionReturnType); if (returnType == null) return; if (_currentFunctionReturnType == null) @@ -361,7 +353,7 @@ public class TypeChecker { var dereferenceType = TypeCheckExpression(dereferenceAssignment.Dereference); if (dereferenceType == null) return; - var valueType = TypeCheckExpression(dereferenceAssignment.Value); + var valueType = TypeCheckExpression(dereferenceAssignment.Value, dereferenceType); if (valueType == null) return; if (!NubType.IsCompatibleWith(dereferenceType, valueType)) @@ -370,17 +362,17 @@ public class TypeChecker } } - private NubType? TypeCheckExpression(ExpressionNode expression) + private NubType? TypeCheckExpression(ExpressionNode expression, NubType? expectedType = null) { var resultType = expression switch { AddressOfNode addressOf => TypeCheckAddressOf(addressOf), ArrayIndexAccessNode arrayIndex => TypeCheckArrayIndex(arrayIndex), ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer), - LiteralNode literal => TypeCheckLiteral(literal), + LiteralNode literal => TypeCheckLiteral(literal, expectedType), IdentifierNode identifier => TypeCheckIdentifier(identifier), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), - CastNode cast => TypeCheckCast(cast), + // CastNode cast => TypeCheckCast(cast), DereferenceNode dereference => TypeCheckDereference(dereference), FixedArrayInitializerNode fixedArray => TypeCheckFixedInitializerArray(fixedArray), FuncCallNode funcCallExpr => TypeCheckFuncCall(funcCallExpr, funcCallExpr), @@ -398,15 +390,34 @@ public class TypeChecker return resultType; } - private NubType TypeCheckLiteral(LiteralNode literal) + private NubType? TypeCheckLiteral(LiteralNode literal, NubType? expectedType = null) { + if (expectedType != null) + { + if (expectedType.IsNumber && literal.Kind is not LiteralKind.Integer and not LiteralKind.Float) + { + ReportError("Expression expects a numeric literal", literal); + return null; + } + + if (expectedType.IsInteger && literal.Kind == LiteralKind.Float) + { + if (literal.Kind == LiteralKind.Float) + { + ReportWarning("Possible loss of precision when using float in integer context", literal); + } + } + + return expectedType; + } + return literal.Kind switch { LiteralKind.Integer => NubPrimitiveType.I64, LiteralKind.Float => NubPrimitiveType.F64, LiteralKind.String => NubPrimitiveType.String, LiteralKind.Bool => NubPrimitiveType.Bool, - _ => throw new UnreachableException() + _ => throw new ArgumentOutOfRangeException() }; } @@ -414,10 +425,10 @@ public class TypeChecker { var expressionType = TypeCheckExpression(arrayIndexAccess.Array); if (expressionType == null) return null; - var indexType = TypeCheckExpression(arrayIndexAccess.Index); - if (indexType != null && !IsInteger(indexType)) + var indexType = TypeCheckExpression(arrayIndexAccess.Index, NubPrimitiveType.U64); + if (indexType is { IsInteger: false }) { - ReportError("Array index type must be an integer", arrayIndexAccess.Index); + ReportError("Array index type must be a number", arrayIndexAccess.Index); } if (expressionType is NubArrayType arrayType) @@ -436,8 +447,8 @@ public class TypeChecker private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer) { - var capacityType = TypeCheckExpression(arrayInitializer.Capacity); - if (capacityType != null && !IsInteger(capacityType)) + var capacityType = TypeCheckExpression(arrayInitializer.Capacity, NubPrimitiveType.U64); + if (capacityType is { IsInteger: false }) { ReportError("Array capacity type must be an integer", arrayInitializer.Capacity); } @@ -516,12 +527,12 @@ public class TypeChecker } } - private NubType? TypeCheckCast(CastNode cast) - { - TypeCheckExpression(cast.Expression); - // TODO: Check if castable - return cast.TargetType; - } + // private NubType? TypeCheckCast(CastNode cast) + // { + // TypeCheckExpression(cast.Expression, cast.TargetType); + // // TODO: Check if castable + // return cast.TargetType; + // } private NubType? TypeCheckStructInitializer(StructInitializerNode structInit) { @@ -543,7 +554,7 @@ public class TypeChecker continue; } - var initializerType = TypeCheckExpression(initializer.Value); + var initializerType = TypeCheckExpression(initializer.Value, definitionField.Type); if (initializerType != null && !NubType.IsCompatibleWith(initializerType, definitionField.Type)) { ReportError($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'", initializer.Value); @@ -654,6 +665,12 @@ public class TypeChecker _diagnostics.Add(diagnostic); } + private void ReportWarning(string message, Node node) + { + var diagnostic = Diagnostic.Warning(message).At(node).Build(); + _diagnostics.Add(diagnostic); + } + private static bool IsNumeric(NubType type) { if (type is not NubPrimitiveType primitiveType) @@ -679,36 +696,13 @@ public class TypeChecker } } - private static bool IsInteger(NubType type) - { - if (type is not NubPrimitiveType primitiveType) - { - return false; - } - - switch (primitiveType.Kind) - { - case PrimitiveTypeKind.I8: - case PrimitiveTypeKind.I16: - case PrimitiveTypeKind.I32: - case PrimitiveTypeKind.I64: - case PrimitiveTypeKind.U8: - case PrimitiveTypeKind.U16: - case PrimitiveTypeKind.U32: - case PrimitiveTypeKind.U64: - return true; - default: - return false; - } - } - - private IFuncSignature? LookupFuncSignature(string @namespace, string name, List parameters) + private IFuncSignature? LookupFuncSignature(string @namespace, string name) { return _sourceFiles .Where(f => f.Namespace == @namespace) .SelectMany(f => f.Definitions) .OfType() - .FirstOrDefault(f => f.SignatureMatches(name, parameters)); + .FirstOrDefault(f => f.Name == name); } private StructDefinitionNode? LookupStructDefinition(string @namespace, string name) @@ -717,6 +711,6 @@ public class TypeChecker .Where(f => f.Namespace == @namespace) .SelectMany(f => f.Definitions) .OfType() - .FirstOrDefault(d => d.Name == name); + .SingleOrDefault(d => d.Name == name); } } \ No newline at end of file