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.os.error;
|
||||||
import tanya.container.array;
|
import tanya.container.array;
|
||||||
import tanya.container.string;
|
import tanya.container.string;
|
||||||
|
import tanya.memory.allocator;
|
||||||
|
|
||||||
private Nullable!String readSource(string source) @nogc
|
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);
|
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
|
||||||
return 2;
|
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));
|
auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate));
|
||||||
if (!handle.valid)
|
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;
|
import tanya.memory.allocator;
|
||||||
public import elna.parser : BinaryOperator;
|
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.
|
* IR visitor.
|
||||||
*/
|
*/
|
||||||
abstract class IRVisitor
|
interface IRVisitor
|
||||||
{
|
{
|
||||||
abstract void visit(Node) @nogc;
|
abstract void visit(Node) @nogc;
|
||||||
abstract void visit(Definition) @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,
|
ASTMapping.Node visit(parser.Node node) @nogc
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
auto numberExpression = defaultAllocator.make!Number;
|
assert(false, "Not implemented");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return constants;
|
ASTMapping.Definition visit(parser.Definition definition) @nogc
|
||||||
}
|
|
||||||
|
|
||||||
Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations)
|
|
||||||
@nogc
|
|
||||||
{
|
|
||||||
typeof(return) variables;
|
|
||||||
|
|
||||||
foreach (ref variableDeclaration; variableDeclarations)
|
|
||||||
{
|
{
|
||||||
auto newDeclaration = defaultAllocator.make!VariableDeclaration;
|
assert(false, "Not implemented");
|
||||||
newDeclaration.identifier = variableDeclaration.identifier;
|
|
||||||
variables.insertBack(newDeclaration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return variables;
|
ASTMapping.VariableDeclaration visit(parser.VariableDeclaration declaration) @nogc
|
||||||
}
|
{
|
||||||
|
assert(false, "Not implemented");
|
||||||
Definition transform(parser.Block block) @nogc
|
}
|
||||||
{
|
|
||||||
auto target = defaultAllocator.make!Definition;
|
ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc
|
||||||
auto constants = transformConstants(block.definitions);
|
{
|
||||||
|
assert(false, "Not implemented");
|
||||||
transformStatement(block.statement, target.statements, constants);
|
}
|
||||||
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
|
|
||||||
|
ASTMapping.Block visit(parser.Block block) @nogc
|
||||||
return target;
|
{
|
||||||
|
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.container.string;
|
||||||
import tanya.memory.allocator;
|
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.
|
* Constant definition.
|
||||||
*/
|
*/
|
||||||
class Definition
|
class Definition : Node
|
||||||
{
|
{
|
||||||
Number number;
|
Number number;
|
||||||
String identifier;
|
String identifier;
|
||||||
|
|
||||||
|
Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||||
|
{
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable declaration.
|
* Variable declaration.
|
||||||
*/
|
*/
|
||||||
class VariableDeclaration
|
class VariableDeclaration : Node
|
||||||
{
|
{
|
||||||
String identifier;
|
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
|
class BangStatement : Statement
|
||||||
{
|
{
|
||||||
Expression expression;
|
Expression expression;
|
||||||
|
|
||||||
|
Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||||
|
{
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Block
|
class Block : Node
|
||||||
{
|
{
|
||||||
Array!Definition definitions;
|
Array!Definition definitions;
|
||||||
Array!VariableDeclaration variableDeclarations;
|
Array!VariableDeclaration variableDeclarations;
|
||||||
Statement statement;
|
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
|
class Number : Expression
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
|
Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||||
|
{
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Variable : Expression
|
class Variable : Expression
|
||||||
{
|
{
|
||||||
String identifier;
|
String identifier;
|
||||||
|
|
||||||
|
Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
|
||||||
|
{
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BinaryOperator
|
enum BinaryOperator
|
||||||
@ -81,6 +148,11 @@ class BinaryExpression : Expression
|
|||||||
assert(false, "Invalid binary operator");
|
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
|
private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc
|
||||||
|
Loading…
Reference in New Issue
Block a user