package org.develnext.jphp.core.syntax.generators;
import org.develnext.jphp.core.compiler.common.ASMExpression;
import org.develnext.jphp.core.tokenizer.token.expr.*;
import php.runtime.common.Messages;
import org.develnext.jphp.core.common.Separator;
import php.runtime.exceptions.FatalException;
import org.develnext.jphp.core.syntax.SyntaxAnalyzer;
import org.develnext.jphp.core.syntax.generators.manually.BodyGenerator;
import org.develnext.jphp.core.syntax.generators.manually.SimpleExprGenerator;
import org.develnext.jphp.core.tokenizer.token.*;
import org.develnext.jphp.core.tokenizer.token.expr.operator.*;
import org.develnext.jphp.core.tokenizer.token.expr.value.*;
import org.develnext.jphp.core.tokenizer.token.stmt.*;
import php.runtime.exceptions.support.ErrorType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
public class ExprGenerator extends Generator<ExprStmtToken> {
public ExprGenerator(SyntaxAnalyzer analyzer) {
super(analyzer);
}
public ExprStmtToken getInBraces(BraceExprToken.Kind kind, ListIterator<Token> iterator){
Token next = nextToken(iterator);
if (!isOpenedBrace(next, kind))
unexpectedToken(next, BraceExprToken.Kind.toOpen(kind));
ExprStmtToken result = analyzer.generator(SimpleExprGenerator.class)
.getToken(nextToken(iterator), iterator, false, kind);
if (!isClosedBrace(nextToken(iterator), kind))
unexpectedToken(next, BraceExprToken.Kind.toClose(kind));
return result;
}
protected void processCase(CaseStmtToken result, ListIterator<Token> iterator){
analyzer.addScope();
if (!(result instanceof DefaultStmtToken)){
Token next = nextToken(iterator);
ExprStmtToken conditional = analyzer.generator(SimpleExprGenerator.class).getToken(
next, iterator, Separator.COLON, null
);
if (conditional == null)
unexpectedToken(next);
result.setConditional(conditional);
} else {
Token next = nextToken(iterator);
if (!(isBreak(next) || next instanceof ColonToken))
unexpectedToken(next);
}
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, true,
EndswitchStmtToken.class, CaseStmtToken.class, DefaultStmtToken.class, BraceExprToken.class
);
result.setBody(body);
result.setLocals(analyzer.removeScope().getVariables());
}
protected void processSwitch(SwitchStmtToken result, ListIterator<Token> iterator){
analyzer.addScope(false).setLevelForGoto(true);
result.setValue(getInBraces(BraceExprToken.Kind.SIMPLE, iterator));
if (result.getValue() == null)
unexpectedToken(iterator);
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, false, false, EndswitchStmtToken.class
);
List<CaseStmtToken> cases = new ArrayList<CaseStmtToken>();
for(ExprStmtToken instruction : body.getInstructions()){
if (instruction.isSingle()){
Token token = instruction.getSingle();
if (token instanceof CaseStmtToken){
cases.add((CaseStmtToken)token);
if (token instanceof DefaultStmtToken){
if (result.getDefaultCase() != null)
unexpectedToken(token);
result.setDefaultCase((DefaultStmtToken)token);
}
} else
unexpectedToken(token);
} else
unexpectedToken(instruction.getSingle());
}
if (body.isAlternativeSyntax())
iterator.next();
result.setCases(cases);
result.setLocal(analyzer.removeScope().getVariables());
}
protected void processIf(IfStmtToken result, ListIterator<Token> iterator){
analyzer.addScope(false);
ExprStmtToken condition = getInBraces(BraceExprToken.Kind.SIMPLE, iterator);
if (condition == null)
unexpectedToken(iterator);
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, EndifStmtToken.class, ElseIfStmtToken.class
);
if (iterator.hasNext()){
Token next = nextToken(iterator);
if (next instanceof ElseStmtToken){
BodyStmtToken bodyElse = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, false, false, EndifStmtToken.class
);
if (!bodyElse.getInstructions().isEmpty())
result.setElseBody(bodyElse);
if (bodyElse.isAlternativeSyntax())
iterator.next();
} else if (next instanceof ElseIfStmtToken){
next = new IfStmtToken(next.getMeta());
BodyStmtToken bodyElse = analyzer.generator(BodyGenerator.class).getToken(
next, iterator, EndifStmtToken.class
);
result.setElseBody(bodyElse);
} else if (next instanceof EndifStmtToken){
// nop
} else
iterator.previous();
}
result.setCondition(condition);
result.setBody(body);
result.setLocal(analyzer.removeScope().getVariables());
}
protected void processForeach(ForeachStmtToken result, ListIterator<Token> iterator){
analyzer.addScope(false).setLevelForGoto(true);
Token next = nextToken(iterator);
if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE))
unexpectedToken(next, "(");
ExprStmtToken expr = analyzer.generator(SimpleExprGenerator.class).getToken(nextToken(iterator), iterator, Separator.AS, null);
if (expr == null) {
unexpectedToken(iterator.previous());
}
result.setIterator(expr);
next = nextToken(iterator);
boolean reference = false;
if (next instanceof AmpersandRefToken){
reference = true;
next = nextToken(iterator);
}
if (next instanceof ListExprToken) {
ListExprToken listExpr = analyzer.generator(SimpleExprGenerator.class).processSingleList(next, iterator);
result.setValue(new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), listExpr));
} else if (next instanceof VariableExprToken && nextTokenAndPrev(iterator) instanceof KeyValueExprToken){
iterator.next();
result.setKey((VariableExprToken)next);
result.setKeyReference(reference);
next = nextToken(iterator);
reference = false;
if (next instanceof AmpersandRefToken){
reference = true;
next = nextToken(iterator);
}
if (next instanceof ListExprToken) {
ListExprToken listExpr = analyzer.generator(SimpleExprGenerator.class)
.processSingleList(next, iterator);
result.setValue(new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), listExpr));
} else {
ExprStmtToken eValue = analyzer.generator(SimpleExprGenerator.class)
.getToken(next, iterator, null, BraceExprToken.Kind.SIMPLE);
if (eValue == null) {
unexpectedToken(next);
return;
}
Token single = eValue.getLast();
if (!(single instanceof VariableExprToken
|| single instanceof ArrayGetExprToken
|| single instanceof DynamicAccessExprToken
|| (single instanceof StaticAccessExprToken && ((StaticAccessExprToken) single).isGetStaticField()))) {
unexpectedToken(single);
}
result.setValue(eValue);
result.setValueReference(reference);
}
} else {
//next = iterator.previous();
ExprStmtToken eValue = analyzer.generator(SimpleExprGenerator.class)
.getToken(next, iterator, null, BraceExprToken.Kind.SIMPLE);
if (eValue == null) {
unexpectedToken(next);
return;
}
Token single = eValue.getLast();
if (!(single instanceof VariableExprToken
|| single instanceof ArrayGetExprToken
|| single instanceof DynamicAccessExprToken
|| (single instanceof StaticAccessExprToken && ((StaticAccessExprToken) single).isGetStaticField())))
unexpectedToken(single);
result.setValue(eValue);
result.setValueReference(reference);
}
//unexpectedToken(next, "$var");
if (result.getValue().isSingle() && result.getValue().getSingle() instanceof ListExprToken) {
ListExprToken listExprToken = (ListExprToken)result.getValue().getSingle();
if (listExprToken.getVariables().isEmpty()) {
analyzer.getEnvironment().error(
listExprToken.toTraceInfo(analyzer.getContext()), ErrorType.E_ERROR,
Messages.ERR_CANNOT_USE_EMPTY_LIST
);
}
}
next = nextToken(iterator);
if (!isClosedBrace(next, BraceExprToken.Kind.SIMPLE))
unexpectedToken(next, ")");
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, EndforeachStmtToken.class
);
if (body != null && body.isAlternativeSyntax())
iterator.next();
result.setBody(body);
Token last = result.getValue().getLast();
if (analyzer.getFunction() != null) {
if (result.getKey() != null){
analyzer.getFunction().variable(result.getKey())
.setReference(true)
.setUnstable(true);
}
if (last instanceof VariableExprToken){
VariableExprToken variable = (VariableExprToken)last;
analyzer.getFunction().variable(variable)
.setReference(true)
.setUnstable(true);
}
}
if (last instanceof ArrayGetExprToken){
result.getValue().getTokens().set(
result.getValue().getTokens().size() - 1, new ArrayGetRefExprToken((ArrayGetExprToken)last)
);
result.getValue().updateAsmExpr(analyzer.getEnvironment(), analyzer.getContext());
}
if (result.getKey() != null)
analyzer.getScope().addVariable(result.getKey());
result.setLocal(analyzer.removeScope().getVariables());
}
protected void processFor(ForStmtToken result, ListIterator<Token> iterator){
analyzer.addScope();
Token next = nextToken(iterator);
if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE))
unexpectedToken(next, "(");
ExprStmtToken init;
List<ExprStmtToken> inits = new ArrayList<ExprStmtToken>();
do {
init = analyzer.generator(SimpleExprGenerator.class)
.getToken(nextToken(iterator), iterator, Separator.COMMA_OR_SEMICOLON, null);
if (init == null)
break;
inits.add(init);
if (iterator.previous() instanceof SemicolonToken) {
iterator.next();
break;
}
iterator.next();
} while (true);
result.setInitLocal(analyzer.removeScope().getVariables());
analyzer.addScope().setLevelForGoto(true);
// CONDITIONS
List<ExprStmtToken> conditions = new ArrayList<ExprStmtToken>();
do {
ExprStmtToken conditionExpr = analyzer.generator(SimpleExprGenerator.class)
.getToken(nextToken(iterator), iterator, Separator.COMMA_OR_SEMICOLON, null);
if (conditionExpr == null)
break;
conditions.add(conditionExpr);
if (iterator.previous() instanceof SemicolonToken) {
iterator.next();
break;
}
iterator.next();
} while (true);
// ITERATIONS
List<ExprStmtToken> iterations = new ArrayList<ExprStmtToken>();
do {
ExprStmtToken iteratorExpr = analyzer.generator(SimpleExprGenerator.class)
.getToken(nextToken(iterator), iterator, Separator.COMMA, BraceExprToken.Kind.SIMPLE);
if (iteratorExpr == null)
break;
iterations.add(iteratorExpr);
if (isClosedBrace(iterator.previous(), BraceExprToken.Kind.SIMPLE)) {
iterator.next();
break;
}
iterator.next();
} while (true);
result.setIterationLocal(new HashSet<VariableExprToken>(analyzer.getScope().getVariables()));
nextAndExpected(iterator, BraceExprToken.class);
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, EndforStmtToken.class
);
if (body != null && body.isAlternativeSyntax())
iterator.next();
result.setInitExpr(inits);
result.setConditionExpr(conditions);
result.setIterationExpr(iterations);
result.setBody(body);
result.setLocal(analyzer.removeScope().getVariables());
}
protected void processWhile(WhileStmtToken result, ListIterator<Token> iterator){
analyzer.addScope().setLevelForGoto(true);
ExprStmtToken condition = getInBraces(BraceExprToken.Kind.SIMPLE, iterator);
if (condition == null)
unexpectedToken(iterator);
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
nextToken(iterator), iterator, EndwhileStmtToken.class
);
if (body != null && body.isAlternativeSyntax())
iterator.next();
result.setCondition(condition);
result.setBody(body);
result.setLocal(analyzer.removeScope().getVariables());
}
protected void processReturn(ReturnStmtToken result, ListIterator<Token> iterator){
Token next = nextToken(iterator);
if (next instanceof SemicolonToken)
result.setValue(null);
else {
ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class)
.getToken(next, iterator);
result.setValue(value);
}
}
protected void processDo(DoStmtToken result, ListIterator<Token> iterator){
analyzer.addScope().setLevelForGoto(true);
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(nextToken(iterator), iterator);
result.setBody(body);
Token next = nextToken(iterator);
if (next instanceof WhileStmtToken){
result.setCondition(getInBraces(BraceExprToken.Kind.SIMPLE, iterator));
if (result.getCondition() == null)
unexpectedToken(iterator);
next = nextToken(iterator);
result.setLocal(analyzer.removeScope().getVariables());
if (next instanceof SemicolonToken)
return;
}
unexpectedToken(next);
}
protected void processGlobal(GlobalStmtToken result, ListIterator<Token> iterator){
List<ValueExprToken> variables = new ArrayList<ValueExprToken>();
Token next = nextToken(iterator);
Token prev = null;
do {
if (next instanceof VariableExprToken) {
VariableExprToken variable = (VariableExprToken)next;
analyzer.getScope().addVariable(variable);
if (analyzer.getFunction() != null) {
analyzer.getFunction().variable(variable)
.setReference(true)
.setUnstable(true);
}
variables.add(variable);
} else if (next instanceof DollarExprToken) {
GetVarExprToken var = analyzer.generator(SimpleExprGenerator.class)
.processVarVar(next, nextTokenAndPrev(iterator), iterator);
variables.add(var);
next = var;
} else if (next instanceof CommaToken){
if (!(prev instanceof VariableValueExprToken))
unexpectedToken(next);
} else if (next instanceof SemicolonToken){
if (!(prev instanceof VariableValueExprToken))
unexpectedToken(next);
break;
} else
unexpectedToken(next);
prev = next;
next = nextToken(iterator);
} while (true);
result.setVariables(variables);
}
protected List<StaticStmtToken> processStatic(StaticExprToken token, ListIterator<Token> iterator){
Token next = nextToken(iterator);
if (!(next instanceof VariableExprToken)){
iterator.previous();
return null;
}
List<StaticStmtToken> list = new ArrayList<StaticStmtToken>();
while (next instanceof VariableExprToken){
VariableExprToken variable = (VariableExprToken)next;
analyzer.getScope().addVariable(variable);
if (analyzer.getFunction() != null){
analyzer.getFunction().variable(variable)
.setReference(true)
.setUnstable(true);
analyzer.getFunction().getStaticLocal().add(variable);
}
StaticStmtToken result = new StaticStmtToken(variable.getMeta());
result.setVariable((VariableExprToken)next);
next = nextToken(iterator);
if (next instanceof AssignExprToken){
ExprStmtToken initValue = analyzer.generator(SimpleExprGenerator.class).getNextExpression(
nextToken(iterator), iterator, Separator.COMMA_OR_SEMICOLON, null
);
if (nextTokenAndPrev(iterator) instanceof CommaToken)
iterator.next();
result.setInitValue(initValue);
list.add(result);
} else if (isBreak(next)){
result.setInitValue(null);
list.add(result);
break;
} else if (next instanceof CommaToken) {
result.setInitValue(null);
list.add(result);
} else
unexpectedToken(next);
next = nextToken(iterator);
}
//unexpectedToken(next); TODO: check it!
return list;
}
protected void processGoto(GotoStmtToken result, ListIterator<Token> iterator) {
NameToken token = nextAndExpected(iterator, NameToken.class);
if (token.getClass() != NameToken.class)
unexpectedToken(token);
nextAndExpected(iterator, SemicolonToken.class);
result.setLevel(analyzer.getScope().getGotoLevel());
result.setLabel(token);
}
protected void processJump(JumpStmtToken result, ListIterator<Token> iterator){
Token next = nextToken(iterator);
long level = 1;
if (next instanceof IntegerExprToken){
level = ((IntegerExprToken) next).getValue();
if (level < 1)
throw new FatalException(
Messages.ERR_OPERATOR_ACCEPTS_ONLY_POSITIVE.fetch(result.getWord()),
result.toTraceInfo(analyzer.getContext())
);
next = nextToken(iterator);
}
result.setLevel((int)level);
if (!(next instanceof SemicolonToken))
unexpectedToken(next);
}
protected void processImport(RequireStmtToken result, ListIterator<Token> iterator){
ExprStmtToken value = analyzer.generator(SimpleExprGenerator.class)
.getToken(nextToken(iterator), iterator, Separator.SEMICOLON, null);
result.setValue(value);
if (value == null)
unexpectedToken(iterator);
if (analyzer.getFunction() != null){
analyzer.getFunction().setDynamicLocal(true);
analyzer.getFunction().setCallsExist(true);
}
}
public void processEcho(EchoStmtToken result, ListIterator<Token> iterator){
List<ExprStmtToken> arguments = new ArrayList<ExprStmtToken>();
ExprStmtToken argument;
do {
argument = analyzer.generator(SimpleExprGenerator.class).getToken(
nextToken(iterator), iterator, Separator.COMMA_OR_SEMICOLON, null
);
if (argument != null)
arguments.add(argument);
Token prev = iterator.previous();
if (isBreak(prev)){
iterator.next();
break;
}
iterator.next();
} while (argument != null);
result.setArguments(arguments);
}
protected List<Token> processSimpleExpr(Token current, ListIterator<Token> iterator){
ExprStmtToken token = analyzer.generator(SimpleExprGenerator.class)
.getToken(current, iterator, Separator.SEMICOLON, null);
return token.getTokens();
}
@SuppressWarnings("unchecked")
public ExprStmtToken getToken(Token current, ListIterator<Token> iterator,
Class<? extends Token>... endTokens) {
List<Token> tokens = new ArrayList<Token>();
do {
if (current instanceof EndStmtToken || isTokenClass(current, endTokens)){
boolean doBreak = true;
if (!isTokenClass(current, endTokens))
unexpectedToken(current);
if (current instanceof BraceExprToken){
if (((BraceExprToken) current).isOpened()){
doBreak = false;
} else if (!isClosedBrace(current, BraceExprToken.Kind.BLOCK))
unexpectedToken(current);
}
if (doBreak)
break;
}
if (current instanceof EchoRawToken){
tokens.add(current);
break;
} else if (current instanceof OpenEchoTagToken){
OpenEchoTagToken result = (OpenEchoTagToken)current;
result.setValue(
analyzer.generator(SimpleExprGenerator.class).getToken(nextToken(iterator), iterator)
);
tokens.add(current);
break;
} else if (isOpenedBrace(current, BraceExprToken.Kind.BLOCK)){
BodyStmtToken body = analyzer.generator(BodyGenerator.class).getToken(
current, iterator, EndforStmtToken.class
);
tokens.add(body);
break;
} else if (current instanceof RequireStmtToken){
processImport((RequireStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof EchoStmtToken){
processEcho((EchoStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof IfStmtToken){
processIf((IfStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof ReturnStmtToken){
processReturn((ReturnStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof ForStmtToken){
processFor((ForStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof ForeachStmtToken){
processForeach((ForeachStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof WhileStmtToken){
processWhile((WhileStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof DoStmtToken){
processDo((DoStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof CaseStmtToken){
processCase((CaseStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof SwitchStmtToken){
processSwitch((SwitchStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof ThrowStmtToken){
tokens.add(analyzer.generator(ThrowGenerator.class).getToken(current, iterator));
break;
} else if (current instanceof TryStmtToken){
tokens.add(analyzer.generator(TryCatchGenerator.class).getToken(current, iterator));
break;
} else if (current instanceof GlobalStmtToken){
processGlobal((GlobalStmtToken) current, iterator);
tokens.add(current);
break;
} else if (current instanceof JumpStmtToken){
processJump((JumpStmtToken)current, iterator);
tokens.add(current);
break;
} else if (current instanceof BreakToken){
tokens.add(current);
break;
} else if (current instanceof GotoStmtToken){
processGoto((GotoStmtToken)current, iterator);
tokens.add(current);
break;
} else if (current instanceof SemicolonToken){
tokens.add(current);
break;
} else if (current instanceof FunctionStmtToken){
FunctionStmtToken token = analyzer.generator(FunctionGenerator.class)
.getToken(current, iterator, true);
token.setStatic(false);
if (token.getName() == null){
ClosureStmtToken closure = new ClosureStmtToken(token.getMeta());
closure.setFunction(token);
closure.setOwnerClass(analyzer.getClazz());
tokens.add(closure);
analyzer.registerClosure(closure);
List<Token> tmp = processSimpleExpr(current, iterator);
tokens.addAll(tmp);
} else {
tokens.add(token);
analyzer.registerFunction(token);
}
break;
} else if (current instanceof ExprToken /*|| current instanceof FunctionStmtToken*/){
if (current instanceof StaticExprToken){
List<StaticStmtToken> result = processStatic((StaticExprToken) current, iterator);
if (result != null){
tokens.addAll(result);
break;
}
}
// check label
if (current.getClass() == NameToken.class
&& iterator.hasNext() && nextTokenAndPrev(iterator) instanceof ColonToken) {
LabelStmtToken labelStmtToken = new LabelStmtToken(current.getMeta());
tokens.add(labelStmtToken);
iterator.next();
analyzer.getScope().addLabel(labelStmtToken);
break;
}
if (isClosedBrace(current, BraceExprToken.Kind.BLOCK)){
if (endTokens != null && !isTokenClass(current, endTokens))
unexpectedToken(current);
break;
}
List<Token> tmp = processSimpleExpr(current, iterator);
tokens.addAll(tmp);
break;
} else if (current instanceof ClassStmtToken){
unexpectedToken(current);
} else if (current instanceof CommentToken) {
tokens.add(current);
break;
// nop
} else {
if (!tokens.isEmpty())
unexpectedToken(current);
break;
}
/* if (iterator.hasNext())
current = nextToken(iterator);
else
current = null; */
} while (current != null);
if (tokens.isEmpty())
return null;
ExprStmtToken stmtToken = new ExprStmtToken(analyzer.getEnvironment(), analyzer.getContext(), tokens);
return stmtToken;
}
@Override
@SuppressWarnings("unchecked")
public ExprStmtToken getToken(Token current, ListIterator<Token> iterator) {
return getToken(current, iterator, (Class[])null);
}
}