221 lines
5.3 KiB
D
221 lines
5.3 KiB
D
module elna.ir;
|
|
|
|
import core.stdc.stdlib;
|
|
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 Statement = .Operand;
|
|
alias BangStatement = .Operand;
|
|
alias Block = .Definition;
|
|
alias Expression = .Operand;
|
|
alias Number = .Number;
|
|
alias Variable = .Number;
|
|
alias BinaryExpression = .Variable;
|
|
|
|
}
|
|
|
|
/**
|
|
* IR visitor.
|
|
*/
|
|
extern(C++, "elna", "ir")
|
|
abstract class 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(Number) @nogc;
|
|
}
|
|
|
|
/**
|
|
* AST node.
|
|
*/
|
|
extern(C++, "elna", "ir")
|
|
abstract class Node
|
|
{
|
|
abstract void accept(IRVisitor) @nogc;
|
|
}
|
|
|
|
/**
|
|
* Definition.
|
|
*/
|
|
extern(C++, "elna", "ir")
|
|
class Definition : Node
|
|
{
|
|
BinaryExpression* statements;
|
|
size_t statementsLength;
|
|
Operand result;
|
|
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
abstract class Statement : Node
|
|
{
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
abstract class Operand : Node
|
|
{
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
class Number : Operand
|
|
{
|
|
int value;
|
|
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
class Variable : Operand
|
|
{
|
|
size_t counter;
|
|
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
class BinaryExpression : Statement
|
|
{
|
|
Operand lhs, rhs;
|
|
BinaryOperator operator;
|
|
|
|
this(Operand lhs, Operand rhs, BinaryOperator operator) @nogc;
|
|
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
extern(C++, "elna", "ir")
|
|
class BangExpression : Statement
|
|
{
|
|
Operand operand;
|
|
|
|
this(Operand operand);
|
|
|
|
override void accept(IRVisitor visitor) @nogc;
|
|
}
|
|
|
|
final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
|
{
|
|
private HashTable!(String, int) constants;
|
|
private BinaryExpression* statements;
|
|
private size_t statementsLength;
|
|
|
|
ASTMapping.Node visit(parser.Node node) @nogc
|
|
{
|
|
assert(false, "Not implemented");
|
|
}
|
|
|
|
ASTMapping.Definition visit(parser.Definition definition) @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.statementsLength = this.statementsLength;
|
|
|
|
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
|
|
);
|
|
this.statements = cast(BinaryExpression*)
|
|
realloc(this.statements, (this.statementsLength + 1) * BinaryExpression.sizeof);
|
|
this.statements[this.statementsLength++] = target;
|
|
|
|
auto newVariable = defaultAllocator.make!Variable;
|
|
newVariable.counter = this.statementsLength;
|
|
|
|
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;
|
|
}
|
|
}
|