package org.develnext.jphp.core.compiler.common; import php.runtime.common.Association; import php.runtime.common.Messages; import php.runtime.exceptions.support.ErrorType; import php.runtime.env.Context; import php.runtime.env.Environment; import org.develnext.jphp.core.tokenizer.token.Token; import org.develnext.jphp.core.tokenizer.token.expr.BraceExprToken; import org.develnext.jphp.core.tokenizer.token.expr.ExprToken; import org.develnext.jphp.core.tokenizer.token.expr.OperatorExprToken; import org.develnext.jphp.core.tokenizer.token.expr.ValueExprToken; import org.develnext.jphp.core.tokenizer.token.expr.operator.*; import org.develnext.jphp.core.tokenizer.token.expr.value.CallExprToken; import org.develnext.jphp.core.tokenizer.token.stmt.ExprStmtToken; import java.util.ArrayList; import java.util.List; import java.util.Stack; public class ASMExpression { protected Context context; protected Environment env; protected ExprStmtToken result; protected ExprStmtToken expr; protected Token prev; public ASMExpression(Environment env, Context context, ExprStmtToken expr){ this.env = env; this.context = context; this.expr = expr; Stack<Token> stack = new Stack<Token>(); List<Token> result = new ArrayList<Token>(); int i = 0, size = expr.getTokens().size(); Token next = null; for(Token token : expr.getTokens()){ next = i >= size - 1 ? null : expr.getTokens().get(i + 1); if (token instanceof OperatorExprToken) { OperatorExprToken operatorToken = (OperatorExprToken)token; if (operatorToken.isBinary()){ if (next == null) unexpectedToken(operatorToken); else if (next instanceof OperatorExprToken){ if (((OperatorExprToken)next).isBinary()) unexpectedToken(next); } } boolean isRight = prev == null; OperatorExprToken operator = null; if (prev instanceof OperatorExprToken) operator = (OperatorExprToken)prev; else if (prev instanceof CallExprToken && ((CallExprToken) prev).getName() instanceof OperatorExprToken) operator = (OperatorExprToken) ((CallExprToken) prev).getName(); if (operator != null){ isRight = operator.getOnlyAssociation() != Association.LEFT; } else if (prev instanceof BraceExprToken){ isRight = ((BraceExprToken) prev).isOpened(); } if (isRight) ((OperatorExprToken) token).setAssociation(Association.RIGHT); else ((OperatorExprToken) token).setAssociation(Association.LEFT); } processToken(token, stack, result); prev = token instanceof ExprToken ? ((ExprToken)token).getLast() : token; i++; } if (!stack.empty()) processOperator(stack, result, null); Stack<Token> checkStack = new Stack<Token>(); i = 0; Token prev = null; for(Token el : result){ if (el instanceof OperatorExprToken){ OperatorExprToken operator = (OperatorExprToken)el; if (!operator.isValidAssociation()) unexpectedToken(operator); if (el instanceof IncExprToken || el instanceof DecExprToken){ if (prev.getClass() == DynamicAccessExprToken.class){ DynamicAccessAssignExprToken newAssign = new DynamicAccessAssignExprToken((DynamicAccessExprToken)prev); newAssign.setAssignOperator(el); result.set(i - 1, newAssign); result.set(i, null); } else if (prev.getClass() == ArrayGetExprToken.class){ ArrayGetRefExprToken newAssign = new ArrayGetRefExprToken((ArrayGetExprToken)prev); result.set(i - 1, newAssign); } } if (operator.isBinary()){ if (checkStack.size() < 2) unexpectedToken(operator); checkStack.pop(); checkStack.pop(); checkStack.push(null); } else { if (checkStack.empty()) unexpectedToken(operator); checkStack.pop(); checkStack.push(null); } } else if (el instanceof CallExprToken){ if (((CallExprToken) el).getName() instanceof OperatorExprToken){ OperatorExprToken operator = (OperatorExprToken) ((CallExprToken) el).getName(); if (operator.isBinary()){ unexpectedToken(operator); } else { if (checkStack.empty()) unexpectedToken(operator); checkStack.pop(); checkStack.push(null); } } else checkStack.push(el); } else { checkStack.push(el); } i++; prev = el; } if (checkStack.size() > 1){ for (Token el : checkStack) if (el != null) unexpectedToken(el); } this.result = new ExprStmtToken(null, null, result); } protected void processOperator(Stack<Token> stack, List<Token> result, OperatorExprToken current){ List<Token> list = new ArrayList<Token>(); boolean isRightOperator = current != null && current.isRightSide(); int prior = current == null ? -1 : current.getPriority(); while (!stack.empty()){ Token el = stack.peek(); int elPrior = getPriority(el); if (el instanceof BraceExprToken) break; if (current != null && current.getAssociation() == Association.RIGHT && !current.isBinary() && prev instanceof OperatorExprToken) break; boolean flush = current == null || elPrior == 1 || (isRightOperator ? elPrior > prior : elPrior <= prior); if (flush){ stack.pop(); list.add(el); } else { break; } } result.addAll(list); } protected void processToken(Token token, Stack<Token> stack, List<Token> result){ //int prior = getPriority(token); if (token instanceof CallExprToken) { CallExprToken call = (CallExprToken)token; if (call.getName() instanceof OperatorExprToken){ processOperator(stack, result, (OperatorExprToken)call.getName()); } result.add(token); } else if (token instanceof ValueExprToken){ result.add(token); } else if (token instanceof BraceExprToken){ BraceExprToken brace = (BraceExprToken)token; if (brace.isSimpleOpened()){ stack.push(brace); } else if (brace.isSimpleClosed()) { if (stack.empty()) unexpectedToken(brace); boolean done = false; do { Token el = stack.pop(); if (el instanceof BraceExprToken && ((BraceExprToken) el).isSimpleOpened()){ done = true; break; } result.add(el); } while (!stack.isEmpty()); if (!done) unexpectedToken(brace); } else unexpectedToken(brace); } else if (token instanceof OperatorExprToken){ OperatorExprToken operator = (OperatorExprToken)token; /*boolean done = !stack.empty(); if (done){ if (operator.isRightSide()) done = getPriority(stack.peek()) > prior; else done = getPriority(stack.peek()) > prior; } if (done){ if (prior == 1){ processOperator(stack, result, prior); result.add(token); return; } stack.push(token); return; }*/ processOperator(stack, result, operator); stack.push(token); } } public ExprStmtToken getResult(){ return result; } private int getPriority(Token token){ if (token instanceof ExprToken) return ((ExprToken)token).getPriority(); else return 0; } /** * @param token */ protected void unexpectedToken(Token token){ env.error( token.toTraceInfo(context), ErrorType.E_PARSE, Messages.ERR_PARSE_UNEXPECTED_X, token.getWord() ); } }