protected void processUses(FunctionStmtToken result, ListIterator<Token> iterator) { Token next = nextToken(iterator); if (next instanceof NamespaceUseStmtToken) { next = nextToken(iterator); if (!isOpenedBrace(next, BraceExprToken.Kind.SIMPLE)) unexpectedToken(next, "("); List<ArgumentStmtToken> arguments = new ArrayList<ArgumentStmtToken>(); while (iterator.hasNext()) { ArgumentStmtToken argument = processArgument(iterator); if (argument == null) break; if (argument.getValue() != null) unexpectedToken(argument.getValue().getSingle()); arguments.add(argument); FunctionStmtToken parent = analyzer.getFunction(true); if (parent != null) { parent.variable(argument.getName()).setUsed(true); if (argument.isReference()) { parent.variable(argument.getName()).setPassed(true).setUnstable(true); } parent = analyzer.peekClosure(); if (parent != null) { parent.variable(argument.getName()).setUnstable(true); } } } result.setUses(arguments); } else { result.setUses(new ArrayList<ArgumentStmtToken>()); iterator.previous(); } }
@SuppressWarnings("unchecked") protected ArgumentStmtToken processArgument(ListIterator<Token> iterator) { boolean isReference = false; boolean isVariadic = false; VariableExprToken variable = null; ExprStmtToken value = null; Token next = nextToken(iterator); if (next instanceof CommaToken || isClosedBrace(next, BraceExprToken.Kind.SIMPLE)) return null; NameToken hintTypeClass = null; HintType hintType = null; if (next instanceof NameToken) { String word = ((NameToken) next).getName().toLowerCase(); if (scalarTypeHints.contains(word)) hintType = HintType.of(word); else { hintType = jphp_scalarTypeHints.contains(word) ? null : HintType.of(word); if (hintType == null) hintTypeClass = analyzer.getRealName((NameToken) next); } next = nextToken(iterator); } if (next instanceof AmpersandRefToken) { isReference = true; next = nextToken(iterator); } if (next instanceof ArgumentUnpackExprToken) { isVariadic = true; next = nextToken(iterator); } if (next instanceof VariableExprToken) { variable = (VariableExprToken) next; } else unexpectedToken(next); next = nextToken(iterator); if (next instanceof AssignExprToken) { if (isVariadic) { unexpectedToken(next); } value = analyzer .generator(SimpleExprGenerator.class) .getToken(nextToken(iterator), iterator, true, BraceExprToken.Kind.SIMPLE); } else { if (next instanceof CommaToken || isClosedBrace(next, BraceExprToken.Kind.SIMPLE)) { if (next instanceof BraceExprToken) { iterator.previous(); } else { if (isVariadic) { unexpectedToken(next); } } } else unexpectedToken(next); } ArgumentStmtToken argument = new ArgumentStmtToken(variable.getMeta()); argument.setName(variable); argument.setHintType(hintType); argument.setHintTypeClass(hintTypeClass); argument.setReference(isReference); argument.setVariadic(isVariadic); argument.setValue(value); if (argument.isReference() && argument.getValue() != null) analyzer.getFunction().variable(argument.getName()).setUsed(true); return argument; }
@SuppressWarnings("unchecked") public FunctionStmtToken getToken( Token current, ListIterator<Token> iterator, boolean closureAllowed) { if (current instanceof FunctionStmtToken) { FunctionStmtToken result = (FunctionStmtToken) current; result.setStatic(analyzer.getFunction() == null); Class<? extends Token>[] excludes = new Class[] {EchoStmtToken.class, ImportExprToken.class}; if (analyzer.getClazz() != null) { excludes = new Class[0]; } Token next = nextTokenSensitive(iterator, excludes); if (next instanceof AmpersandRefToken) { result.setReturnReference(true); next = nextTokenSensitive(iterator, excludes); } if (next instanceof NameToken) { /*if (analyzer.getFunction() != null) unexpectedToken(current);*/ analyzer.addScope(true); FunctionStmtToken oldFunction = analyzer.getFunction(); analyzer.setFunction(result); BraceExprToken brace = nextAndExpected(iterator, BraceExprToken.class); if (!brace.isSimpleOpened()) unexpectedToken(brace, "("); result.setNamespace(analyzer.getNamespace()); result.setName((NameToken) next); processArguments(result, iterator); processBody(result, iterator); result.setLabels(analyzer.getScope().getLabels()); result.setLocal(analyzer.removeScope().getVariables()); analyzer.setFunction(oldFunction); return result; } else if (next instanceof BraceExprToken) { // xClosure if (((BraceExprToken) next).isSimpleOpened()) { if (closureAllowed) { analyzer.pushClosure(result); analyzer.addScope(true); processArguments(result, iterator); processUses(result, iterator); processBody(result, iterator); // boolean thisExists = result.isThisExists(); result.setLabels(analyzer.getScope().getLabels()); result.setStaticExists(analyzer.getScope().isStaticExists()); result.setLocal(analyzer.removeScope().getVariables()); // result.setThisExists(thisExists); analyzer.popClosure(); FunctionStmtToken prevClosure = analyzer.peekClosure(); if (prevClosure != null) { if (result.isThisExists()) { analyzer.getScope().addVariable(FunctionStmtToken.thisVariable); // prevClosure.variable(FunctionStmtToken.thisVariable).setUsed(true); // prevClosure.setThisExists(true); } } List<VariableExprToken> uses = new ArrayList<VariableExprToken>(); for (ArgumentStmtToken argument : result.getUses()) { if (argument.isReference()) { if (analyzer.getFunction() != null) { analyzer.getFunction().variable(argument.getName()).setReference(true); } } uses.add(argument.getName()); } analyzer.getScope().addVariables(uses); return result; } iterator.previous(); return null; } } unexpectedToken(next); } return null; }
@Override public MethodEntity compile() { if (statement != null) { if (external) statement.setDynamicLocal(true); if (statement.getDocComment() != null) entity.setDocComment(new DocumentComment(statement.getDocComment().getComment())); entity.setAbstract(statement.isAbstract()); entity.setAbstractable(statement.getBody() == null); entity.setFinal(statement.isFinal()); entity.setStatic(statement.isStatic()); entity.setModifier(statement.getModifier()); entity.setReturnReference(statement.isReturnReference()); entity.setTrace(statement.toTraceInfo(compiler.getContext())); entity.setImmutable(statement.getArguments().isEmpty()); entity.setGeneratorEntity(generatorEntity); if (clazz.isSystem()) entity.setInternalName(entity.getName()); else entity.setInternalName(entity.getName() + "$" + clazz.entity.nextMethodIndex()); ParameterEntity[] parameters = new ParameterEntity[statement.getArguments().size()]; int i = 0; for (ArgumentStmtToken argument : statement.getArguments()) { parameters[i] = new ParameterEntity(compiler.getContext()); ParameterEntity parameter = parameters[i]; parameter.setReference(argument.isReference()); parameter.setName(argument.getName().getName()); parameter.setTrace(argument.toTraceInfo(compiler.getContext())); parameter.setMutable( statement.isDynamicLocal() || statement.variable(argument.getName()).isMutable()); parameter.setUsed(!statement.isUnusedVariable(argument.getName())); parameter.setVariadic(argument.isVariadic()); parameter.setType(argument.getHintType()); if (argument.getHintTypeClass() != null) { parameter.setTypeClass(argument.getHintTypeClass().getName()); } ExpressionStmtCompiler expressionStmtCompiler = new ExpressionStmtCompiler(compiler); ExprStmtToken value = argument.getValue(); if (value != null) { Memory defaultValue = expressionStmtCompiler.writeExpression(value, true, true, false); // try detect constant if (value.isSingle()) { if (value.getSingle() instanceof NameToken) { parameter.setDefaultValueConstName(((NameToken) value.getSingle()).getName()); if (defaultValue == null) { defaultValue = (new ConstantMemory(((NameToken) value.getSingle()).getName())); parameter.setMutable(true); } } else if (value.getSingle() instanceof StaticAccessExprToken) { StaticAccessExprToken access = (StaticAccessExprToken) value.getSingle(); if (access.getClazz() instanceof NameToken && access.getField() instanceof NameToken) { if (defaultValue == null) defaultValue = (new ClassConstantMemory( ((NameToken) access.getClazz()).getName(), ((NameToken) access.getField()).getName())); parameter.setDefaultValueConstName( ((NameToken) access.getClazz()).getName() + "::" + ((NameToken) access.getField()).getName()); parameter.setMutable(true); } } } if (defaultValue == null) compiler .getEnvironment() .error( argument.toTraceInfo(compiler.getContext()), ErrorType.E_COMPILE_ERROR, Messages.ERR_EXPECTED_CONST_VALUE, "$" + argument.getName().getName()); parameter.setDefaultValue(defaultValue); } i++; } entity.setParameters(parameters); } if (statement != null && clazz.statement.isInterface()) { if (!statement.isInterfacable()) { compiler .getEnvironment() .error( entity.getTrace(), Messages.ERR_INTERFACE_FUNCTION_CANNOT_CONTAIN_BODY.fetch( entity.getSignatureString(false))); } if (statement.isAbstract() || statement.isFinal()) { compiler .getEnvironment() .error( entity.getTrace(), Messages.ERR_ACCESS_TYPE_FOR_INTERFACE_METHOD.fetch( entity.getSignatureString(false))); } } else { writeHeader(); if (statement.isGenerator()) { entity.setEmpty(false); entity.setImmutable(false); GeneratorStmtCompiler generatorStmtCompiler = new GeneratorStmtCompiler(compiler, statement); entity.setGeneratorEntity(generatorStmtCompiler.compile()); ExpressionStmtCompiler expr = new ExpressionStmtCompiler(this, null); expr.makeUnknown(new TypeInsnNode(NEW, entity.getGeneratorEntity().getInternalName())); expr.stackPush(Memory.Type.REFERENCE); expr.writePushDup(); // env expr.writePushEnv(); // classEntity expr.writePushDup(); expr.writePushConstString(compiler.getModule().getInternalName()); expr.writePushConstInt((int) entity.getGeneratorEntity().getId()); expr.writeSysDynamicCall( Environment.class, "__getGenerator", ClassEntity.class, String.class, Integer.TYPE); // self expr.writePushThis(); // uses expr.writeVarLoad("~args"); expr.writeSysCall( entity.getGeneratorEntity().getInternalName(), INVOKESPECIAL, Constants.INIT_METHOD, void.class, Environment.class, ClassEntity.class, Memory.class, Memory[].class); expr.writeSysStaticCall(ObjectMemory.class, "valueOf", Memory.class, IObject.class); expr.makeUnknown(new InsnNode(Opcodes.ARETURN)); expr.stackPop(); } else { ExpressionStmtCompiler expr = new ExpressionStmtCompiler(this, null); entity.setEmpty(true); if (statement != null && statement.getBody() != null) { expr.writeDefineVariables(statement.getLocal()); expr.write(statement.getBody()); if (!statement.getBody().getInstructions().isEmpty()) { entity.setEmpty(false); } } if (generatorEntity != null) { expr.writeVarLoad("~this"); expr.writePushConstBoolean(false); expr.writeSysDynamicCall(null, "_setValid", void.class, Boolean.TYPE); } ReturnStmtToken token = new ReturnStmtToken(new TokenMeta("", 0, 0, 0, 0)); token.setValue(null); expr.getCompiler(ReturnStmtToken.class).write(token); } writeFooter(); } return entity; }
void writeHeader() { int access = 0; if (statement != null) { if (compiler.getScope().isDebugMode()) { statement.setDynamicLocal(true); } switch (statement.getModifier()) { case PRIVATE: access += Opcodes.ACC_PRIVATE; break; case PROTECTED: access += Opcodes.ACC_PROTECTED; break; case PUBLIC: access += Opcodes.ACC_PUBLIC; break; } if (statement.isStatic()) access += Opcodes.ACC_STATIC; // if (statement.isAbstract()) access += Opcodes.ACC_ABSTRACT; if (statement.isFinal()) access += Opcodes.ACC_FINAL; node.access = access; node.name = clazz.isSystem() || entity == null ? statement.getName().getName() : entity.getInternalName(); node.desc = Type.getMethodDescriptor( Type.getType(Memory.class), Type.getType(Environment.class), Type.getType(Memory[].class)); if (external) { node.desc = Type.getMethodDescriptor( Type.getType(Memory.class), Type.getType(Environment.class), Type.getType(Memory[].class), Type.getType(ArrayMemory.class)); } } if (statement != null) { LabelNode label = labelStart = writeLabel(node, statement.getMeta().getStartLine()); if (!statement.isStatic()) addLocalVariable("~this", label, Object.class); ExpressionStmtCompiler expressionCompiler = new ExpressionStmtCompiler(this, null); addLocalVariable("~env", label, Environment.class); // Environment env LocalVariable args = addLocalVariable("~args", label, Memory[].class); // Memory[] arguments if (statement.isDynamicLocal()) { if (external) addLocalVariable("~passedLocal", label, ArrayMemory.class); LocalVariable local = addLocalVariable("~local", label, ArrayMemory.class); if (external) { expressionCompiler.writeVarLoad("~passedLocal"); expressionCompiler.writeSysStaticCall( ArrayMemory.class, "valueOfRef", ArrayMemory.class, ArrayMemory.class); expressionCompiler.setStackPeekAsImmutable(); expressionCompiler.writeVarStore(local, false, true); } else { expressionCompiler.writePushConstNull(); expressionCompiler.writeSysStaticCall( ArrayMemory.class, "valueOfRef", ArrayMemory.class, ArrayMemory.class); expressionCompiler.setStackPeekAsImmutable(); expressionCompiler.writeVarStore(local, false, true); } } if (statement.getUses() != null && !statement.getUses().isEmpty()) { int i = 0; expressionCompiler.writeVarLoad("~this"); expressionCompiler.writeGetDynamic("uses", Memory[].class); for (ArgumentStmtToken argument : statement.getUses()) { LocalVariable local; if (statement.isDynamicLocal()) { expressionCompiler.writeDefineVariable(argument.getName()); local = getLocalVariable(argument.getName().getName()); } else { local = addLocalVariable(argument.getName().getName(), label, Memory.class); } if (argument.isReference()) { local.setReference(true); statement.variable(argument.getName()).setUnstable(true); } expressionCompiler.writePushDup(); expressionCompiler.writePushGetFromArray(i, Memory.class); if (statement.isDynamicLocal()) { expressionCompiler.writeVarAssign(local, argument.getName(), false, false); } else { expressionCompiler.writeVarStore(local, false, false); } local.pushLevel(); i++; } expressionCompiler.writePopAll(1); } int i = 0; for (ArgumentStmtToken argument : statement.getArguments()) { if (argument.isReference()) { statement.variable(argument.getName()).setReference(true).setUnstable(true); } LabelNode next = new LabelNode(); expressionCompiler.writeDefineVariable(argument.getName()); LocalVariable local = getLocalVariable(argument.getName().getName()); if (local != null) { expressionCompiler.writeVarLoad(args); expressionCompiler.writePushGetFromArray(i, Memory.class); expressionCompiler.writeVarAssign(local, argument.getName(), true, false); // if length <= i then undefined node.instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, next)); expressionCompiler.stackPop(); if (argument.getValue() == null) expressionCompiler.writePushNull(); else expressionCompiler.writeExpression(argument.getValue(), true, false); expressionCompiler.writeVarAssign(local, argument.getName(), false, false); node.instructions.add(next); local.pushLevel(); } i++; } } else { LabelNode label = labelStart = writeLabel(node, clazz.statement.getMeta().getStartLine()); } }