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,
|
STRING = 2,
|
||||||
ARRAY = 3,
|
ARRAY = 3,
|
||||||
MAP = 4,
|
MAP = 4,
|
||||||
FUNCTION = 5;
|
FUNCTION = 5,
|
||||||
|
CLASS = 6;
|
||||||
|
|
||||||
private static final int FIRST = OBJECT;
|
private static final int FIRST = OBJECT;
|
||||||
private static final int LAST = FUNCTION;
|
private static final int LAST = CLASS;
|
||||||
private static final String[] NAMES = {"object", "number", "string", "array", "map", "function"};
|
private static final String[] NAMES = {
|
||||||
|
"object", "number", "string", "array", "map", "function", "class"
|
||||||
|
};
|
||||||
|
|
||||||
public static String typeToString(int type) {
|
public static String typeToString(int type) {
|
||||||
if (FIRST <= type && type <= LAST) {
|
if (FIRST <= type && type <= LAST) {
|
||||||
|
@ -10,7 +10,7 @@ import com.annimon.ownlang.parser.ast.Statement;
|
|||||||
*
|
*
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public final class UserDefinedFunction implements Function {
|
public class UserDefinedFunction implements Function {
|
||||||
|
|
||||||
public final Arguments arguments;
|
public final Arguments arguments;
|
||||||
public final Statement body;
|
public final Statement body;
|
||||||
|
@ -105,6 +105,8 @@ public final class Lexer {
|
|||||||
KEYWORDS.put("case", TokenType.CASE);
|
KEYWORDS.put("case", TokenType.CASE);
|
||||||
KEYWORDS.put("extract", TokenType.EXTRACT);
|
KEYWORDS.put("extract", TokenType.EXTRACT);
|
||||||
KEYWORDS.put("include", TokenType.INCLUDE);
|
KEYWORDS.put("include", TokenType.INCLUDE);
|
||||||
|
KEYWORDS.put("class", TokenType.CLASS);
|
||||||
|
KEYWORDS.put("new", TokenType.NEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getKeywords() {
|
public static Set<String> getKeywords() {
|
||||||
|
@ -159,6 +159,9 @@ public final class Parser {
|
|||||||
if (match(TokenType.MATCH)) {
|
if (match(TokenType.MATCH)) {
|
||||||
return match();
|
return match();
|
||||||
}
|
}
|
||||||
|
if (match(TokenType.CLASS)) {
|
||||||
|
return classDeclaration();
|
||||||
|
}
|
||||||
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) {
|
if (lookMatch(0, TokenType.WORD) && lookMatch(1, TokenType.LPAREN)) {
|
||||||
return new ExprStatement(functionChain(qualifiedName()));
|
return new ExprStatement(functionChain(qualifiedName()));
|
||||||
}
|
}
|
||||||
@ -438,6 +441,30 @@ public final class Parser {
|
|||||||
return new MatchExpression(expression, patterns);
|
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() {
|
private Expression expression() {
|
||||||
return assignment();
|
return assignment();
|
||||||
}
|
}
|
||||||
@ -450,7 +477,7 @@ public final class Parser {
|
|||||||
return ternary();
|
return ternary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression assignmentStrict() {
|
private AssignmentExpression assignmentStrict() {
|
||||||
// x[0].prop += ...
|
// x[0].prop += ...
|
||||||
final int position = pos;
|
final int position = pos;
|
||||||
final Expression targetExpr = qualifiedName();
|
final Expression targetExpr = qualifiedName();
|
||||||
@ -667,23 +694,23 @@ public final class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Expression multiplicative() {
|
private Expression multiplicative() {
|
||||||
Expression result = unary();
|
Expression result = objectCreation();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (match(TokenType.STAR)) {
|
if (match(TokenType.STAR)) {
|
||||||
result = new BinaryExpression(BinaryExpression.Operator.MULTIPLY, result, unary());
|
result = new BinaryExpression(BinaryExpression.Operator.MULTIPLY, result, expression());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (match(TokenType.SLASH)) {
|
if (match(TokenType.SLASH)) {
|
||||||
result = new BinaryExpression(BinaryExpression.Operator.DIVIDE, result, unary());
|
result = new BinaryExpression(BinaryExpression.Operator.DIVIDE, result, expression());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (match(TokenType.PERCENT)) {
|
if (match(TokenType.PERCENT)) {
|
||||||
result = new BinaryExpression(BinaryExpression.Operator.REMAINDER, result, unary());
|
result = new BinaryExpression(BinaryExpression.Operator.REMAINDER, result, expression());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (match(TokenType.STARSTAR)) {
|
if (match(TokenType.STARSTAR)) {
|
||||||
result = new BinaryExpression(BinaryExpression.Operator.POWER, result, unary());
|
result = new BinaryExpression(BinaryExpression.Operator.POWER, result, expression());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -692,6 +719,21 @@ public final class Parser {
|
|||||||
return result;
|
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() {
|
private Expression unary() {
|
||||||
if (match(TokenType.PLUSPLUS)) {
|
if (match(TokenType.PLUSPLUS)) {
|
||||||
return new UnaryExpression(UnaryExpression.Operator.INCREMENT_PREFIX, primary());
|
return new UnaryExpression(UnaryExpression.Operator.INCREMENT_PREFIX, primary());
|
||||||
|
@ -28,6 +28,8 @@ public enum TokenType {
|
|||||||
CASE,
|
CASE,
|
||||||
EXTRACT,
|
EXTRACT,
|
||||||
INCLUDE,
|
INCLUDE,
|
||||||
|
CLASS,
|
||||||
|
NEW,
|
||||||
|
|
||||||
PLUS, // +
|
PLUS, // +
|
||||||
MINUS, // -
|
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:
|
case Types.STRING:
|
||||||
return ((StringValue) container).access(lastIndex);
|
return ((StringValue) container).access(lastIndex);
|
||||||
|
|
||||||
|
case Types.CLASS:
|
||||||
|
return ((ClassInstanceValue) container).access(lastIndex);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TypeException("Array or map expected. Got " + Types.typeToString(container.type()));
|
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(BinaryExpression s, T t);
|
||||||
R visit(BlockStatement s, T t);
|
R visit(BlockStatement s, T t);
|
||||||
R visit(BreakStatement s, T t);
|
R visit(BreakStatement s, T t);
|
||||||
|
R visit(ClassDeclarationStatement s, T t);
|
||||||
R visit(ConditionalExpression s, T t);
|
R visit(ConditionalExpression s, T t);
|
||||||
R visit(ContainerAccessExpression s, T t);
|
R visit(ContainerAccessExpression s, T t);
|
||||||
R visit(ContinueStatement 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(IncludeStatement s, T t);
|
||||||
R visit(MapExpression s, T t);
|
R visit(MapExpression s, T t);
|
||||||
R visit(MatchExpression s, T t);
|
R visit(MatchExpression s, T t);
|
||||||
|
R visit(ObjectCreationExpression s, T t);
|
||||||
R visit(PrintStatement s, T t);
|
R visit(PrintStatement s, T t);
|
||||||
R visit(PrintlnStatement s, T t);
|
R visit(PrintlnStatement s, T t);
|
||||||
R visit(ReturnStatement s, T t);
|
R visit(ReturnStatement s, T t);
|
||||||
|
@ -11,6 +11,7 @@ public interface Visitor {
|
|||||||
void visit(BinaryExpression s);
|
void visit(BinaryExpression s);
|
||||||
void visit(BlockStatement s);
|
void visit(BlockStatement s);
|
||||||
void visit(BreakStatement s);
|
void visit(BreakStatement s);
|
||||||
|
void visit(ClassDeclarationStatement s);
|
||||||
void visit(ConditionalExpression s);
|
void visit(ConditionalExpression s);
|
||||||
void visit(ContainerAccessExpression s);
|
void visit(ContainerAccessExpression s);
|
||||||
void visit(ContinueStatement s);
|
void visit(ContinueStatement s);
|
||||||
@ -27,6 +28,7 @@ public interface Visitor {
|
|||||||
void visit(IncludeStatement s);
|
void visit(IncludeStatement s);
|
||||||
void visit(MapExpression s);
|
void visit(MapExpression s);
|
||||||
void visit(MatchExpression s);
|
void visit(MatchExpression s);
|
||||||
|
void visit(ObjectCreationExpression s);
|
||||||
void visit(PrintStatement s);
|
void visit(PrintStatement s);
|
||||||
void visit(PrintlnStatement s);
|
void visit(PrintlnStatement s);
|
||||||
void visit(ReturnStatement s);
|
void visit(ReturnStatement s);
|
||||||
|
@ -75,6 +75,11 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visit(ClassDeclarationStatement s, T t) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visit(ConditionalExpression s, T t) {
|
public Node visit(ConditionalExpression s, T t) {
|
||||||
final Node expr1 = s.expr1.accept(this, t);
|
final Node expr1 = s.expr1.accept(this, t);
|
||||||
@ -315,6 +320,24 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
|||||||
return s;
|
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
|
@Override
|
||||||
public Node visit(PrintStatement s, T t) {
|
public Node visit(PrintStatement s, T t) {
|
||||||
final Node expression = s.expression.accept(this, t);
|
final Node expression = s.expression.accept(this, t);
|
||||||
|
@ -39,6 +39,11 @@ public abstract class AbstractVisitor implements Visitor {
|
|||||||
public void visit(BreakStatement s) {
|
public void visit(BreakStatement s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ClassDeclarationStatement s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConditionalExpression s) {
|
public void visit(ConditionalExpression s) {
|
||||||
s.expr1.accept(this);
|
s.expr1.accept(this);
|
||||||
@ -137,6 +142,13 @@ public abstract class AbstractVisitor implements Visitor {
|
|||||||
s.expression.accept(this);
|
s.expression.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ObjectCreationExpression s) {
|
||||||
|
for (Expression argument : s.constructorArguments) {
|
||||||
|
argument.accept(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PrintStatement s) {
|
public void visit(PrintStatement s) {
|
||||||
s.expression.accept(this);
|
s.expression.accept(this);
|
||||||
|
@ -7,6 +7,7 @@ import com.annimon.ownlang.lib.Types;
|
|||||||
import com.annimon.ownlang.lib.UserDefinedFunction;
|
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||||
import com.annimon.ownlang.parser.ast.*;
|
import com.annimon.ownlang.parser.ast.*;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder> {
|
public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder> {
|
||||||
@ -79,6 +80,23 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
|||||||
return t;
|
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
|
@Override
|
||||||
public StringBuilder visit(ConditionalExpression s, StringBuilder t) {
|
public StringBuilder visit(ConditionalExpression s, StringBuilder t) {
|
||||||
s.expr1.accept(this, t);
|
s.expr1.accept(this, t);
|
||||||
@ -209,14 +227,7 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
|||||||
} else {
|
} else {
|
||||||
s.functionExpr.accept(this, t);
|
s.functionExpr.accept(this, t);
|
||||||
}
|
}
|
||||||
t.append("(");
|
printArgs(t, s.arguments);
|
||||||
boolean firstElement = true;
|
|
||||||
for (Expression expr : s.arguments) {
|
|
||||||
if (firstElement) firstElement = false;
|
|
||||||
else t.append(", ");
|
|
||||||
expr.accept(this, t);
|
|
||||||
}
|
|
||||||
t.append(")");
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +302,13 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringBuilder visit(ObjectCreationExpression s, StringBuilder t) {
|
||||||
|
t.append("new ").append(s.className);
|
||||||
|
printArgs(t, s.constructorArguments);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StringBuilder visit(PrintStatement s, StringBuilder t) {
|
public StringBuilder visit(PrintStatement s, StringBuilder t) {
|
||||||
t.append("print ");
|
t.append("print ");
|
||||||
@ -423,6 +441,17 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
|||||||
return t;
|
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) {
|
private void newLine(StringBuilder t) {
|
||||||
t.append(Console.newline());
|
t.append(Console.newline());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user