Generate IR in a visitor

This commit is contained in:
Eugen Wissner 2022-06-25 15:24:43 +02:00
parent b785147ded
commit 0d3453e7a9
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
3 changed files with 231 additions and 96 deletions

View File

@ -14,6 +14,7 @@ import std.typecons;
import tanya.os.error; import tanya.os.error;
import tanya.container.array; import tanya.container.array;
import tanya.container.string; import tanya.container.string;
import tanya.memory.allocator;
private Nullable!String readSource(string source) @nogc private Nullable!String readSource(string source) @nogc
{ {
@ -50,7 +51,9 @@ int generate(string inFile, ref String outputFilename) @nogc
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr); printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 2; return 2;
} }
auto ir = transform(ast.result); auto transformVisitor = defaultAllocator.make!TransformVisitor();
auto ir = transformVisitor.visit(ast.result);
defaultAllocator.dispose(transformVisitor);
auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate)); auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate));
if (!handle.valid) if (!handle.valid)

View File

@ -7,10 +7,28 @@ import tanya.container.string;
import tanya.memory.allocator; import tanya.memory.allocator;
public import elna.parser : BinaryOperator; public import elna.parser : BinaryOperator;
/**
* Mapping between the parser and IR AST.
*/
struct ASTMapping
{
alias Node = .Node;
alias Definition = .Definition;
alias VariableDeclaration = .VariableDeclaration;
alias Statement = Array!(.Statement);
alias BangStatement = .Expression;
alias Block = .Definition;
alias Expression = .Expression;
alias Number = .Number;
alias Variable = .Variable;
alias BinaryExpression = .BinaryExpression;
}
/** /**
* IR visitor. * IR visitor.
*/ */
abstract class IRVisitor interface IRVisitor
{ {
abstract void visit(Node) @nogc; abstract void visit(Node) @nogc;
abstract void visit(Definition) @nogc; abstract void visit(Definition) @nogc;
@ -112,18 +130,72 @@ class BinaryExpression : Node
} }
} }
private Number transformNumber(parser.Number number) @nogc final class TransformVisitor : parser.ParserVisitor!ASTMapping
{ {
return defaultAllocator.make!Number(number.value); private HashTable!(String, int) constants;
}
private Variable binaryExpression(parser.BinaryExpression binaryExpression, ASTMapping.Node visit(parser.Node node) @nogc
ref Array!Statement statements, {
ref HashTable!(String, int) constants) @nogc assert(false, "Not implemented");
{ }
ASTMapping.Definition visit(parser.Definition definition) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.VariableDeclaration visit(parser.VariableDeclaration declaration) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Block visit(parser.Block block) @nogc
{
auto target = defaultAllocator.make!Definition;
this.constants = transformConstants(block.definitions);
target.statements = block.statement.accept(this);
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
return target;
}
ASTMapping.Expression visit(parser.Expression expression) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Number visit(parser.Number number) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Variable visit(parser.Variable variable) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.BinaryExpression visit(parser.BinaryExpression) @nogc
{
assert(false, "Not implemented");
}
private Number transformNumber(parser.Number number) @nogc
{
return defaultAllocator.make!Number(number.value);
}
private Variable binaryExpression(parser.BinaryExpression binaryExpression,
ref Array!Statement statements) @nogc
{
auto target = defaultAllocator.make!BinaryExpression( auto target = defaultAllocator.make!BinaryExpression(
expression(binaryExpression.lhs, statements, constants), expression(binaryExpression.lhs, statements),
expression(binaryExpression.rhs, statements, constants), expression(binaryExpression.rhs, statements),
binaryExpression.operator binaryExpression.operator
); );
@ -135,12 +207,11 @@ private Variable binaryExpression(parser.BinaryExpression binaryExpression,
newVariable.counter = statements.length; newVariable.counter = statements.length;
return newVariable; return newVariable;
} }
private Expression expression(parser.Expression expression, private Expression expression(parser.Expression expression,
ref Array!Statement statements, ref Array!Statement statements) @nogc
ref HashTable!(String, int) constants) @nogc {
{
if ((cast(parser.Number) expression) !is null) if ((cast(parser.Number) expression) !is null)
{ {
auto numberExpression = defaultAllocator.make!Number; auto numberExpression = defaultAllocator.make!Number;
@ -151,30 +222,29 @@ private Expression expression(parser.Expression expression,
if ((cast(parser.Variable) expression) !is null) if ((cast(parser.Variable) expression) !is null)
{ {
auto numberExpression = defaultAllocator.make!Number; auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = constants[(cast(parser.Variable) expression).identifier]; numberExpression.value = this.constants[(cast(parser.Variable) expression).identifier];
return numberExpression; return numberExpression;
} }
else if ((cast(parser.BinaryExpression) expression) !is null) else if ((cast(parser.BinaryExpression) expression) !is null)
{ {
return binaryExpression(cast(parser.BinaryExpression) expression, statements, constants); return binaryExpression(cast(parser.BinaryExpression) expression, statements);
} }
return null; return null;
} }
Expression transformStatement(parser.Statement statement, override Array!Statement visit(parser.Statement statement) @nogc
ref Array!Statement statements, {
ref HashTable!(String, int) constants) @nogc typeof(return) statements;
{
if ((cast(parser.BangStatement) statement) !is null) if ((cast(parser.BangStatement) statement) !is null)
{ {
return expression((cast(parser.BangStatement) statement).expression, statements, constants); expression((cast(parser.BangStatement) statement).expression, statements);
}
return statements;
} }
return null;
}
HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
{ {
typeof(return) constants; typeof(return) constants;
foreach (definition; definitions[]) foreach (definition; definitions[])
@ -183,11 +253,11 @@ HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definit
} }
return constants; return constants;
} }
Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations) Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations)
@nogc @nogc
{ {
typeof(return) variables; typeof(return) variables;
foreach (ref variableDeclaration; variableDeclarations) foreach (ref variableDeclaration; variableDeclarations)
@ -198,15 +268,5 @@ Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.Variab
} }
return variables; return variables;
} }
Definition transform(parser.Block block) @nogc
{
auto target = defaultAllocator.make!Definition;
auto constants = transformConstants(block.definitions);
transformStatement(block.statement, target.statements, constants);
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
return target;
} }

View File

@ -6,51 +6,118 @@ import tanya.container.array;
import tanya.container.string; import tanya.container.string;
import tanya.memory.allocator; import tanya.memory.allocator;
/**
* Parser visitor.
*/
interface ParserVisitor(Mapping)
{
Mapping.Node visit(Node) @nogc;
Mapping.Definition visit(Definition) @nogc;
Mapping.VariableDeclaration visit(VariableDeclaration) @nogc;
Mapping.Statement visit(Statement) @nogc;
Mapping.BangStatement visit(BangStatement) @nogc;
Mapping.Block visit(Block) @nogc;
Mapping.Expression visit(Expression) @nogc;
Mapping.Number visit(Number) @nogc;
Mapping.Variable visit(Variable) @nogc;
Mapping.BinaryExpression visit(BinaryExpression) @nogc;
}
/**
* AST node.
*/
abstract class Node
{
Mapping.Node accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
/** /**
* Constant definition. * Constant definition.
*/ */
class Definition class Definition : Node
{ {
Number number; Number number;
String identifier; String identifier;
Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
/** /**
* Variable declaration. * Variable declaration.
*/ */
class VariableDeclaration class VariableDeclaration : Node
{ {
String identifier; String identifier;
Mapping.VariableDeclaration accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
abstract class Statement abstract class Statement : Node
{ {
Mapping.Statement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
class BangStatement : Statement class BangStatement : Statement
{ {
Expression expression; Expression expression;
Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
class Block class Block : Node
{ {
Array!Definition definitions; Array!Definition definitions;
Array!VariableDeclaration variableDeclarations; Array!VariableDeclaration variableDeclarations;
Statement statement; Statement statement;
Mapping.Block accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
abstract class Expression abstract class Expression : Node
{ {
Mapping.Expression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
class Number : Expression class Number : Expression
{ {
int value; int value;
Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
class Variable : Expression class Variable : Expression
{ {
String identifier; String identifier;
Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
enum BinaryOperator enum BinaryOperator
@ -81,6 +148,11 @@ class BinaryExpression : Expression
assert(false, "Invalid binary operator"); assert(false, "Invalid binary operator");
} }
} }
Mapping.BinaryExpression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
} }
private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc