Generate IR in a visitor
This commit is contained in:
parent
b785147ded
commit
0d3453e7a9
@ -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)
|
||||
|
240
source/elna/ir.d
240
source/elna/ir.d
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user