Урок 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;
@ -49,6 +49,11 @@ public final class ArrayAccessExpression implements Expression {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return variable + indices; return variable + indices;

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;
@ -19,6 +19,11 @@ public final class ArrayAssignmentStatement implements Statement {
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() {
return String.format("%s = %s", array, expression); return String.format("%s = %s", array, expression);

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;
@ -26,6 +26,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() {
return elements.toString(); return elements.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;
@ -23,6 +23,11 @@ public final class AssignmentStatement implements Statement {
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() {
return String.format("%s = %s", variable, expression); 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 { 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;
@ -53,6 +53,11 @@ public final class BinaryExpression implements Expression {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return String.format("[%s %c %s]", expr1, operation, expr2); 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 { 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<>();
@ -26,6 +26,11 @@ public final class BlockStatement implements Statement {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
final StringBuilder result = new StringBuilder(); final StringBuilder result = new StringBuilder();

View File

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

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;
@ -79,6 +79,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() {
return String.format("[%s %s %s]", expr1, operation.getName(), expr2); 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; throw this;
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return "continue"; return "continue";

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;
@ -28,6 +28,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() {
return "do " + statement + " while " + condition; return "do " + statement + " while " + condition;

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;
@ -31,6 +31,11 @@ public final class ForStatement implements Statement {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return "for " + initialization + ", " + termination + ", " + increment + " " + statement; return "for " + initialization + ", " + termination + ", " + increment + " " + statement;

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;
@ -25,6 +25,11 @@ public final class FunctionDefineStatement implements Statement {
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() {
return "def (" + argNames.toString() + ") " + body.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 { 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;
@ -17,6 +17,11 @@ public final class FunctionStatement implements Statement {
function.eval(); function.eval();
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return function.toString(); return function.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;
@ -55,6 +55,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() {
return name + "(" + arguments.toString() + ")"; return name + "(" + arguments.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;
@ -25,6 +25,11 @@ public final class IfStatement implements Statement {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
final StringBuilder result = new StringBuilder(); 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 { 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;
@ -17,6 +17,11 @@ public final class PrintStatement implements Statement {
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() {
return "print " + expression; return "print " + expression;

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) {
@ -25,6 +25,11 @@ public final class ReturnStatement extends RuntimeException implements Statement
throw this; throw this;
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return "return"; return "return";

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,8 +9,8 @@ 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;
@ -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);
@ -25,6 +25,11 @@ public final class ValueExpression implements Expression {
return value; return value;
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return value.asString(); return value.asString();

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;
@ -21,6 +21,11 @@ public final class VariableExpression implements Expression {
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() {
return name; 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 { 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;
@ -27,6 +27,11 @@ public final class WhileStatement implements Statement {
} }
} }
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override @Override
public String toString() { public String toString() {
return "while " + condition + " " + statement; 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