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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,8 +11,8 @@ import com.annimon.ownlang.lib.Value;
*/ */
public final class BinaryExpression implements Expression { public final class BinaryExpression implements Expression {
private final Expression expr1, expr2; public final Expression expr1, expr2;
private final char operation; public final char operation;
public BinaryExpression(char operation, Expression expr1, Expression expr2) { public BinaryExpression(char operation, Expression expr1, Expression expr2) {
this.operation = operation; this.operation = operation;
@ -52,6 +52,11 @@ public final class BinaryExpression implements Expression {
return new NumberValue(number1 + number2); return new NumberValue(number1 + number2);
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,8 +14,8 @@ import java.util.List;
*/ */
public final class FunctionalExpression implements Expression { public final class FunctionalExpression implements Expression {
private final String name; public final String name;
private final List<Expression> arguments; public final List<Expression> arguments;
public FunctionalExpression(String name) { public FunctionalExpression(String name) {
this.name = name; this.name = name;
@ -30,7 +30,7 @@ public final class FunctionalExpression implements Expression {
public void addArgument(Expression arg) { public void addArgument(Expression arg) {
arguments.add(arg); arguments.add(arg);
} }
@Override @Override
public Value eval() { public Value eval() {
final int size = arguments.size(); final int size = arguments.size();
@ -54,6 +54,11 @@ public final class FunctionalExpression implements Expression {
} }
return function.execute(values); return function.execute(values);
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

View File

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

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 { public final class PrintStatement implements Statement {
private final Expression expression; public final Expression expression;
public PrintStatement(Expression expression) { public PrintStatement(Expression expression) {
this.expression = expression; this.expression = expression;
@ -16,6 +16,11 @@ public final class PrintStatement implements Statement {
public void execute() { public void execute() {
System.out.print(expression.eval()); System.out.print(expression.eval());
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

View File

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

View File

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

View File

@ -9,14 +9,14 @@ import com.annimon.ownlang.lib.Value;
*/ */
public final class UnaryExpression implements Expression { public final class UnaryExpression implements Expression {
private final Expression expr1; public final Expression expr1;
private final char operation; public final char operation;
public UnaryExpression(char operation, Expression expr1) { public UnaryExpression(char operation, Expression expr1) {
this.operation = operation; this.operation = operation;
this.expr1 = expr1; this.expr1 = expr1;
} }
@Override @Override
public Value eval() { public Value eval() {
switch (operation) { switch (operation) {
@ -27,6 +27,11 @@ public final class UnaryExpression implements Expression {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return String.format("%c %s", operation, expr1); 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 { public final class ValueExpression implements Expression {
private final Value value; public final Value value;
public ValueExpression(double value) { public ValueExpression(double value) {
this.value = new NumberValue(value); this.value = new NumberValue(value);
@ -24,6 +24,11 @@ public final class ValueExpression implements Expression {
public Value eval() { public Value eval() {
return value; return value;
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

View File

@ -9,7 +9,7 @@ import com.annimon.ownlang.lib.Variables;
*/ */
public final class VariableExpression implements Expression { public final class VariableExpression implements Expression {
private final String name; public final String name;
public VariableExpression(String name) { public VariableExpression(String name) {
this.name = name; this.name = name;
@ -20,6 +20,11 @@ public final class VariableExpression implements Expression {
if (!Variables.isExists(name)) throw new RuntimeException("Variable does not exists"); if (!Variables.isExists(name)) throw new RuntimeException("Variable does not exists");
return Variables.get(name); return Variables.get(name);
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

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 { public final class WhileStatement implements Statement {
private final Expression condition; public final Expression condition;
private final Statement statement; public final Statement statement;
public WhileStatement(Expression condition, Statement statement) { public WhileStatement(Expression condition, Statement statement) {
this.condition = condition; this.condition = condition;
@ -26,6 +26,11 @@ public final class WhileStatement implements Statement {
} }
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {

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