Урок 13. Шаблон проектирования «Посетитель»

This commit is contained in:
Victor 2015-06-29 20:50:59 +03:00
parent 5144524ba2
commit ebed6c56d2
31 changed files with 390 additions and 39 deletions

View File

@ -4,6 +4,9 @@ import com.annimon.ownlang.parser.Lexer;
import com.annimon.ownlang.parser.Parser;
import com.annimon.ownlang.parser.Token;
import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.parser.visitors.AssignValidator;
import com.annimon.ownlang.parser.visitors.FunctionAdder;
import com.annimon.ownlang.parser.visitors.VariablePrinter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
@ -15,7 +18,7 @@ import java.util.List;
public final class Main {
public static void main(String[] args) throws IOException {
final String input = new String( Files.readAllBytes(Paths.get("program.own")), "UTF-8");
final String input = new String( Files.readAllBytes(Paths.get("visitor.own")), "UTF-8");
final List<Token> tokens = new Lexer(input).tokenize();
for (Token token : tokens) {
System.out.println(token);
@ -23,6 +26,9 @@ public final class Main {
final Statement program = new Parser(tokens).parse();
System.out.println(program.toString());
program.accept(new FunctionAdder());
program.accept(new VariablePrinter());
program.accept(new AssignValidator());
program.execute();
}
}

View File

@ -11,8 +11,8 @@ import java.util.List;
*/
public final class ArrayAccessExpression implements Expression {
private final String variable;
private final List<Expression> indices;
public final String variable;
public final List<Expression> indices;
public ArrayAccessExpression(String variable, List<Expression> indices) {
this.variable = variable;
@ -49,6 +49,11 @@ public final class ArrayAccessExpression implements Expression {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return variable + indices;

View File

@ -6,8 +6,8 @@ package com.annimon.ownlang.parser.ast;
*/
public final class ArrayAssignmentStatement implements Statement {
private final ArrayAccessExpression array;
private final Expression expression;
public final ArrayAccessExpression array;
public final Expression expression;
public ArrayAssignmentStatement(ArrayAccessExpression array, Expression expression) {
this.array = array;
@ -19,6 +19,11 @@ public final class ArrayAssignmentStatement implements Statement {
array.getArray().set(array.lastIndex(), expression.eval());
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("%s = %s", array, expression);

View File

@ -10,7 +10,7 @@ import java.util.List;
*/
public final class ArrayExpression implements Expression {
private final List<Expression> elements;
public final List<Expression> elements;
public ArrayExpression(List<Expression> arguments) {
this.elements = arguments;
@ -26,6 +26,11 @@ public final class ArrayExpression implements Expression {
return array;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return elements.toString();

View File

@ -9,8 +9,8 @@ import com.annimon.ownlang.lib.Variables;
*/
public final class AssignmentStatement implements Statement {
private final String variable;
private final Expression expression;
public final String variable;
public final Expression expression;
public AssignmentStatement(String variable, Expression expression) {
this.variable = variable;
@ -23,6 +23,11 @@ public final class AssignmentStatement implements Statement {
Variables.set(variable, result);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("%s = %s", variable, expression);

View File

@ -11,8 +11,8 @@ import com.annimon.ownlang.lib.Value;
*/
public final class BinaryExpression implements Expression {
private final Expression expr1, expr2;
private final char operation;
public final Expression expr1, expr2;
public final char operation;
public BinaryExpression(char operation, Expression expr1, Expression expr2) {
this.operation = operation;
@ -53,6 +53,11 @@ public final class BinaryExpression implements Expression {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("[%s %c %s]", expr1, operation, expr2);

View File

@ -9,7 +9,7 @@ import java.util.List;
*/
public final class BlockStatement implements Statement {
private final List<Statement> statements;
public final List<Statement> statements;
public BlockStatement() {
statements = new ArrayList<>();
@ -26,6 +26,11 @@ public final class BlockStatement implements Statement {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();

View File

@ -11,6 +11,11 @@ public final class BreakStatement extends RuntimeException implements Statement
throw this;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "break";

View File

@ -38,8 +38,8 @@ public final class ConditionalExpression implements Expression {
}
}
private final Expression expr1, expr2;
private final Operator operation;
public final Expression expr1, expr2;
public final Operator operation;
public ConditionalExpression(Operator operation, Expression expr1, Expression expr2) {
this.operation = operation;
@ -79,6 +79,11 @@ public final class ConditionalExpression implements Expression {
return new NumberValue(result);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("[%s %s %s]", expr1, operation.getName(), expr2);

View File

@ -11,6 +11,11 @@ public final class ContinueStatement extends RuntimeException implements Stateme
throw this;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "continue";

View File

@ -6,8 +6,8 @@ package com.annimon.ownlang.parser.ast;
*/
public final class DoWhileStatement implements Statement {
private final Expression condition;
private final Statement statement;
public final Expression condition;
public final Statement statement;
public DoWhileStatement(Expression condition, Statement statement) {
this.condition = condition;
@ -28,6 +28,11 @@ public final class DoWhileStatement implements Statement {
while (condition.eval().asNumber() != 0);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "do " + statement + " while " + condition;

View File

@ -6,7 +6,7 @@ import com.annimon.ownlang.lib.Value;
*
* @author aNNiMON
*/
public interface Expression {
public interface Expression extends Node {
Value eval();
}

View File

@ -6,10 +6,10 @@ package com.annimon.ownlang.parser.ast;
*/
public final class ForStatement implements Statement {
private final Statement initialization;
private final Expression termination;
private final Statement increment;
private final Statement statement;
public final Statement initialization;
public final Expression termination;
public final Statement increment;
public final Statement statement;
public ForStatement(Statement initialization, Expression termination, Statement increment, Statement block) {
this.initialization = initialization;
@ -31,6 +31,11 @@ public final class ForStatement implements Statement {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "for " + initialization + ", " + termination + ", " + increment + " " + statement;

View File

@ -10,9 +10,9 @@ import java.util.List;
*/
public final class FunctionDefineStatement implements Statement {
private final String name;
private final List<String> argNames;
private final Statement body;
public final String name;
public final List<String> argNames;
public final Statement body;
public FunctionDefineStatement(String name, List<String> argNames, Statement body) {
this.name = name;
@ -25,6 +25,11 @@ public final class FunctionDefineStatement implements Statement {
Functions.set(name, new UserDefinedFunction(argNames, body));
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "def (" + argNames.toString() + ") " + body.toString();

View File

@ -6,7 +6,7 @@ package com.annimon.ownlang.parser.ast;
*/
public final class FunctionStatement implements Statement {
private final FunctionalExpression function;
public final FunctionalExpression function;
public FunctionStatement(FunctionalExpression function) {
this.function = function;
@ -17,6 +17,11 @@ public final class FunctionStatement implements Statement {
function.eval();
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return function.toString();

View File

@ -14,8 +14,8 @@ import java.util.List;
*/
public final class FunctionalExpression implements Expression {
private final String name;
private final List<Expression> arguments;
public final String name;
public final List<Expression> arguments;
public FunctionalExpression(String name) {
this.name = name;
@ -55,6 +55,11 @@ public final class FunctionalExpression implements Expression {
return function.execute(values);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return name + "(" + arguments.toString() + ")";

View File

@ -6,8 +6,8 @@ package com.annimon.ownlang.parser.ast;
*/
public final class IfStatement implements Statement {
private final Expression expression;
private final Statement ifStatement, elseStatement;
public final Expression expression;
public final Statement ifStatement, elseStatement;
public IfStatement(Expression expression, Statement ifStatement, Statement elseStatement) {
this.expression = expression;
@ -25,6 +25,11 @@ public final class IfStatement implements Statement {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();

View File

@ -0,0 +1,10 @@
package com.annimon.ownlang.parser.ast;
/**
*
* @author aNNiMON
*/
public interface Node {
void accept(Visitor visitor);
}

View File

@ -6,7 +6,7 @@ package com.annimon.ownlang.parser.ast;
*/
public final class PrintStatement implements Statement {
private final Expression expression;
public final Expression expression;
public PrintStatement(Expression expression) {
this.expression = expression;
@ -17,6 +17,11 @@ public final class PrintStatement implements Statement {
System.out.print(expression.eval());
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "print " + expression;

View File

@ -8,7 +8,7 @@ import com.annimon.ownlang.lib.Value;
*/
public final class ReturnStatement extends RuntimeException implements Statement {
private final Expression expression;
public final Expression expression;
private Value result;
public ReturnStatement(Expression expression) {
@ -25,6 +25,11 @@ public final class ReturnStatement extends RuntimeException implements Statement
throw this;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "return";

View File

@ -4,7 +4,7 @@ package com.annimon.ownlang.parser.ast;
*
* @author aNNiMON
*/
public interface Statement {
public interface Statement extends Node {
void execute();
}

View File

@ -9,8 +9,8 @@ import com.annimon.ownlang.lib.Value;
*/
public final class UnaryExpression implements Expression {
private final Expression expr1;
private final char operation;
public final Expression expr1;
public final char operation;
public UnaryExpression(char operation, Expression expr1) {
this.operation = operation;
@ -27,6 +27,11 @@ public final class UnaryExpression implements Expression {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("%c %s", operation, expr1);

View File

@ -10,7 +10,7 @@ import com.annimon.ownlang.lib.Value;
*/
public final class ValueExpression implements Expression {
private final Value value;
public final Value value;
public ValueExpression(double value) {
this.value = new NumberValue(value);
@ -25,6 +25,11 @@ public final class ValueExpression implements Expression {
return value;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return value.asString();

View File

@ -9,7 +9,7 @@ import com.annimon.ownlang.lib.Variables;
*/
public final class VariableExpression implements Expression {
private final String name;
public final String name;
public VariableExpression(String name) {
this.name = name;
@ -21,6 +21,11 @@ public final class VariableExpression implements Expression {
return Variables.get(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return name;

View File

@ -0,0 +1,30 @@
package com.annimon.ownlang.parser.ast;
/**
*
* @author aNNiMON
*/
public interface Visitor {
void visit(ArrayAccessExpression s);
void visit(ArrayAssignmentStatement s);
void visit(ArrayExpression s);
void visit(AssignmentStatement s);
void visit(BinaryExpression s);
void visit(BlockStatement s);
void visit(BreakStatement s);
void visit(ConditionalExpression s);
void visit(ContinueStatement s);
void visit(DoWhileStatement s);
void visit(ForStatement s);
void visit(FunctionDefineStatement s);
void visit(FunctionStatement s);
void visit(FunctionalExpression s);
void visit(IfStatement s);
void visit(PrintStatement s);
void visit(ReturnStatement s);
void visit(UnaryExpression s);
void visit(ValueExpression s);
void visit(VariableExpression s);
void visit(WhileStatement st);
}

View File

@ -6,8 +6,8 @@ package com.annimon.ownlang.parser.ast;
*/
public final class WhileStatement implements Statement {
private final Expression condition;
private final Statement statement;
public final Expression condition;
public final Statement statement;
public WhileStatement(Expression condition, Statement statement) {
this.condition = condition;
@ -27,6 +27,11 @@ public final class WhileStatement implements Statement {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "while " + condition + " " + statement;

View File

@ -0,0 +1,132 @@
package com.annimon.ownlang.parser.visitors;
import com.annimon.ownlang.parser.ast.*;
/**
*
* @author aNNiMON
*/
public abstract class AbstractVisitor implements Visitor {
@Override
public void visit(ArrayAccessExpression s) {
for (Expression index : s.indices) {
index.accept(this);
}
}
@Override
public void visit(ArrayAssignmentStatement s) {
s.array.accept(this);
s.expression.accept(this);
}
@Override
public void visit(ArrayExpression s) {
for (Expression index : s.elements) {
index.accept(this);
}
}
@Override
public void visit(AssignmentStatement s) {
s.expression.accept(this);
}
@Override
public void visit(BinaryExpression s) {
s.expr1.accept(this);
s.expr2.accept(this);
}
@Override
public void visit(BlockStatement s) {
for (Statement statement : s.statements) {
statement.accept(this);
}
}
@Override
public void visit(BreakStatement s) {
}
@Override
public void visit(ConditionalExpression s) {
s.expr1.accept(this);
s.expr2.accept(this);
}
@Override
public void visit(ContinueStatement s) {
}
@Override
public void visit(DoWhileStatement s) {
s.condition.accept(this);
s.statement.accept(this);
}
@Override
public void visit(ForStatement s) {
s.initialization.accept(this);
s.termination.accept(this);
s.increment.accept(this);
s.statement.accept(this);
}
@Override
public void visit(FunctionDefineStatement s) {
s.body.accept(this);
}
@Override
public void visit(FunctionStatement s) {
s.function.accept(this);
}
@Override
public void visit(FunctionalExpression s) {
for (Expression argument : s.arguments) {
argument.accept(this);
}
}
@Override
public void visit(IfStatement s) {
s.expression.accept(this);
s.ifStatement.accept(this);
if (s.elseStatement != null) {
s.elseStatement.accept(this);
}
}
@Override
public void visit(PrintStatement s) {
s.expression.accept(this);
}
@Override
public void visit(ReturnStatement s) {
s.expression.accept(this);
}
@Override
public void visit(UnaryExpression s) {
s.expr1.accept(this);
}
@Override
public void visit(ValueExpression s) {
}
@Override
public void visit(VariableExpression s) {
}
@Override
public void visit(WhileStatement st) {
st.condition.accept(this);
st.statement.accept(this);
}
}

View File

@ -0,0 +1,19 @@
package com.annimon.ownlang.parser.visitors;
import com.annimon.ownlang.lib.Variables;
import com.annimon.ownlang.parser.ast.*;
/**
*
* @author aNNiMON
*/
public final class AssignValidator extends AbstractVisitor {
@Override
public void visit(AssignmentStatement s) {
super.visit(s);
if (Variables.isExists(s.variable)) {
throw new RuntimeException("Cannot assign value to constant");
}
}
}

View File

@ -0,0 +1,16 @@
package com.annimon.ownlang.parser.visitors;
import com.annimon.ownlang.parser.ast.*;
/**
*
* @author aNNiMON
*/
public final class FunctionAdder extends AbstractVisitor {
@Override
public void visit(FunctionDefineStatement s) {
super.visit(s);
s.execute();
}
}

View File

@ -0,0 +1,28 @@
package com.annimon.ownlang.parser.visitors;
import com.annimon.ownlang.parser.ast.*;
/**
*
* @author aNNiMON
*/
public final class VariablePrinter extends AbstractVisitor {
@Override
public void visit(ArrayAccessExpression s) {
super.visit(s);
System.out.println(s.variable);
}
@Override
public void visit(AssignmentStatement s) {
super.visit(s);
System.out.println(s.variable);
}
@Override
public void visit(VariableExpression s) {
super.visit(s);
System.out.println(s.name);
}
}

5
visitor.own Normal file
View File

@ -0,0 +1,5 @@
func()
def func() print "function\n"
a = 2 + 3 * 4
print a