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.container.array;
import tanya.container.string;
import tanya.memory.allocator;
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);
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));
if (!handle.valid)

View File

@ -7,10 +7,28 @@ import tanya.container.string;
import tanya.memory.allocator;
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.
*/
abstract class IRVisitor
interface IRVisitor
{
abstract void visit(Node) @nogc;
abstract void visit(Definition) @nogc;
@ -112,101 +130,143 @@ 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,
ref Array!Statement statements,
ref HashTable!(String, int) constants) @nogc
{
auto target = defaultAllocator.make!BinaryExpression(
expression(binaryExpression.lhs, statements, constants),
expression(binaryExpression.rhs, statements, constants),
binaryExpression.operator
);
auto newStatement = defaultAllocator.make!Statement;
newStatement.expression = target;
statements.insertBack(newStatement);
auto newVariable = defaultAllocator.make!Variable;
newVariable.counter = statements.length;
return newVariable;
}
private Expression expression(parser.Expression expression,
ref Array!Statement statements,
ref HashTable!(String, int) constants) @nogc
{
if ((cast(parser.Number) expression) !is null)
ASTMapping.Node visit(parser.Node node) @nogc
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = (cast(parser.Number) expression).value;
return numberExpression;
}
if ((cast(parser.Variable) expression) !is null)
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = constants[(cast(parser.Variable) expression).identifier];
return numberExpression;
}
else if ((cast(parser.BinaryExpression) expression) !is null)
{
return binaryExpression(cast(parser.BinaryExpression) expression, statements, constants);
}
return null;
}
Expression transformStatement(parser.Statement statement,
ref Array!Statement statements,
ref HashTable!(String, int) constants) @nogc
{
if ((cast(parser.BangStatement) statement) !is null)
{
return expression((cast(parser.BangStatement) statement).expression, statements, constants);
}
return null;
}
HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
{
typeof(return) constants;
foreach (definition; definitions[])
{
constants[definition.identifier] = definition.number.value;
assert(false, "Not implemented");
}
return constants;
}
Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations)
@nogc
{
typeof(return) variables;
foreach (ref variableDeclaration; variableDeclarations)
ASTMapping.Definition visit(parser.Definition definition) @nogc
{
auto newDeclaration = defaultAllocator.make!VariableDeclaration;
newDeclaration.identifier = variableDeclaration.identifier;
variables.insertBack(newDeclaration);
assert(false, "Not implemented");
}
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;
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(
expression(binaryExpression.lhs, statements),
expression(binaryExpression.rhs, statements),
binaryExpression.operator
);
auto newStatement = defaultAllocator.make!Statement;
newStatement.expression = target;
statements.insertBack(newStatement);
auto newVariable = defaultAllocator.make!Variable;
newVariable.counter = statements.length;
return newVariable;
}
private Expression expression(parser.Expression expression,
ref Array!Statement statements) @nogc
{
if ((cast(parser.Number) expression) !is null)
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = (cast(parser.Number) expression).value;
return numberExpression;
}
if ((cast(parser.Variable) expression) !is null)
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = this.constants[(cast(parser.Variable) expression).identifier];
return numberExpression;
}
else if ((cast(parser.BinaryExpression) expression) !is null)
{
return binaryExpression(cast(parser.BinaryExpression) expression, statements);
}
return null;
}
override Array!Statement visit(parser.Statement statement) @nogc
{
typeof(return) statements;
if ((cast(parser.BangStatement) statement) !is null)
{
expression((cast(parser.BangStatement) statement).expression, statements);
}
return statements;
}
private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
{
typeof(return) constants;
foreach (definition; definitions[])
{
constants[definition.identifier] = definition.number.value;
}
return constants;
}
Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations)
@nogc
{
typeof(return) variables;
foreach (ref variableDeclaration; variableDeclarations)
{
auto newDeclaration = defaultAllocator.make!VariableDeclaration;
newDeclaration.identifier = variableDeclaration.identifier;
variables.insertBack(newDeclaration);
}
return variables;
}
}

View File

@ -6,51 +6,118 @@ import tanya.container.array;
import tanya.container.string;
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.
*/
class Definition
class Definition : Node
{
Number number;
String identifier;
Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
/**
* Variable declaration.
*/
class VariableDeclaration
class VariableDeclaration : Node
{
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
{
Expression expression;
Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class Block
class Block : Node
{
Array!Definition definitions;
Array!VariableDeclaration variableDeclarations;
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
{
int value;
Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class Variable : Expression
{
String identifier;
Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
enum BinaryOperator
@ -81,6 +148,11 @@ class BinaryExpression : Expression
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