package org.develnext.jphp.core.syntax.generators; import org.develnext.jphp.core.syntax.SyntaxAnalyzer; import org.develnext.jphp.core.syntax.generators.manually.SimpleExprGenerator; import org.develnext.jphp.core.tokenizer.TokenType; import org.develnext.jphp.core.tokenizer.token.CommentToken; import org.develnext.jphp.core.tokenizer.token.SemicolonToken; 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.CommaToken; import org.develnext.jphp.core.tokenizer.token.expr.operator.AssignExprToken; import org.develnext.jphp.core.tokenizer.token.expr.value.*; import org.develnext.jphp.core.tokenizer.token.stmt.*; import php.runtime.common.LangMode; import php.runtime.common.Messages; import php.runtime.common.Modifier; import org.develnext.jphp.core.common.Separator; import php.runtime.common.StringUtils; import php.runtime.env.Package; import php.runtime.exceptions.ParseException; import php.runtime.exceptions.support.ErrorType; import php.runtime.reflection.ClassEntity; import java.util.*; public class ClassGenerator extends Generator<ClassStmtToken> { @SuppressWarnings("unchecked") private final static Class<? extends Token>[] modifiers = new Class[]{ PrivateStmtToken.class, ProtectedStmtToken.class, PublicStmtToken.class, StaticExprToken.class, FinalStmtToken.class, AbstractStmtToken.class, VarStmtToken.class, ConstStmtToken.class }; public ClassGenerator(SyntaxAnalyzer analyzer) { super(analyzer); } protected void processName(ClassStmtToken result, ListIterator<Token> iterator){ Token name = nextTokenSensitive(iterator); if (name instanceof NameToken){ result.setName((NameToken)name); if (name instanceof ParentExprToken) unexpectedToken(name); } else unexpectedToken(name, TokenType.T_STRING); } protected void _processImplements(Token token, ClassStmtToken result, ListIterator<Token> iterator){ ImplementsStmtToken implement = new ImplementsStmtToken(token.getMeta()); Token prev = null; List<FulledNameToken> names = new ArrayList<FulledNameToken>(); do { token = nextToken(iterator); if (token instanceof NameToken){ names.add(analyzer.getRealName((NameToken)token)); } else if (token instanceof CommaToken){ if (!(prev instanceof NameToken)) unexpectedToken(token); } else if (isOpenedBrace(token, BraceExprToken.Kind.BLOCK)){ iterator.previous(); break; } else unexpectedToken(token); prev = token; } while (true); implement.setNames(names); result.setImplement(implement); } protected void processExtends(ClassStmtToken result, ListIterator<Token> iterator){ Token token = nextToken(iterator); if (token instanceof ExtendsStmtToken){ if (result.isTrait()) unexpectedToken(token); if (result.isInterface()){ _processImplements(token, result, iterator); } else { ExtendsStmtToken extend = (ExtendsStmtToken)token; FulledNameToken what = analyzer.generator(NameGenerator.class).getToken(nextToken(iterator), iterator); if (what == null) { unexpectedToken(extend); } extend.setName(analyzer.getRealName(what)); result.setExtend(extend); } } else iterator.previous(); } protected void processImplements(ClassStmtToken result, ListIterator<Token> iterator){ checkUnexpectedEnd(iterator); Token token = iterator.next(); if (token instanceof ImplementsStmtToken){ if (result.isTrait()) unexpectedToken(token); if (result.isInterface()) unexpectedToken(token, "extends"); _processImplements(token, result, iterator); /* ImplementsStmtToken implement = new ImplementsStmtToken(token.getMeta()); Token prev = null; List<FulledNameToken> names = new ArrayList<FulledNameToken>(); do { token = nextToken(iterator); if (token instanceof NameToken){ names.add(analyzer.getRealName((NameToken)token)); } else if (token instanceof CommaToken){ if (!(prev instanceof NameToken)) unexpectedToken(token); } else if (isOpenedBrace(token, BraceExprToken.Kind.BLOCK)){ iterator.previous(); break; } else unexpectedToken(token); prev = token; } while (true); implement.setNames(names); result.setImplement(implement);*/ } else iterator.previous(); } protected List<ClassVarStmtToken> processProperty(ClassStmtToken clazz, VariableExprToken current, List<Token> modifiers, ListIterator<Token> iterator){ Token next = current; Token prev = null; Set<VariableExprToken> variables = new LinkedHashSet<VariableExprToken>(); List<ExprStmtToken> initValues = new ArrayList<>(); ExprStmtToken initValue = null; List<ClassVarStmtToken> result = new ArrayList<ClassVarStmtToken>(); Modifier modifier = Modifier.PUBLIC; boolean isStatic = false; for(Token token : modifiers){ if (token instanceof PrivateStmtToken) modifier = Modifier.PRIVATE; else if (token instanceof ProtectedStmtToken) modifier = Modifier.PROTECTED; else if (token instanceof StaticExprToken) isStatic = true; } do { if (next instanceof VariableExprToken){ if (!variables.add((VariableExprToken)next)) { throw new ParseException( Messages.ERR_IDENTIFIER_X_ALREADY_USED.fetch(next.getWord()), next.toTraceInfo(analyzer.getContext()) ); } initValues.add(null); } else if (next instanceof CommaToken){ if (!(prev instanceof VariableExprToken)) unexpectedToken(next); } else if (next instanceof AssignExprToken){ if (!(prev instanceof VariableExprToken)) unexpectedToken(next); initValue = analyzer.generator(SimpleExprGenerator.class) .getToken(nextToken(iterator), iterator, Separator.COMMA_OR_SEMICOLON, null); initValues.set(initValues.size() - 1, initValue); if (iterator.hasPrevious() && isBreak(iterator.previous())) { iterator.next(); break; } if (iterator.hasNext()) { iterator.next(); } //break; } else if (next instanceof SemicolonToken){ if (!(prev instanceof VariableExprToken)) unexpectedToken(next); break; } prev = next; next = nextToken(iterator); } while (true); int i = 0; for(VariableExprToken variable : variables){ ClassVarStmtToken classVar = new ClassVarStmtToken(variable.getMeta()); classVar.setModifier(modifier); classVar.setStatic(isStatic); classVar.setValue(initValues.get(i)); classVar.setVariable(variable); classVar.setClazz(clazz); result.add(classVar); i++; } return result; } protected void processUse(ClassStmtToken result, ListIterator<Token> iterator) { if (result.isInterface()) unexpectedToken(iterator.previous()); Token prev = null; List<NameToken> uses = new ArrayList<NameToken>(); do { Token token = nextToken(iterator); if (token instanceof NameToken){ uses.add(analyzer.getRealName((NameToken)token)); } else if (token instanceof CommaToken){ if (!(prev instanceof NameToken)) unexpectedToken(token); } else if (token instanceof SemicolonToken) { break; } else if (isOpenedBrace(token, BraceExprToken.Kind.BLOCK)){ processBlock(result, uses.get(0), iterator); break; } else unexpectedToken(token); prev = token; } while (true); result.getUses().addAll(uses); } protected void processBlock(ClassStmtToken result, NameToken firstTraitName, ListIterator<Token> iterator) { if (result.isInterface()) unexpectedToken(iterator.previous()); while (true) { NameToken className = nextAndExpectedSensitive(iterator, NameToken.class); NameToken methodName; Token token = nextToken(iterator); if (token instanceof StaticAccessExprToken) { className = analyzer.getRealName(className); Token nextTokenSensitive = nextTokenSensitive(iterator); if (nextTokenSensitive instanceof NameToken) { methodName = (NameToken) nextTokenSensitive; } else { unexpectedToken(nextTokenSensitive); return; } } else { iterator.previous(); methodName = className; if (className.getClass() != NameToken.class) unexpectedToken(className); className = firstTraitName; } Token what = nextToken(iterator); if (what instanceof AsStmtToken) { Token one = nextTokenSensitive(iterator, PrivateStmtToken.class, ProtectedStmtToken.class, PublicStmtToken.class, FinalStmtToken.class, StaticExprToken.class); if (one instanceof NameToken) { result.addAlias( className.getName(), methodName.getName(), null, ((NameToken) one).getName() ); } else if (isTokenClass(one, PrivateStmtToken.class, ProtectedStmtToken.class, PublicStmtToken.class)) { Modifier modifier = Modifier.PRIVATE; if (one instanceof ProtectedStmtToken) modifier = Modifier.PROTECTED; else if (one instanceof PublicStmtToken) modifier = Modifier.PUBLIC; token = nextTokenSensitive(iterator); String name = null; if (token instanceof NameToken) { NameToken two = (NameToken)token; if (two.getClass() != NameToken.class) unexpectedToken(two); name = two.getName(); } else if (token instanceof SemicolonToken) { iterator.previous(); // nop } else unexpectedToken(token); result.addAlias(className.getName(), methodName.getName(), modifier, name); } else unexpectedToken(one); nextAndExpected(iterator, SemicolonToken.class); } else if (what instanceof InsteadofStmtToken) { Set<String> names = new HashSet<String>(); Set<String> namesLower = new HashSet<String>(); NameToken cls; while (true) { cls = nextAndExpected(iterator, NameToken.class); cls = analyzer.getRealName(cls); if (!namesLower.add(cls.getName().toLowerCase())) { analyzer.getEnvironment().error( iterator.previous().toTraceInfo(analyzer.getContext()), ErrorType.E_ERROR, Messages.ERR_TRAIT_MULTIPLE_RULE, methodName.getName(), cls.getName() ); } names.add(cls.getName()); Token next = nextToken(iterator); if (next instanceof CommaToken) continue; if (next instanceof SemicolonToken) break; } if (!result.addReplacement(className.getName(), methodName.getName(), names)){ analyzer.getEnvironment().error( iterator.previous().toTraceInfo(analyzer.getContext()), ErrorType.E_ERROR, Messages.ERR_TRAIT_MULTIPLE_RULE, methodName.getName(), cls.getName() ); } } else unexpectedToken(what); if (isClosedBrace(nextTokenAndPrev(iterator), BraceExprToken.Kind.BLOCK)) { iterator.next(); break; } } } @SuppressWarnings("unchecked") protected void processBody(ClassStmtToken result, ListIterator<Token> iterator){ analyzer.setClazz(result); Token token = nextToken(iterator); if (token instanceof BraceExprToken){ BraceExprToken brace = (BraceExprToken)token; if (brace.isBlockOpened()){ List<ConstStmtToken> constants = new ArrayList<ConstStmtToken>(); List<MethodStmtToken> methods = new ArrayList<MethodStmtToken>(); List<ClassVarStmtToken> properties = new ArrayList<ClassVarStmtToken>(); List<Token> modifiers = new ArrayList<Token>(); CommentToken lastComment = null; boolean breakByClose = false; while (iterator.hasNext()){ Token current = iterator.next(); if (current instanceof ExprStmtToken) unexpectedToken(current, "expression"); if (current instanceof ConstStmtToken){ if (!modifiers.isEmpty()) unexpectedToken(modifiers.get(0)); if (result.isTrait()) unexpectedToken(current); ConstStmtToken one = analyzer.generator(ConstGenerator.class).getToken(current, iterator); one.setClazz(result); one.setDocComment(lastComment); lastComment = null; constants.add(one); modifiers.clear(); } else if (isTokenClass(current, ClassGenerator.modifiers)){ for(Token modifier : modifiers){ if (modifier.getType() == current.getType()) unexpectedToken(current); } modifiers.add(current); } else if (current instanceof VariableExprToken) { if (result.isInterface()) { analyzer.getEnvironment().error( result.toTraceInfo(analyzer.getContext()), ErrorType.E_ERROR, Messages.ERR_INTERFACE_MAY_NOT_INCLUDE_VARS ); } for(Token modifier : modifiers){ if (isTokenClass(modifier, FinalStmtToken.class, AbstractStmtToken.class)) { unexpectedToken(modifier); } } List<ClassVarStmtToken> vars = processProperty( result, (VariableExprToken)current, modifiers, iterator ); if (lastComment != null) { for (ClassVarStmtToken var : vars) { var.setDocComment(lastComment); } lastComment = null; } properties.addAll(vars); modifiers.clear(); } else if (current instanceof FunctionStmtToken) { FunctionStmtToken function = analyzer.generator(FunctionGenerator.class).getToken(current, iterator); if (function == null) { nextToken(iterator); unexpectedToken(iterator); } MethodStmtToken method = new MethodStmtToken(function); method.setClazz(result); method.setDocComment(lastComment); lastComment = null; for (Token modifier : modifiers) { if (modifier instanceof AbstractStmtToken) method.setAbstract(true); else if (modifier instanceof StaticExprToken) method.setStatic(true); else if (modifier instanceof FinalStmtToken) { method.setFinal(true); } else if (modifier instanceof PublicStmtToken) { if (method.getModifier() != null) unexpectedToken(modifier); method.setModifier(Modifier.PUBLIC); } else if (modifier instanceof PrivateStmtToken) { if (method.getModifier() != null) unexpectedToken(modifier); method.setModifier(Modifier.PRIVATE); } else if (modifier instanceof ProtectedStmtToken) { if (method.getModifier() != null) unexpectedToken(modifier); method.setModifier(Modifier.PROTECTED); } } if (method.getModifier() == null) method.setModifier(Modifier.PUBLIC); methods.add(method); modifiers.clear(); } else if (current instanceof NamespaceUseStmtToken) { processUse(result, iterator); lastComment = null; } else if (isClosedBrace(current, BraceExprToken.Kind.BLOCK)) { breakByClose = true; break; } else if (current instanceof CommentToken){ lastComment = (CommentToken) current; } else unexpectedToken(current); } if (!breakByClose) { // bug-fix from DN. token = nextTokenAndPrev(iterator); if (!isClosedBrace(token, BraceExprToken.Kind.BLOCK)) { unexpectedToken(token); } } // --- result.setConstants(constants); result.setMethods(methods); result.setProperties(properties); analyzer.setClazz(null); return; } } unexpectedToken(token, "{"); } @SuppressWarnings("unchecked") protected ClassStmtToken processDefine(Token current, ListIterator<Token> iterator){ ClassStmtToken result = null; if (isTokenClass(current, FinalStmtToken.class, AbstractStmtToken.class)){ Token next = nextToken(iterator); if (next instanceof ClassStmtToken){ result = (ClassStmtToken)next; result.setInterface(false); result.setAbstract(current instanceof AbstractStmtToken); result.setFinal(current instanceof FinalStmtToken); //return result; } else if (next instanceof InterfaceStmtToken || next instanceof TraitStmtToken) { unexpectedToken(current); } else if (next instanceof AbstractStmtToken || next instanceof FinalStmtToken){ unexpectedToken(next); } else { iterator.previous(); } } if (current instanceof ClassStmtToken) result = (ClassStmtToken)current; else if (current instanceof InterfaceStmtToken){ result = new ClassStmtToken(current.getMeta()); result.setInterface(true); } else if (current instanceof TraitStmtToken) { result = new ClassStmtToken(current.getMeta()); result.setClassType(ClassEntity.Type.TRAIT); } if (result != null) { iterator.previous(); if (result.isFinal() || result.isAbstract()) iterator.previous(); if (iterator.hasPrevious()) { Token tk = iterator.previous(); if (tk instanceof CommentToken) { result.setDocComment((CommentToken)tk); } iterator.next(); } if (result.isFinal() || result.isAbstract()) iterator.next(); iterator.next(); } return result; } @Override public ClassStmtToken getToken(Token current, ListIterator<Token> iterator) { ClassStmtToken result = processDefine(current, iterator); if (result != null) { if (analyzer.getClazz() != null) unexpectedToken(current); analyzer.setClazz(result); result.setNamespace(analyzer.getNamespace()); processName(result, iterator); processExtends(result, iterator); processImplements(result, iterator); processBody(result, iterator); analyzer.setClazz(null); } return result; } }