internal void EmitDefinition(CodeGenerator/*!*/ codeGenerator) { if (type.IsComplete) { Debug.Assert(type.IsComplete, "Incomplete types should be converted to evals."); Debug.Assert(type.RealTypeBuilder != null, "A class declared during compilation should have a type builder."); attributes.Emit(codeGenerator, this); typeSignature.Emit(codeGenerator); codeGenerator.EnterTypeDeclaration(type); foreach (TypeMemberDecl member_decl in members) { member_decl.EnterCodegenerator(codeGenerator); member_decl.Emit(codeGenerator); member_decl.LeaveCodegenerator(codeGenerator); } // emit stubs for implemented methods & properties that were not declared by this type: codeGenerator.EmitGhostStubs(type); codeGenerator.LeaveTypeDeclaration(); } else { Debug.Assert(this.typeDefinitionCode != null); // LOAD DynamicCode.Eval(<code>, context, definedVariables, self, includer, source, line, column, evalId) // wrap Eval into static method MethodBuilder method = codeGenerator.IL.TypeBuilder.DefineMethod( string.Format("{0}{1}", ScriptModule.DeclareHelperNane, type.FullName), MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName, Types.Void, Types.ScriptContext); var il = new ILEmitter(method); codeGenerator.EnterLambdaDeclaration(il, false, LiteralPlace.Null, new IndexedPlace(PlaceHolder.Argument, 0), LiteralPlace.Null, LiteralPlace.Null); if (true) { codeGenerator.EmitEval( EvalKinds.SyntheticEval, new StringLiteral(position, this.typeDefinitionCode, AccessType.Read), position, (this.Namespace != null) ? this.Namespace.QualifiedName : (QualifiedName?)null, this.validAliases); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ret); } codeGenerator.LeaveFunctionDeclaration(); // il = codeGenerator.IL; type.IncompleteClassDeclareMethodInfo = method; type.IncompleteClassDeclarationId = String.Format("{0}${1}:{2}:{3}", type.FullName, unchecked((uint)codeGenerator.SourceUnit.SourceFile.ToString().GetHashCode()), position.FirstLine, position.FirstColumn); // sequence point here codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); if (type.Declaration.IsConditional) { // CALL <Declare>.<FullName>(<context>) codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, method); } else { // if (!<context>.IncompleteTypeDeclared(<id>)) // CALL <Declare>.<FullName>(<context>) var end_if = il.DefineLabel(); codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Ldstr, type.IncompleteClassDeclarationId); il.Emit(OpCodes.Call, Methods.ScriptContext.IncompleteTypeDeclared); il.Emit(OpCodes.Brtrue, end_if); if (true) { codeGenerator.EmitLoadScriptContext(); il.Emit(OpCodes.Call, type.IncompleteClassDeclareMethodInfo); } il.MarkLabel(end_if); il.ForgetLabel(end_if); } } }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator/*!*/ codeGenerator) { Statistics.AST.AddNode("FunctionDecl"); // marks a sequence point if function is declared here (i.e. is m-decl): //Note: this sequence point goes to the function where this function is declared not to this declared function! if (!function.IsLambda && function.Declaration.IsConditional) codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); // emits attributes on the function itself, its return value, type parameters and regular parameters: attributes.Emit(codeGenerator, this); signature.Emit(codeGenerator); typeSignature.Emit(codeGenerator); // prepares code generator for emitting arg-full overload; // false is returned when the body should not be emitted: if (!codeGenerator.EnterFunctionDeclaration(function)) return; // emits the arg-full overload: codeGenerator.EmitArgfullOverloadBody(function, body, entireDeclarationPosition, declarationBodyPosition); // restores original code generator settings: codeGenerator.LeaveFunctionDeclaration(); // emits function declaration (if needed): // ignore s-decl function declarations except for __autoload; // __autoload function is declared in order to avoid using callbacks when called: if (function.Declaration.IsConditional && !function.QualifiedName.IsAutoloadName) { Debug.Assert(!function.IsLambda); codeGenerator.EmitDeclareFunction(function); } }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator) { Statistics.AST.AddNode("LambdaFunctionExpr"); var typeBuilder = codeGenerator.IL.TypeBuilder; // define argless and argfull this.function.DefineBuilders(typeBuilder); // codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); if (!codeGenerator.EnterFunctionDeclaration(function)) throw new Exception("EnterFunctionDeclaration() failed!"); codeGenerator.EmitArgfullOverloadBody(function, body, entireDeclarationPosition, declarationBodyPosition); codeGenerator.LeaveFunctionDeclaration(); // new Closure( <context>, new RoutineDelegate(null,function.ArgLess), <parameters>, <static> ) codeGenerator.EmitLoadScriptContext(); var/*!*/il = codeGenerator.IL; il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldftn, function.ArgLessInfo); il.Emit(OpCodes.Newobj, Constructors.RoutineDelegate); int userParamsCount = (useParams != null) ? useParams.Count : 0; if (signature.FormalParams != null && signature.FormalParams.Count > userParamsCount) { // array = new PhpArray(<int_count>, <string_count>); il.Emit(OpCodes.Ldc_I4, 0); il.Emit(OpCodes.Ldc_I4, signature.FormalParams.Count); il.Emit(OpCodes.Newobj, Constructors.PhpArray.Int32_Int32); for (int i = userParamsCount; i < signature.FormalParams.Count; i++) { var p = signature.FormalParams[i]; // CALL array.SetArrayItem("&$name", "<required>" | "<optional>"); il.Emit(OpCodes.Dup); // PhpArray string keyValue = string.Format("{0}${1}", p.PassedByRef ? "&" : null, p.Name.Value); il.Emit(OpCodes.Ldstr, keyValue); il.Emit(OpCodes.Ldstr, (p.InitValue != null) ? "<optional>" : "<required>"); il.LdcI4(IntStringKey.StringKeyToArrayIndex(keyValue)); il.Emit(OpCodes.Call, Methods.PhpArray.SetArrayItemExact_String); } } else { il.Emit(OpCodes.Ldnull); } if (userParamsCount > 0) { // array = new PhpArray(<int_count>, <string_count>); il.Emit(OpCodes.Ldc_I4, 0); il.Emit(OpCodes.Ldc_I4, useParams.Count); il.Emit(OpCodes.Newobj, Constructors.PhpArray.Int32_Int32); foreach (var p in useParams) { // <stack>.SetArrayItem{Ref} il.Emit(OpCodes.Dup); // PhpArray string variableName = p.Name.Value; il.Emit(OpCodes.Ldstr, variableName); if (p.PassedByRef) { DirectVarUse.EmitLoadRef(codeGenerator, p.Name); il.Emit(OpCodes.Call, Methods.PhpArray.SetArrayItemRef_String); } else { // LOAD PhpVariable.Copy( <name>, Assigned ) DirectVarUse.EmitLoad(codeGenerator, p.Name); il.LdcI4((int)CopyReason.Assigned); il.Emit(OpCodes.Call, Methods.PhpVariable.Copy); // .SetArrayItemExact( <stack>, <stack>, <hashcode> ) il.LdcI4(IntStringKey.StringKeyToArrayIndex(variableName)); il.Emit(OpCodes.Call, Methods.PhpArray.SetArrayItemExact_String); } } } else { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Newobj, typeof(PHP.Library.SPL.Closure).GetConstructor(new Type[] { typeof(ScriptContext), typeof(RoutineDelegate), typeof(PhpArray), typeof(PhpArray) })); return PhpTypeCode.Object; }