WIP: dev #1
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
namespace Compiler;
|
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();
|
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++)
|
foreach (var (i, structType) in moduleGraph.GetStructTypes().Index())
|
||||||
// {
|
structTypeNames[structType] = $"s{i}";
|
||||||
// var structType = ast.StructTypes[i];
|
|
||||||
// structTypeNames[structType] = $"s{i}";
|
foreach (var typeName in structTypeNames)
|
||||||
// }
|
writer.WriteLine($"struct {typeName.Value};");
|
||||||
//
|
|
||||||
// foreach (var structType in ast.StructTypes)
|
writer.WriteLine();
|
||||||
// {
|
|
||||||
// var name = structTypeNames[structType];
|
foreach (var typeName in structTypeNames)
|
||||||
// writer.WriteLine($"struct {name}");
|
{
|
||||||
// writer.WriteLine("{");
|
writer.WriteLine($"struct {typeName.Value}");
|
||||||
// using (writer.Indent())
|
writer.WriteLine("{");
|
||||||
// {
|
using (writer.Indent())
|
||||||
// foreach (var field in structType.Fields)
|
{
|
||||||
// {
|
foreach (var field in typeName.Key.Fields)
|
||||||
// writer.WriteLine($"{CType(field.Type, field.Name)};");
|
writer.WriteLine($"{CType(field.Type, field.Name)};");
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
//
|
writer.WriteLine("};");
|
||||||
// writer.WriteLine("};");
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
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} }}",
|
TypedNodeExpressionStringLiteral expression => $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}",
|
||||||
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
||||||
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(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)
|
_ => 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;
|
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 class NubType : IEquatable<NubType>
|
||||||
{
|
{
|
||||||
public abstract override string ToString();
|
public abstract override string ToString();
|
||||||
@@ -28,7 +28,7 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
|||||||
diagnostics.Add(e.Diagnostic);
|
diagnostics.Add(e.Diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Ast(definitions);
|
return new Ast(definitions, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodeDefinition ParseDefinition()
|
private NodeDefinition ParseDefinition()
|
||||||
@@ -82,12 +82,6 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
|||||||
return new NodeDefinitionModule(TokensFrom(startIndex), name);
|
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());
|
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))
|
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))
|
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;
|
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 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 sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens)
|
||||||
{
|
{
|
||||||
public readonly TokenIdent Name = name;
|
public readonly TokenIdent Name = name;
|
||||||
@@ -660,11 +658,17 @@ public sealed class NodeExpressionMemberAccess(List<Token> tokens, NodeExpressio
|
|||||||
public readonly TokenIdent Name = name;
|
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 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 sealed class NodeExpressionBinary(List<Token> tokens, NodeExpression left, NodeExpressionBinary.Op operation, NodeExpression right) : NodeExpression(tokens)
|
||||||
{
|
{
|
||||||
public readonly NodeExpression Left = left;
|
public readonly NodeExpression Left = left;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Compiler;
|
using Compiler;
|
||||||
|
|
||||||
|
var moduleGraphBuilder = ModuleGraph.Create();
|
||||||
|
var asts = new List<Ast>();
|
||||||
|
|
||||||
foreach (var fileName in args)
|
foreach (var fileName in args)
|
||||||
{
|
{
|
||||||
var file = File.ReadAllText(fileName);
|
var file = File.ReadAllText(fileName);
|
||||||
@@ -21,19 +24,25 @@ foreach (var fileName in args)
|
|||||||
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||||
return 1;
|
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);
|
||||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
|
||||||
|
|
||||||
if (typeResolverDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
foreach (var diagnostic in moduleGraphDiagnostics)
|
||||||
return 1;
|
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||||
|
|
||||||
var functions = new List<TypedNodeDefinitionFunc>();
|
if (moduleGraphDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||||
|
return 1;
|
||||||
|
|
||||||
foreach (var function in ast.Definitions.OfType<NodeDefinitionFunc>())
|
var functions = new List<TypedNodeDefinitionFunc>();
|
||||||
|
|
||||||
|
foreach (var ast in asts)
|
||||||
|
{
|
||||||
|
foreach (var func in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||||
{
|
{
|
||||||
var typedFunction = TypeChecker.CheckFunction(fileName, function, typeResolver, out var typeCheckerDiagnostics);
|
var typedFunction = TypeChecker.CheckFunction(ast.FileName, func, moduleGraph, out var typeCheckerDiagnostics);
|
||||||
|
|
||||||
foreach (var diagnostic in typeCheckerDiagnostics)
|
foreach (var diagnostic in typeCheckerDiagnostics)
|
||||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||||
@@ -43,16 +52,15 @@ foreach (var fileName in args)
|
|||||||
|
|
||||||
functions.Add(typedFunction);
|
functions.Add(typedFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = Generator.Emit(functions);
|
|
||||||
|
|
||||||
Directory.Delete(".build", recursive: true);
|
|
||||||
Directory.CreateDirectory(".build");
|
|
||||||
|
|
||||||
var outFilePath = Path.Combine(".build", Path.ChangeExtension(fileName, "c"));
|
|
||||||
File.WriteAllText(outFilePath, output);
|
|
||||||
|
|
||||||
Process.Start("gcc", ["-Og", "-g", "-c", "-o", Path.ChangeExtension(outFilePath, "o"), outFilePath]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var output = Generator.Emit(functions, moduleGraph);
|
||||||
|
|
||||||
|
Directory.Delete(".build", recursive: true);
|
||||||
|
Directory.CreateDirectory(".build");
|
||||||
|
|
||||||
|
File.WriteAllText(".build/out.c", output);
|
||||||
|
|
||||||
|
Process.Start("gcc", ["-Og", "-g", "-o", ".build/out", ".build/out.c"]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -347,8 +347,6 @@ public sealed class Tokenizer(string fileName, string contents)
|
|||||||
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
|
"while" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.While),
|
||||||
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
|
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
|
||||||
"module" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Module),
|
"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),
|
"true" => new TokenBoolLiteral(line, startColumn, column - startColumn, true),
|
||||||
"false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false),
|
"false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false),
|
||||||
_ => new TokenIdent(line, startColumn, column - startColumn, value)
|
_ => new TokenIdent(line, startColumn, column - startColumn, value)
|
||||||
@@ -482,8 +480,6 @@ public enum Keyword
|
|||||||
While,
|
While,
|
||||||
Return,
|
Return,
|
||||||
Module,
|
Module,
|
||||||
Import,
|
|
||||||
Export,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TokenKeyword(int line, int column, int length, Keyword keyword) : Token(line, column, length)
|
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.While => "while",
|
||||||
Keyword.Return => "return",
|
Keyword.Return => "return",
|
||||||
Keyword.Module => "module",
|
Keyword.Module => "module",
|
||||||
Keyword.Import => "import",
|
|
||||||
Keyword.Export => "export",
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(symbol), symbol, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(symbol), symbol, null)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
namespace Compiler;
|
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)
|
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
returnType = typeResolver.Resolve(function.ReturnType);
|
returnType = ResolveType(function.ReturnType);
|
||||||
}
|
}
|
||||||
catch (CompileException e)
|
catch (CompileException e)
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
|||||||
|
|
||||||
private TypedNodeDefinitionFunc.Param CheckDefinitionFuncParameter(NodeDefinitionFunc.Param node)
|
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)
|
private TypedNodeStatement CheckStatement(NodeStatement node)
|
||||||
@@ -102,7 +102,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
|||||||
|
|
||||||
private TypedNodeStatementVariableDeclaration CheckStatementVariableDeclaration(NodeStatementVariableDeclaration statement)
|
private TypedNodeStatementVariableDeclaration CheckStatementVariableDeclaration(NodeStatementVariableDeclaration statement)
|
||||||
{
|
{
|
||||||
var type = typeResolver.Resolve(statement.Type);
|
var type = ResolveType(statement.Type);
|
||||||
var value = CheckExpression(statement.Value);
|
var value = CheckExpression(statement.Value);
|
||||||
|
|
||||||
if (type != value.Type)
|
if (type != value.Type)
|
||||||
@@ -125,7 +125,8 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
|||||||
NodeExpressionBinary expression => CheckExpressionBinary(expression),
|
NodeExpressionBinary expression => CheckExpressionBinary(expression),
|
||||||
NodeExpressionUnary expression => CheckExpressionUnary(expression),
|
NodeExpressionUnary expression => CheckExpressionUnary(expression),
|
||||||
NodeExpressionBoolLiteral expression => CheckExpressionBoolLiteral(expression),
|
NodeExpressionBoolLiteral expression => CheckExpressionBoolLiteral(expression),
|
||||||
NodeExpressionIdent expression => CheckExpressionIdent(expression),
|
NodeExpressionLocalIdent expression => CheckExpressionIdent(expression),
|
||||||
|
NodeExpressionModuleIdent expression => CheckExpressionModuleIdent(expression),
|
||||||
NodeExpressionIntLiteral expression => CheckExpressionIntLiteral(expression),
|
NodeExpressionIntLiteral expression => CheckExpressionIntLiteral(expression),
|
||||||
NodeExpressionMemberAccess expression => CheckExpressionMemberAccess(expression),
|
NodeExpressionMemberAccess expression => CheckExpressionMemberAccess(expression),
|
||||||
NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(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);
|
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);
|
var type = scope.GetIdentifierType(expression.Value.Ident);
|
||||||
if (type == null)
|
if (type == null)
|
||||||
throw new CompileException(Diagnostic.Error($"Identifier '{expression.Value.Ident}' is not declared").At(fileName, expression.Value).Build());
|
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)
|
private TypedNodeExpressionIntLiteral CheckExpressionIntLiteral(NodeExpressionIntLiteral expression)
|
||||||
@@ -306,7 +313,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Ty
|
|||||||
|
|
||||||
private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression)
|
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)
|
if (type == null)
|
||||||
throw new CompileException(Diagnostic.Error($"Undeclared struct '{expression.Module.Ident}::{expression.Name.Ident}'").At(fileName, expression.Name).Build());
|
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);
|
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 class Scope(Scope? parent)
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, NubType> identifiers = new();
|
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 abstract class TypedNodeStatement(List<Token> tokens) : TypedNode(tokens);
|
||||||
|
|
||||||
public sealed class TypedNodeStatementBlock(List<Token> tokens, List<TypedNodeStatement> statements) : TypedNodeStatement(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 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 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 sealed class TypedNodeExpressionBinary(List<Token> tokens, NubType type, TypedNodeExpression left, TypedNodeExpressionBinary.Op operation, TypedNodeExpression right) : TypedNodeExpression(tokens, type)
|
||||||
{
|
{
|
||||||
public readonly TypedNodeExpression Left = left;
|
public readonly TypedNodeExpression Left = left;
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
struct person {
|
|
||||||
age: i32
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main(): i32 {
|
func main(): i32 {
|
||||||
let x: i32 = 23
|
let x: i32 = 23
|
||||||
x = 24
|
x = 24
|
||||||
@@ -25,11 +20,8 @@ func main(): i32 {
|
|||||||
x = i
|
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
|
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