2024-02-28 16:18:39 +01:00

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;
}
}