269 lines
6.2 KiB
D
269 lines
6.2 KiB
D
module elna.ir;
|
|
|
|
import parser = elna.parser;
|
|
import tanya.container.array;
|
|
import tanya.container.hashtable;
|
|
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 = .Operand;
|
|
alias BangStatement = .Operand;
|
|
alias Block = .Definition;
|
|
alias Expression = .Operand;
|
|
alias Number = .Number;
|
|
alias Variable = .Number;
|
|
alias BinaryExpression = .Variable;
|
|
|
|
}
|
|
|
|
/**
|
|
* IR visitor.
|
|
*/
|
|
interface IRVisitor
|
|
{
|
|
abstract void visit(Node) @nogc;
|
|
abstract void visit(Definition) @nogc;
|
|
abstract void visit(Operand) @nogc;
|
|
abstract void visit(BinaryExpression) @nogc;
|
|
abstract void visit(Variable) @nogc;
|
|
abstract void visit(VariableDeclaration) @nogc;
|
|
abstract void visit(Number) @nogc;
|
|
}
|
|
|
|
/**
|
|
* AST node.
|
|
*/
|
|
abstract class Node
|
|
{
|
|
abstract void accept(IRVisitor) @nogc;
|
|
}
|
|
|
|
/**
|
|
* Definition.
|
|
*/
|
|
class Definition : Node
|
|
{
|
|
char[] identifier;
|
|
Array!BinaryExpression statements;
|
|
Array!VariableDeclaration variableDeclarations;
|
|
Operand result;
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
abstract class Statement : Node
|
|
{
|
|
}
|
|
|
|
abstract class Operand : Node
|
|
{
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
class Number : Operand
|
|
{
|
|
int value;
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
class Variable : Operand
|
|
{
|
|
size_t counter;
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
class VariableDeclaration : Node
|
|
{
|
|
String identifier;
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
class BinaryExpression : Statement
|
|
{
|
|
Operand lhs, rhs;
|
|
BinaryOperator operator;
|
|
|
|
this(Operand lhs, Operand rhs, BinaryOperator operator)
|
|
@nogc
|
|
{
|
|
this.lhs = lhs;
|
|
this.rhs = rhs;
|
|
this.operator = operator;
|
|
}
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
class BangExpression : Statement
|
|
{
|
|
Operand operand;
|
|
|
|
this(Operand operand)
|
|
{
|
|
this.operand = operand;
|
|
}
|
|
|
|
override void accept(IRVisitor visitor) @nogc
|
|
{
|
|
visitor.visit(this);
|
|
}
|
|
}
|
|
|
|
final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
|
{
|
|
private HashTable!(String, int) constants;
|
|
private Array!BinaryExpression statements;
|
|
|
|
ASTMapping.Node visit(parser.Node node) @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
|
|
{
|
|
return statement.expression.accept(this);
|
|
}
|
|
|
|
ASTMapping.Block visit(parser.Block block) @nogc
|
|
{
|
|
auto target = defaultAllocator.make!Definition;
|
|
this.constants = transformConstants(block.definitions);
|
|
|
|
target.result = block.statement.accept(this);
|
|
target.statements = this.statements;
|
|
|
|
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
|
|
|
|
return target;
|
|
}
|
|
|
|
ASTMapping.Expression visit(parser.Expression expression) @nogc
|
|
{
|
|
if ((cast(parser.Number) expression) !is null)
|
|
{
|
|
return (cast(parser.Number) expression).accept(this);
|
|
}
|
|
if ((cast(parser.Variable) expression) !is null)
|
|
{
|
|
return (cast(parser.Variable) expression).accept(this);
|
|
}
|
|
else if ((cast(parser.BinaryExpression) expression) !is null)
|
|
{
|
|
return (cast(parser.BinaryExpression) expression).accept(this);
|
|
}
|
|
assert(false, "Invalid expression type");
|
|
}
|
|
|
|
ASTMapping.Number visit(parser.Number number) @nogc
|
|
{
|
|
auto numberExpression = defaultAllocator.make!Number;
|
|
numberExpression.value = number.value;
|
|
|
|
return numberExpression;
|
|
}
|
|
|
|
ASTMapping.Variable visit(parser.Variable variable) @nogc
|
|
{
|
|
auto numberExpression = defaultAllocator.make!Number;
|
|
numberExpression.value = this.constants[variable.identifier];
|
|
|
|
return numberExpression;
|
|
}
|
|
|
|
ASTMapping.BinaryExpression visit(parser.BinaryExpression binaryExpression) @nogc
|
|
{
|
|
auto target = defaultAllocator.make!BinaryExpression(
|
|
binaryExpression.lhs.accept(this),
|
|
binaryExpression.rhs.accept(this),
|
|
binaryExpression.operator
|
|
);
|
|
statements.insertBack(target);
|
|
|
|
auto newVariable = defaultAllocator.make!Variable;
|
|
newVariable.counter = statements.length;
|
|
|
|
return newVariable;
|
|
}
|
|
|
|
private Number transformNumber(parser.Number number) @nogc
|
|
{
|
|
return defaultAllocator.make!Number(number.value);
|
|
}
|
|
|
|
override Operand visit(parser.Statement statement) @nogc
|
|
{
|
|
if ((cast(parser.BangStatement) statement) !is null)
|
|
{
|
|
return (cast(parser.BangStatement) statement).accept(this);
|
|
}
|
|
assert(false, "Invalid statement type");
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|