...
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -32,3 +32,5 @@ _UpgradeReport_Files/
|
|||||||
Thumbs.db
|
Thumbs.db
|
||||||
Desktop.ini
|
Desktop.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
Nub.Lang/Nub.Lang/Output/out*
|
||||||
272
Nub.Lang/Nub.Lang/Generation/Generator.cs
Normal file
272
Nub.Lang/Nub.Lang/Generation/Generator.cs
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Nub.Lang.Parsing;
|
||||||
|
|
||||||
|
namespace Nub.Lang.Generation;
|
||||||
|
|
||||||
|
public class Generator
|
||||||
|
{
|
||||||
|
private const string Entrypoint = "main";
|
||||||
|
|
||||||
|
private readonly IReadOnlyCollection<DefinitionNode> _definitions;
|
||||||
|
private readonly SymbolTable _symbolTable;
|
||||||
|
private readonly StringBuilder _builder;
|
||||||
|
private Dictionary<string, string> _strings;
|
||||||
|
private int _stringIndex;
|
||||||
|
|
||||||
|
public Generator(IReadOnlyCollection<DefinitionNode> definitions)
|
||||||
|
{
|
||||||
|
_strings = [];
|
||||||
|
_definitions = definitions;
|
||||||
|
_builder = new StringBuilder();
|
||||||
|
_symbolTable = new SymbolTable(definitions.OfType<GlobalVariableDefinitionNode>().ToList());
|
||||||
|
foreach (var funcDefinitionNode in definitions.OfType<FuncDefinitionNode>())
|
||||||
|
{
|
||||||
|
_symbolTable.DefineFunc(funcDefinitionNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Generate()
|
||||||
|
{
|
||||||
|
_builder.AppendLine("global _start");
|
||||||
|
|
||||||
|
_builder.AppendLine();
|
||||||
|
_builder.AppendLine("section .bss");
|
||||||
|
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
|
||||||
|
{
|
||||||
|
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
|
||||||
|
_builder.AppendLine($" {symbol.Identifier}: resq 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
_builder.AppendLine();
|
||||||
|
_builder.AppendLine("section .text");
|
||||||
|
_builder.AppendLine("_start:");
|
||||||
|
|
||||||
|
var main = _symbolTable.ResolveFunc(Entrypoint, []);
|
||||||
|
|
||||||
|
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
|
||||||
|
{
|
||||||
|
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
|
||||||
|
_builder.AppendLine($" ; Initialize global variable {symbol.Name}");
|
||||||
|
GenerateExpression(globalVariable.Value, main);
|
||||||
|
_builder.AppendLine($" mov [{symbol.Identifier}], rax");
|
||||||
|
}
|
||||||
|
|
||||||
|
_builder.AppendLine();
|
||||||
|
_builder.AppendLine($" ; Call entrypoint {Entrypoint}");
|
||||||
|
_builder.AppendLine($" call {main.Label}");
|
||||||
|
|
||||||
|
_builder.AppendLine();
|
||||||
|
_builder.AppendLine(" ; Exit with status code 0");
|
||||||
|
_builder.AppendLine(" mov rax, 60");
|
||||||
|
_builder.AppendLine(" mov rdi, 0");
|
||||||
|
_builder.AppendLine(" syscall");
|
||||||
|
|
||||||
|
foreach (var funcDefinition in _definitions.OfType<FuncDefinitionNode>())
|
||||||
|
{
|
||||||
|
_builder.AppendLine();
|
||||||
|
GenerateFuncDefinition(funcDefinition);
|
||||||
|
}
|
||||||
|
_builder.AppendLine();
|
||||||
|
_builder.AppendLine("section .data");
|
||||||
|
foreach (var str in _strings)
|
||||||
|
{
|
||||||
|
_builder.AppendLine($"{str.Key}: db `{str.Value}`, 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateFuncDefinition(FuncDefinitionNode funcDefinition)
|
||||||
|
{
|
||||||
|
var symbol = _symbolTable.ResolveFunc(funcDefinition.Name, funcDefinition.Parameters.Select(p => p.Type).ToList());
|
||||||
|
_builder.AppendLine($"; {funcDefinition.ToString()}");
|
||||||
|
_builder.AppendLine($"{symbol.Label}:");
|
||||||
|
_builder.AppendLine(" push rbp");
|
||||||
|
_builder.AppendLine(" mov rbp, rsp");
|
||||||
|
_builder.AppendLine($" sub rsp, {symbol.StackAllocation}");
|
||||||
|
|
||||||
|
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
|
for (var i = 0; i < symbol.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameter = symbol.Parameters.ElementAt(i);
|
||||||
|
|
||||||
|
if (i < registers.Length)
|
||||||
|
{
|
||||||
|
var variable = symbol.ResolveLocalVariable(parameter.Name);
|
||||||
|
_builder.AppendLine($" mov [rbp - {variable.Offset}], {registers[i]}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Implement parameters passed on the stack
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateBlock(funcDefinition.Body, symbol);
|
||||||
|
_builder.AppendLine(" mov rsp, rbp");
|
||||||
|
_builder.AppendLine(" pop rbp");
|
||||||
|
_builder.AppendLine(" ret");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateBlock(BlockNode block, Func func)
|
||||||
|
{
|
||||||
|
foreach (var statement in block.Statements)
|
||||||
|
{
|
||||||
|
GenerateStatement(statement, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateStatement(StatementNode statement, Func func)
|
||||||
|
{
|
||||||
|
switch (statement)
|
||||||
|
{
|
||||||
|
case FuncCallStatementNode funcCallStatement:
|
||||||
|
GenerateFuncCall(funcCallStatement.FuncCall, func);
|
||||||
|
break;
|
||||||
|
case SyscallStatementNode syscallStatement:
|
||||||
|
GenerateSyscall(syscallStatement.Syscall, func);
|
||||||
|
break;
|
||||||
|
case VariableAssignmentNode variableAssignment:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(statement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateExpression(ExpressionNode expression, Func func)
|
||||||
|
{
|
||||||
|
switch (expression)
|
||||||
|
{
|
||||||
|
case FuncCallExpressionNode funcCallExpression:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
case IdentifierNode identifier:
|
||||||
|
GenerateIdentifier(identifier, func);
|
||||||
|
break;
|
||||||
|
case LiteralNode literal:
|
||||||
|
GenerateLiteral(literal, func);
|
||||||
|
break;
|
||||||
|
case SyscallExpressionNode syscallExpression:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(expression));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateIdentifier(IdentifierNode identifier, Func func)
|
||||||
|
{
|
||||||
|
var variable = func.ResolveVariable(identifier.Identifier);
|
||||||
|
|
||||||
|
switch (variable)
|
||||||
|
{
|
||||||
|
case GlobalVariable globalVariable:
|
||||||
|
_builder.AppendLine($" mov rax, [{globalVariable.Identifier}]");
|
||||||
|
break;
|
||||||
|
case LocalVariable localVariable:
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" mov rax, [rbp - {localVariable.Offset}]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(variable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateLiteral(LiteralNode literal, Func func)
|
||||||
|
{
|
||||||
|
switch (literal.Type)
|
||||||
|
{
|
||||||
|
case DelegateType:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
case StringType:
|
||||||
|
var ident = $"string{++_stringIndex}";
|
||||||
|
_strings.Add(ident, literal.Literal);
|
||||||
|
_builder.AppendLine($" mov rax, {ident}");
|
||||||
|
break;
|
||||||
|
case PrimitiveType primitive:
|
||||||
|
switch (primitive.Kind)
|
||||||
|
{
|
||||||
|
case PrimitiveTypeKind.Bool:
|
||||||
|
{
|
||||||
|
var value = literal.Literal == "true" ? 1 : 0;
|
||||||
|
_builder.AppendLine($" mov al, {value}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PrimitiveTypeKind.Char:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Int8:
|
||||||
|
case PrimitiveTypeKind.UInt8:
|
||||||
|
_builder.AppendLine($" mov al, {literal.Literal}");
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Int16:
|
||||||
|
case PrimitiveTypeKind.UInt16:
|
||||||
|
_builder.AppendLine($" mov ax, {literal.Literal}");
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Int32:
|
||||||
|
case PrimitiveTypeKind.UInt32:
|
||||||
|
_builder.AppendLine($" mov eax, {literal.Literal}");
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Int64:
|
||||||
|
case PrimitiveTypeKind.UInt64:
|
||||||
|
_builder.AppendLine($" mov rax, {literal.Literal}");
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Float:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
case PrimitiveTypeKind.Double:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use stack for more than 6 parameters
|
||||||
|
private void GenerateFuncCall(FuncCall funcCall, Func func)
|
||||||
|
{
|
||||||
|
var symbol = _symbolTable.ResolveFunc(funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
|
||||||
|
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
|
foreach (var parameter in funcCall.Parameters)
|
||||||
|
{
|
||||||
|
GenerateExpression(parameter, func);
|
||||||
|
_builder.AppendLine(" push rax");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = funcCall.Parameters.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" pop {registers[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_builder.AppendLine($" call {symbol.Label}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateSyscall(Syscall syscall, Func func)
|
||||||
|
{
|
||||||
|
string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"];
|
||||||
|
|
||||||
|
foreach (var parameter in syscall.Parameters)
|
||||||
|
{
|
||||||
|
GenerateExpression(parameter, func);
|
||||||
|
_builder.AppendLine(" push rax");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = syscall.Parameters.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" pop {registers[i]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_builder.AppendLine(" syscall");
|
||||||
|
}
|
||||||
|
}
|
||||||
128
Nub.Lang/Nub.Lang/Generation/SymbolTable.cs
Normal file
128
Nub.Lang/Nub.Lang/Generation/SymbolTable.cs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
using Nub.Lang.Parsing;
|
||||||
|
using Nub.Lib;
|
||||||
|
|
||||||
|
namespace Nub.Lang.Generation;
|
||||||
|
|
||||||
|
public class SymbolTable
|
||||||
|
{
|
||||||
|
private readonly List<Func> _functions = [];
|
||||||
|
private readonly List<GlobalVariable> _globalVariables = [];
|
||||||
|
private int _labelIndex;
|
||||||
|
|
||||||
|
public SymbolTable(IReadOnlyCollection<GlobalVariableDefinitionNode> globalVariableDefinitions)
|
||||||
|
{
|
||||||
|
var globalVariableIndex = 0;
|
||||||
|
foreach (var globalVariable in globalVariableDefinitions)
|
||||||
|
{
|
||||||
|
var identifier = $"variable{++globalVariableIndex}";
|
||||||
|
_globalVariables.Add(new GlobalVariable(globalVariable.Name, globalVariable.Value.Type, identifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DefineFunc(FuncDefinitionNode funcDefinition)
|
||||||
|
{
|
||||||
|
var label = $"func{++_labelIndex}";
|
||||||
|
var localVariables = ResolveFunctionVariables(funcDefinition);
|
||||||
|
_functions.Add(new Func(label, funcDefinition.Name, funcDefinition.Parameters, funcDefinition.ReturnType, _globalVariables.Concat<Variable>(localVariables.Variables).ToList(), localVariables.StackSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
private (int StackSize, List<LocalVariable> Variables) ResolveFunctionVariables(FuncDefinitionNode funcDefinition)
|
||||||
|
{
|
||||||
|
var offset = 0;
|
||||||
|
List<LocalVariable> variables = [];
|
||||||
|
|
||||||
|
foreach (var parameter in funcDefinition.Parameters)
|
||||||
|
{
|
||||||
|
offset += 8;
|
||||||
|
variables.Add(new LocalVariable(parameter.Name, parameter.Type, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var statement in funcDefinition.Body.Statements)
|
||||||
|
{
|
||||||
|
if (statement is VariableAssignmentNode variableAssignment)
|
||||||
|
{
|
||||||
|
offset += 8;
|
||||||
|
variables.Add(new LocalVariable(variableAssignment.Name, variableAssignment.Value.Type, offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (offset, variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func ResolveFunc(string name, IReadOnlyCollection<Type> parameterTypes)
|
||||||
|
{
|
||||||
|
var func = _functions.FirstOrDefault(f => f.Name == name && f.Parameters.Count == parameterTypes.Count && f.Parameters.Where((p, i) => p.Type == parameterTypes.ElementAt(i)).Count() == parameterTypes.Count);
|
||||||
|
if (func == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Func {name}({string.Join(", ", parameterTypes)}) is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalVariable ResolveGlobalVariable(string name)
|
||||||
|
{
|
||||||
|
var variable = _globalVariables.FirstOrDefault(v => v.Name == name);
|
||||||
|
if (variable == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Global variable {name} is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class Variable(string name, Type type)
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public Type Type { get; } = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LocalVariable(string name, Type type, int offset) : Variable(name, type)
|
||||||
|
{
|
||||||
|
public int Offset { get; } = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GlobalVariable(string name, Type type, string identifier) : Variable(name, type)
|
||||||
|
{
|
||||||
|
public string Identifier { get; } = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Func(string label, string name, IReadOnlyCollection<FuncParameter> parameters, Optional<Type> returnType, IReadOnlyCollection<Variable> variables, int stackAllocation)
|
||||||
|
{
|
||||||
|
public string Label { get; } = label;
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public IReadOnlyCollection<FuncParameter> Parameters { get; } = parameters;
|
||||||
|
public Optional<Type> ReturnType { get; } = returnType;
|
||||||
|
public IReadOnlyCollection<Variable> Variables { get; } = variables;
|
||||||
|
public int StackAllocation { get; } = stackAllocation;
|
||||||
|
|
||||||
|
public Variable ResolveVariable(string name)
|
||||||
|
{
|
||||||
|
var variable = Variables.FirstOrDefault(v => v.Name == name);
|
||||||
|
if (variable == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Variable {name} is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalVariable ResolveLocalVariable(string name)
|
||||||
|
{
|
||||||
|
var variable = Variables.FirstOrDefault(v => v.Name == name);
|
||||||
|
if (variable == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Variable {name} is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variable is not LocalVariable localVariable)
|
||||||
|
{
|
||||||
|
throw new Exception($"Variable {name} is not a local variable");
|
||||||
|
}
|
||||||
|
|
||||||
|
return localVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ let STD_OUT = 1;
|
|||||||
let STD_ERR = 2;
|
let STD_ERR = 2;
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
write("test");
|
write("test\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(msg: Func) {
|
func write(msg: pointer) {
|
||||||
syscall(SYS_WRITE, STD_OUT, msg);
|
syscall(SYS_WRITE, STD_OUT, msg, 5);
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ public class Lexer
|
|||||||
buffer += current.Value;
|
buffer += current.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LiteralToken(new PointerType(), buffer);
|
return new LiteralToken(new StringType(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (char.IsWhiteSpace(current.Value))
|
if (char.IsWhiteSpace(current.Value))
|
||||||
|
|||||||
9
Nub.Lang/Nub.Lang/Output/run.sh
Normal file
9
Nub.Lang/Nub.Lang/Output/run.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
nasm -g -felf64 out.asm -o out.o
|
||||||
|
ld out.o -o out
|
||||||
|
./out
|
||||||
|
|
||||||
|
rm out.o
|
||||||
|
|
||||||
|
echo "Process exited with status code $?"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Nub.Lang.Parsing;
|
namespace Nub.Lang.Parsing;
|
||||||
|
|
||||||
public class BlockNode(IEnumerable<StatementNode> statements) : Node
|
public class BlockNode(IReadOnlyCollection<StatementNode> statements) : Node
|
||||||
{
|
{
|
||||||
public IEnumerable<StatementNode> Statements { get; } = statements;
|
public IReadOnlyCollection<StatementNode> Statements { get; } = statements;
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
namespace Nub.Lang.Parsing;
|
namespace Nub.Lang.Parsing;
|
||||||
|
|
||||||
public class FuncCall(string name, IEnumerable<ExpressionNode> parameters)
|
public class FuncCall(string name, IReadOnlyCollection<ExpressionNode> parameters)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
|
public IReadOnlyCollection<ExpressionNode> Parameters { get; } = parameters;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}()";
|
public override string ToString() => $"{Name}()";
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace Nub.Lang.Parsing;
|
namespace Nub.Lang.Parsing;
|
||||||
|
|
||||||
public class FuncDefinitionNode(string name, IEnumerable<FuncParameter> parameters, BlockNode body, Optional<Type> returnType) : DefinitionNode
|
public class FuncDefinitionNode(string name, IReadOnlyCollection<FuncParameter> parameters, BlockNode body, Optional<Type> returnType) : DefinitionNode
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public IEnumerable<FuncParameter> Parameters { get; } = parameters;
|
public IReadOnlyCollection<FuncParameter> Parameters { get; } = parameters;
|
||||||
public BlockNode Body { get; } = body;
|
public BlockNode Body { get; } = body;
|
||||||
public Optional<Type> ReturnType { get; } = returnType;
|
public Optional<Type> ReturnType { get; } = returnType;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}({Parameters.Select(p => p.ToString())}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ public class Parser
|
|||||||
private readonly Token[] _tokens;
|
private readonly Token[] _tokens;
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public Parser(IEnumerable<Token> tokens)
|
public Parser(IReadOnlyCollection<Token> tokens)
|
||||||
{
|
{
|
||||||
_tokens = tokens.ToArray();
|
_tokens = tokens.ToArray();
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,12 @@ public class Parser
|
|||||||
|
|
||||||
var returnType = Optional<Type>.OfNullable(typeArguments.LastOrDefault());
|
var returnType = Optional<Type>.OfNullable(typeArguments.LastOrDefault());
|
||||||
|
|
||||||
return new DelegateType(typeArguments.Take(typeArguments.Count - 1), returnType);
|
return new DelegateType(typeArguments.Take(typeArguments.Count - 1).ToList(), returnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "pointer")
|
||||||
|
{
|
||||||
|
return new StringType();
|
||||||
}
|
}
|
||||||
|
|
||||||
return PrimitiveType.Parse(name);
|
return PrimitiveType.Parse(name);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Nub.Lang.Parsing;
|
namespace Nub.Lang.Parsing;
|
||||||
|
|
||||||
public class Syscall(IEnumerable<ExpressionNode> parameters)
|
public class Syscall(IReadOnlyCollection<ExpressionNode> parameters)
|
||||||
{
|
{
|
||||||
public IEnumerable<ExpressionNode> Parameters { get; } = parameters;
|
public IReadOnlyCollection<ExpressionNode> Parameters { get; } = parameters;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Nub.Lang.Lexing;
|
using Nub.Lang.Generation;
|
||||||
|
using Nub.Lang.Lexing;
|
||||||
using Nub.Lang.Parsing;
|
using Nub.Lang.Parsing;
|
||||||
using Nub.Lang.Typing;
|
using Nub.Lang.Typing;
|
||||||
|
|
||||||
@@ -11,4 +12,11 @@ var parser = new Parser(tokens);
|
|||||||
var definitions = parser.Parse();
|
var definitions = parser.Parse();
|
||||||
|
|
||||||
var typer = new ExpressionTyper(definitions);
|
var typer = new ExpressionTyper(definitions);
|
||||||
typer.Populate();
|
typer.Populate();
|
||||||
|
|
||||||
|
var generator = new Generator(definitions);
|
||||||
|
var asm = generator.Generate();
|
||||||
|
|
||||||
|
Console.WriteLine(asm);
|
||||||
|
|
||||||
|
File.WriteAllText(args[1], asm);
|
||||||
@@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
namespace Nub.Lang;
|
namespace Nub.Lang;
|
||||||
|
|
||||||
public abstract class Type;
|
public abstract record Type;
|
||||||
|
|
||||||
public class PrimitiveType(PrimitiveTypeKind kind) : Type
|
public record PrimitiveType : Type
|
||||||
{
|
{
|
||||||
|
public PrimitiveType(PrimitiveTypeKind kind)
|
||||||
|
{
|
||||||
|
Kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
public static PrimitiveType Parse(string value)
|
public static PrimitiveType Parse(string value)
|
||||||
{
|
{
|
||||||
var kind = value switch
|
var kind = value switch
|
||||||
@@ -28,7 +33,9 @@ public class PrimitiveType(PrimitiveTypeKind kind) : Type
|
|||||||
return new PrimitiveType(kind);
|
return new PrimitiveType(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrimitiveTypeKind Kind { get; } = kind;
|
public PrimitiveTypeKind Kind { get; }
|
||||||
|
|
||||||
|
public override string ToString() => Kind.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PrimitiveTypeKind
|
public enum PrimitiveTypeKind
|
||||||
@@ -47,10 +54,21 @@ public enum PrimitiveTypeKind
|
|||||||
Double,
|
Double,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PointerType : Type;
|
public record StringType : Type
|
||||||
|
|
||||||
public class DelegateType(IEnumerable<Type> parameters, Optional<Type> returnType) : Type
|
|
||||||
{
|
{
|
||||||
public IEnumerable<Type> Parameters { get; } = parameters;
|
public override string ToString() => "string";
|
||||||
public Optional<Type> ReturnType { get; } = returnType;
|
}
|
||||||
|
|
||||||
|
public record DelegateType : Type
|
||||||
|
{
|
||||||
|
public DelegateType(IReadOnlyCollection<Type> parameters, Optional<Type> returnType)
|
||||||
|
{
|
||||||
|
Parameters = parameters;
|
||||||
|
ReturnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyCollection<Type> Parameters { get; }
|
||||||
|
public Optional<Type> ReturnType { get; }
|
||||||
|
|
||||||
|
public override string ToString() => $"({string.Join(", ", Parameters)}): {(ReturnType.HasValue ? ReturnType.Value.ToString() : "")}";
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user