...
This commit is contained in:
@@ -14,6 +14,9 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
|
||||
private string Emit()
|
||||
{
|
||||
foreach (var (i, structType) in moduleGraph.GetModules().SelectMany(x => x.GetCustomTypes().OfType<NubTypeStruct>().Index()))
|
||||
structTypeNames[structType] = $"s{i}";
|
||||
|
||||
writer.WriteLine("""
|
||||
#include <float.h>
|
||||
#include <stdarg.h>
|
||||
@@ -28,9 +31,6 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
|
||||
""");
|
||||
|
||||
foreach (var (i, structType) in moduleGraph.GetModules().SelectMany(x => x.GetCustomTypes().OfType<NubTypeStruct>().Index()))
|
||||
structTypeNames[structType] = $"s{i}";
|
||||
|
||||
foreach (var typeName in structTypeNames)
|
||||
writer.WriteLine($"struct {typeName.Value};");
|
||||
|
||||
@@ -45,30 +45,55 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
foreach (var field in typeName.Key.Fields)
|
||||
writer.WriteLine($"{CType(field.Type, field.Name)};");
|
||||
}
|
||||
|
||||
writer.WriteLine("};");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
foreach (var node in functions)
|
||||
foreach (var module in moduleGraph.GetModules())
|
||||
{
|
||||
var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident));
|
||||
writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)});");
|
||||
foreach (var (name, type) in module.GetIdentifierTypes())
|
||||
{
|
||||
if (type is NubTypeFunc fn)
|
||||
{
|
||||
if (!functions.Any(x => x.GetMangledName() == SymbolNameGen.Exported(module.Name, name, type)))
|
||||
writer.Write("extern ");
|
||||
|
||||
writer.WriteLine($"{CType(fn.ReturnType)} {SymbolNameGen.Exported(module.Name, name, type)}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"{CType(type)} {SymbolNameGen.Exported(module.Name, name, type)};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
foreach (var node in functions)
|
||||
var main = functions.FirstOrDefault(x => x.Module == "main" && x.Name.Ident == "main");
|
||||
|
||||
if (main != null)
|
||||
{
|
||||
var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident));
|
||||
writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)})");
|
||||
writer.WriteLine("int main(int argc, char *argv[])");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
EmitStatement(node.Body);
|
||||
writer.WriteLine($"return {main.GetMangledName()}();");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
foreach (var function in functions)
|
||||
{
|
||||
var parameters = function.Parameters.Select(x => CType(x.Type, x.Name.Ident));
|
||||
writer.WriteLine($"{CType(function.ReturnType, function.GetMangledName())}({string.Join(", ", parameters)})");
|
||||
writer.WriteLine("{");
|
||||
using (writer.Indent())
|
||||
{
|
||||
EmitStatement(function.Body);
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
writer.WriteLine();
|
||||
}
|
||||
@@ -114,7 +139,6 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
foreach (var statement in node.Statements)
|
||||
EmitStatement(statement);
|
||||
}
|
||||
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
@@ -153,7 +177,6 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
{
|
||||
EmitStatement(statement.ThenBlock);
|
||||
}
|
||||
|
||||
writer.WriteLine("}");
|
||||
|
||||
if (statement.ElseBlock != null)
|
||||
@@ -169,7 +192,6 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
{
|
||||
EmitStatement(statement.ElseBlock);
|
||||
}
|
||||
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
}
|
||||
@@ -183,7 +205,6 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
{
|
||||
EmitStatement(statement.Block);
|
||||
}
|
||||
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
@@ -199,7 +220,7 @@ public sealed class Generator(List<TypedNodeDefinitionFunc> functions, ModuleGra
|
||||
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
||||
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression),
|
||||
TypedNodeExpressionLocalIdent expression => expression.Value.Ident,
|
||||
TypedNodeExpressionModuleIdent expression => expression.Value.Ident,
|
||||
TypedNodeExpressionModuleIdent expression => SymbolNameGen.Exported(expression.Module.Ident, expression.Value.Ident, expression.Type),
|
||||
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||
};
|
||||
|
||||
@@ -24,11 +24,16 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
private readonly Dictionary<string, NubType> customTypes = new();
|
||||
private readonly Dictionary<string, NubType> identifierTypes = new();
|
||||
|
||||
public List<NubType> GetCustomTypes()
|
||||
public IReadOnlyList<NubType> GetCustomTypes()
|
||||
{
|
||||
return customTypes.Values.ToList();
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, NubType> GetIdentifierTypes()
|
||||
{
|
||||
return identifierTypes;
|
||||
}
|
||||
|
||||
public bool TryResolveCustomType(string name, [NotNullWhen(true)] out NubType? customType)
|
||||
{
|
||||
customType = customTypes.GetValueOrDefault(name);
|
||||
@@ -61,7 +66,7 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
asts.Add(ast);
|
||||
}
|
||||
|
||||
public ModuleGraph Build(out List<Diagnostic> diagnostics)
|
||||
public ModuleGraph? Build(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
diagnostics = [];
|
||||
|
||||
@@ -71,24 +76,11 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
// First pass: Register modules
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
|
||||
|
||||
if (moduleDefinitions.Count == 0)
|
||||
diagnostics.Add(Diagnostic.Error("Missing module declaration").At(ast.FileName, 1, 1, 1).Build());
|
||||
|
||||
foreach (var extraModuleDefinition in moduleDefinitions.Skip(1))
|
||||
diagnostics.Add(Diagnostic.Warning("Duplicate module declaration will be ignored").At(ast.FileName, extraModuleDefinition).Build());
|
||||
|
||||
if (moduleDefinitions.Count >= 1)
|
||||
if (!modules.ContainsKey(ast.ModuleName.Ident))
|
||||
{
|
||||
var currentModule = moduleDefinitions[0].Name.Ident;
|
||||
|
||||
if (!modules.ContainsKey(currentModule))
|
||||
{
|
||||
var module = new Module(currentModule);
|
||||
modules.Add(currentModule, module);
|
||||
astModuleCache[ast] = module;
|
||||
}
|
||||
var module = new Module(ast.ModuleName.Ident);
|
||||
modules.Add(ast.ModuleName.Ident, module);
|
||||
astModuleCache[ast] = module;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +125,9 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
|
||||
}
|
||||
}
|
||||
|
||||
if (diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
return null;
|
||||
|
||||
return new ModuleGraph(modules);
|
||||
|
||||
NubType ResolveType(NodeType node)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Compiler;
|
||||
|
||||
public abstract class NubType
|
||||
@@ -153,6 +155,8 @@ public sealed class NubTypeFunc : NubType
|
||||
public IReadOnlyList<NubType> Parameters { get; }
|
||||
public NubType ReturnType { get; }
|
||||
|
||||
public string MangledName(string name, string module) => SymbolNameGen.Exported(name, module, this);
|
||||
|
||||
private NubTypeFunc(List<NubType> parameters, NubType returnType)
|
||||
{
|
||||
Parameters = parameters;
|
||||
@@ -163,3 +167,109 @@ public sealed class NubTypeFunc : NubType
|
||||
|
||||
private readonly record struct Signature(IReadOnlyList<NubType> Parameters, NubType ReturnType);
|
||||
}
|
||||
|
||||
static class TypeMangler
|
||||
{
|
||||
public static string Encode(NubType type)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
Encode(type, sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void Encode(NubType type, StringBuilder sb)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NubTypeVoid:
|
||||
sb.Append('V');
|
||||
break;
|
||||
|
||||
case NubTypeBool:
|
||||
sb.Append('B');
|
||||
break;
|
||||
|
||||
case NubTypeUInt u:
|
||||
sb.Append("U(");
|
||||
sb.Append(u.Width);
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeSInt s:
|
||||
sb.Append("U(");
|
||||
sb.Append(s.Width);
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeString:
|
||||
sb.Append('S');
|
||||
break;
|
||||
|
||||
case NubTypePointer p:
|
||||
sb.Append("P(");
|
||||
Encode(p.To, sb);
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeStruct st:
|
||||
sb.Append($"T({st.Module}::{st.Name})").Append(st.Module).Append("::").Append(st.Name).Append(')');
|
||||
break;
|
||||
|
||||
case NubTypeFunc fn:
|
||||
sb.Append("F(");
|
||||
for (int i = 0; i < fn.Parameters.Count; i++)
|
||||
{
|
||||
Encode(fn.Parameters[i], sb);
|
||||
sb.Append(',');
|
||||
}
|
||||
Encode(fn.ReturnType, sb);
|
||||
sb.Append(')');
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(type.GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Hashing
|
||||
{
|
||||
public static ulong Fnv1a64(string text)
|
||||
{
|
||||
const ulong offset = 14695981039346656037UL;
|
||||
const ulong prime = 1099511628211UL;
|
||||
|
||||
ulong hash = offset;
|
||||
foreach (var c in Encoding.UTF8.GetBytes(text))
|
||||
{
|
||||
hash ^= c;
|
||||
hash *= prime;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
static class SymbolNameGen
|
||||
{
|
||||
public static string Exported(string module, string function, NubType type)
|
||||
{
|
||||
var canonical = TypeMangler.Encode(type);
|
||||
var hash = Hashing.Fnv1a64(canonical);
|
||||
|
||||
return $"nub_{Sanitize(module)}_{Sanitize(function)}_{hash:x16}";
|
||||
}
|
||||
|
||||
private static string Sanitize(string s)
|
||||
{
|
||||
var sb = new StringBuilder(s.Length);
|
||||
foreach (var c in s)
|
||||
{
|
||||
if (char.IsLetterOrDigit(c))
|
||||
sb.Append(c);
|
||||
else
|
||||
sb.Append('_');
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,25 @@ namespace Compiler;
|
||||
|
||||
public sealed class Parser(string fileName, List<Token> tokens)
|
||||
{
|
||||
public static Ast Parse(string fileName, List<Token> tokens, out List<Diagnostic> diagnostics)
|
||||
public static Ast? Parse(string fileName, List<Token> tokens, out List<Diagnostic> diagnostics)
|
||||
{
|
||||
return new Parser(fileName, tokens).Parse(out diagnostics);
|
||||
}
|
||||
|
||||
private int index;
|
||||
|
||||
private Ast Parse(out List<Diagnostic> diagnostics)
|
||||
private Ast? Parse(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
var definitions = new List<NodeDefinition>();
|
||||
diagnostics = [];
|
||||
|
||||
TokenIdent? moduleName = null;
|
||||
|
||||
try
|
||||
{
|
||||
ExpectKeyword(Keyword.Module);
|
||||
moduleName = ExpectIdent();
|
||||
|
||||
while (Peek() != null)
|
||||
{
|
||||
definitions.Add(ParseDefinition());
|
||||
@@ -28,7 +33,10 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
|
||||
return new Ast(definitions, fileName);
|
||||
if (moduleName == null || diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
return null;
|
||||
|
||||
return new Ast(fileName, moduleName, definitions);
|
||||
}
|
||||
|
||||
private NodeDefinition ParseDefinition()
|
||||
@@ -76,12 +84,6 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
return new NodeDefinitionStruct(TokensFrom(startIndex), name, fields);
|
||||
}
|
||||
|
||||
if (TryExpectKeyword(Keyword.Module))
|
||||
{
|
||||
var name = ExpectIdent();
|
||||
return new NodeDefinitionModule(TokensFrom(startIndex), name);
|
||||
}
|
||||
|
||||
throw new CompileException(Diagnostic.Error("Not a valid definition").At(fileName, Peek()).Build());
|
||||
}
|
||||
|
||||
@@ -355,6 +357,17 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
return tokens.GetRange(startIndex, index - startIndex);
|
||||
}
|
||||
|
||||
private void ExpectKeyword(Keyword keyword)
|
||||
{
|
||||
if (Peek() is TokenKeyword token && token.Keyword == keyword)
|
||||
{
|
||||
Next();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new CompileException(Diagnostic.Error($"Expected '{keyword.AsString()}'").At(fileName, Peek()).Build());
|
||||
}
|
||||
|
||||
private bool TryExpectKeyword(Keyword keyword)
|
||||
{
|
||||
if (Peek() is TokenKeyword token && token.Keyword == keyword)
|
||||
@@ -529,9 +542,10 @@ public sealed class Parser(string fileName, List<Token> tokens)
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Ast(List<NodeDefinition> definitions, string fileName)
|
||||
public sealed class Ast(string fileName, TokenIdent moduleName, List<NodeDefinition> definitions)
|
||||
{
|
||||
public string FileName { get; } = fileName;
|
||||
public TokenIdent ModuleName { get; } = moduleName;
|
||||
public List<NodeDefinition> Definitions { get; } = definitions;
|
||||
}
|
||||
|
||||
@@ -542,11 +556,6 @@ public abstract class Node(List<Token> tokens)
|
||||
|
||||
public abstract class NodeDefinition(List<Token> tokens) : Node(tokens);
|
||||
|
||||
public sealed class NodeDefinitionModule(List<Token> tokens, TokenIdent name) : NodeDefinition(tokens)
|
||||
{
|
||||
public TokenIdent Name { get; } = name;
|
||||
}
|
||||
|
||||
public sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens)
|
||||
{
|
||||
public TokenIdent Name { get; } = name;
|
||||
|
||||
@@ -13,7 +13,7 @@ foreach (var fileName in args)
|
||||
foreach (var diagnostic in tokenizerDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
|
||||
if (tokenizerDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
if (tokens == null)
|
||||
return 1;
|
||||
|
||||
var ast = Parser.Parse(fileName, tokens, out var parserDiagnostics);
|
||||
@@ -21,7 +21,7 @@ foreach (var fileName in args)
|
||||
foreach (var diagnostic in parserDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
|
||||
if (parserDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
if (ast == null)
|
||||
return 1;
|
||||
|
||||
moduleGraphBuilder.AddAst(ast);
|
||||
@@ -33,7 +33,7 @@ var moduleGraph = moduleGraphBuilder.Build(out var moduleGraphDiagnostics);
|
||||
foreach (var diagnostic in moduleGraphDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
|
||||
if (moduleGraphDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
if (moduleGraph == null)
|
||||
return 1;
|
||||
|
||||
var functions = new List<TypedNodeDefinitionFunc>();
|
||||
@@ -42,7 +42,7 @@ foreach (var ast in asts)
|
||||
{
|
||||
foreach (var func in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||
{
|
||||
var typedFunction = TypeChecker.CheckFunction(ast.FileName, func, moduleGraph, out var typeCheckerDiagnostics);
|
||||
var typedFunction = TypeChecker.CheckFunction(ast.FileName, ast.ModuleName.Ident, func, moduleGraph, out var typeCheckerDiagnostics);
|
||||
|
||||
foreach (var diagnostic in typeCheckerDiagnostics)
|
||||
DiagnosticFormatter.Print(diagnostic, Console.Error);
|
||||
@@ -61,6 +61,6 @@ Directory.CreateDirectory(".build");
|
||||
|
||||
File.WriteAllText(".build/out.c", output);
|
||||
|
||||
Process.Start("gcc", ["-Og", "-g", "-o", ".build/out", ".build/out.c"]);
|
||||
Process.Start("gcc", ["-Og", "-g", "-o", ".build/out", ".build/out.c", "-fvisibility=hidden","-fno-builtin"]);
|
||||
|
||||
return 0;
|
||||
@@ -5,7 +5,7 @@ namespace Compiler;
|
||||
|
||||
public sealed class Tokenizer(string fileName, string contents)
|
||||
{
|
||||
public static List<Token> Tokenize(string fileName, string contents, out List<Diagnostic> diagnostics)
|
||||
public static List<Token>? Tokenize(string fileName, string contents, out List<Diagnostic> diagnostics)
|
||||
{
|
||||
return new Tokenizer(fileName, contents).Tokenize(out diagnostics);
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public sealed class Tokenizer(string fileName, string contents)
|
||||
private int line = 1;
|
||||
private int column = 1;
|
||||
|
||||
private List<Token> Tokenize(out List<Diagnostic> diagnostics)
|
||||
private List<Token>? Tokenize(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
var tokens = new List<Token>();
|
||||
diagnostics = [];
|
||||
@@ -53,6 +53,9 @@ public sealed class Tokenizer(string fileName, string contents)
|
||||
}
|
||||
}
|
||||
|
||||
if (diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
|
||||
return null;
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace Compiler;
|
||||
|
||||
public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, ModuleGraph moduleGraph)
|
||||
public sealed class TypeChecker(string fileName, string moduleName, NodeDefinitionFunc function, ModuleGraph moduleGraph)
|
||||
{
|
||||
public static TypedNodeDefinitionFunc? CheckFunction(string fileName, NodeDefinitionFunc function, ModuleGraph moduleGraph, out List<Diagnostic> diagnostics)
|
||||
public static TypedNodeDefinitionFunc? CheckFunction(string fileName, string moduleName, NodeDefinitionFunc function, ModuleGraph moduleGraph, out List<Diagnostic> diagnostics)
|
||||
{
|
||||
return new TypeChecker(fileName, function, moduleGraph).CheckFunction(out diagnostics);
|
||||
return new TypeChecker(fileName, moduleName, function, moduleGraph).CheckFunction(out diagnostics);
|
||||
}
|
||||
|
||||
private readonly Scope scope = new(null);
|
||||
@@ -52,7 +52,7 @@ public sealed class TypeChecker(string fileName, NodeDefinitionFunc function, Mo
|
||||
if (body == null || returnType == null || invalidParameter)
|
||||
return null;
|
||||
|
||||
return new TypedNodeDefinitionFunc(function.Tokens, function.Name, parameters, body, returnType);
|
||||
return new TypedNodeDefinitionFunc(function.Tokens, moduleName, function.Name, parameters, body, returnType);
|
||||
}
|
||||
|
||||
private TypedNodeDefinitionFunc.Param CheckDefinitionFuncParameter(NodeDefinitionFunc.Param node)
|
||||
@@ -409,15 +409,28 @@ public abstract class TypedNode(List<Token> tokens)
|
||||
public List<Token> Tokens { get; } = tokens;
|
||||
}
|
||||
|
||||
public abstract class TypedNodeDefinition(List<Token> tokens) : TypedNode(tokens);
|
||||
public abstract class TypedNodeDefinition(List<Token> tokens, string module) : TypedNode(tokens)
|
||||
{
|
||||
public string Module { get; } = module;
|
||||
}
|
||||
|
||||
public sealed class TypedNodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<TypedNodeDefinitionFunc.Param> parameters, TypedNodeStatement body, NubType returnType) : TypedNodeDefinition(tokens)
|
||||
public sealed class TypedNodeDefinitionFunc(List<Token> tokens, string module, TokenIdent name, List<TypedNodeDefinitionFunc.Param> parameters, TypedNodeStatement body, NubType returnType) : TypedNodeDefinition(tokens, module)
|
||||
{
|
||||
public TokenIdent Name { get; } = name;
|
||||
public List<Param> Parameters { get; } = parameters;
|
||||
public TypedNodeStatement Body { get; } = body;
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
|
||||
public NubTypeFunc GetNubType()
|
||||
{
|
||||
return NubTypeFunc.Get(Parameters.Select(x => x.Type).ToList(), ReturnType);
|
||||
}
|
||||
|
||||
public string GetMangledName()
|
||||
{
|
||||
return SymbolNameGen.Exported(Module, Name.Ident, GetNubType());
|
||||
}
|
||||
|
||||
public sealed class Param(List<Token> tokens, TokenIdent name, NubType type) : TypedNode(tokens)
|
||||
{
|
||||
public TokenIdent Name { get; } = name;
|
||||
|
||||
Reference in New Issue
Block a user