From 0d3453e7a9fc77d53f8aec5d39c89e1f118bb015 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 25 Jun 2022 15:24:43 +0200 Subject: [PATCH] Generate IR in a visitor --- source/elna/backend.d | 5 +- source/elna/ir.d | 240 ++++++++++++++++++++++++++---------------- source/elna/parser.d | 82 ++++++++++++++- 3 files changed, 231 insertions(+), 96 deletions(-) diff --git a/source/elna/backend.d b/source/elna/backend.d index 86afaed..995efda 100644 --- a/source/elna/backend.d +++ b/source/elna/backend.d @@ -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) diff --git a/source/elna/ir.d b/source/elna/ir.d index db6bae9..edb70fa 100644 --- a/source/elna/ir.d +++ b/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; + } } diff --git a/source/elna/parser.d b/source/elna/parser.d index 3c14bda..c0bf048 100644 --- a/source/elna/parser.d +++ b/source/elna/parser.d @@ -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