279 lines
6.3 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.
*/
extern(C++)
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.
*/
extern(C++)
abstract class Node
{
abstract void accept(IRVisitor) @nogc;
}
/**
* Definition.
*/
extern(C++)
class Definition : Node
{
char[] identifier;
Array!BinaryExpression statements;
Array!VariableDeclaration variableDeclarations;
Operand result;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
extern(C++)
abstract class Statement : Node
{
}
extern(C++)
abstract class Operand : Node
{
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
extern(C++)
class Number : Operand
{
int value;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
extern(C++)
class Variable : Operand
{
size_t counter;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
extern(C++)
class VariableDeclaration : Node
{
String identifier;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
extern(C++)
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);
}
}
extern(C++)
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;
}
}