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
0bd2aa10d5
commit
6774dc1004
27
examples/basics/classes.own
Normal file
27
examples/basics/classes.own
Normal file
@ -0,0 +1,27 @@
|
||||
use ["std"]
|
||||
|
||||
class Point {
|
||||
def Point(x = 0, y = 0) {
|
||||
this.x = x
|
||||
this.y = y
|
||||
}
|
||||
|
||||
def moveBy(p) {
|
||||
this.move(p.x, p.y)
|
||||
}
|
||||
|
||||
def move(dx, dy) {
|
||||
this.x += dx
|
||||
this.y += dy
|
||||
}
|
||||
|
||||
def toString() = "(" + this.x + ", " + this.y + ")"
|
||||
}
|
||||
|
||||
p = new Point(20, 30)
|
||||
p.move(10, -5)
|
||||
println p.toString()
|
||||
|
||||
p2 = new Point(1, 1)
|
||||
p2.moveBy(p)
|
||||
println p2.toString()
|
@ -0,0 +1,15 @@
|
||||
package com.annimon.ownlang.exceptions;
|
||||
|
||||
public final class UnknownClassException extends RuntimeException {
|
||||
|
||||
private final String className;
|
||||
|
||||
public UnknownClassException(String name) {
|
||||
super("Unknown class " + name);
|
||||
this.className = name;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
}
|
37
src/main/java/com/annimon/ownlang/lib/ClassDeclarations.java
Normal file
37
src/main/java/com/annimon/ownlang/lib/ClassDeclarations.java
Normal file
@ -0,0 +1,37 @@
|
||||
package com.annimon.ownlang.lib;
|
||||
|
||||
import com.annimon.ownlang.exceptions.UnknownFunctionException;
|
||||
import com.annimon.ownlang.parser.ast.ClassDeclarationStatement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class ClassDeclarations {
|
||||
|
||||
private static final Map<String, ClassDeclarationStatement> declarations;
|
||||
static {
|
||||
declarations = new HashMap<>();
|
||||
}
|
||||
|
||||
private ClassDeclarations() { }
|
||||
|
||||
public static void clear() {
|
||||
declarations.clear();
|
||||
}
|
||||
|
||||
public static Map<String, ClassDeclarationStatement> getAll() {
|
||||
return declarations;
|
||||
}
|
||||
|
||||
public static boolean isExists(String key) {
|
||||
return declarations.containsKey(key);
|
||||
}
|
||||
|
||||
public static ClassDeclarationStatement get(String key) {
|
||||
if (!isExists(key)) throw new UnknownFunctionException(key);
|
||||
return declarations.get(key);
|
||||
}
|
||||
|
||||
public static void set(String key, ClassDeclarationStatement classDef) {
|
||||
declarations.put(key, classDef);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.annimon.ownlang.lib;
|
||||
|
||||
import com.annimon.ownlang.exceptions.TypeException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ClassInstanceValue implements Value {
|
||||
|
||||
private final String className;
|
||||
private final MapValue thisMap;
|
||||
private ClassMethod constructor;
|
||||
|
||||
public ClassInstanceValue(String name) {
|
||||
this.className = name;
|
||||
thisMap = new MapValue(10);
|
||||
}
|
||||
|
||||
public MapValue getThisMap() {
|
||||
return thisMap;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public void addField(String name, Value value) {
|
||||
thisMap.set(name, value);
|
||||
}
|
||||
|
||||
public void addMethod(String name, ClassMethod method) {
|
||||
thisMap.set(name, method);
|
||||
if (name.equals(className)) {
|
||||
constructor = method;
|
||||
}
|
||||
}
|
||||
|
||||
public void callConstructor(Value[] args) {
|
||||
if (constructor != null) {
|
||||
constructor.execute(args);
|
||||
}
|
||||
}
|
||||
|
||||
public Value access(Value value) {
|
||||
return thisMap.get(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object raw() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int asInt() {
|
||||
throw new TypeException("Cannot cast class to integer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double asNumber() {
|
||||
throw new TypeException("Cannot cast class to integer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return "class " + className + "@" + thisMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int type() {
|
||||
return Types.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 37 * hash + Objects.hash(className, thisMap);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final ClassInstanceValue other = (ClassInstanceValue) obj;
|
||||
return Objects.equals(this.className, other.className)
|
||||
&& Objects.equals(this.thisMap, other.thisMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o) {
|
||||
return asString().compareTo(o.asString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
}
|
26
src/main/java/com/annimon/ownlang/lib/ClassMethod.java
Normal file
26
src/main/java/com/annimon/ownlang/lib/ClassMethod.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.annimon.ownlang.lib;
|
||||
|
||||
import com.annimon.ownlang.parser.ast.Arguments;
|
||||
import com.annimon.ownlang.parser.ast.Statement;
|
||||
|
||||
public class ClassMethod extends UserDefinedFunction {
|
||||
|
||||
public final ClassInstanceValue classInstance;
|
||||
|
||||
public ClassMethod(Arguments arguments, Statement body, ClassInstanceValue classInstance) {
|
||||
super(arguments, body);
|
||||
this.classInstance = classInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value execute(Value[] values) {
|
||||
Variables.push();
|
||||
Variables.define("this", classInstance.getThisMap());
|
||||
|
||||
try {
|
||||
return super.execute(values);
|
||||
} finally {
|
||||
Variables.pop();
|
||||
}
|
||||
}
|
||||
}
|
36
src/main/java/com/annimon/ownlang/lib/Classes.java
Normal file
36
src/main/java/com/annimon/ownlang/lib/Classes.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.annimon.ownlang.lib;
|
||||
|
||||
import com.annimon.ownlang.exceptions.UnknownClassException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class Classes {
|
||||
|
||||
private static final Map<String, ClassInstanceValue> classes;
|
||||
static {
|
||||
classes = new HashMap<>();
|
||||
}
|
||||
|
||||
private Classes() { }
|
||||
|
||||
public static void clear() {
|
||||
classes.clear();
|
||||
}
|
||||
|
||||
public static Map<String, ClassInstanceValue> getFunctions() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public static boolean isExists(String key) {
|
||||
return classes.containsKey(key);
|
||||
}
|
||||
|
||||
public static ClassInstanceValue get(String key) {
|
||||
if (!isExists(key)) throw new UnknownClassException(key);
|
||||
return classes.get(key);
|
||||
}
|
||||
|
||||
public static void set(String key, ClassInstanceValue classDef) {
|
||||
classes.put(key, classDef);
|
||||
}
|
||||
}
|
@ -8,11 +8,14 @@ public final class Types {
|
||||
STRING = 2,
|
||||
ARRAY = 3,
|
||||
MAP = 4,
|
||||
FUNCTION = 5;
|
||||
FUNCTION = 5,
|
||||
CLASS = 6;
|
||||
|
||||
private static final int FIRST = OBJECT;
|
||||
private static final int LAST = FUNCTION;
|
||||
private static final String[] NAMES = {"object", "number", "string", "array", "map", "function"};
|
||||
private static final int LAST = CLASS;
|
||||
private static final String[] NAMES = {
|
||||
"object", "number", "string", "array", "map", "function", "class"
|
||||
};
|
||||
|
||||
public static String typeToString(int type) {
|
||||
if (FIRST <= type && type <= LAST) {
|
||||
|
@ -10,7 +10,7 @@ import com.annimon.ownlang.parser.ast.Statement;
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public final class UserDefinedFunction implements Function {
|
||||
public class UserDefinedFunction implements Function {
|
||||
|
||||
public final Arguments arguments;
|
||||
public final Statement body;
|
||||
|
@ -105,6 +105,8 @@ public final class Lexer {
|
||||
KEYWORDS.put("case", TokenType.CASE);
|
||||
KEYWORDS.put("extract", TokenType.EXTRACT);
|
||||
KEYWORDS.put("include", TokenType.INCLUDE);
|
||||
KEYWORDS.put("class", TokenType.CLASS);
|
||||
KEYWORDS.put("new", TokenType.NEW);
|
||||
}
|
||||
|
||||
public static Set<String> getKeywords() {
|
||||
|
@ -159,6 +159,9 @@ public final class Parser {
|
||||
if (match(TokenType.MATCH)) {
|
||||
return match();
|
||||
}
|
||||
if (match(TokenType.CLASS)) {
|
||||
return classDeclaration();
|
||||
}
|
||||
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) {
|
||||
return new ExprStatement(functionChain(qualifiedName()));
|
||||
}
|
||||
@ -438,6 +441,30 @@ public final class Parser {
|
||||
return new MatchExpression(expression, patterns);
|
||||
}
|
||||
|
||||
private Statement classDeclaration() {
|
||||
// class Name {
|
||||
// x = 123
|
||||
// str = ""
|
||||
// def method() = str
|
||||
// }
|
||||
final String name = consume(TokenType.WORD).getText();
|
||||
final ClassDeclarationStatement classDeclaration = new ClassDeclarationStatement(name);
|
||||
consume(TokenType.LBRACE);
|
||||
do {
|
||||
if (match(TokenType.DEF)) {
|
||||
classDeclaration.addMethod(functionDefine());
|
||||
} else {
|
||||
final AssignmentExpression fieldDeclaration = assignmentStrict();
|
||||
if (fieldDeclaration != null) {
|
||||
classDeclaration.addField(fieldDeclaration);
|
||||
} else {
|
||||
throw new ParseException("Class can contain only assignments and function declarations");
|
||||
}
|
||||
}
|
||||
} while (!match(TokenType.RBRACE));
|
||||
return classDeclaration;
|
||||
}
|
||||
|
||||
private Expression expression() {
|
||||
return assignment();
|
||||
}
|
||||
@ -450,7 +477,7 @@ public final class Parser {
|
||||
return ternary();
|
||||
}
|
||||
|
||||
private Expression assignmentStrict() {
|
||||
private AssignmentExpression assignmentStrict() {
|
||||
// x[0].prop += ...
|
||||
final int position = pos;
|
||||
final Expression targetExpr = qualifiedName();
|
||||
@ -667,23 +694,23 @@ public final class Parser {
|
||||
}
|
||||
|
||||
private Expression multiplicative() {
|
||||
Expression result = unary();
|
||||
Expression result = objectCreation();
|
||||
|
||||
while (true) {
|
||||
if (match(TokenType.STAR)) {
|
||||
result = new BinaryExpression(BinaryExpression.Operator.MULTIPLY, result, unary());
|
||||
result = new BinaryExpression(BinaryExpression.Operator.MULTIPLY, result, expression());
|
||||
continue;
|
||||
}
|
||||
if (match(TokenType.SLASH)) {
|
||||
result = new BinaryExpression(BinaryExpression.Operator.DIVIDE, result, unary());
|
||||
result = new BinaryExpression(BinaryExpression.Operator.DIVIDE, result, expression());
|
||||
continue;
|
||||
}
|
||||
if (match(TokenType.PERCENT)) {
|
||||
result = new BinaryExpression(BinaryExpression.Operator.REMAINDER, result, unary());
|
||||
result = new BinaryExpression(BinaryExpression.Operator.REMAINDER, result, expression());
|
||||
continue;
|
||||
}
|
||||
if (match(TokenType.STARSTAR)) {
|
||||
result = new BinaryExpression(BinaryExpression.Operator.POWER, result, unary());
|
||||
result = new BinaryExpression(BinaryExpression.Operator.POWER, result, expression());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -692,6 +719,21 @@ public final class Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Expression objectCreation() {
|
||||
if (match(TokenType.NEW)) {
|
||||
final String className = consume(TokenType.WORD).getText();
|
||||
final List<Expression> args = new ArrayList<>();
|
||||
consume(TokenType.LPAREN);
|
||||
while (!match(TokenType.RPAREN)) {
|
||||
args.add(expression());
|
||||
match(TokenType.COMMA);
|
||||
}
|
||||
return new ObjectCreationExpression(className, args);
|
||||
}
|
||||
|
||||
return unary();
|
||||
}
|
||||
|
||||
private Expression unary() {
|
||||
if (match(TokenType.PLUSPLUS)) {
|
||||
return new UnaryExpression(UnaryExpression.Operator.INCREMENT_PREFIX, primary());
|
||||
|
@ -28,6 +28,8 @@ public enum TokenType {
|
||||
CASE,
|
||||
EXTRACT,
|
||||
INCLUDE,
|
||||
CLASS,
|
||||
NEW,
|
||||
|
||||
PLUS, // +
|
||||
MINUS, // -
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.annimon.ownlang.parser.ast;
|
||||
|
||||
import com.annimon.ownlang.lib.ClassDeclarations;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class ClassDeclarationStatement implements Statement {
|
||||
|
||||
public final String name;
|
||||
public final List<FunctionDefineStatement> methods;
|
||||
public final List<AssignmentExpression> fields;
|
||||
|
||||
public ClassDeclarationStatement(String name) {
|
||||
this.name = name;
|
||||
methods = new ArrayList<>();
|
||||
fields = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addField(AssignmentExpression expr) {
|
||||
fields.add(expr);
|
||||
}
|
||||
|
||||
public void addMethod(FunctionDefineStatement statement) {
|
||||
methods.add(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
ClassDeclarations.set(name, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T t) {
|
||||
return visitor.visit(this, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("class %s {\n %s %s}", name, fields, methods);
|
||||
}
|
||||
}
|
@ -51,6 +51,9 @@ public final class ContainerAccessExpression implements Expression, Accessible {
|
||||
case Types.STRING:
|
||||
return ((StringValue) container).access(lastIndex);
|
||||
|
||||
case Types.CLASS:
|
||||
return ((ClassInstanceValue) container).access(lastIndex);
|
||||
|
||||
default:
|
||||
throw new TypeException("Array or map expected. Got " + Types.typeToString(container.type()));
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
package com.annimon.ownlang.parser.ast;
|
||||
|
||||
import com.annimon.ownlang.lib.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public final class ObjectCreationExpression implements Expression {
|
||||
|
||||
public final String className;
|
||||
public final List<Expression> constructorArguments;
|
||||
|
||||
public ObjectCreationExpression(String className, List<Expression> constructorArguments) {
|
||||
this.className = className;
|
||||
this.constructorArguments = constructorArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value eval() {
|
||||
final ClassDeclarationStatement cd = ClassDeclarations.get(className);
|
||||
|
||||
// Create an instance and put evaluated fields with method declarations
|
||||
final ClassInstanceValue instance = new ClassInstanceValue(className);
|
||||
for (AssignmentExpression f : cd.fields) {
|
||||
// TODO check only variable assignments
|
||||
final String fieldName = ((VariableExpression) f.target).name;
|
||||
instance.addField(fieldName, f.eval());
|
||||
}
|
||||
for (FunctionDefineStatement m : cd.methods) {
|
||||
instance.addMethod(m.name, new ClassMethod(m.arguments, m.body, instance));
|
||||
}
|
||||
|
||||
// Call a constructor
|
||||
final int argsSize = constructorArguments.size();
|
||||
final Value[] ctorArgs = new Value[argsSize];
|
||||
for (int i = 0; i < argsSize; i++) {
|
||||
ctorArgs[i] = constructorArguments.get(i).eval();
|
||||
}
|
||||
instance.callConstructor(ctorArgs);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T> R accept(ResultVisitor<R, T> visitor, T t) {
|
||||
return visitor.visit(this, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("new ").append(className).append(' ');
|
||||
final Iterator<Expression> it = constructorArguments.iterator();
|
||||
if (it.hasNext()) {
|
||||
sb.append(it.next());
|
||||
while (it.hasNext()) {
|
||||
sb.append(", ").append(it.next());
|
||||
}
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ public interface ResultVisitor<R, T> {
|
||||
R visit(BinaryExpression s, T t);
|
||||
R visit(BlockStatement s, T t);
|
||||
R visit(BreakStatement s, T t);
|
||||
R visit(ClassDeclarationStatement s, T t);
|
||||
R visit(ConditionalExpression s, T t);
|
||||
R visit(ContainerAccessExpression s, T t);
|
||||
R visit(ContinueStatement s, T t);
|
||||
@ -29,6 +30,7 @@ public interface ResultVisitor<R, T> {
|
||||
R visit(IncludeStatement s, T t);
|
||||
R visit(MapExpression s, T t);
|
||||
R visit(MatchExpression s, T t);
|
||||
R visit(ObjectCreationExpression s, T t);
|
||||
R visit(PrintStatement s, T t);
|
||||
R visit(PrintlnStatement s, T t);
|
||||
R visit(ReturnStatement s, T t);
|
||||
|
@ -11,6 +11,7 @@ public interface Visitor {
|
||||
void visit(BinaryExpression s);
|
||||
void visit(BlockStatement s);
|
||||
void visit(BreakStatement s);
|
||||
void visit(ClassDeclarationStatement s);
|
||||
void visit(ConditionalExpression s);
|
||||
void visit(ContainerAccessExpression s);
|
||||
void visit(ContinueStatement s);
|
||||
@ -27,6 +28,7 @@ public interface Visitor {
|
||||
void visit(IncludeStatement s);
|
||||
void visit(MapExpression s);
|
||||
void visit(MatchExpression s);
|
||||
void visit(ObjectCreationExpression s);
|
||||
void visit(PrintStatement s);
|
||||
void visit(PrintlnStatement s);
|
||||
void visit(ReturnStatement s);
|
||||
|
@ -75,6 +75,11 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ClassDeclarationStatement s, T t) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ConditionalExpression s, T t) {
|
||||
final Node expr1 = s.expr1.accept(this, t);
|
||||
@ -315,6 +320,24 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(ObjectCreationExpression s, T t) {
|
||||
final List<Expression> args = new ArrayList<>();
|
||||
boolean changed = false;
|
||||
for (Expression argument : s.constructorArguments) {
|
||||
final Node expr = argument.accept(this, t);
|
||||
if (expr != argument) {
|
||||
changed = true;
|
||||
}
|
||||
args.add((Expression) expr);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
return new ObjectCreationExpression(s.className, args);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(PrintStatement s, T t) {
|
||||
final Node expression = s.expression.accept(this, t);
|
||||
|
@ -39,6 +39,11 @@ public abstract class AbstractVisitor implements Visitor {
|
||||
public void visit(BreakStatement s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ClassDeclarationStatement s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalExpression s) {
|
||||
s.expr1.accept(this);
|
||||
@ -137,6 +142,13 @@ public abstract class AbstractVisitor implements Visitor {
|
||||
s.expression.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ObjectCreationExpression s) {
|
||||
for (Expression argument : s.constructorArguments) {
|
||||
argument.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PrintStatement s) {
|
||||
s.expression.accept(this);
|
||||
|
@ -7,6 +7,7 @@ import com.annimon.ownlang.lib.Types;
|
||||
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||
import com.annimon.ownlang.parser.ast.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder> {
|
||||
@ -79,6 +80,23 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(ClassDeclarationStatement s, StringBuilder t) {
|
||||
t.append("class ").append(s.name).append(" {");
|
||||
newLine(t);
|
||||
|
||||
increaseIndent();
|
||||
for (AssignmentExpression field : s.fields) {
|
||||
field.accept(this, t);
|
||||
}
|
||||
for (FunctionDefineStatement method : s.methods) {
|
||||
method.accept(this, t);
|
||||
}
|
||||
decreaseIndent();
|
||||
t.append("}");
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(ConditionalExpression s, StringBuilder t) {
|
||||
s.expr1.accept(this, t);
|
||||
@ -209,14 +227,7 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
} else {
|
||||
s.functionExpr.accept(this, t);
|
||||
}
|
||||
t.append("(");
|
||||
boolean firstElement = true;
|
||||
for (Expression expr : s.arguments) {
|
||||
if (firstElement) firstElement = false;
|
||||
else t.append(", ");
|
||||
expr.accept(this, t);
|
||||
}
|
||||
t.append(")");
|
||||
printArgs(t, s.arguments);
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -291,6 +302,13 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(ObjectCreationExpression s, StringBuilder t) {
|
||||
t.append("new ").append(s.className);
|
||||
printArgs(t, s.constructorArguments);
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilder visit(PrintStatement s, StringBuilder t) {
|
||||
t.append("print ");
|
||||
@ -423,6 +441,17 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
||||
return t;
|
||||
}
|
||||
|
||||
private void printArgs(StringBuilder t, List<Expression> args) {
|
||||
t.append("(");
|
||||
boolean firstElement = true;
|
||||
for (Expression expr : args) {
|
||||
if (firstElement) firstElement = false;
|
||||
else t.append(", ");
|
||||
expr.accept(this, t);
|
||||
}
|
||||
t.append(")");
|
||||
}
|
||||
|
||||
private void newLine(StringBuilder t) {
|
||||
t.append(Console.newline());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user