Add void type
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
namespace c
|
||||
|
||||
extern func printf(fmt: ^u8, ...args: any)
|
||||
extern func printf(fmt: ^u8, ...args: any): void
|
||||
extern func getchar(): i32
|
||||
extern func puts(fmt: ^u8)
|
||||
|
||||
extern func malloc(size: i64): ^any
|
||||
extern func calloc(num: i64, size: i64): ^any
|
||||
extern func realloc(ptr: ^any, size: i64): ^any
|
||||
extern func free(ptr: ^any)
|
||||
extern func malloc(size: i64): ^void
|
||||
extern func calloc(num: i64, size: i64): ^void
|
||||
extern func realloc(ptr: ^void, size: i64): ^void
|
||||
extern func free(ptr: ^void)
|
||||
|
||||
extern func sin(x: f64): f64
|
||||
extern func cos(x: f64): f64
|
||||
|
||||
@@ -4,7 +4,7 @@ struct Human {
|
||||
age: ^u64
|
||||
}
|
||||
|
||||
export func main(args: []^string) {
|
||||
export func main(args: []^string): i64 {
|
||||
let x = [3]f64
|
||||
|
||||
x[0] = 1
|
||||
@@ -14,4 +14,6 @@ export func main(args: []^string) {
|
||||
c::printf("%f\n", x[0])
|
||||
c::printf("%f\n", x[1])
|
||||
c::printf("%f\n", x[2])
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public class Diagnostic
|
||||
var lineNumWidth = Math.Min(endLine + contextLines, lines.Length).ToString().Length;
|
||||
|
||||
var contextStart = Math.Max(1, startLine - contextLines);
|
||||
var contextEnd = Math.Min(lines.Length + 1, endLine + contextLines);
|
||||
var contextEnd = Math.Min(lines.Length, endLine + contextLines);
|
||||
|
||||
var contextWidth = 0;
|
||||
for (var i = contextStart; i <= contextEnd; i++)
|
||||
|
||||
@@ -84,68 +84,6 @@ public class Generator
|
||||
return _builder.ToString();
|
||||
}
|
||||
|
||||
private enum TypeContext
|
||||
{
|
||||
FuncDef,
|
||||
FuncCall,
|
||||
}
|
||||
|
||||
private static string QBEType(NubType type, TypeContext context)
|
||||
{
|
||||
return context switch
|
||||
{
|
||||
TypeContext.FuncDef => type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in function definitions"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
},
|
||||
TypeContext.FuncCall => type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType pointerType => pointerType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => "l",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(context), context, null)
|
||||
};
|
||||
}
|
||||
|
||||
private static string QBEStore(NubType type)
|
||||
{
|
||||
return $"store{type switch
|
||||
@@ -165,12 +103,11 @@ public class Generator
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in store instructions"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
||||
}}";
|
||||
}
|
||||
|
||||
@@ -193,12 +130,11 @@ public class Generator
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in load instructions"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
||||
}}";
|
||||
}
|
||||
|
||||
@@ -221,12 +157,11 @@ public class Generator
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in variables"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType => "l",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
||||
}}";
|
||||
}
|
||||
|
||||
@@ -240,7 +175,6 @@ public class Generator
|
||||
{
|
||||
case PrimitiveTypeKind.I64:
|
||||
case PrimitiveTypeKind.U64:
|
||||
case PrimitiveTypeKind.Any:
|
||||
return 8;
|
||||
case PrimitiveTypeKind.I32:
|
||||
case PrimitiveTypeKind.U32:
|
||||
@@ -304,18 +238,59 @@ public class Generator
|
||||
}
|
||||
|
||||
_builder.Append("function ");
|
||||
if (node.ReturnType.HasValue)
|
||||
if (node.ReturnType is not NubVoidType)
|
||||
{
|
||||
_builder.Append($"{QBEType(node.ReturnType.Value, TypeContext.FuncDef)} ");
|
||||
}
|
||||
else if (!node.ReturnType.HasValue && node.Name == "main")
|
||||
{
|
||||
_builder.Append("l ");
|
||||
_builder.Append(node.ReturnType switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new NotSupportedException($"'{node.ReturnType}' type cannot be used as a function return type")
|
||||
});
|
||||
_builder.Append(' ');
|
||||
}
|
||||
|
||||
_builder.Append(_funcNames[node]);
|
||||
|
||||
var parameterStrings = node.Parameters.Select(parameter => parameter.Variadic ? "..." : $"{QBEType(parameter.Type, TypeContext.FuncDef)} %{parameter.Name}");
|
||||
var parameterStrings = node.Parameters.Select(parameter => parameter.Variadic ? "..." : $"{parameter.Type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type")
|
||||
}} %{parameter.Name}");
|
||||
|
||||
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
||||
_builder.AppendLine("@start");
|
||||
@@ -324,25 +299,25 @@ public class Generator
|
||||
{
|
||||
var parameterName = parameter.Name;
|
||||
|
||||
switch (QBEType(parameter.Type, TypeContext.FuncDef))
|
||||
{
|
||||
case "sb":
|
||||
parameterName = GenVarName();
|
||||
_builder.AppendLine($" {parameterName} =w extsb %{parameter.Name}");
|
||||
break;
|
||||
case "ub":
|
||||
parameterName = GenVarName();
|
||||
_builder.AppendLine($" {parameterName} =w extub %{parameter.Name}");
|
||||
break;
|
||||
case "sh":
|
||||
parameterName = GenVarName();
|
||||
_builder.AppendLine($" {parameterName} =w extsh %{parameter.Name}");
|
||||
break;
|
||||
case "uh":
|
||||
parameterName = GenVarName();
|
||||
_builder.AppendLine($" {parameterName} =w extuh %{parameter.Name}");
|
||||
break;
|
||||
}
|
||||
// switch (QBEType(parameter.Type))
|
||||
// {
|
||||
// case "sb":
|
||||
// parameterName = GenVarName();
|
||||
// _builder.AppendLine($" {parameterName} =w extsb %{parameter.Name}");
|
||||
// break;
|
||||
// case "ub":
|
||||
// parameterName = GenVarName();
|
||||
// _builder.AppendLine($" {parameterName} =w extub %{parameter.Name}");
|
||||
// break;
|
||||
// case "sh":
|
||||
// parameterName = GenVarName();
|
||||
// _builder.AppendLine($" {parameterName} =w extsh %{parameter.Name}");
|
||||
// break;
|
||||
// case "uh":
|
||||
// parameterName = GenVarName();
|
||||
// _builder.AppendLine($" {parameterName} =w extuh %{parameter.Name}");
|
||||
// break;
|
||||
// }
|
||||
|
||||
if (IsLargeType(parameter.Type))
|
||||
{
|
||||
@@ -364,13 +339,7 @@ public class Generator
|
||||
|
||||
if (node.Body.Statements.LastOrDefault() is not ReturnNode)
|
||||
{
|
||||
if (!node.ReturnType.HasValue && node.Name == "main")
|
||||
{
|
||||
_builder.AppendLine();
|
||||
_builder.AppendLine(" # Implicit return for main");
|
||||
_builder.AppendLine(" ret 0");
|
||||
}
|
||||
else if (!node.ReturnType.HasValue)
|
||||
if (node.ReturnType is NubVoidType)
|
||||
{
|
||||
_builder.AppendLine();
|
||||
_builder.AppendLine(" # Implicit return");
|
||||
@@ -386,40 +355,34 @@ public class Generator
|
||||
_builder.Append($"type :{structDefinition.Namespace}_{structDefinition.Name} = {{ ");
|
||||
foreach (var structDefinitionField in structDefinition.Fields)
|
||||
{
|
||||
var fieldDefinition = GenerateFieldType(structDefinitionField.Type);
|
||||
_builder.Append(fieldDefinition + ", ");
|
||||
var fieldQbeType = structDefinitionField.Type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "h",
|
||||
PrimitiveTypeKind.I8 => "b",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "h",
|
||||
PrimitiveTypeKind.U8 => "b",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
_ => throw new UnreachableException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||
_ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
|
||||
};
|
||||
_builder.Append(fieldQbeType + ", ");
|
||||
}
|
||||
_builder.AppendLine("}");
|
||||
}
|
||||
|
||||
private string GenerateFieldType(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "h",
|
||||
PrimitiveTypeKind.I8 => "b",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "h",
|
||||
PrimitiveTypeKind.U8 => "b",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
}
|
||||
|
||||
private void GenerateStatement(StatementNode statement)
|
||||
{
|
||||
switch (statement)
|
||||
@@ -1739,13 +1702,35 @@ public class Generator
|
||||
var parameter = funcCall.Parameters[i];
|
||||
var result = GenerateExpression(parameter);
|
||||
|
||||
var qbeParameterType = QBEType(parameter.Type, TypeContext.FuncCall);
|
||||
var qbeParameterType = parameter.Type switch
|
||||
{
|
||||
NubArrayType => "l",
|
||||
NubPointerType => "l",
|
||||
NubPrimitiveType pointerType => pointerType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 => "l",
|
||||
PrimitiveTypeKind.I32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
PrimitiveTypeKind.Bool => "w",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
|
||||
NubFixedArrayType => "l",
|
||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
|
||||
};
|
||||
parameterStrings.Add($"{qbeParameterType} {result}");
|
||||
}
|
||||
|
||||
var funcName = _funcNames[funcDefinition];
|
||||
|
||||
if (funcDefinition.ReturnType.HasValue)
|
||||
if (funcDefinition.ReturnType is not NubVoidType)
|
||||
{
|
||||
var outputName = GenVarName();
|
||||
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcName}({string.Join(", ", parameterStrings)})");
|
||||
|
||||
@@ -18,30 +18,30 @@ public interface IFuncSignature
|
||||
public string Name { get; }
|
||||
public string Namespace { get; }
|
||||
public List<FuncParameter> Parameters { get; }
|
||||
public Optional<NubType> ReturnType { get; }
|
||||
public NubType ReturnType { get; }
|
||||
|
||||
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){": " + ReturnType}";
|
||||
}
|
||||
|
||||
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, List<FuncParameter> parameters, BlockNode body, NubType returnType, bool exported) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Namespace { get; } = @namespace;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public BlockNode Body { get; } = body;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
public bool Exported { get; } = exported;
|
||||
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){": " + ReturnType}";
|
||||
}
|
||||
|
||||
public class ExternFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, string callName, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
public class ExternFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, string @namespace, string callName, List<FuncParameter> parameters, NubType returnType) : DefinitionNode(tokens, documentation), IFuncSignature
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string CallName { get; } = callName;
|
||||
public List<FuncParameter> Parameters { get; } = parameters;
|
||||
public Optional<NubType> ReturnType { get; } = returnType;
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){": " + ReturnType}";
|
||||
}
|
||||
@@ -99,11 +99,7 @@ public class Parser
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = Optional<NubType>.Empty();
|
||||
if (TryExpectSymbol(Symbol.Colon))
|
||||
{
|
||||
returnType = ParseType();
|
||||
}
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new NubVoidType();
|
||||
|
||||
var isExtern = modifiers.RemoveAll(x => x.Modifier == Modifier.Extern) > 0;
|
||||
if (isExtern)
|
||||
@@ -665,20 +661,28 @@ public class Parser
|
||||
{
|
||||
if (TryExpectIdentifier(out var name))
|
||||
{
|
||||
if (name == "any")
|
||||
{
|
||||
return new NubAnyType();
|
||||
}
|
||||
|
||||
if (name == "void")
|
||||
{
|
||||
return new NubVoidType();
|
||||
}
|
||||
|
||||
if (NubPrimitiveType.TryParse(name, out var primitiveTypeKind))
|
||||
{
|
||||
return new NubPrimitiveType(primitiveTypeKind.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var @namespace = _namespace;
|
||||
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||
{
|
||||
@namespace = ExpectIdentifier().Value;
|
||||
}
|
||||
|
||||
return new NubStructType(@namespace, name);
|
||||
var @namespace = _namespace;
|
||||
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||
{
|
||||
@namespace = ExpectIdentifier().Value;
|
||||
}
|
||||
|
||||
return new NubStructType(@namespace, name);
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.Caret))
|
||||
|
||||
@@ -6,7 +6,7 @@ public abstract class NubType
|
||||
{
|
||||
public static bool IsCompatibleWith(NubType sourceType, NubType targetType)
|
||||
{
|
||||
if (targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType))
|
||||
if (targetType is NubAnyType || sourceType.Equals(targetType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -16,11 +16,6 @@ public abstract class NubType
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (sourceType.Equals(NubPrimitiveType.String) && targetType is NubArrayType arrayType && IsCompatibleWith(NubPrimitiveType.U8, arrayType.ElementType))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -136,6 +131,36 @@ public class NubFixedArrayType(NubType elementType, int capacity) : NubType
|
||||
}
|
||||
}
|
||||
|
||||
public class NubAnyType : NubType
|
||||
{
|
||||
public override string ToString() => "any";
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NubAnyType;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetType().GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class NubVoidType : NubType
|
||||
{
|
||||
public override string ToString() => "void";
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NubVoidType;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetType().GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
|
||||
{
|
||||
public PrimitiveTypeKind Kind { get; } = kind;
|
||||
@@ -154,7 +179,6 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
|
||||
public static NubPrimitiveType F32 => new(PrimitiveTypeKind.F32);
|
||||
|
||||
public static NubPrimitiveType Bool => new(PrimitiveTypeKind.Bool);
|
||||
public static NubPrimitiveType Any => new(PrimitiveTypeKind.Any);
|
||||
|
||||
public static bool TryParse(string s, [NotNullWhen(true)] out PrimitiveTypeKind? kind)
|
||||
{
|
||||
@@ -171,7 +195,6 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
|
||||
"f64" => PrimitiveTypeKind.F64,
|
||||
"f32" => PrimitiveTypeKind.F32,
|
||||
"bool" => PrimitiveTypeKind.Bool,
|
||||
"any" => PrimitiveTypeKind.Any,
|
||||
_ => null
|
||||
};
|
||||
|
||||
@@ -206,7 +229,6 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
|
||||
PrimitiveTypeKind.F64 => "f64",
|
||||
|
||||
PrimitiveTypeKind.Bool => "bool",
|
||||
PrimitiveTypeKind.Any => "any",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null)
|
||||
};
|
||||
}
|
||||
@@ -224,6 +246,5 @@ public enum PrimitiveTypeKind
|
||||
U8,
|
||||
F64,
|
||||
F32,
|
||||
Bool,
|
||||
Any
|
||||
Bool
|
||||
}
|
||||
@@ -14,14 +14,12 @@ public class TypeChecker
|
||||
private List<SourceFile> _sourceFiles = [];
|
||||
private List<Diagnostic> _diagnostics = [];
|
||||
private NubType? _currentFunctionReturnType;
|
||||
private bool _hasReturnStatement;
|
||||
|
||||
public DiagnosticsResult TypeCheck(List<SourceFile> sourceFiles)
|
||||
{
|
||||
_variables = new Dictionary<string, NubType>();
|
||||
_diagnostics = [];
|
||||
_currentFunctionReturnType = null;
|
||||
_hasReturnStatement = false;
|
||||
_sourceFiles = sourceFiles;
|
||||
|
||||
var externFuncDefinitions = _sourceFiles
|
||||
@@ -85,8 +83,7 @@ public class TypeChecker
|
||||
private void TypeCheckFuncDef(LocalFuncDefinitionNode funcDef)
|
||||
{
|
||||
_variables.Clear();
|
||||
_currentFunctionReturnType = funcDef.ReturnType.HasValue ? funcDef.ReturnType.Value : null;
|
||||
_hasReturnStatement = false;
|
||||
_currentFunctionReturnType = funcDef.ReturnType;
|
||||
|
||||
foreach (var param in funcDef.Parameters)
|
||||
{
|
||||
@@ -94,11 +91,6 @@ public class TypeChecker
|
||||
}
|
||||
|
||||
TypeCheckBlock(funcDef.Body);
|
||||
|
||||
if (_currentFunctionReturnType != null && !_hasReturnStatement)
|
||||
{
|
||||
ReportError($"Function '{funcDef.Name}' must return a value of type '{_currentFunctionReturnType}'", funcDef);
|
||||
}
|
||||
}
|
||||
|
||||
private void TypeCheckBlock(BlockNode block)
|
||||
@@ -292,7 +284,7 @@ public class TypeChecker
|
||||
}
|
||||
}
|
||||
|
||||
return funcDefinition.ReturnType.HasValue ? funcDefinition.ReturnType.Value : NubPrimitiveType.Any;
|
||||
return funcDefinition.ReturnType;
|
||||
}
|
||||
|
||||
private void TypeCheckIf(IfNode ifNode)
|
||||
@@ -325,8 +317,6 @@ public class TypeChecker
|
||||
|
||||
private void TypeCheckReturn(ReturnNode returnNode)
|
||||
{
|
||||
_hasReturnStatement = true;
|
||||
|
||||
if (returnNode.Value.HasValue)
|
||||
{
|
||||
var returnType = TypeCheckExpression(returnNode.Value.Value, _currentFunctionReturnType);
|
||||
|
||||
Reference in New Issue
Block a user