/** Declare a function. TODO: static vs. instance. */ @Override void declareFunction(FunctionNode func) { func.parseFunctionBody(classScope.getProblems()); final FunctionDefinition funcDef = func.getDefinition(); final boolean is_constructor = func.isConstructor(); functionSemanticChecks(func); // Save the constructor function until // we've seen all the instance variables // that might need initialization. if (is_constructor) { if (this.ctorFunction == null) this.ctorFunction = func; else { // If we already have a ctor, must be multiply defined. Ignore it and generate problem String name = this.className.getBaseName(); classScope.addProblem(new MultipleContructorDefinitionsProblem(func, name)); } } else { LexicalScope ls = funcDef.isStatic() ? classStaticScope : classScope; MethodInfo mi = classScope.getGenerator().generateFunction(func, ls, null); if (mi != null) { Name funcName = funcDef.getMName(classScope.getProject()); ITraitVisitor tv = ls.traitsVisitor.visitMethodTrait( functionTraitKind(func, TRAIT_Method), funcName, 0, mi); if (funcName != null) classScope .getMethodBodySemanticChecker() .checkFunctionForConflictingDefinitions(func, funcDef); if (!funcDef.isStatic()) if (funcDef.getNamespaceReference() instanceof NamespaceDefinition.IProtectedNamespaceDefinition) this.iinfo.flags |= ABCConstants.CLASS_FLAG_protected; ls.processMetadata(tv, getAllMetaTags(funcDef)); if (func.hasModifier(ASModifier.FINAL)) tv.visitAttribute(Trait.TRAIT_FINAL, Boolean.TRUE); if (func.hasModifier(ASModifier.OVERRIDE)) tv.visitAttribute(Trait.TRAIT_OVERRIDE, Boolean.TRUE); tv.visitEnd(); } } }
/** * Generate instructions for field initializers or static initialization statements. * * @param node - the AST at the root of the statement. * @param isStatic - true if the code should be generated in a static context. */ private void generateInstructions(IASNode node, final boolean isStatic) { // Do we need to create new information for the class' // static initialization method? Note that this may // be undone if the codgen fails or doesn't produce // any instructions. final boolean createNewCinit = isStatic && this.cinfo.cInit == null; if (createNewCinit) { // Speculatively initialize the class' cinit // (static class initializer routine)'s data // structures; the code generator may need to // store information in them. this.cinfo.cInit = new MethodInfo(); MethodBodyInfo cinit_info = new MethodBodyInfo(); cinit_info.setMethodInfo(this.cinfo.cInit); this.classStaticScope.setMethodInfo(this.cinfo.cInit); this.classStaticScope.methodVisitor = emitter.visitMethod(this.cinfo.cInit); this.classStaticScope.methodVisitor.visit(); this.classStaticScope.methodBodyVisitor = this.classStaticScope.methodVisitor.visitBody(cinit_info); this.classStaticScope.methodBodyVisitor.visit(); } InstructionList cgResult = null; LexicalScope ls = isStatic ? this.classStaticScope : this.classScope; ls.resetDebugInfo(); cgResult = ls.getGenerator().generateInstructions(node, CmcEmitter.__statement_NT, ls); // If nothing came back, revert any change made to the cinit information. if ((cgResult == null || cgResult.isEmpty()) && createNewCinit) { this.cinfo.cInit = null; this.classStaticScope.resetMethodInfo(); this.classStaticScope.methodVisitor = null; this.classStaticScope.methodBodyVisitor = null; } // Save the generated instructions, if present. if (cgResult != null) { if (isStatic) this.cinitInsns.addAll(cgResult); else this.iinitInsns.addAll(cgResult); } }
/** Process an import directive. */ @Override void processImportDirective(ImportNode imp) { // Run the BURM, but for the purpose of semantic checking not code generation. classScope.getGenerator().generateInstructions(imp, CmcEmitter.__statement_NT, this.classScope); }
/** Declare a variable. */ @Override void declareVariable(VariableNode var) { verifyVariableModifiers(var); VariableDefinition varDef = (VariableDefinition) var.getDefinition(); boolean is_static = var.hasModifier(ASModifier.STATIC); boolean is_const = SemanticUtils.isConst(var, classScope.getProject()); final ICompilerProject project = this.classScope.getProject(); ICodeGenerator codeGenerator = classScope.getGenerator(); IExpressionNode assignedValueNode = var.getAssignedValueNode(); IConstantValue constantValue = codeGenerator.generateConstantValue(assignedValueNode, project); // initializer is null if no constant value // can be generated, and null is the correct value for "no value." Object initializer = constantValue != null ? constantValue.getValue() : null; // Reducing the constant value may have produced problems in the // LexicalScope used for constant reduction. Transfer them over // to the LexicalScope for this class. Collection<ICompilerProblem> problems = constantValue != null ? constantValue.getProblems() : null; if (problems != null) classScope.addProblems(problems); final MethodBodySemanticChecker checker = MethodBodySemanticCheckerFactory.getChecker(this.classScope); // CO-5148 DefinitionBase varType = (DefinitionBase) varDef.resolveType(project); Object transformed_initializer = null; if ((initializer != null) && (varType != null)) { transformed_initializer = checker .checkInitialValue( var, new Binding(null, varType.getMName(this.classScope.getProject()), varType), new PooledValue(initializer)) .getValue(); } else { transformed_initializer = initializer; } ITraitVisitor tv = declareVariable(var, varDef, is_static, is_const, transformed_initializer); if (is_static) this.classStaticScope.processMetadata(tv, getAllMetaTags(varDef)); else this.classScope.processMetadata(tv, getAllMetaTags(varDef)); tv.visitEnd(); // Generate variable initializers and append them to the // proper initialization list. if (transformed_initializer == null && var.getAssignedValueNode() != null) { // Emit initialization instructions for non-static vars. Static var // instructions will be emitted during finishClassDefinition() if (is_static) staticVariableInitializers.add(var); else generateInstructions(var, false); } else { checker.checkClassField(var, is_static); // Massive kludge -- grovel over chained variable decls and add them one by one for (int i = 0; i < var.getChildCount(); i++) { IASNode candidate = var.getChild(i); if (candidate instanceof VariableNode) { declareVariable((VariableNode) candidate); } } } }
/** Finish the class' definition. */ void finishClassDefinition() { // the generation of instructions for variable initialization is delayed // until now, so we can add that initialization to the front of // the cinit instruction list. if (!staticVariableInitializers.isEmpty()) { InstructionList exisitingCinitInsns = null; if (!this.cinitInsns.isEmpty()) { exisitingCinitInsns = new InstructionList(); exisitingCinitInsns.addAll(this.cinitInsns); this.cinitInsns = new InstructionList(); } for (VariableNode var : staticVariableInitializers) generateInstructions(var, true); if (exisitingCinitInsns != null) this.cinitInsns.addAll(exisitingCinitInsns); } // add "goto_definition_help" metadata to user defined metadata. ITraitVisitor tv = classScope.getGlobalScope().traitsVisitor.visitClassTrait(TRAIT_Class, className, 0, cinfo); IMetaInfo[] metaTags = getAllMetaTags(classDefinition); // Add "goto definition help" metadata for the constructor. if (this.ctorFunction != null) { FunctionDefinition ctorDef = this.ctorFunction.getDefinition(); MetaTag metaTag = MetaTag.createGotoDefinitionHelp( classDefinition, classDefinition.getContainingFilePath(), Integer.toString(ctorDef.getNameStart()), true); if (metaTag != null) metaTags = MetaTag.addMetaTag(metaTags, metaTag); } this.classScope.processMetadata(tv, metaTags); tv.visitEnd(); // Need to do this before generating the CTOR as the generated code may result in insns that // need to be added to the ctor. generateBindableImpl(); generateRequiredContingentDefinitions(); addAnyEmbeddedAsset(); // Make any vistEnd method calls // that were deferred. // callVisitEnds must be called on the same thread // that started code generation. Since we don't generate // classes in parallel yet, we know that we are on the thread // that started code generation here. classScope.callVisitEnds(); classStaticScope.callVisitEnds(); // Create the class' constructor function. if (this.ctorFunction != null) { MethodInfo mi = classScope .getGenerator() .generateFunction(this.ctorFunction, classScope, this.iinitInsns); if (mi != null) this.iinfo.iInit = mi; } else if (!this.iinitInsns.isEmpty()) { // Synthesize a constructor. this.iinfo.iInit = new MethodInfo(); MethodBodyInfo iinit = new MethodBodyInfo(); iinit.setMethodInfo(this.iinfo.iInit); IMethodVisitor mv = emitter.visitMethod(this.iinfo.iInit); mv.visit(); IMethodBodyVisitor mbv = mv.visitBody(iinit); InstructionList ctor_insns = new InstructionList(); ctor_insns.addInstruction(OP_getlocal0); ctor_insns.addInstruction(OP_pushscope); ctor_insns.addAll(this.iinitInsns); // Call the superclass' constructor after the instance // init instructions; this doesn't seem like an abstractly // correct sequence, but it's what ASC does. ctor_insns.addInstruction(OP_getlocal0); ctor_insns.addInstruction(OP_constructsuper, 0); ctor_insns.addInstruction(OP_returnvoid); mbv.visit(); mbv.visitInstructionList(ctor_insns); mbv.visitEnd(); mv.visitEnd(); } // If the class has static initialization // logic, emit a cinit routine. if (!this.cinitInsns.isEmpty()) { InstructionList cinit_insns = new InstructionList(); cinit_insns.addInstruction(OP_getlocal0); cinit_insns.addInstruction(OP_pushscope); // TODO: Examine other end-of-function processing // and ensure it's completed. this.classStaticScope.finishClassStaticInitializer(this.cinitInsns); cinit_insns.addAll(this.cinitInsns); cinit_insns.addInstruction(OP_returnvoid); this.classStaticScope.methodBodyVisitor.visitInstructionList(cinit_insns); this.classStaticScope.methodBodyVisitor.visitEnd(); this.classStaticScope.methodVisitor.visitEnd(); } else { // Ensure nothing got dropped. assert (this.classStaticScope.methodBodyVisitor == null); } itraits.visitEnd(); ctraits.visitEnd(); cv.visitEnd(); }