...
This commit is contained in:
@@ -12,4 +12,6 @@ public record StructFieldNode(string Name, NubType Type, ExpressionNode? Value)
|
||||
|
||||
public record StructFuncNode(string Name, string? Hook, FuncSignatureNode Signature, BlockNode Body) : Node;
|
||||
|
||||
public record StructNode(string Module, string Name, List<StructFieldNode> Fields, List<StructFuncNode> Functions) : DefinitionNode(Module, Name);
|
||||
public record StructNode(string Module, string Name, List<StructFieldNode> Fields, List<StructFuncNode> Functions) : DefinitionNode(Module, Name);
|
||||
|
||||
public record GlobalVariableNode(string Module, string Name, ExpressionNode Value) : DefinitionNode(Module, Name);
|
||||
@@ -46,27 +46,33 @@ public sealed class TypeChecker
|
||||
Definitions.Clear();
|
||||
ReferencedStructTypes.Clear();
|
||||
|
||||
foreach (var definition in _syntaxTree.Definitions)
|
||||
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
|
||||
{
|
||||
try
|
||||
foreach (var definition in _syntaxTree.Definitions)
|
||||
{
|
||||
switch (definition)
|
||||
try
|
||||
{
|
||||
case FuncSyntax funcSyntax:
|
||||
Definitions.Add(CheckFuncDefinition(funcSyntax));
|
||||
break;
|
||||
case StructSyntax structSyntax:
|
||||
Definitions.Add(CheckStructDefinition(structSyntax));
|
||||
break;
|
||||
case StructTemplateSyntax:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
switch (definition)
|
||||
{
|
||||
case FuncSyntax funcSyntax:
|
||||
Definitions.Add(CheckFuncDefinition(funcSyntax));
|
||||
break;
|
||||
case StructSyntax structSyntax:
|
||||
Definitions.Add(CheckStructDefinition(structSyntax));
|
||||
break;
|
||||
case GlobalVariableSyntax globalVariableSyntax:
|
||||
Definitions.Add(CheckGlobalVariable(globalVariableSyntax));
|
||||
break;
|
||||
case StructTemplateSyntax:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
catch (TypeCheckerException e)
|
||||
{
|
||||
Diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
}
|
||||
catch (TypeCheckerException e)
|
||||
{
|
||||
Diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,9 +91,41 @@ public sealed class TypeChecker
|
||||
return new ScopeDisposer(this);
|
||||
}
|
||||
|
||||
private ScopeDisposer BeginRootScope(string module)
|
||||
private ScopeDisposer BeginRootScope(string moduleName)
|
||||
{
|
||||
_scopes.Push(new Scope(module));
|
||||
if (!_visibleModules.TryGetValue(moduleName, out var moduleScope))
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Module with name {moduleName} not found").Build());
|
||||
}
|
||||
|
||||
var scope = new Scope(moduleName);
|
||||
_scopes.Push(scope);
|
||||
|
||||
foreach (var globalVariable in moduleScope.GlobalVariables(true))
|
||||
{
|
||||
NubType? type;
|
||||
|
||||
if (globalVariable.ExplicitType != null)
|
||||
{
|
||||
type = ResolveType(globalVariable.ExplicitType);
|
||||
var valueExpression = CheckExpression(globalVariable.Value, type);
|
||||
|
||||
if (valueExpression.Type != ResolveType(globalVariable.ExplicitType))
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error("Value does not match explicit type of global variable")
|
||||
.At(globalVariable.Value)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
type = CheckExpression(globalVariable.Value).Type;
|
||||
}
|
||||
|
||||
scope.DeclareVariable(new Variable(globalVariable.Name, type, VariableKind.LValue));
|
||||
}
|
||||
|
||||
return new ScopeDisposer(this);
|
||||
}
|
||||
|
||||
@@ -105,30 +143,27 @@ public sealed class TypeChecker
|
||||
|
||||
private StructNode CheckStructDefinition(StructSyntax node)
|
||||
{
|
||||
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
|
||||
{
|
||||
var fieldTypes = node.Fields
|
||||
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
|
||||
.ToList();
|
||||
var fieldTypes = node.Fields
|
||||
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
|
||||
.ToList();
|
||||
|
||||
var fieldFunctions = node.Functions
|
||||
.Select(x =>
|
||||
{
|
||||
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
|
||||
var returnType = ResolveType(x.Signature.ReturnType);
|
||||
return new NubStructFuncType(x.Name, x.Hook, parameters, returnType);
|
||||
})
|
||||
.ToList();
|
||||
var fieldFunctions = node.Functions
|
||||
.Select(x =>
|
||||
{
|
||||
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
|
||||
var returnType = ResolveType(x.Signature.ReturnType);
|
||||
return new NubStructFuncType(x.Name, x.Hook, parameters, returnType);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var structType = new NubStructType(CurrentScope.Module, node.Name, fieldTypes, fieldFunctions);
|
||||
var structType = new NubStructType(CurrentScope.Module, node.Name, fieldTypes, fieldFunctions);
|
||||
|
||||
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
|
||||
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
|
||||
|
||||
var fields = node.Fields.Select(CheckStructField).ToList();
|
||||
var functions = node.Functions.Select(CheckStructFunc).ToList();
|
||||
var fields = node.Fields.Select(CheckStructField).ToList();
|
||||
var functions = node.Functions.Select(CheckStructFunc).ToList();
|
||||
|
||||
return new StructNode(CurrentScope.Module, node.Name, fields, functions);
|
||||
}
|
||||
return new StructNode(CurrentScope.Module, node.Name, fields, functions);
|
||||
}
|
||||
|
||||
private StructFuncNode CheckStructFunc(StructFuncSyntax function)
|
||||
@@ -157,42 +192,44 @@ public sealed class TypeChecker
|
||||
|
||||
private FuncNode CheckFuncDefinition(FuncSyntax node)
|
||||
{
|
||||
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
|
||||
foreach (var parameter in node.Signature.Parameters)
|
||||
{
|
||||
foreach (var parameter in node.Signature.Parameters)
|
||||
{
|
||||
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
|
||||
}
|
||||
|
||||
var signature = CheckFuncSignature(node.Signature);
|
||||
|
||||
BlockNode? body = null;
|
||||
if (node.Body != null)
|
||||
{
|
||||
_funcReturnTypes.Push(signature.ReturnType);
|
||||
|
||||
body = CheckBlock(node.Body);
|
||||
|
||||
if (!AlwaysReturns(body))
|
||||
{
|
||||
if (signature.ReturnType is NubVoidType)
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(null));
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Error("Not all code paths return a value")
|
||||
.At(node.Body)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
_funcReturnTypes.Pop();
|
||||
}
|
||||
|
||||
return new FuncNode(CurrentScope.Module, node.Name, node.ExternSymbol, signature, body);
|
||||
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
|
||||
}
|
||||
|
||||
var signature = CheckFuncSignature(node.Signature);
|
||||
|
||||
BlockNode? body = null;
|
||||
if (node.Body != null)
|
||||
{
|
||||
_funcReturnTypes.Push(signature.ReturnType);
|
||||
|
||||
body = CheckBlock(node.Body);
|
||||
|
||||
if (!AlwaysReturns(body))
|
||||
{
|
||||
if (signature.ReturnType is NubVoidType)
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(null));
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Error("Not all code paths return a value")
|
||||
.At(node.Body)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
_funcReturnTypes.Pop();
|
||||
}
|
||||
|
||||
return new FuncNode(CurrentScope.Module, node.Name, node.ExternSymbol, signature, body);
|
||||
}
|
||||
|
||||
private GlobalVariableNode CheckGlobalVariable(GlobalVariableSyntax node)
|
||||
{
|
||||
return new GlobalVariableNode(CurrentScope.Module, node.Name, CheckExpression(node.Value));
|
||||
}
|
||||
|
||||
private AssignmentNode CheckAssignment(AssignmentSyntax statement)
|
||||
@@ -701,6 +738,19 @@ public sealed class TypeChecker
|
||||
|
||||
var includePrivate = expression.Module == CurrentScope.Module;
|
||||
|
||||
var globalVariable = module.GlobalVariables(includePrivate).FirstOrDefault(x => x.Name == expression.Name);
|
||||
if (globalVariable != null)
|
||||
{
|
||||
// todo(nub31): This should be done in the global scope
|
||||
NubType? type = null;
|
||||
if (globalVariable.ExplicitType != null)
|
||||
{
|
||||
type = ResolveType(globalVariable.ExplicitType);
|
||||
}
|
||||
|
||||
return CheckExpression(globalVariable.Value, type);
|
||||
}
|
||||
|
||||
// First, look for the exported function in the specified module
|
||||
var function = module.Functions(includePrivate).FirstOrDefault(x => x.Name == expression.Name);
|
||||
if (function != null)
|
||||
@@ -733,8 +783,8 @@ public sealed class TypeChecker
|
||||
{
|
||||
return floatType.Width switch
|
||||
{
|
||||
32 => new Float32LiteralNode(floatType, float.Parse(expression.Value)),
|
||||
64 => new Float64LiteralNode(floatType, double.Parse(expression.Value)),
|
||||
32 => new Float32LiteralNode(floatType, float.Parse(expression.Value, CultureInfo.InvariantCulture)),
|
||||
64 => new Float64LiteralNode(floatType, double.Parse(expression.Value, CultureInfo.InvariantCulture)),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
@@ -749,6 +799,30 @@ public sealed class TypeChecker
|
||||
? new Float32LiteralNode(type, float.Parse(expression.Value, CultureInfo.InvariantCulture))
|
||||
: new Float64LiteralNode(type, double.Parse(expression.Value, CultureInfo.InvariantCulture));
|
||||
}
|
||||
case LiteralKind.Hex:
|
||||
{
|
||||
if (expectedType is NubIntType intType)
|
||||
{
|
||||
return intType.Signed
|
||||
? new IntLiteralNode(intType, Convert.ToInt64(expression.Value, 16))
|
||||
: new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value, 16));
|
||||
}
|
||||
|
||||
var type = new NubIntType(true, 64);
|
||||
return new IntLiteralNode(type, Convert.ToInt64(expression.Value, 16));
|
||||
}
|
||||
case LiteralKind.Binary:
|
||||
{
|
||||
if (expectedType is NubIntType intType)
|
||||
{
|
||||
return intType.Signed
|
||||
? new IntLiteralNode(intType, Convert.ToInt64(expression.Value[2..], 2))
|
||||
: new UIntLiteralNode(intType, Convert.ToUInt64(expression.Value[2..], 2));
|
||||
}
|
||||
|
||||
var type = new NubIntType(true, 64);
|
||||
return new IntLiteralNode(type, Convert.ToInt64(expression.Value.Substring(2), 2));
|
||||
}
|
||||
case LiteralKind.String:
|
||||
{
|
||||
return expectedType switch
|
||||
|
||||
Reference in New Issue
Block a user