mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Добавлены оптимизаторы-посетители
This commit is contained in:
parent
b29986a4b5
commit
8c5090d9d2
87
src/com/annimon/ownlang/parser/visitors/ConstantFolding.java
Normal file
87
src/com/annimon/ownlang/parser/visitors/ConstantFolding.java
Normal file
@ -0,0 +1,87 @@
|
||||
package com.annimon.ownlang.parser.visitors;
|
||||
|
||||
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
||||
import com.annimon.ownlang.parser.Optimizer;
|
||||
import com.annimon.ownlang.parser.ast.BinaryExpression;
|
||||
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
||||
import com.annimon.ownlang.parser.ast.Node;
|
||||
import com.annimon.ownlang.parser.ast.UnaryExpression;
|
||||
import com.annimon.ownlang.parser.ast.ValueExpression;
|
||||
|
||||
/**
|
||||
* Performs constant folding optimization.
|
||||
*/
|
||||
public class ConstantFolding extends OptimizationVisitor<Void> implements Optimizer.Info {
|
||||
|
||||
private int binaryExpressionFoldingCount;
|
||||
private int conditionalExpressionFoldingCount;
|
||||
private int unaryExpressionFoldingCount;
|
||||
|
||||
public ConstantFolding() {
|
||||
binaryExpressionFoldingCount = 0;
|
||||
conditionalExpressionFoldingCount = 0;
|
||||
unaryExpressionFoldingCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int optimizationsCount() {
|
||||
return binaryExpressionFoldingCount
|
||||
+ conditionalExpressionFoldingCount
|
||||
+ unaryExpressionFoldingCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String summaryInfo() {
|
||||
if (optimizationsCount() == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (binaryExpressionFoldingCount > 0) {
|
||||
sb.append("\nBinaryExpression foldings: ").append(binaryExpressionFoldingCount);
|
||||
}
|
||||
if (conditionalExpressionFoldingCount > 0) {
|
||||
sb.append("\nConditionalExpression foldings: ").append(conditionalExpressionFoldingCount);
|
||||
}
|
||||
if (unaryExpressionFoldingCount > 0) {
|
||||
sb.append("\nUnaryExpression foldings: ").append(unaryExpressionFoldingCount);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(BinaryExpression s, Void t) {
|
||||
if ( (s.expr1 instanceof ValueExpression) && (s.expr2 instanceof ValueExpression) ) {
|
||||
binaryExpressionFoldingCount++;
|
||||
try {
|
||||
return new ValueExpression(s.eval());
|
||||
} catch (OperationIsNotSupportedException op) {
|
||||
binaryExpressionFoldingCount--;
|
||||
}
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ConditionalExpression s, Void t) {
|
||||
if ( (s.expr1 instanceof ValueExpression) && (s.expr2 instanceof ValueExpression) ) {
|
||||
conditionalExpressionFoldingCount++;
|
||||
try {
|
||||
return new ValueExpression(s.eval());
|
||||
} catch (OperationIsNotSupportedException op) {
|
||||
conditionalExpressionFoldingCount--;
|
||||
}
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(UnaryExpression s, Void t) {
|
||||
if (s.expr1 instanceof ValueExpression) {
|
||||
unaryExpressionFoldingCount++;
|
||||
try {
|
||||
return new ValueExpression(s.eval());
|
||||
} catch (OperationIsNotSupportedException op) {
|
||||
unaryExpressionFoldingCount--;
|
||||
}
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.annimon.ownlang.parser.visitors;
|
||||
|
||||
import com.annimon.ownlang.parser.Optimizer;
|
||||
import com.annimon.ownlang.parser.ast.ExprStatement;
|
||||
import com.annimon.ownlang.parser.ast.IfStatement;
|
||||
import com.annimon.ownlang.parser.ast.Node;
|
||||
import com.annimon.ownlang.parser.ast.TernaryExpression;
|
||||
import com.annimon.ownlang.parser.ast.ValueExpression;
|
||||
import com.annimon.ownlang.parser.ast.WhileStatement;
|
||||
|
||||
/**
|
||||
* Performs dead code elimination.
|
||||
*/
|
||||
public class DeadCodeElimination extends OptimizationVisitor<Void> implements Optimizer.Info {
|
||||
|
||||
private int ifStatementEliminatedCount;
|
||||
private int ternaryExpressionEliminatedCount;
|
||||
private int whileStatementEliminatedCount;
|
||||
|
||||
@Override
|
||||
public int optimizationsCount() {
|
||||
return ifStatementEliminatedCount + ternaryExpressionEliminatedCount
|
||||
+ whileStatementEliminatedCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String summaryInfo() {
|
||||
if (optimizationsCount() == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (ifStatementEliminatedCount > 0) {
|
||||
sb.append("\nEliminated IfStatement: ").append(ifStatementEliminatedCount);
|
||||
}
|
||||
if (ternaryExpressionEliminatedCount > 0) {
|
||||
sb.append("\nEliminated TernaryExpression: ").append(ternaryExpressionEliminatedCount);
|
||||
}
|
||||
if (whileStatementEliminatedCount > 0) {
|
||||
sb.append("\nEliminated WhileStatement: ").append(whileStatementEliminatedCount);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(IfStatement s, Void t) {
|
||||
if (s.expression instanceof ValueExpression) {
|
||||
ifStatementEliminatedCount++;
|
||||
// true statement
|
||||
if (s.expression.eval().asInt() != 0) {
|
||||
return s.ifStatement;
|
||||
}
|
||||
// false statement
|
||||
if (s.elseStatement != null) {
|
||||
return s.elseStatement;
|
||||
}
|
||||
return new ExprStatement(s.expression);
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(TernaryExpression s, Void t) {
|
||||
if (s.condition instanceof ValueExpression) {
|
||||
ternaryExpressionEliminatedCount++;
|
||||
if (s.condition.eval().asInt() != 0) {
|
||||
return s.trueExpr;
|
||||
}
|
||||
return s.falseExpr;
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(WhileStatement s, Void t) {
|
||||
if (s.condition instanceof ValueExpression) {
|
||||
if (s.condition.eval().asInt() == 0) {
|
||||
whileStatementEliminatedCount++;
|
||||
return new ExprStatement(s.condition);
|
||||
}
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
}
|
332
src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java
Normal file
332
src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java
Normal file
@ -0,0 +1,332 @@
|
||||
package com.annimon.ownlang.parser.visitors;
|
||||
|
||||
import com.annimon.ownlang.parser.ast.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
||||
|
||||
@Override
|
||||
public Node visit(ArrayExpression s, T t) {
|
||||
final List<Expression> elements = new ArrayList<>(s.elements.size());
|
||||
boolean changed = false;
|
||||
for (Expression expression : s.elements) {
|
||||
final Node node = expression.accept(this, t);
|
||||
if (node != expression) {
|
||||
changed = true;
|
||||
}
|
||||
elements.add((Expression) node);
|
||||
}
|
||||
if (changed) {
|
||||
return new ArrayExpression(elements);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(AssignmentExpression s, T t) {
|
||||
final Node node = s.expression.accept(this, t);
|
||||
if (node != s.expression) {
|
||||
return new AssignmentExpression(s.operation, s.target, (Expression) node);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(BinaryExpression s, T t) {
|
||||
final Node expr1 = s.expr1.accept(this, t);
|
||||
final Node expr2 = s.expr2.accept(this, t);
|
||||
if (expr1 != s.expr1 || expr2 != s.expr2) {
|
||||
return new BinaryExpression(s.operation, (Expression) expr1, (Expression) expr2);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(BlockStatement s, T t) {
|
||||
boolean changed = false;
|
||||
final BlockStatement result = new BlockStatement();
|
||||
for (Statement statement : s.statements) {
|
||||
final Node node = statement.accept(this, t);
|
||||
if (node != statement) {
|
||||
changed = true;
|
||||
}
|
||||
result.add((Statement) node);
|
||||
}
|
||||
if (changed) {
|
||||
return result;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(BreakStatement s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ConditionalExpression s, T t) {
|
||||
final Node expr1 = s.expr1.accept(this, t);
|
||||
final Node expr2 = s.expr2.accept(this, t);
|
||||
if (expr1 != s.expr1 || expr2 != s.expr2) {
|
||||
return new ConditionalExpression(s.operation, (Expression) expr1, (Expression) expr2);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ContainerAccessExpression s, T t) {
|
||||
final List<Expression> indices = new ArrayList<>(s.indices.size());
|
||||
boolean changed = false;
|
||||
for (Expression expression : s.indices) {
|
||||
final Node node = expression.accept(this, t);
|
||||
if (node != expression) {
|
||||
changed = true;
|
||||
}
|
||||
indices.add((Expression) node);
|
||||
}
|
||||
if (changed) {
|
||||
return new ContainerAccessExpression(s.variable, indices);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ContinueStatement s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(DoWhileStatement s, T t) {
|
||||
final Node condition = s.condition.accept(this, t);
|
||||
final Node statement = s.statement.accept(this, t);
|
||||
if (condition != s.condition || statement != s.statement) {
|
||||
return new DoWhileStatement((Expression) condition, (Statement) statement);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(DestructuringAssignmentStatement s, T t) {
|
||||
final Node expr = s.containerExpression.accept(this, t);
|
||||
if (expr != s.containerExpression) {
|
||||
return new DestructuringAssignmentStatement(s.variables, (Expression) expr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ForStatement s, T t) {
|
||||
final Node initialization = s.initialization.accept(this, t);
|
||||
final Node termination = s.termination.accept(this, t);
|
||||
final Node increment = s.increment.accept(this, t);
|
||||
final Node statement = s.statement.accept(this, t);
|
||||
if (initialization != s.initialization || termination != s.termination
|
||||
|| increment != s.increment || statement != s.statement) {
|
||||
return new ForStatement((Statement) initialization,
|
||||
(Expression) termination, (Statement) increment, (Statement) statement);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ForeachArrayStatement s, T t) {
|
||||
final Node container = s.container.accept(this, t);
|
||||
final Node body = s.body.accept(this, t);
|
||||
if (container != s.container || body != s.body) {
|
||||
return new ForeachArrayStatement(s.variable, (Expression) container, (Statement) body);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ForeachMapStatement s, T t) {
|
||||
final Node container = s.container.accept(this, t);
|
||||
final Node body = s.body.accept(this, t);
|
||||
if (container != s.container || body != s.body) {
|
||||
return new ForeachMapStatement(s.key, s.value, (Expression) container, (Statement) body);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(FunctionDefineStatement s, T t) {
|
||||
final Node body = s.body.accept(this, t);
|
||||
if (body != s.body) {
|
||||
return new FunctionDefineStatement(s.name, s.arguments, (Statement) body);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(FunctionReferenceExpression s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ExprStatement s, T t) {
|
||||
final Node expr = s.expr.accept(this, t);
|
||||
if (expr != s.expr) {
|
||||
return new ExprStatement((Expression) expr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(FunctionalExpression s, T t) {
|
||||
final Node functionExpr = s.functionExpr.accept(this, t);
|
||||
final FunctionalExpression result = new FunctionalExpression((Expression) functionExpr);
|
||||
boolean changed = functionExpr != s.functionExpr;
|
||||
for (Expression argument : s.arguments) {
|
||||
final Node expr = argument.accept(this, t);
|
||||
if (expr != argument) {
|
||||
changed = true;
|
||||
}
|
||||
result.addArgument((Expression) expr);
|
||||
}
|
||||
if (changed) {
|
||||
return result;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(IfStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
final Node ifStatement = s.ifStatement.accept(this, t);
|
||||
final Node elseStatement;
|
||||
if (s.elseStatement != null) {
|
||||
elseStatement = s.elseStatement.accept(this, t);
|
||||
} else {
|
||||
elseStatement = null;
|
||||
}
|
||||
if (expression != s.expression || ifStatement != s.ifStatement || elseStatement != s.elseStatement) {
|
||||
return new IfStatement((Expression) expression, (Statement) ifStatement, (Statement) elseStatement);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(IncludeStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
if (expression != s.expression) {
|
||||
return new IncludeStatement((Expression) expression);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(MapExpression s, T t) {
|
||||
final Map<Expression, Expression> elements = new HashMap<>(s.elements.size());
|
||||
boolean changed = false;
|
||||
for (Map.Entry<Expression, Expression> entry : s.elements.entrySet()) {
|
||||
final Node key = entry.getKey().accept(this, t);
|
||||
final Node value = entry.getValue().accept(this, t);
|
||||
if (key != entry.getKey() || value != entry.getValue()) {
|
||||
changed = true;
|
||||
}
|
||||
elements.put((Expression) key, (Expression) value);
|
||||
}
|
||||
if (changed) {
|
||||
return new MapExpression(elements);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(MatchExpression s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
boolean changed = expression != s.expression;
|
||||
final List<MatchExpression.Pattern> patterns = new ArrayList<>(s.patterns.size());
|
||||
for (MatchExpression.Pattern pattern : s.patterns) {
|
||||
final Node patternResult = pattern.result.accept(this, t);
|
||||
if (patternResult != pattern.result) {
|
||||
changed = true;
|
||||
pattern.result = (Statement) patternResult;
|
||||
}
|
||||
patterns.add(pattern);
|
||||
}
|
||||
if (changed) {
|
||||
return new MatchExpression((Expression) expression, patterns);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(PrintStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
if (expression != s.expression) {
|
||||
return new PrintStatement((Expression) expression);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(PrintlnStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
if (expression != s.expression) {
|
||||
return new PrintlnStatement((Expression) expression);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ReturnStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
if (expression != s.expression) {
|
||||
return new ReturnStatement((Expression) expression);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(TernaryExpression s, T t) {
|
||||
final Node condition = s.condition.accept(this, t);
|
||||
final Node trueExpr = s.trueExpr.accept(this, t);
|
||||
final Node falseExpr = s.falseExpr.accept(this, t);
|
||||
if (condition != s.condition || trueExpr != s.trueExpr || falseExpr != s.falseExpr) {
|
||||
return new TernaryExpression((Expression) condition, (Expression) trueExpr, (Expression) falseExpr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(UnaryExpression s, T t) {
|
||||
final Node expr1 = s.expr1.accept(this, t);
|
||||
if (expr1 != s.expr1) {
|
||||
return new UnaryExpression(s.operation, (Expression) expr1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ValueExpression s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(VariableExpression s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(WhileStatement s, T t) {
|
||||
final Node condition = s.condition.accept(this, t);
|
||||
final Node statement = s.statement.accept(this, t);
|
||||
if (condition != s.condition || statement != s.statement) {
|
||||
return new WhileStatement((Expression) condition, (Statement) statement);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(UseStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
if (expression != s.expression) {
|
||||
return new UseStatement((Expression) expression);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user