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