...
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Compiler;
|
||||
|
||||
public sealed class Generator(List<TypedNodeDefinitionFunc> functions)
|
||||
public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGraph moduleGraph)
|
||||
{
|
||||
public static string Emit(List<TypedNodeDefinitionFunc> functions)
|
||||
public static string Emit(List<TypedNodeDefinitionFunc> functions, ModuleGraph moduleGraph)
|
||||
{
|
||||
return new Generator(functions).Emit();
|
||||
return new Generator(functions, moduleGraph).Emit();
|
||||
}
|
||||
|
||||
private readonly IndentedTextWriter writer = new();
|
||||
@@ -28,27 +28,26 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions)
|
||||
|
||||
""");
|
||||
|
||||
// for (var i = 0; i < ast.StructTypes.Count; i++)
|
||||
// {
|
||||
// var structType = ast.StructTypes[i];
|
||||
// structTypeNames[structType] = $"s{i}";
|
||||
// }
|
||||
//
|
||||
// foreach (var structType in ast.StructTypes)
|
||||
// {
|
||||
// var name = structTypeNames[structType];
|
||||
// writer.WriteLine($"struct {name}");
|
||||
// writer.WriteLine("{");
|
||||
// using (writer.Indent())
|
||||
// {
|
||||
// foreach (var field in structType.Fields)
|
||||
// {
|
||||
// writer.WriteLine($"{CType(field.Type, field.Name)};");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// writer.WriteLine("};");
|
||||
// }
|
||||
foreach (var (i, structType) in moduleGraph.GetStructTypes().Index())
|
||||
structTypeNames[structType] = $"s{i}";
|
||||
|
||||
foreach (var typeName in structTypeNames)
|
||||
writer.WriteLine($"struct {typeName.Value};");
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
foreach (var typeName in structTypeNames)
|
||||
{
|
||||
writer.WriteLine($"struct {typeName.Value}");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
foreach (var field in typeName.Key.Fields)
|
||||
writer.WriteLine($"{CType(field.Type, field.Name)};");
|
||||
}
|
||||
|
||||
writer.WriteLine("};");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
@@ -199,7 +198,8 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions)
|
||||
TypedNodeExpressionStringLiteral expression => $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}",
|
||||
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
||||
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression),
|
||||
TypedNodeExpressionIdent expression => expression.Value.Ident,
|
||||
TypedNodeExpressionLocalIdent expression => expression.Value.Ident,
|
||||
TypedNodeExpressionModuleIdent expression => expression.Value.Ident,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||
};
|
||||
}
|
||||
|
||||
178
compiler/ModuleGraph.cs
Normal file
178
compiler/ModuleGraph.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
namespace Compiler;
|
||||
|
||||
public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
{
|
||||
public static Builder Create() => new();
|
||||
|
||||
public NubTypeStruct ResolveStruct(string moduleName, string name)
|
||||
{
|
||||
var module = modules.GetValueOrDefault(moduleName);
|
||||
if (module == null)
|
||||
throw new CompileException(Diagnostic.Error($"Module '{moduleName}' not found").Build());
|
||||
|
||||
var structType = module.ResolveStruct(name);
|
||||
if (structType == null)
|
||||
throw new CompileException(Diagnostic.Error($"Struct '{moduleName}::{name}' not found").Build());
|
||||
|
||||
return structType;
|
||||
}
|
||||
|
||||
public NubType ResolveIdentifier(string moduleName, string name)
|
||||
{
|
||||
var module = modules.GetValueOrDefault(moduleName);
|
||||
if (module == null)
|
||||
throw new CompileException(Diagnostic.Error($"Module '{moduleName}' not found").Build());
|
||||
|
||||
var identType = module.ResolveIdentifier(name);
|
||||
if (identType == null)
|
||||
throw new CompileException(Diagnostic.Error($"Function '{moduleName}::{name}' not found").Build());
|
||||
|
||||
return identType;
|
||||
}
|
||||
|
||||
public List<NubTypeStruct> GetStructTypes()
|
||||
{
|
||||
return modules.SelectMany(x => x.Value.GetStructTypes()).ToList();
|
||||
}
|
||||
|
||||
public sealed class Module
|
||||
{
|
||||
private readonly Dictionary<string, NubTypeStruct> structTypes = new();
|
||||
private readonly Dictionary<string, NubType> identifierTypes = new();
|
||||
|
||||
public List<NubTypeStruct> GetStructTypes()
|
||||
{
|
||||
return structTypes.Values.ToList();
|
||||
}
|
||||
|
||||
public List<NubType> GetIdentifiers()
|
||||
{
|
||||
return identifierTypes.Values.ToList();
|
||||
}
|
||||
|
||||
public NubTypeStruct? ResolveStruct(string name)
|
||||
{
|
||||
return structTypes.GetValueOrDefault(name);
|
||||
}
|
||||
|
||||
public NubType? ResolveIdentifier(string name)
|
||||
{
|
||||
return identifierTypes.GetValueOrDefault(name);
|
||||
}
|
||||
|
||||
public void AddStruct(string name, NubTypeStruct structType)
|
||||
{
|
||||
structTypes.Add(name, structType);
|
||||
}
|
||||
|
||||
public void AddIdentifier(string name, NubType identifier)
|
||||
{
|
||||
identifierTypes.Add(name, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
public class Builder
|
||||
{
|
||||
private readonly List<Ast> asts = [];
|
||||
|
||||
public void AddAst(Ast ast)
|
||||
{
|
||||
asts.Add(ast);
|
||||
}
|
||||
|
||||
public ModuleGraph Build(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
diagnostics = [];
|
||||
|
||||
var modules = new Dictionary<string, Module>();
|
||||
|
||||
// First pass: Register modules
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
var currentModule = moduleDefinitions[0].Name.Ident;
|
||||
|
||||
if (!modules.ContainsKey(currentModule))
|
||||
modules.Add(currentModule, new Module());
|
||||
}
|
||||
|
||||
// Second pass: Register struct types without fields
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
var currentModule = moduleDefinitions[0].Name.Ident;
|
||||
|
||||
if (!modules.TryGetValue(currentModule, out var module))
|
||||
{
|
||||
module = new Module();
|
||||
modules[currentModule] = module;
|
||||
}
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
module.AddStruct(structDef.Name.Ident, new NubTypeStruct());
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass: Resolve struct fields
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
var module = modules[moduleDefinitions[0].Name.Ident];
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
var structType = module.ResolveStruct(structDef.Name.Ident);
|
||||
var fields = structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, Resolve(f.Type))).ToList();
|
||||
structType.ResolveFields(fields);
|
||||
}
|
||||
}
|
||||
|
||||
// Fourth pass: Register identifiers
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
var module = modules[moduleDefinitions[0].Name.Ident];
|
||||
|
||||
foreach (var funcDef in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||
{
|
||||
var parameters = funcDef.Parameters.Select(x => Resolve(x.Type)).ToList();
|
||||
var returnType = Resolve(funcDef.ReturnType);
|
||||
var funcType = new NubTypeFunc(parameters, returnType);
|
||||
module.AddIdentifier(funcDef.Name.Ident, funcType);
|
||||
}
|
||||
}
|
||||
|
||||
return new ModuleGraph(modules);
|
||||
|
||||
NubType Resolve(NodeType node)
|
||||
{
|
||||
return node switch
|
||||
{
|
||||
NodeTypeBool type => new NubTypeBool(),
|
||||
NodeTypeCustom type => ResolveStruct(type),
|
||||
NodeTypeFunc type => new NubTypeFunc(type.Parameters.Select(Resolve).ToList(), Resolve(type.ReturnType)),
|
||||
NodeTypePointer type => new NubTypePointer(Resolve(type.To)),
|
||||
NodeTypeSInt type => new NubTypeSInt(type.Width),
|
||||
NodeTypeUInt type => new NubTypeUInt(type.Width),
|
||||
NodeTypeString type => new NubTypeString(),
|
||||
NodeTypeVoid type => new NubTypeVoid(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
};
|
||||
}
|
||||
|
||||
NubTypeStruct ResolveStruct(NodeTypeCustom type)
|
||||
{
|
||||
var module = modules.GetValueOrDefault(type.Module.Ident);
|
||||
if (module == null)
|
||||
throw new CompileException(Diagnostic.Error($"Unknown module: {type.Module.Ident}").Build());
|
||||
|
||||
var structType = module.ResolveStruct(type.Name.Ident);
|
||||
if (structType == null)
|
||||
throw new CompileException(Diagnostic.Error($"Unknown custom type: {type.Module.Ident}::{type.Name.Ident}").Build());
|
||||
|
||||
return structType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +1,5 @@
|
||||
namespace Compiler;
|
||||
|
||||
public sealed class TypeResolver(string fileName)
|
||||
{
|
||||
private readonly Dictionary<(string Module, string Name), NubTypeStruct> structTypes = [];
|
||||
|
||||
public NubTypeStruct? GetNamedStruct(string module, string name) => structTypes.GetValueOrDefault((module, name));
|
||||
|
||||
public static TypeResolver Create(string fileName, Ast ast, out List<Diagnostic> diagnostics)
|
||||
{
|
||||
diagnostics = [];
|
||||
var resolver = new TypeResolver(fileName);
|
||||
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
|
||||
if (moduleDefinitions.Count == 0)
|
||||
diagnostics.Add(Diagnostic.Error($"'{fileName}' is not part of a module").At(fileName, 1, 1, 1).Build());
|
||||
|
||||
foreach (var moduleDefinition in moduleDefinitions.Skip(1))
|
||||
diagnostics.Add(Diagnostic.Warning("Duplicate module definition").At(fileName, moduleDefinition).Build());
|
||||
|
||||
if (moduleDefinitions.Count >= 1)
|
||||
{
|
||||
var currentModule = moduleDefinitions[0].Name.Ident;
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
if (resolver.structTypes.ContainsKey((currentModule, structDef.Name.Ident)))
|
||||
{
|
||||
diagnostics.Add(Diagnostic.Error($"Duplicate struct: {structDef.Name.Ident}").At(fileName, structDef.Name).Build());
|
||||
continue;
|
||||
}
|
||||
|
||||
resolver.structTypes.Add((currentModule, structDef.Name.Ident), new NubTypeStruct());
|
||||
}
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
var structType = resolver.structTypes[(currentModule, structDef.Name.Ident)];
|
||||
|
||||
try
|
||||
{
|
||||
structType.ResolveFields(structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, resolver.Resolve(f.Type))).ToList());
|
||||
}
|
||||
catch (CompileException e)
|
||||
{
|
||||
diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolver;
|
||||
}
|
||||
|
||||
public NubType Resolve(NodeType node)
|
||||
{
|
||||
return node switch
|
||||
{
|
||||
NodeTypeBool type => new NubTypeBool(),
|
||||
NodeTypeCustom type => ResolveStruct(type),
|
||||
NodeTypeFunc type => new NubTypeFunc(type.Parameters.Select(Resolve).ToList(), Resolve(type.ReturnType)),
|
||||
NodeTypePointer type => new NubTypePointer(Resolve(type.To)),
|
||||
NodeTypeSInt type => new NubTypeSInt(type.Width),
|
||||
NodeTypeUInt type => new NubTypeUInt(type.Width),
|
||||
NodeTypeString type => new NubTypeString(),
|
||||
NodeTypeVoid type => new NubTypeVoid(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
};
|
||||
}
|
||||
|
||||
private NubTypeStruct ResolveStruct(NodeTypeCustom type)
|
||||
{
|
||||
var structType = structTypes.GetValueOrDefault((type.Module.Ident, type.Name.Ident));
|
||||
if (structType == null)
|
||||
throw new CompileException(Diagnostic.Error($"Unknown custom type: {type.Module.Ident}::{type.Name.Ident}").At(fileName, type).Build());
|
||||
|
||||
return structType;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class NubType : IEquatable<NubType>
|
||||
{
|
||||
public abstract override string ToString();
|
||||
@@ -28,7 +28,7 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
|
||||
return new Ast(definitions);
|
||||
return new Ast(definitions, fileName);
|
||||
}
|
||||
|
||||
private NodeDefinition ParseDefinition()
|
||||
@@ -82,12 +82,6 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
return new NodeDefinitionModule(TokensFrom(startIndex), name);
|
||||
}
|
||||
|
||||
if (TryExpectKeyword(Keyword.Import))
|
||||
{
|
||||
var name = ExpectIdent();
|
||||
return new NodeDefinitionImport(TokensFrom(startIndex), name);
|
||||
}
|
||||
|
||||
throw new CompileException(Diagnostic.Error("Not a valid definition").At(fileName, Peek()).Build());
|
||||
}
|
||||
|
||||
@@ -244,7 +238,15 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
}
|
||||
else if (TryExpectIdent(out var ident))
|
||||
{
|
||||
expr = new NodeExpressionIdent(TokensFrom(startIndex), ident);
|
||||
if (TryExpectSymbol(Symbol.ColonColon))
|
||||
{
|
||||
var name = ExpectIdent();
|
||||
expr = new NodeExpressionModuleIdent(TokensFrom(startIndex), ident, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
expr = new NodeExpressionLocalIdent(TokensFrom(startIndex), ident);
|
||||
}
|
||||
}
|
||||
else if (TryExpectKeyword(Keyword.Struct))
|
||||
{
|
||||
@@ -532,8 +534,9 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Ast(List<NodeDefinition> definitions)
|
||||
public sealed class Ast(List<NodeDefinition> definitions, string fileName)
|
||||
{
|
||||
public string FileName = fileName;
|
||||
public readonly List<NodeDefinition> Definitions = definitions;
|
||||
}
|
||||
|
||||
@@ -549,11 +552,6 @@ public sealed class NodeDefinitionModule(List<Token> tokens, TokenIdent name) :
|
||||
public readonly TokenIdent Name = name;
|
||||
}
|
||||
|
||||
public sealed class NodeDefinitionImport(List<Token> tokens, TokenIdent name) : NodeDefinition(tokens)
|
||||
{
|
||||
public readonly TokenIdent Name = name;
|
||||
}
|
||||
|
||||
public sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens)
|
||||
{
|
||||
public readonly TokenIdent Name = name;
|
||||
@@ -660,11 +658,17 @@ public sealed class NodeExpressionMemberAccess(List<Token> tokens, NodeExpressio
|
||||
public readonly TokenIdent Name = name;
|
||||
}
|
||||
|
||||
public sealed class NodeExpressionIdent(List<Token> tokens, TokenIdent value) : NodeExpression(tokens)
|
||||
public sealed class NodeExpressionLocalIdent(List<Token> tokens, TokenIdent value) : NodeExpression(tokens)
|
||||
{
|
||||
public readonly TokenIdent Value = value;
|
||||
}
|
||||
|
||||
public sealed class NodeExpressionModuleIdent(List<Token> tokens, TokenIdent module, TokenIdent value) : NodeExpression(tokens)
|
||||
{
|
||||
public readonly TokenIdent Module = module;
|
||||
public readonly TokenIdent Value = value;
|
||||
}
|
||||
|
||||
public sealed class NodeExpressionBinary(List<Token> tokens, NodeExpression left, NodeExpressionBinary.Op operation, NodeExpression right) : NodeExpression(tokens)
|
||||
{
|
||||
public readonly NodeExpression Left = left;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
using Compiler;
|
||||
|
||||
var moduleGraphBuilder = ModuleGraph.Create();
|
||||
var asts = new List<Ast>();
|
||||
|
||||
foreach (var fileName in args)
|
||||
{
|
||||
var file = File.ReadAllText(fileName);
|
||||
@@ -21,19 +24,25 @@ foreach (var fileName in args)
|
||||
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
return 1;
|
||||
|
||||
var typeResolver = TypeResolver.Create(fileName, ast, out var typeResolverDiagnostics);
|
||||
moduleGraphBuilder.AddAst(ast);
|
||||
asts.Add(ast);
|
||||
}
|
||||
|
||||
foreach (var diagnostic in typeResolverDiagnostics)
|
||||
var moduleGraph = moduleGraphBuilder.Build(out var moduleGraphDiagnostics);
|
||||
|
||||
foreach (var diagnostic in moduleGraphDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
|
||||
if (typeResolverDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
if (moduleGraphDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
return 1;
|
||||
|
||||
var functions = new List<TypedNodeDefinitionFunc>();
|
||||
|
||||
foreach (var function in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var typedFunction = TypeChecker.CheckFunction(fileName, function, typeResolver, out var typeCheckerDiagnostics);
|
||||
foreach (var func in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||
{
|
||||
var typedFunction = TypeChecker.CheckFunction(ast.FileName, func, moduleGraph, out var typeCheckerDiagnostics);
|
||||
|
||||
foreach (var diagnostic in typeCheckerDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
@@ -43,16 +52,15 @@ foreach (var fileName in args)
|
||||
|
||||
functions.Add(typedFunction);
|
||||
}
|
||||
}
|
||||
|
||||
var output = Generator.Emit(functions);
|
||||
var output = Generator.Emit(functions, moduleGraph);
|
||||
|
||||
Directory.Delete(".build", recursive: true);
|
||||
Directory.CreateDirectory(".build");
|
||||
|
||||
var outFilePath = Path.Combine(".build", Path.ChangeExtension(fileName, "c"));
|
||||
File.WriteAllText(outFilePath, output);
|
||||
File.WriteAllText(".build/out.c", output);
|
||||
|
||||
Process.Start("gcc", ["-Og", "-g", "-c", "-o", Path.ChangeExtension(outFilePath, "o"), outFilePath]);
|
||||
}
|
||||
Process.Start("gcc", ["-Og", "-g", "-o", ".build/out", ".build/out.c"]);
|
||||
|
||||
return 0;
|
||||
@@ -347,8 +347,6 @@ public sealed class Tokenizer(string fileName, string contents)
|
||||
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
|
||||
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
|
||||
"module" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Module),
|
||||
"import" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Import),
|
||||
"export" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Export),
|
||||
"true" => new TokenBoolLiteral(line, startColumn, column - startColumn, true),
|
||||
"false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false),
|
||||
_ => new TokenIdent(line, startColumn, column - startColumn, value)
|
||||
@@ -482,8 +480,6 @@ public enum Keyword
|
||||
While,
|
||||
Return,
|
||||
Module,
|
||||
Import,
|
||||
Export,
|
||||
}
|
||||
|
||||
public sealed class TokenKeyword(int line, int column, int length, Keyword keyword) : Token(line, column, length)
|
||||
@@ -546,8 +542,6 @@ public static class TokenExtensions
|
||||
Keyword.While => "while",
|
||||
Keyword.Return => "return",
|
||||
Keyword.Module => "module",
|
||||
Keyword.Import => "import",
|
||||
Keyword.Export => "export",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(symbol), symbol, null)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
namespace Compiler;
|
||||
|
||||
public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, TypeResolver typeResolver)
|
||||
public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, ModuleGraph moduleGraph)
|
||||
{
|
||||
public static TypedNodeDefinitionFunc? CheckFunction(string fileName, NodeDefinitionFunc function, TypeResolver typeResolver, out List<Diagnostic> diagnostics)
|
||||
public static TypedNodeDefinitionFunc? CheckFunction(string fileName, NodeDefinitionFunc function, ModuleGraph moduleGraph, out List<Diagnostic> diagnostics)
|
||||
{
|
||||
return new TypeChecker(fileName, function, typeResolver).CheckFunction(out diagnostics);
|
||||
return new TypeChecker(fileName, function, moduleGraph).CheckFunction(out diagnostics);
|
||||
}
|
||||
|
||||
private Scope scope = new(null);
|
||||
private readonly Scope scope = new(null);
|
||||
|
||||
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
|
||||
try
|
||||
{
|
||||
returnType = typeResolver.Resolve(function.ReturnType);
|
||||
returnType = ResolveType(function.ReturnType);
|
||||
}
|
||||
catch (CompileException e)
|
||||
{
|
||||
@@ -57,7 +57,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
|
||||
private TypedNodeDefinitionFunc.Param CheckDefinitionFuncParameter(NodeDefinitionFunc.Param node)
|
||||
{
|
||||
return new TypedNodeDefinitionFunc.Param(node.Tokens, node.Name, typeResolver.Resolve(node.Type));
|
||||
return new TypedNodeDefinitionFunc.Param(node.Tokens, node.Name, ResolveType(node.Type));
|
||||
}
|
||||
|
||||
private TypedNodeStatement CheckStatement(NodeStatement node)
|
||||
@@ -102,7 +102,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
|
||||
private TypedNodeStatementVariableDeclaration CheckStatementVariableDeclaration(NodeStatementVariableDeclaration statement)
|
||||
{
|
||||
var type = typeResolver.Resolve(statement.Type);
|
||||
var type = ResolveType(statement.Type);
|
||||
var value = CheckExpression(statement.Value);
|
||||
|
||||
if (type != value.Type)
|
||||
@@ -125,7 +125,8 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
NodeExpressionBinary expression => CheckExpressionBinary(expression),
|
||||
NodeExpressionUnary expression => CheckExpressionUnary(expression),
|
||||
NodeExpressionBoolLiteral expression => CheckExpressionBoolLiteral(expression),
|
||||
NodeExpressionIdent expression => CheckExpressionIdent(expression),
|
||||
NodeExpressionLocalIdent expression => CheckExpressionIdent(expression),
|
||||
NodeExpressionModuleIdent expression => CheckExpressionModuleIdent(expression),
|
||||
NodeExpressionIntLiteral expression => CheckExpressionIntLiteral(expression),
|
||||
NodeExpressionMemberAccess expression => CheckExpressionMemberAccess(expression),
|
||||
NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression),
|
||||
@@ -272,13 +273,19 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
return new TypedNodeExpressionBoolLiteral(expression.Tokens, new NubTypeBool(), expression.Value);
|
||||
}
|
||||
|
||||
private TypedNodeExpressionIdent CheckExpressionIdent(NodeExpressionIdent expression)
|
||||
private TypedNodeExpressionLocalIdent CheckExpressionIdent(NodeExpressionLocalIdent expression)
|
||||
{
|
||||
var type = scope.GetIdentifierType(expression.Value.Ident);
|
||||
if (type == null)
|
||||
throw new CompileException(Diagnostic.Error($"Identifier '{expression.Value.Ident}' is not declared").At(fileName, expression.Value).Build());
|
||||
|
||||
return new TypedNodeExpressionIdent(expression.Tokens, type, expression.Value);
|
||||
return new TypedNodeExpressionLocalIdent(expression.Tokens, type, expression.Value);
|
||||
}
|
||||
|
||||
private TypedNodeExpressionModuleIdent CheckExpressionModuleIdent(NodeExpressionModuleIdent expression)
|
||||
{
|
||||
var identifierType = moduleGraph.ResolveIdentifier(expression.Module.Ident, expression.Value.Ident);
|
||||
return new TypedNodeExpressionModuleIdent(expression.Tokens, identifierType, expression.Module, expression.Value);
|
||||
}
|
||||
|
||||
private TypedNodeExpressionIntLiteral CheckExpressionIntLiteral(NodeExpressionIntLiteral expression)
|
||||
@@ -306,7 +313,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
|
||||
private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression)
|
||||
{
|
||||
var type = typeResolver.GetNamedStruct(expression.Module.Ident, expression.Name.Ident);
|
||||
var type = moduleGraph.ResolveStruct(expression.Module.Ident, expression.Name.Ident);
|
||||
if (type == null)
|
||||
throw new CompileException(Diagnostic.Error($"Undeclared struct '{expression.Module.Ident}::{expression.Name.Ident}'").At(fileName, expression.Name).Build());
|
||||
|
||||
@@ -327,6 +334,22 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
||||
return new TypedNodeExpressionStructLiteral(expression.Tokens, type, initializers);
|
||||
}
|
||||
|
||||
private NubType ResolveType(NodeType node)
|
||||
{
|
||||
return node switch
|
||||
{
|
||||
NodeTypeBool type => new NubTypeBool(),
|
||||
NodeTypeCustom type => moduleGraph.ResolveStruct(type.Module.Ident, type.Name.Ident),
|
||||
NodeTypeFunc type => new NubTypeFunc(type.Parameters.Select(ResolveType).ToList(), ResolveType(type.ReturnType)),
|
||||
NodeTypePointer type => new NubTypePointer(ResolveType(type.To)),
|
||||
NodeTypeSInt type => new NubTypeSInt(type.Width),
|
||||
NodeTypeUInt type => new NubTypeUInt(type.Width),
|
||||
NodeTypeString type => new NubTypeString(),
|
||||
NodeTypeVoid type => new NubTypeVoid(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
};
|
||||
}
|
||||
|
||||
private class Scope(Scope? parent)
|
||||
{
|
||||
private readonly Dictionary<string, NubType> identifiers = new();
|
||||
@@ -366,18 +389,6 @@ public sealed class TypedNodeDefinitionFunc(List<Token> tokens, TokenIdent name,
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TypedNodeDefinitionStruct(List<Token> tokens, TokenIdent name, List<TypedNodeDefinitionStruct.Field> fields) : TypedNodeDefinition(tokens)
|
||||
{
|
||||
public readonly TokenIdent Name = name;
|
||||
public readonly List<Field> Fields = fields;
|
||||
|
||||
public sealed class Field(List<Token> tokens, TokenIdent name, NubType type) : TypedNode(tokens)
|
||||
{
|
||||
public readonly TokenIdent Name = name;
|
||||
public readonly NubType Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TypedNodeStatement(List<Token> tokens) : TypedNode(tokens);
|
||||
|
||||
public sealed class TypedNodeStatementBlock(List<Token> tokens, List<TypedNodeStatement> statements) : TypedNodeStatement(tokens)
|
||||
@@ -459,11 +470,17 @@ public sealed class TypedNodeExpressionMemberAccess(List<Token> tokens, NubType
|
||||
public readonly TokenIdent Name = name;
|
||||
}
|
||||
|
||||
public sealed class TypedNodeExpressionIdent(List<Token> tokens, NubType type, TokenIdent value) : TypedNodeExpression(tokens, type)
|
||||
public sealed class TypedNodeExpressionLocalIdent(List<Token> tokens, NubType type, TokenIdent value) : TypedNodeExpression(tokens, type)
|
||||
{
|
||||
public readonly TokenIdent Value = value;
|
||||
}
|
||||
|
||||
public sealed class TypedNodeExpressionModuleIdent(List<Token> tokens, NubType type, TokenIdent module, TokenIdent value) : TypedNodeExpression(tokens, type)
|
||||
{
|
||||
public readonly TokenIdent Module = module;
|
||||
public readonly TokenIdent Value = value;
|
||||
}
|
||||
|
||||
public sealed class TypedNodeExpressionBinary(List<Token> tokens, NubType type, TypedNodeExpression left, TypedNodeExpressionBinary.Op operation, TypedNodeExpression right) : TypedNodeExpression(tokens, type)
|
||||
{
|
||||
public readonly TypedNodeExpression Left = left;
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
module main
|
||||
|
||||
struct person {
|
||||
age: i32
|
||||
name: string
|
||||
}
|
||||
|
||||
func main(): i32 {
|
||||
let x: i32 = 23
|
||||
x = 24
|
||||
@@ -25,11 +20,8 @@ func main(): i32 {
|
||||
x = i
|
||||
}
|
||||
|
||||
let me: main::person = struct main::person { age = 21 name = "Oliver" }
|
||||
let me: test::person = struct test::person { age = 21 name = "Oliver" }
|
||||
|
||||
do_something(me.name)
|
||||
test::do_something(me.name)
|
||||
return x
|
||||
}
|
||||
|
||||
func do_something(text: string): void {
|
||||
}
|
||||
9
compiler/test2.nub
Normal file
9
compiler/test2.nub
Normal file
@@ -0,0 +1,9 @@
|
||||
module test
|
||||
|
||||
struct person {
|
||||
age: i32
|
||||
name: string
|
||||
}
|
||||
|
||||
func do_something(name: string): void {
|
||||
}
|
||||
Reference in New Issue
Block a user