Commit f1eb4fd9 authored by EmreTr1's avatar EmreTr1
Browse files

commit current status

parent 21a3fdd6
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
......@@ -24,9 +24,6 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.14.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.14.0'
}
test {
......
package com.bedrockk.molang;
import com.bedrockk.molang.parser.MoLangParser;
import com.bedrockk.molang.parser.tokenizer.TokenIterator;
import com.bedrockk.molang.runtime.MoLangRuntime;
import com.bedrockk.molang.util.Util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class MoLang {
// TODO
public static MoLangParser newParser(String code) {
return new MoLangParser(new TokenIterator(code));
}
public static MoLangParser newParser(Path path) {
byte[] fileBytes;
try {
fileBytes = Files.readAllBytes(path);
} catch (IOException e) {
fileBytes = new byte[0];
}
return new MoLangParser(new TokenIterator(new String(fileBytes, StandardCharsets.UTF_8)));
}
public static MoLangParser newParser(InputStream stream) throws IOException {
return new MoLangParser(new TokenIterator(Util.readFile(stream)));
}
public static MoLangRuntime newRuntime() {
return new MoLangRuntime();
}
}
package com.bedrockk.molang.parser;
import com.bedrockk.molang.parser.visitor.FindingVisitor;
import java.util.List;
import java.util.function.Predicate;
public class ExprFinder {
public static List<Expression> find(List<Expression> expressions, Predicate<Expression> predicate) {
ExprTraverser traverser = new ExprTraverser();
FindingVisitor visitor = new FindingVisitor(predicate);
traverser.getVisitors().add(visitor);
traverser.traverse(expressions);
return visitor.getFoundExpressions();
}
}
package com.bedrockk.molang.parser;
import lombok.Getter;
import lombok.NonNull;
import java.lang.reflect.Field;
import java.util.*;
@Getter
public class ExprTraverser {
private boolean stopTraversal = false;
private final List<ExprVisitor> visitors = new LinkedList<>();
public void traverse(List<Expression> expressions) {
for (ExprVisitor visitor : visitors) {
visitor.beforeTraverse(expressions);
}
stopTraversal = false;
traverseArray(expressions);
for (ExprVisitor visitor : visitors) {
visitor.afterTraverse(expressions);
}
}
private void traverseArray(List<Expression> expressions) {
List<Expression> list = new ArrayList<>(expressions);
for (int i = 0; i < list.size(); i++) {
Expression expression = list.get(i);
boolean removeCurrent = false;
boolean traverseChildren = true;
boolean traverseCurrent = true;
for (ExprVisitor visitor : visitors) {
Object result = visitor.onVisit(expression);
if (result instanceof ActionType) {
switch ((ActionType) result) {
case REMOVE_CURRENT:
removeCurrent = true;
break;
case STOP_TRAVERSAL:
stopTraversal = true;
break;
case DONT_TRAVERSE_CURRENT_AND_CHILDREN:
traverseCurrent = false;
case DONT_TRAVERSE_CHILDREN:
traverseChildren = false;
break;
}
} else if (result instanceof Expression) {
expression = (Expression) result;
}
}
if (!traverseCurrent) {
break;
} else if (traverseChildren && !removeCurrent) {
traverseExpr(expression);
}
if (removeCurrent) {
expressions.remove(i);
} else {
expressions.set(i, expression);
}
if (stopTraversal) {
break;
}
}
}
private void traverseExpr(@NonNull Expression expression) {
for (Field field : getAllFields(expression.getClass())) {
field.setAccessible(true);
Object fieldValue = getFieldValue(field, expression);
if (fieldValue instanceof Expression) {
Expression subExpr = (Expression) fieldValue;
boolean removeCurrent = false;
boolean traverseChildren = true;
boolean traverseCurrent = true;
for (ExprVisitor visitor : visitors) {
Object result = visitor.onVisit(subExpr);
if (result instanceof ActionType) {
switch ((ActionType) result) {
case REMOVE_CURRENT:
removeCurrent = true;
break;
case STOP_TRAVERSAL:
stopTraversal = true;
break;
case DONT_TRAVERSE_CURRENT_AND_CHILDREN:
traverseCurrent = false;
case DONT_TRAVERSE_CHILDREN:
traverseChildren = false;
break;
}
} else if (result instanceof Expression) {
subExpr = (Expression) result;
}
}
if (!traverseCurrent) {
break;
} else if (traverseChildren && !removeCurrent) {
traverseExpr(subExpr);
}
if (removeCurrent) {
setFieldValue(field, expression, null);
} else {
setFieldValue(field, expression, subExpr);
}
if (stopTraversal) {
break;
}
} else if (fieldValue != null && fieldValue.getClass().isArray()) {
Object[] array = (Object[]) fieldValue;
List<Expression> exprs = new ArrayList<>();
for (Object i : array) {
if (i instanceof Expression) {
exprs.add((Expression) i);
}
}
traverseArray(exprs);
setFieldValue(field, expression, exprs.toArray(new Expression[0]));
}
}
}
public static List<Field> getAllFields(Class<?> type) {
List<Field> fields = new ArrayList<>();
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
private Object getFieldValue(Field field, Object obj) {
try {
return field.get(obj);
} catch (Throwable throwable) {
// noop
}
return null;
}
private void setFieldValue(Field field, Object obj, Object value) {
try {
field.set(obj, value);
} catch (Throwable throwable) {
// noop
}
}
public enum ActionType{
REMOVE_CURRENT,
STOP_TRAVERSAL,
DONT_TRAVERSE_CURRENT_AND_CHILDREN,
DONT_TRAVERSE_CHILDREN
}
}
package com.bedrockk.molang.parser;
import java.util.List;
public interface ExprVisitor {
default void beforeTraverse(List<Expression> expressions) {
// noop
}
Object onVisit(Expression expression);
default void afterTraverse(List<Expression> expressions) {
// noop
}
}
package com.bedrockk.molang.parser;
import com.bedrockk.molang.runtime.MoLangEnvironment;
public interface Expression {
Object evaluate(MoLangEnvironment environment);
}
......@@ -2,7 +2,20 @@ package com.bedrockk.molang.parser;
import com.bedrockk.molang.parser.tokenizer.Token;
public interface InfixParselet {
public abstract class InfixParselet {
Expression parse(MoLangParser parser, Token token, Expression leftExpr);
private final Precedence precedence;
public InfixParselet() {
this.precedence = Precedence.ANYTHING;
}
public InfixParselet(Precedence precedence) {
this.precedence = precedence;
}
public abstract Expression parse(MoLangParser parser, Token token, Expression leftExpr);
public Precedence getPrecedence() {
return precedence;
}
}
......@@ -5,6 +5,7 @@ import com.bedrockk.molang.parser.tokenizer.Token;
import com.bedrockk.molang.parser.tokenizer.TokenIterator;
import com.bedrockk.molang.parser.tokenizer.TokenType;
import lombok.extern.log4j.Log4j2;
import lombok.var;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -14,20 +15,19 @@ import java.util.Map;
@Log4j2
public final class MoLangParser {
private final static Map<TokenType, Parselet> prefixParselets = new HashMap<>();
private final static Map<TokenType, PrefixParselet> prefixParselets = new HashMap<>();
private final static Map<TokenType, InfixParselet> infixParselets = new HashMap<>();
private final TokenIterator tokenIterator;
private final List<Token> readTokens = new ArrayList<>();
private Token lastConsumed;
private Expression lastExpression;
static {
prefixParselets.put(TokenType.NAME, new NameParselet());
prefixParselets.put(TokenType.STRING, new StringParselet());
prefixParselets.put(TokenType.NUMBER, new NumberParselet());
prefixParselets.put(TokenType.TRUE, new BooleanParselet());
prefixParselets.put(TokenType.FALSE, new BooleanParselet());
prefixParselets.put(TokenType.TRUE, new BooleanParselet(Precedence.PREFIX));
prefixParselets.put(TokenType.FALSE, new BooleanParselet(Precedence.PREFIX));
prefixParselets.put(TokenType.RETURN, new ReturnParselet());
prefixParselets.put(TokenType.CONTINUE, new ContinueParselet());
prefixParselets.put(TokenType.BREAK, new BreakParselet());
......@@ -35,28 +35,28 @@ public final class MoLangParser {
prefixParselets.put(TokenType.FOR_EACH, new ForEachParselet());
prefixParselets.put(TokenType.THIS, new ThisParselet());
prefixParselets.put(TokenType.BRACKET_LEFT, new GroupParselet());
prefixParselets.put(TokenType.CURLY_BRACKET_LEFT, new BracketScopeParselet());
prefixParselets.put(TokenType.MINUS, new UnaryMinusParselet());
prefixParselets.put(TokenType.PLUS, new UnaryPlusParselet());
prefixParselets.put(TokenType.BANG, new BooleanNotParselet());
infixParselets.put(TokenType.QUESTION, new TernaryParselet());
infixParselets.put(TokenType.ARRAY_LEFT, new ArrayAccessParselet());
infixParselets.put(TokenType.PLUS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.MINUS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.SLASH, new GenericBinaryOpParselet());
infixParselets.put(TokenType.ASTERISK, new GenericBinaryOpParselet());
infixParselets.put(TokenType.EQUALS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.NOT_EQUALS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.GREATER, new GenericBinaryOpParselet());
infixParselets.put(TokenType.GREATER_OR_EQUALS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.SMALLER, new GenericBinaryOpParselet());
infixParselets.put(TokenType.SMALLER_OR_EQUALS, new GenericBinaryOpParselet());
infixParselets.put(TokenType.AND, new GenericBinaryOpParselet());
infixParselets.put(TokenType.OR, new GenericBinaryOpParselet());
infixParselets.put(TokenType.COALESCE, new GenericBinaryOpParselet());
prefixParselets.put(TokenType.CURLY_BRACKET_LEFT, new BracketScopeParselet(Precedence.SCOPE));
prefixParselets.put(TokenType.MINUS, new UnaryMinusParselet(Precedence.PREFIX));
prefixParselets.put(TokenType.PLUS, new UnaryPlusParselet(Precedence.PREFIX));
prefixParselets.put(TokenType.BANG, new BooleanNotParselet(Precedence.PREFIX));
infixParselets.put(TokenType.QUESTION, new TernaryParselet(Precedence.CONDITIONAL));
infixParselets.put(TokenType.ARRAY_LEFT, new ArrayAccessParselet(Precedence.ARRAY_ACCESS));
infixParselets.put(TokenType.PLUS, new GenericBinaryOpParselet(Precedence.SUM));
infixParselets.put(TokenType.MINUS, new GenericBinaryOpParselet(Precedence.SUM));
infixParselets.put(TokenType.SLASH, new GenericBinaryOpParselet(Precedence.PRODUCT));
infixParselets.put(TokenType.ASTERISK, new GenericBinaryOpParselet(Precedence.PRODUCT));
infixParselets.put(TokenType.EQUALS, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.NOT_EQUALS, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.GREATER, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.GREATER_OR_EQUALS, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.SMALLER, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.SMALLER_OR_EQUALS, new GenericBinaryOpParselet(Precedence.COMPARE));
infixParselets.put(TokenType.AND, new GenericBinaryOpParselet(Precedence.AND));
infixParselets.put(TokenType.OR, new GenericBinaryOpParselet(Precedence.OR));
infixParselets.put(TokenType.COALESCE, new GenericBinaryOpParselet(Precedence.COALESCE));
infixParselets.put(TokenType.ARROW, new GenericBinaryOpParselet());
infixParselets.put(TokenType.ASSIGN, new AssignParselet());
infixParselets.put(TokenType.ASSIGN, new AssignParselet(Precedence.ASSIGNMENT));
}
public MoLangParser(TokenIterator iterator) {
......@@ -67,38 +67,60 @@ public final class MoLangParser {
List<Expression> exprs = new ArrayList<>();
do {
exprs.add(parseExpression());
Expression expr = parseExpression();
if (expr != null) {
exprs.add(expr);
} else {
break;
}
} while (matchToken(TokenType.SEMICOLON));
return exprs;
}
public Expression parseExpression() {
return parseExpression(Precedence.ANYTHING);
}
public Expression parseExpression(Precedence precedence) {
Token token = consumeToken();
if (token.getType().equals(TokenType.EOF)) {
return null;
}
Parselet parselet = prefixParselets.get(token.getType());
PrefixParselet parselet = prefixParselets.get(token.getType());
if (parselet == null) {
throw new RuntimeException("Cannot parse " + token.getType().name() + " expression " + token.getText());
throw new RuntimeException("Cannot parse " + token.getType().name() + " expression");
}
return parseInfixExpression(parselet.parse(this, token));
return parseInfixExpression(parselet.parse(this, token), precedence);
}
private Expression parseInfixExpression(Expression expression) {
Token nextToken = readToken();
private Expression parseInfixExpression(Expression left, Precedence precedence) {
Token token;
if (infixParselets.containsKey(nextToken.getType())) {
Token token = consumeToken();
while (precedence.ordinal() < getPrecedence().ordinal()) {
token = consumeToken();
left = infixParselets.get(token.getType()).parse(this, token, left);
}
return infixParselets.get(nextToken.getType()).parse(this, token, expression);
return left;
}
private Precedence getPrecedence() {
Token token = readToken();
if (token != null) {
InfixParselet parselet = infixParselets.get(token.getType());
if (parselet != null) {
return parselet.getPrecedence();
}
}
return expression;
return Precedence.ANYTHING;
}
public List<Expression> parseArgs() {
......
package com.bedrockk.molang.parser;
import com.bedrockk.molang.parser.tokenizer.Token;
public interface Parselet {
Expression parse(MoLangParser parser, Token token);
}
package com.bedrockk.molang.parser;
public enum Precedence {
ANYTHING,
SCOPE,
ASSIGNMENT,
CONDITIONAL,
ARRAY_ACCESS,
COALESCE,
AND,
OR,
COMPARE,
SUM,
PRODUCT,
PREFIX
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment