package org.develnext.jphp.core.syntax.generators.manually; import org.develnext.jphp.core.common.Separator; import org.develnext.jphp.core.compiler.common.ASMExpression; import org.develnext.jphp.core.syntax.ExpressionInfo; import org.develnext.jphp.core.syntax.Scope; import org.develnext.jphp.core.syntax.SyntaxAnalyzer; import org.develnext.jphp.core.syntax.generators.ExprGenerator; import org.develnext.jphp.core.syntax.generators.FunctionGenerator; import org.develnext.jphp.core.syntax.generators.Generator; import org.develnext.jphp.core.tokenizer.TokenMeta; import org.develnext.jphp.core.tokenizer.Tokenizer; import org.develnext.jphp.core.tokenizer.token.BreakToken; import org.develnext.jphp.core.tokenizer.token.ColonToken; import org.develnext.jphp.core.tokenizer.token.SemicolonToken; import org.develnext.jphp.core.tokenizer.token.Token; import org.develnext.jphp.core.tokenizer.token.expr.*; import org.develnext.jphp.core.tokenizer.token.expr.operator.*; import org.develnext.jphp.core.tokenizer.token.expr.operator.cast.CastExprToken; import org.develnext.jphp.core.tokenizer.token.expr.operator.cast.UnsetCastExprToken; import org.develnext.jphp.core.tokenizer.token.expr.value.*; import org.develnext.jphp.core.tokenizer.token.expr.value.macro.MacroToken; import org.develnext.jphp.core.tokenizer.token.stmt.*; import php.runtime.common.Callback; import php.runtime.common.Messages; import php.runtime.env.TraceInfo; import php.runtime.exceptions.ParseException; import java.util.*; import static org.develnext.jphp.core.tokenizer.token.expr.BraceExprToken.Kind.ARRAY; import static org.develnext.jphp.core.tokenizer.token.expr.BraceExprToken.Kind.BLOCK; public class SimpleExprGenerator extends Generator<ExprStmtToken> { private boolean isRef = false; private boolean canStartByReference = false; private static final Set<String> dynamicLocalFunctions = new HashSet<String>(){{ add("extract"); add("compact"); add("get_defined_vars"); add("eval"); }}; public SimpleExprGenerator(SyntaxAnalyzer analyzer) { super(analyzer); } public SimpleExprGenerator setCanStartByReference(boolean canStartByReference) { this.canStartByReference = canStartByReference; return this; } @Override public boolean isSingleton() { return false; } protected Token processClosure(Token current, Token next, ListIterator<Token> iterator){ FunctionStmtToken functionStmtToken = analyzer.generator(FunctionGenerator.class).getToken( current, iterator, true ); if (functionStmtToken.getName() == null){ //unexpectedToken(functionStmtToken.getName()); ClosureStmtToken result = new ClosureStmtToken(current.getMeta()); result.setFunction(functionStmtToken); result.setOwnerClass(analyzer.getClazz()); analyzer.registerClosure(result); return result; } else { analyzer.registerFunction(functionStmtToken); return functionStmtToken; } } public ListExprToken processSingleList(Token current, ListIterator<Token> iterator) { return processList(current, iterator, null, null, -1); } protected ListExprToken processList(Token current, ListIterator<Token> iterator, List<Integer> indexes, BraceExprToken.Kind closedBraceKind, int braceOpened){ ListExprToken result = (ListExprToken)current; Token next = nextToken(iterator); if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)) unexpectedToken(next, "("); int i = 0; while (true){ next = nextToken(iterator); /*if (next instanceof VariableExprToken){ if (prev != null && !(prev instanceof CommaToken)) unexpectedToken(next); analyzer.getLocalScope().add((VariableExprToken)next); result.addVariable(((VariableExprToken) next), i, indexes); } else*/ if (next instanceof ListExprToken){ List<Integer> indexes_ = new ArrayList<Integer>(); if (indexes != null) indexes_.addAll(indexes); indexes_.add(i); ListExprToken tmp = processList(next, iterator, indexes_, null, -1); result.addList(tmp); if (nextTokenAndPrev(iterator) instanceof CommaToken) iterator.next(); i++; } else if (isClosedBrace(next, BraceExprToken.Kind.SIMPLE)){ break; } else if (next instanceof CommaToken){ i++; } else { SimpleExprGenerator generator = analyzer.generator(SimpleExprGenerator.class); ExprStmtToken var = generator.getToken(next, iterator, Separator.COMMA, BraceExprToken.Kind.SIMPLE); Token single = var.getLast(); if (!(single instanceof VariableExprToken || single instanceof ArrayGetExprToken || single instanceof DynamicAccessExprToken || single instanceof ArrayPushExprToken || (single instanceof StaticAccessExprToken && ((StaticAccessExprToken) single).isGetStaticField()))){ unexpectedToken(single); } if (single instanceof ArrayGetExprToken){ single = new ArrayGetRefExprToken((ArrayGetExprToken)single); var.getTokens().set(var.getTokens().size() - 1, single); var.updateAsmExpr(analyzer.getEnvironment(), analyzer.getContext()); } result.addVariable(var, i, indexes); i++; } } if (braceOpened != -1){ next = nextToken(iterator); if (!(next instanceof AssignExprToken)) unexpectedToken(next, "="); ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, BraceExprToken.Kind.ANY ); result.setValue(value); } return result; } protected DieExprToken processDie(Token current, Token next, ListIterator<Token> iterator){ DieExprToken die = (DieExprToken)current; if (isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)){ die.setValue( analyzer.generator(ExprGenerator.class).getInBraces(BraceExprToken.Kind.SIMPLE, iterator) ); } return die; } protected EmptyExprToken processEmpty(Token current, ListIterator<Token> iterator){ ExprStmtToken value = analyzer.generator(ExprGenerator.class).getInBraces(BraceExprToken.Kind.SIMPLE, iterator); if (value == null) unexpectedToken(iterator.previous()); assert value != null; Token last = value.getLast(); if (last instanceof DynamicAccessExprToken){ last = new DynamicAccessEmptyExprToken((DynamicAccessExprToken)last); value.getTokens().set(value.getTokens().size() - 1, last); } else if (last instanceof VariableExprToken || last instanceof GetVarExprToken){ // nop } else if (last instanceof StaticAccessExprToken && ((StaticAccessExprToken) last).isGetStaticField()){ last = new StaticAccessIssetExprToken((StaticAccessExprToken)last); value.getTokens().set(value.getTokens().size() - 1, last); } else if (last instanceof ArrayGetExprToken){ ArrayGetEmptyExprToken el = new ArrayGetEmptyExprToken(last.getMeta()); el.setParameters(((ArrayGetExprToken) last).getParameters()); value.getTokens().set(value.getTokens().size() - 1, el); } else unexpectedToken(last); EmptyExprToken result = (EmptyExprToken)current; value.updateAsmExpr(analyzer.getEnvironment(), analyzer.getContext()); result.setValue(value); return result; } protected IssetExprToken processIsset(Token previous, Token current, ListIterator<Token> iterator){ Token next = nextTokenAndPrev(iterator); if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)) unexpectedToken(next, "("); CallExprToken call = processCall(current, nextToken(iterator), iterator); for(ExprStmtToken param : call.getParameters()){ List<Token> tokens = param.getTokens(); Token last = tokens.get(tokens.size() - 1); Token newToken = null; if (last instanceof DynamicAccessExprToken){ newToken = new DynamicAccessIssetExprToken((DynamicAccessExprToken)last); if (analyzer.getClazz() != null && !"__isset".equals(analyzer.getFunction().getFulledName())){ ((DynamicAccessIssetExprToken)newToken).setWithMagic(false); } } else if (last instanceof VariableExprToken || last instanceof GetVarExprToken){ // nop } else if (last instanceof StaticAccessExprToken && ((StaticAccessExprToken) last).isGetStaticField()){ newToken = new StaticAccessIssetExprToken((StaticAccessExprToken)last); } else if (last instanceof ArrayGetExprToken){ ArrayGetIssetExprToken el = new ArrayGetIssetExprToken(last.getMeta()); el.setParameters(((ArrayGetExprToken) last).getParameters()); newToken = el; } else unexpectedToken(param.getSingle()); if (newToken != null) { tokens.set(tokens.size() - 1, newToken); param.updateAsmExpr(analyzer.getEnvironment(), analyzer.getContext()); } } IssetExprToken result = (IssetExprToken)current; result.setParameters(call.getParameters()); return result; } protected UnsetExprToken processUnset(Token previous, Token current, ListIterator<Token> iterator){ Token next = nextTokenAndPrev(iterator); if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)) unexpectedToken(next, "("); CallExprToken call = processCall(current, nextToken(iterator), iterator); for(ExprStmtToken param : call.getParameters()){ List<Token> tokens = param.getTokens(); Token last = tokens.get(tokens.size() - 1); Token newToken = null; if (param.getSingle() instanceof StaticAccessExprToken && ((StaticAccessExprToken) param.getSingle()).isGetStaticField()) { // allow class::$var } else if (!(param.getSingle() instanceof VariableValueExprToken)) unexpectedToken(param); if (last instanceof VariableExprToken || last instanceof GetVarExprToken){ newToken = last; // nop } else if (last instanceof ArrayGetExprToken){ ArrayGetUnsetExprToken el = new ArrayGetUnsetExprToken(last.getMeta()); el.setParameters(((ArrayGetExprToken) last).getParameters()); newToken = el; } else if (last instanceof DynamicAccessExprToken){ newToken = new DynamicAccessUnsetExprToken((DynamicAccessExprToken)last); } else if (last instanceof StaticAccessExprToken){ newToken = new StaticAccessUnsetExprToken((StaticAccessExprToken)last); } else unexpectedToken(last); tokens.set(tokens.size() - 1, newToken); param.updateAsmExpr(analyzer.getEnvironment(), analyzer.getContext()); } UnsetExprToken result = (UnsetExprToken)current; result.setParameters(call.getParameters()); return result; } protected CallExprToken processCall(Token previous, Token current, ListIterator<Token> iterator){ ExprStmtToken param; List<ExprStmtToken> parameters = new ArrayList<>(); do { param = analyzer.generator(SimpleExprGenerator.class) .getNextExpression(nextToken(iterator), iterator, Separator.COMMA, BraceExprToken.Kind.SIMPLE); if (param != null) { parameters.add(param); if (param.isSingle()){ if (param.getTokens().get(0) instanceof VariableExprToken) { if (analyzer.getFunction() != null) analyzer.getFunction().variable((VariableExprToken)param.getTokens().get(0)).setPassed(true); } } } if (isClosedBrace(nextToken(iterator), BraceExprToken.Kind.SIMPLE)) { break; } } while (param != null); //nextToken(iterator); CallExprToken result = new CallExprToken(TokenMeta.of(previous, current)); if (previous instanceof ValueExprToken) { result.setName(analyzer.getRealName((ValueExprToken)previous, NamespaceUseStmtToken.UseType.FUNCTION)); if (analyzer.getFunction() != null){ if (result.getName() instanceof NameToken) { String name = ((NameToken) result.getName()).getName().toLowerCase(); if (result.getName() instanceof FulledNameToken) { name = ((FulledNameToken) result.getName()).getLastName().getName().toLowerCase(); } if (dynamicLocalFunctions.contains(name.toLowerCase())) analyzer.getFunction().setDynamicLocal(true); if ("get_called_class".equalsIgnoreCase(name)) { analyzer.getScope().setStaticExists(true); } } } } else { if (previous instanceof DynamicAccessExprToken) { result.setName((ExprToken)previous); } else result.setName(null); } result.setParameters(parameters); if (analyzer.getFunction() != null){ analyzer.getFunction().setCallsExist(true); } return result; } protected Token processYield(Token current, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBrace) { if (analyzer.getFunction() == null) { analyzer.getEnvironment().error( current.toTraceInfo(analyzer.getContext()), Messages.ERR_YIELD_CAN_ONLY_INSIDE_FUNCTION.fetch() ); } analyzer.getFunction().setGenerator(true); YieldExprToken result = (YieldExprToken) current; if (next instanceof OperatorExprToken && ((OperatorExprToken) next).isBinary()) { result.setValue(null); } else { ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, BraceExprToken.Kind.ANY ); result.setValue(value); } return result; } protected ImportExprToken processImport(Token current, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBrace, int braceOpened){ ImportExprToken result = (ImportExprToken)current; ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, BraceExprToken.Kind.ANY ); result.setValue(value); if (analyzer.getFunction() != null) analyzer.getFunction().setDynamicLocal(true); return result; } protected CallExprToken processPrint(Token current, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBrace, int braceOpened){ CallExprToken callExprToken = new CallExprToken(current.getMeta()); callExprToken.setName((ExprToken) current); ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, BraceExprToken.Kind.ANY ); if (value == null) unexpectedToken(iterator.previous()); callExprToken.setParameters(Arrays.asList(value)); return callExprToken; } protected Token processStaticAccess(Token current, Token previous, ListIterator<Token> iterator) { Token name = previous; if (name != null && !isTokenClass(name, SelfExprToken.class, StaticExprToken.class, ParentExprToken.class)) { name = makeSensitive(previous); } if (name == null || name instanceof NameToken || name instanceof VariableExprToken || name instanceof SelfExprToken || name instanceof StaticExprToken || name instanceof ParentExprToken) { if (name instanceof StaticExprToken) { analyzer.getScope().setStaticExists(true); } StaticAccessExprToken result = (StaticAccessExprToken) current; ValueExprToken clazz = (ValueExprToken) name; if (clazz instanceof NameToken){ clazz = analyzer.getRealName((NameToken)clazz); } else if (clazz instanceof SelfExprToken){ if (analyzer.getClazz() == null) { ; } else { if (!analyzer.getClazz().isTrait()) { clazz = new FulledNameToken(clazz.getMeta(), new ArrayList<Token>() {{ if (analyzer.getClazz().getNamespace().getName() != null) addAll(analyzer.getClazz().getNamespace().getName().getNames()); add(analyzer.getClazz().getName()); }}); } } } result.setClazz(clazz); if (name != null) { nextToken(iterator); } current = nextToken(iterator); if (!isTokenClass(current, ClassStmtToken.class)) { current = makeSensitive(current); } if (isOpenedBrace(current, BLOCK)){ ExprStmtToken expr = getToken(nextToken(iterator), iterator, false, BLOCK); result.setFieldExpr(expr); nextAndExpected(iterator, BraceExprToken.class); } else if (current instanceof NameToken || current instanceof VariableExprToken){ result.setField((ValueExprToken)current); } else if (current instanceof DollarExprToken) { Token nm = nextToken(iterator); if (nm instanceof VariableExprToken) { result.setFieldExpr(new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), nm)); } else if (nm instanceof DollarExprToken) { result.setFieldExpr(new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), processVarVar(nm, nextTokenAndPrev(iterator), iterator))); } else if (isOpenedBrace(nm, BLOCK)) { iterator.previous(); result.setFieldExpr( analyzer.generator(ExprGenerator.class).getInBraces(BLOCK, iterator) ); } else unexpectedToken(current); } else if (current instanceof ClassStmtToken) { // PHP 5.5 ::class if (clazz instanceof ParentExprToken || clazz instanceof StaticExprToken) { if (clazz instanceof StaticExprToken) { analyzer.getScope().setStaticExists(true); } result.setField(new ClassExprToken(current.getMeta())); } else if (clazz instanceof NameToken) { return new StringExprToken( TokenMeta.of(((NameToken) clazz).getName(), clazz), StringExprToken.Quote.SINGLE ); } else unexpectedToken(current); } else unexpectedToken(current); if (name == null) { return new StaticAccessOperatorExprToken(result); } return result; } else unexpectedToken(name); return null; } protected DynamicAccessExprToken processDynamicAccess(Token current, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBraceKind, int braceOpened){ if (next != null && next.isNamedToken() && !(next instanceof NameToken)) next = new NameToken(next.getMeta()); DynamicAccessExprToken result = (DynamicAccessExprToken)current; if (next instanceof NameToken || next instanceof VariableExprToken){ result.setField((ValueExprToken) next); next = iterator.next(); if (result.getField() instanceof VariableExprToken) { if (isOpenedBrace(nextTokenAndPrev(iterator), ARRAY)){ ArrayGetExprToken arr = (ArrayGetExprToken) processArrayToken(next, nextToken(iterator), iterator); result.setFieldExpr(new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), result.getField(), arr)); result.setField(null); } } } else if (isOpenedBrace(next, BLOCK)){ ExprStmtToken name = analyzer.generator(ExprGenerator.class).getInBraces( BLOCK, iterator ); result.setFieldExpr(name); } if (iterator.hasNext()){ next = iterator.next(); if (next instanceof AssignableOperatorToken){ DynamicAccessAssignExprToken dResult = new DynamicAccessAssignExprToken(result); dResult.setAssignOperator(next); ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class) .setCanStartByReference(true) .getNextExpression(nextToken(iterator), iterator, BraceExprToken.Kind.ANY); dResult.setValue(value); return dResult; } iterator.previous(); } return result; } public GetVarExprToken processVarVar(Token current, Token next, ListIterator<Token> iterator){ ExprStmtToken name = null; if (next instanceof VariableExprToken){ // $$var name = new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), next); nextToken(iterator); } else if (next instanceof DollarExprToken){ // $$$var current = nextToken(iterator); next = nextToken(iterator); name = new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), processVarVar(current, next, iterator)); iterator.previous(); } else if (isOpenedBrace(next, BLOCK)){ // ${var} name = analyzer.generator(ExprGenerator.class).getInBraces( BLOCK, iterator ); } else if (next == null) { unexpectedEnd(current); } if (name == null) { unexpectedToken(next); } if (analyzer.getFunction() != null){ analyzer.getFunction().setDynamicLocal(true); analyzer.getFunction().setVarsExists(true); } GetVarExprToken result = new GetVarExprToken(TokenMeta.of(current, name)); result.setName(name); return result; } protected Token processValueIfElse(ValueIfElseToken current, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBrace, int braceOpened, Separator separator){ ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class).getToken( nextToken(iterator), iterator, Separator.COLON, closedBrace ); /*if (closedBrace == null || braceOpened < 1) iterator.previous();*/ current.setValue(value); if (!((next = iterator.previous()) instanceof ColonToken)) unexpectedToken(next, ":"); iterator.next(); ExprStmtToken alternative = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, separator, BraceExprToken.Kind.ANY ); if (alternative == null) unexpectedToken(iterator.next()); current.setAlternative(alternative); return current; } protected ExprStmtToken processNewExpr(Token next, BraceExprToken.Kind closedBrace, int braceOpened, ListIterator<Token> iterator, boolean first) { List<Token> tmp = new ArrayList<Token>(); if (first) { if (next instanceof VariableExprToken) { analyzer.getScope().addVariable((VariableExprToken) next); if (analyzer.getFunction() != null) { analyzer.getFunction().setVarsExists(true); analyzer.getFunction().variable((VariableExprToken) next).setUsed(true); } } tmp.add(next); } Token previous = next; Token token = nextToken(iterator); if (isOpenedBrace(token, ARRAY) || isOpenedBrace(token, BLOCK)) { tmp.add(processArrayToken(previous, token, iterator)); if (iterator.hasNext()) { if (nextTokenAndPrev(iterator) instanceof DynamicAccessExprToken) tmp.addAll(processNewExpr(next, closedBrace, braceOpened, iterator, false).getTokens()); } } else if (token instanceof DynamicAccessExprToken) { next = null; if (iterator.hasNext()) { next = iterator.next(); iterator.previous(); } tmp.add(processDynamicAccess(token, next, iterator, closedBrace, braceOpened)); if (iterator.hasNext()) { token = nextTokenAndPrev(iterator); if (isOpenedBrace(token, ARRAY) || isOpenedBrace(token, BLOCK) || token instanceof DynamicAccessExprToken) { tmp.addAll(processNewExpr(next, closedBrace, braceOpened, iterator, false).getTokens()); } } } else iterator.previous(); if (!first) { return new ExprStmtToken(null, null, tmp); } return new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), tmp); } protected Token processNew(Token current, BraceExprToken.Kind closedBrace, int braceOpened, ListIterator<Token> iterator){ NewExprToken result = (NewExprToken)current; Token next = nextToken(iterator); if (!isTokenClass(next, StaticExprToken.class, ParentExprToken.class, SelfExprToken.class)) { next = makeSensitive(next); } if (next instanceof NameToken){ FulledNameToken nameToken = analyzer.getRealName((NameToken)next); result.setName(nameToken); iterator.previous(); iterator.previous(); if (iterator.hasPrevious()) { Token previous = iterator.previous(); if (previous instanceof AssignExprToken) { if (iterator.hasPrevious()) { previous = iterator.previous(); if (previous instanceof VariableExprToken) { analyzer.getScope().typeInfoOf(previous).addType(nameToken.getName()); } iterator.next(); } } iterator.next(); } iterator.next(); iterator.next(); } else if (next instanceof VariableExprToken) { result.setName(processNewExpr(next, closedBrace, braceOpened, iterator, true)); } else if (next instanceof StaticExprToken) { Scope scope = analyzer.getScope(); scope.setStaticExists(true); result.setName((StaticExprToken)next); } else if (next instanceof SelfExprToken){ if (analyzer.getClazz() == null) { result.setName((SelfExprToken) next); } else { if (analyzer.getClazz().isTrait()) { result.setName((SelfExprToken) next); } else { result.setName(new FulledNameToken(next.getMeta(), new ArrayList<Token>() {{ if (analyzer.getClazz().getNamespace().getName() != null) addAll(analyzer.getClazz().getNamespace().getName().getNames()); add(analyzer.getClazz().getName()); }})); } } } else unexpectedToken(next); next = nextToken(iterator); if (isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)){ ExprStmtToken param; List<ExprStmtToken> parameters = new ArrayList<ExprStmtToken>(); do { param = analyzer.generator(SimpleExprGenerator.class) .getToken(nextToken(iterator), iterator, true, BraceExprToken.Kind.SIMPLE); if (param != null) parameters.add(param); } while (param != null); nextToken(iterator); result.setParameters(parameters); } else { result.setParameters(new ArrayList<ExprStmtToken>()); iterator.previous(); } if (analyzer.getFunction() != null){ analyzer.getFunction().setCallsExist(true); } return result; } protected Token processString(StringExprToken string) { if (string.getSegments().isEmpty()){ if (string.getQuote() == StringExprToken.Quote.SHELL) { return new ShellExecExprToken(string.getMeta(), Arrays.<Token>asList(string)); } return string; } List<Token> tokens = new ArrayList<Token>(); int i = 0; String value = string.getValue(); TokenMeta meta = string.getMeta(); for(StringExprToken.Segment segment : string.getSegments()){ String prev = value.substring(i, segment.from); if (!prev.isEmpty()) { StringExprToken item = new StringExprToken(new TokenMeta( prev, meta.getStartLine() + i, meta.getEndLine(), meta.getStartLine(), meta.getEndLine() ), StringExprToken.Quote.SINGLE); tokens.add(item); } String dynamic = value.substring(segment.from, segment.to); if (!segment.isVariable) dynamic = dynamic.substring(1, dynamic.length() - 1); Tokenizer tokenizer = new Tokenizer(dynamic + ";", analyzer.getContext()); try { SyntaxAnalyzer syntaxAnalyzer = new SyntaxAnalyzer(analyzer.getEnvironment(), tokenizer, analyzer.getFunction()); List<Token> tree = syntaxAnalyzer.getTree(); analyzer.getScope().addVariables(syntaxAnalyzer.getScope().getVariables()); assert tree.size() > 0; Token item = tree.get(0); if (!(item instanceof ExprStmtToken)) unexpectedToken(item); ExprStmtToken expr = (ExprStmtToken)item; if (expr.isSingle()){ tokens.add(expr.getSingle()); } else tokens.add(expr); } catch (ParseException e){ TraceInfo oldTrace = e.getTraceInfo(); e.setTraceInfo(new TraceInfo( analyzer.getContext(), meta.getStartLine() + oldTrace.getStartLine(), meta.getEndLine() + oldTrace.getEndLine(), meta.getStartLine() + oldTrace.getStartLine(), meta.getEndLine() + oldTrace.getEndLine() )); throw e; } i = segment.to; } String prev = value.substring(i); if (!prev.isEmpty()){ StringExprToken item = new StringExprToken(new TokenMeta( prev, meta.getStartLine() + i, meta.getEndLine(), meta.getStartLine(), meta.getEndLine() ), StringExprToken.Quote.SINGLE); tokens.add(item); } if (string.getQuote() == StringExprToken.Quote.SHELL) { return new ShellExecExprToken(meta, tokens); } StringBuilderExprToken result = new StringBuilderExprToken(meta, tokens); result.setBinary(string.isBinary()); return result; } protected Token processSimpleToken(Token current, Token previous, Token next, ListIterator<Token> iterator, BraceExprToken.Kind closedBraceKind, int braceOpened, Separator separator){ if (current instanceof DynamicAccessExprToken){ return processDynamicAccess(current, next, iterator, closedBraceKind, braceOpened); } if (current instanceof OperatorExprToken) { isRef = false; if (current instanceof InstanceofExprToken && next instanceof NameToken) { if (previous instanceof VariableExprToken) { analyzer.getScope().typeInfoOf(previous).addType(analyzer.getRealName((NameToken) next, NamespaceUseStmtToken.UseType.CLASS).getName()); } } } if (current instanceof NameToken && next instanceof StringExprToken) { // binary string if (((NameToken) current).getName().equalsIgnoreCase("b")) { ((StringExprToken) next).setBinary(true); iterator.next(); return processString((StringExprToken)next); } } if (current instanceof YieldExprToken) { return processYield(current, next, iterator, closedBraceKind); } if (current instanceof ImportExprToken) { return processImport(current, next, iterator, closedBraceKind, braceOpened); } if (current instanceof PrintNameToken) { return processPrint(current, next, iterator, closedBraceKind, braceOpened); } if (current instanceof NewExprToken) { return processNew(current, closedBraceKind, braceOpened, iterator); } if (current instanceof DollarExprToken){ return processVarVar(current, next, iterator); } if (current instanceof VariableExprToken){ analyzer.getScope().addVariable((VariableExprToken) current); if (analyzer.getFunction() != null) { analyzer.getFunction().setVarsExists(true); analyzer.getFunction().variable((VariableExprToken)current).setUsed(true); } } // Если переменная меняется, значит она нестабильна и не может быть заменена на костантное значение. if ((current instanceof AssignOperatorExprToken || current instanceof IncExprToken || current instanceof DecExprToken) && previous instanceof VariableExprToken) { if (analyzer.getFunction() != null) { analyzer.getFunction().variable((VariableExprToken) previous).setUnstable(true); } } if (current instanceof AssignExprToken && previous instanceof VariableExprToken && next instanceof VariableExprToken) { ExpressionInfo info = analyzer.getScope().typeInfoOf(next); analyzer.getScope().typeInfoOf(previous).addTypes(info.getTypes()); } if (current instanceof ValueIfElseToken){ return processValueIfElse((ValueIfElseToken)current, next, iterator, closedBraceKind, braceOpened, separator); } // & if (current instanceof AmpersandRefToken){ /*if (previous == null) unexpectedToken(current);*/ isRef = true; if (next instanceof VariableExprToken) if (analyzer.getFunction() != null) { analyzer.getFunction().variable((VariableExprToken)next) .setReference(true) .setMutable(true); } if (previous instanceof AssignExprToken || previous instanceof KeyValueExprToken || (canStartByReference && previous == null)) { if (previous instanceof AssignExprToken) ((AssignExprToken) previous).setAsReference(true); iterator.previous(); Token token = iterator.previous(); // = if (iterator.hasPrevious()) { token = iterator.previous(); if (token instanceof VariableExprToken && analyzer.getFunction() != null){ analyzer.getFunction().variable((VariableExprToken)token) .setReference(true) .setMutable(true); // analyzer.getFunction().getUnstableLocal().add((VariableExprToken)token); TODO: check is needed? } iterator.next(); } iterator.next(); iterator.next(); if (!(next instanceof ValueExprToken)) unexpectedToken(token); } else { return new AndExprToken(current.getMeta()); } return current; } // &$var, &$obj->prop['x'], &class::$prop, &$arr['x'], &call()->x; if (previous instanceof AmpersandRefToken){ if (current instanceof VariableExprToken) if (analyzer.getFunction() != null) analyzer.getFunction().variable((VariableExprToken)current).setReference(true); } if ((current instanceof MinusExprToken || current instanceof PlusExprToken) && (next instanceof IntegerExprToken || next instanceof DoubleExprToken)){ if (!(previous instanceof ValueExprToken || previous instanceof ArrayGetExprToken || previous instanceof DynamicAccessExprToken || isClosedBrace(previous, BraceExprToken.Kind.SIMPLE))){ iterator.next(); // if it minus if (current instanceof MinusExprToken){ if (next instanceof IntegerExprToken){ return new IntegerExprToken(TokenMeta.of(current, next)); } else if (next instanceof DoubleExprToken){ return new DoubleExprToken(TokenMeta.of(current, next)); } } // if it plus nothing return next; } } if (current instanceof MinusExprToken){ if (!(previous instanceof ValueExprToken || previous instanceof ArrayGetExprToken || previous instanceof DynamicAccessExprToken || isClosedBrace(previous))){ return new UnarMinusExprToken(current.getMeta()); } } if (current instanceof LogicOperatorExprToken){ if (next == null) unexpectedToken(current); final LogicOperatorExprToken logic = (LogicOperatorExprToken)current; ExprStmtToken result = analyzer.generator(SimpleExprGenerator.class).getNextExpression( nextToken(iterator), iterator, separator, braceOpened > 0 ? BraceExprToken.Kind.SIMPLE : closedBraceKind ); logic.setRightValue(result); return logic; } if (next instanceof StaticAccessExprToken) { return processStaticAccess(next, current, iterator); } if (current instanceof StaticAccessExprToken) { return processStaticAccess(current, null, iterator); } if (current instanceof StringExprToken){ return processString((StringExprToken) current); } if (current instanceof NameToken) { if (previous instanceof InstanceofExprToken) { return analyzer.getRealName((NameToken) current, NamespaceUseStmtToken.UseType.CLASS); } else { return analyzer.getRealName((NameToken) current, NamespaceUseStmtToken.UseType.CONSTANT); } } if (current instanceof MacroToken) { return null; } if (current instanceof OperatorExprToken) { return null; } if (current.isNamedToken()) { return makeSensitive(current); } return null; } protected Token processNewArray(Token current, ListIterator<Token> iterator){ ArrayExprToken result = new ArrayExprToken(current.getMeta()); List<ExprStmtToken> parameters = new ArrayList<ExprStmtToken>(); Token next; BraceExprToken.Kind braceKind; if (isOpenedBrace(current, ARRAY)) { next = current; braceKind = ARRAY; } else { next = nextToken(iterator); if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)) unexpectedToken(next, "("); braceKind = BraceExprToken.Kind.SIMPLE; } do { SimpleExprGenerator generator = analyzer.generator(SimpleExprGenerator.class); generator.setCanStartByReference(true); ExprStmtToken argument = generator.getToken(nextToken(iterator), iterator, Separator.COMMA, braceKind); if (argument == null) break; parameters.add(argument); } while (true); nextToken(iterator); // skip ) result.setParameters(parameters); return result; } protected Token processArrayToken(Token previous, Token current, ListIterator<Token> iterator){ BraceExprToken.Kind braceKind = ARRAY; Separator separator = Separator.ARRAY; if (isOpenedBrace(current, BLOCK)){ braceKind = BLOCK; separator = Separator.ARRAY_BLOCK; } VariableExprToken var = null; if (previous instanceof VariableExprToken) { if (analyzer.getFunction() != null){ analyzer.getFunction().variable(var = (VariableExprToken)previous).setArrayAccess(true); } } Token next = nextToken(iterator); if (isClosedBrace(next, braceKind)){ //Token tk = nextTokenAndPrev(iterator); //if (tk instanceof AssignableOperatorToken || isOpenedBrace(tk, BraceExprToken.Kind.ARRAY)) { // !!! allow [] anywhere return new ArrayPushExprToken(TokenMeta.of(current, next)); /*} else unexpectedToken(tk);*/ } else iterator.previous(); ExprStmtToken param; List<ExprStmtToken> parameters = new ArrayList<>(); boolean lastPush = false; do { Token token = nextToken(iterator); if (isClosedBrace(token, ARRAY)) { iterator.previous(); if (iterator.hasPrevious()) { iterator.previous(); } lastPush = true; break; } else { param = analyzer.generator(SimpleExprGenerator.class).getNextExpression(token, iterator, separator, braceKind); } if (param != null) { parameters.add(param); if (iterator.hasNext()){ iterator.next(); if (iterator.hasNext()) { Token tmp = nextToken(iterator); if (isOpenedBrace(tmp, ARRAY)) { braceKind = ARRAY; separator = Separator.ARRAY; continue; } else if (isOpenedBrace(tmp, BLOCK)) { braceKind = BLOCK; separator = Separator.ARRAY_BLOCK; continue; } iterator.previous(); } break; } } } while (param != null); //nextToken(iterator); // skip ] ArrayGetExprToken result; result = new ArrayGetExprToken(current.getMeta()); result.setParameters(parameters); if (isRef) { result = new ArrayGetRefExprToken(result); ((ArrayGetRefExprToken)result).setShortcut(true); if (var != null && analyzer.getFunction() != null) { analyzer.getFunction().variable(var).setMutable(true); } } else if (iterator.hasNext()){ next = iterator.next(); if (next instanceof AssignableOperatorToken || lastPush){ result = new ArrayGetRefExprToken(result); if (var != null && analyzer.getFunction() != null) { analyzer.getFunction().variable(var).setMutable(true); } } iterator.previous(); } return result; } public ExprStmtToken getToken(Token current, ListIterator<Token> iterator, boolean commaSeparator, BraceExprToken.Kind closedBraceKind) { return getToken( current, iterator, commaSeparator ? Separator.COMMA : Separator.SEMICOLON, closedBraceKind, null ); } public ExprStmtToken getNextExpression(Token current, ListIterator<Token> iterator, BraceExprToken.Kind closedBraceKind){ return getNextExpression(current, iterator, Separator.COMMA_OR_SEMICOLON, closedBraceKind); } public ExprStmtToken getNextExpression(Token current, ListIterator<Token> iterator, Separator separator, BraceExprToken.Kind closedBraceKind){ ExprStmtToken value = getToken( current, iterator, separator, closedBraceKind ); Token tk = iterator.previous(); if (!isBreak(tk) && (separator == null || !separator.is(tk))){ iterator.next(); } return value; } public ExprStmtToken getToken(Token current, ListIterator<Token> iterator, Separator separator, BraceExprToken.Kind closedBraceKind) { return getToken( current, iterator, separator, closedBraceKind, null ); } @SuppressWarnings("unchecked") public ExprStmtToken getToken(Token current, ListIterator<Token> iterator, Separator separator, BraceExprToken.Kind closedBraceKind, Callback<Boolean, Token> breakCallback) { isRef = false; List<Token> tokens = new ArrayList<Token>(); Token previous = null; Token next = iterator.hasNext() ? iterator.next() : null; if (next != null) iterator.previous(); int braceOpened = 0; boolean needBreak = false; do { if (breakCallback != null && current != null && breakCallback.call(current)){ break; } if (isOpenedBrace(current, BraceExprToken.Kind.SIMPLE)){ boolean isFunc = false; if (previous instanceof NameToken && previous.getMeta().getWord().equalsIgnoreCase("array")){ iterator.previous(); tokens.set(tokens.size() - 1, current = processNewArray(previous, iterator)); } else { if (previous instanceof NameToken || previous instanceof VariableExprToken || previous instanceof ClosureStmtToken || previous instanceof ArrayGetExprToken || previous instanceof CallExprToken) isFunc = true; else if (previous instanceof StaticAccessExprToken){ isFunc = true; // !((StaticAccessExprToken)previous).isGetStaticField(); TODO check it! } else if (previous instanceof DynamicAccessExprToken){ isFunc = true; } if (isFunc){ CallExprToken call = processCall(previous, current, iterator); if (call.getName() != null) { current = call; tokens.set(tokens.size() - 1, call); } else { tokens.add(current = new CallOperatorToken(call)); } } else { if (needBreak) unexpectedToken(current); braceOpened += 1; tokens.add(current); } } } else if (braceOpened > 0 && isClosedBrace(current, BraceExprToken.Kind.SIMPLE)){ braceOpened -= 1; tokens.add(current); if (isOpenedBrace(previous, BraceExprToken.Kind.SIMPLE)) unexpectedToken(current); } else if (isOpenedBrace(current, ARRAY) || isOpenedBrace(current, BLOCK)){ if (isTokenClass(previous, NameToken.class, VariableExprToken.class, GetVarExprToken.class, CallExprToken.class, ArrayGetExprToken.class, DynamicAccessExprToken.class, StringExprToken.class, StringBuilderExprToken.class, CallOperatorToken.class, ArrayPushExprToken.class) || (previous instanceof StaticAccessExprToken && ((StaticAccessExprToken)previous).isGetStaticField())){ // array current = processArrayToken(previous, current, iterator); if (previous instanceof DynamicAccessExprToken && current instanceof ArrayGetRefExprToken){ tokens.set(tokens.size() - 1, new DynamicAccessGetRefExprToken((DynamicAccessExprToken)previous)); } tokens.add(current); } else if (previous instanceof OperatorExprToken || previous == null || isOpenedBrace(previous, BraceExprToken.Kind.SIMPLE) || isOpenedBrace(previous, BLOCK)) { tokens.add(current = processNewArray(current, iterator)); } else unexpectedToken(current); } else if (braceOpened == 0 && isClosedBrace(current, ARRAY)){ if (separator == Separator.ARRAY) break; if (closedBraceKind == ARRAY || closedBraceKind == BraceExprToken.Kind.ANY){ //if (tokens.isEmpty()) iterator.previous(); break; } unexpectedToken(current); } else if (separator == Separator.ARRAY_BLOCK && braceOpened == 0 && isClosedBrace(current, BLOCK)){ break; } else if (current instanceof FunctionStmtToken){ current = processClosure(current, next, iterator); tokens.add(current); } else if (current instanceof ListExprToken && isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)){ current = processList(current, iterator, null, closedBraceKind, braceOpened); tokens.add(current); } else if (current instanceof DieExprToken){ processDie(current, next, iterator); tokens.add(current); } else if (current instanceof EmptyExprToken){ processEmpty(current, iterator); tokens.add(current); } else if (current instanceof IssetExprToken){ processIsset(previous, current, iterator); tokens.add(current); } else if (current instanceof UnsetExprToken){ if (isOpenedBrace(previous, BraceExprToken.Kind.SIMPLE) && isClosedBrace(next, BraceExprToken.Kind.SIMPLE)){ current = new UnsetCastExprToken(current.getMeta()); tokens.set(tokens.size() - 1, current); iterator.next(); braceOpened--; } else { if (previous != null) unexpectedToken(current); processUnset(previous, current, iterator); tokens.add(current); needBreak = true; } } else if (current instanceof CommaToken){ if (separator == Separator.COMMA || separator == Separator.COMMA_OR_SEMICOLON){ if (tokens.isEmpty()) unexpectedToken(current); break; } else { unexpectedToken(current); } } else if (current instanceof AsStmtToken){ if (separator == Separator.AS) break; unexpectedToken(current); } else if (isClosedBrace(current, closedBraceKind)){ iterator.previous(); break; } else if (current instanceof BreakToken){ break; } else if (current instanceof ColonToken){ if (separator == Separator.COLON) { /*if (tokens.isEmpty()) see: issues/93 unexpectedToken(current);*/ break; } unexpectedToken(current); } else if (current instanceof SemicolonToken){ // TODO refactor! if (separator == Separator.SEMICOLON || separator == Separator.COMMA_OR_SEMICOLON) { /*if (tokens.isEmpty()) see: issues/94 unexpectedToken(current);*/ break; } if (separator == Separator.COMMA || closedBraceKind != null || tokens.isEmpty()) unexpectedToken(current); break; } else if (current instanceof BraceExprToken){ if (closedBraceKind == BraceExprToken.Kind.ANY && isClosedBrace(current)) { iterator.previous(); break; } unexpectedToken(current); } else if (current instanceof ArrayExprToken){ if (needBreak) unexpectedToken(current); tokens.add(current = processNewArray(current, iterator)); } else if (current instanceof ExprToken) { if (needBreak) unexpectedToken(current); CastExprToken cast = null; if (current instanceof NameToken && isOpenedBrace(previous, BraceExprToken.Kind.SIMPLE) && isClosedBrace(next, BraceExprToken.Kind.SIMPLE)){ cast = CastExprToken.valueOf(((NameToken)current).getName(), current.getMeta()); if (cast != null){ current = cast; iterator.next(); braceOpened--; tokens.set(tokens.size() - 1, current); } } if (cast == null){ Token token = processSimpleToken( current, previous, next, iterator, closedBraceKind, braceOpened, separator ); if (token != null) current = token; tokens.add(current); } } else unexpectedToken(current); previous = current; if (iterator.hasNext()){ current = nextToken(iterator); next = iterator.hasNext() ? iterator.next() : null; if (next != null) iterator.previous(); } else current = null; if (current == null) nextToken(iterator); } while (current != null); if (tokens.isEmpty()) return null; if (braceOpened != 0) unexpectedToken(iterator.previous()); ExprStmtToken exprStmtToken = new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), tokens); return exprStmtToken; } @Override public ExprStmtToken getToken(Token current, ListIterator<Token> iterator){ return getToken(current, iterator, false, null); } @Override public boolean isAutomatic() { return false; } }