/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> /// <remarks> /// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack. /// </remarks> internal override void Emit(CodeGenerator/*!*/ codeGenerator) { Statistics.AST.AddNode("EchoStmt"); codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); foreach (Expression parameter in parameters) { // skip empty evaluated expression if (parameter.HasValue && ( parameter.Value == null || (parameter.Value is string && ((string)parameter.Value) == string.Empty) || Convert.ObjectToPhpBytes(parameter.Value).Length == 0 )) { continue; } // emit the echo of parameter expression codeGenerator.EmitEcho(parameter); } }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator/*!*/ codeGenerator) { Statistics.AST.AddNode("SwitchStmt"); ILEmitter il = codeGenerator.IL; // Note: // SwitchStmt is now implemented in the most general (and unefficient) way. The whole switch // is understood as a series of if-elseif-else statements. Label exit_label = il.DefineLabel(); bool fall_through = false; Label fall_through_label = il.DefineLabel(); Label last_default_label = il.DefineLabel(); DefaultItem last_default = GetLastDefaultItem(); LocalBuilder branch_to_lastdefault = null; if (last_default != null) { branch_to_lastdefault = il.DeclareLocal(Types.Bool[0]); il.LdcI4(0); il.Stloc(branch_to_lastdefault); } codeGenerator.BranchingStack.BeginLoop(exit_label, exit_label, codeGenerator.ExceptionBlockNestingLevel); // marks a sequence point containing the discriminator evaluation: codeGenerator.MarkSequencePoint( switchValue.Position.FirstLine, switchValue.Position.FirstColumn, switchValue.Position.LastLine, switchValue.Position.LastColumn + 1); // Evaluate condition value and store the result into local variable codeGenerator.EmitBoxing(switchValue.Emit(codeGenerator)); LocalBuilder condition_value = il.DeclareLocal(Types.Object[0]); il.Stloc(condition_value); foreach (SwitchItem item in switchItems) { item.MarkSequencePoint(codeGenerator); // switch item is either CaseItem ("case xxx:") or DefaultItem ("default") item: CaseItem case_item = item as CaseItem; if (case_item != null) { Label false_label = il.DefineLabel(); // PhpComparer.Default.CompareEq(<switch expr. value>,<case value>); /*changed to static method*/ //il.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default); codeGenerator.EmitCompareEq( cg => { cg.IL.Ldloc(condition_value); return PhpTypeCode.Object; }, cg => case_item.EmitCaseValue(cg)); // IF (!STACK) GOTO false_label; il.Emit(OpCodes.Brfalse, false_label); if (fall_through == true) { il.MarkLabel(fall_through_label, true); fall_through = false; } case_item.EmitStatements(codeGenerator); if (fall_through == false) { fall_through_label = il.DefineLabel(); fall_through = true; } il.Emit(OpCodes.Br, fall_through_label); il.MarkLabel(false_label, true); } else { DefaultItem default_item = (DefaultItem)item; // Only the last default branch defined in source code is used. // So skip default while testing "case" items at runtime. Label false_label = il.DefineLabel(); il.Emit(OpCodes.Br, false_label); if (default_item == last_default) { il.MarkLabel(last_default_label, false); } if (fall_through == true) { il.MarkLabel(fall_through_label, true); fall_through = false; } default_item.EmitStatements(codeGenerator); if (fall_through == false) { fall_through_label = il.DefineLabel(); fall_through = true; } il.Emit(OpCodes.Br, fall_through_label); il.MarkLabel(false_label, true); } } // If no case branch matched, branch to last default case if any is defined if (last_default != null) { // marks a sequence point containing the condition evaluation or skip of the default case: codeGenerator.MarkSequencePoint( last_default.Position.FirstLine, last_default.Position.FirstColumn, last_default.Position.LastLine, last_default.Position.LastColumn + 1); Debug.Assert(branch_to_lastdefault != null); Label temp = il.DefineLabel(); // IF (!branch_to_lastdefault) THEN il.Ldloc(branch_to_lastdefault); il.LdcI4(0); il.Emit(OpCodes.Bne_Un, temp); if (true) { // branch_to_lastdefault = TRUE; il.LdcI4(1); il.Stloc(branch_to_lastdefault); // GOTO last_default_label; il.Emit(OpCodes.Br, last_default_label); } il.MarkLabel(temp, true); // END IF; il.ForgetLabel(last_default_label); } if (fall_through == true) { il.MarkLabel(fall_through_label, true); } il.MarkLabel(exit_label); codeGenerator.BranchingStack.EndLoop(); il.ForgetLabel(exit_label); }
/// <summary> /// Marks a sequence point "default". /// </summary> internal override void MarkSequencePoint(CodeGenerator/*!*/ codeGenerator) { codeGenerator.MarkSequencePoint( position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 1); }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator/*!*/ codeGenerator) { if (position.IsValid) { codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); } }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator codeGenerator) { Statistics.AST.AddNode("UnsetStmt"); codeGenerator.MarkSequencePoint( position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 1); foreach (VariableUse variable in varList) { codeGenerator.ChainBuilder.Create(); codeGenerator.ChainBuilder.QuietRead = true; variable.EmitUnset(codeGenerator); codeGenerator.ChainBuilder.End(); } }
/// <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); } }
internal override void Emit(CodeGenerator/*!*/ codeGenerator) { if (expression.DoMarkSequencePoint) codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 1); try { // emit the expression expression.Emit(codeGenerator); } catch (CompilerException ex) { // put the error into the error sink, // so the user can see, which expression is problematic (work item 20695) codeGenerator.Context.Errors.Add( ex.ErrorInfo, codeGenerator.SourceUnit, Position, // exact position of the statement ex.ErrorParams ); // terminate the emit with standard Exception throw new Exception(CoreResources.GetString(ex.ErrorInfo.MessageId, ex.ErrorParams)); } }
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); } } }
internal void EmitDeclaration(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."); if (type.Declaration.IsConditional) { ILEmitter il = codeGenerator.IL; codeGenerator.MarkSequencePoint(position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); // this class was conditionally declared, so we'll emit code that activates it: type.EmitAutoDeclareOnScriptContext(il, codeGenerator.ScriptContextPlace); if (codeGenerator.Context.Config.Compiler.Debug) il.Emit(OpCodes.Nop); } } else { // declared in emitted Eval } }
internal override void Emit(CodeGenerator/*!*/ codeGenerator) { codeGenerator.MarkSequencePoint( position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 1 ); // CALL Operators.Throw(<context>, <expression>); codeGenerator.EmitLoadScriptContext(); expression.Emit(codeGenerator); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.Throw); }
/// <summary> /// Emits the catch-block. /// </summary> /// <param name="codeGenerator">A code generator.</param> /// <param name="exceptionLocal">A local variable containing an instance of <see cref="Library.SPL.Exception"/>.</param> /// <param name="endLabel">A label in IL stream where the processing of the try-catch blocks ends.</param> /// <param name="nextCatchLabel">A label in IL stream where the next catch block processing begins.</param> internal void Emit(CodeGenerator/*!*/ codeGenerator, LocalBuilder/*!*/ exceptionLocal, Label endLabel, Label nextCatchLabel) { ILEmitter il = codeGenerator.IL; codeGenerator.MarkSequencePoint( variable.Position.FirstLine, variable.Position.FirstColumn, variable.Position.LastLine, variable.Position.LastColumn + 1 ); // IF !InstanceOf(<class name>) GOTO next_catch; il.Ldloc(exceptionLocal); resolvedType.EmitInstanceOf(codeGenerator, null); il.Emit(OpCodes.Brfalse, nextCatchLabel); // variable = exception; variable.Emit(codeGenerator); il.Ldloc(exceptionLocal); variable.EmitAssign(codeGenerator); foreach (Statement statement in statements) statement.Emit(codeGenerator); // LEAVE end; il.Emit(OpCodes.Leave, endLabel); }
/// <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; }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator codeGenerator) { Statistics.AST.AddNode("JumpStmt"); // marks a sequence point: codeGenerator.MarkSequencePoint( position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 1); switch (type) { case Types.Break: // Emit simple break; - break the most inner loop if (expr == null) { codeGenerator.BranchingStack.EmitBreak(); } else if (expr.HasValue) { // We can get the number at compile time and generate the right branch // instruction for break x; where x is Literal codeGenerator.BranchingStack.EmitBreak(Convert.ObjectToInteger(expr.Value)); } else { // In this case we emit the switch that decides where to branch at runtime. codeGenerator.EmitConversion(expr, PhpTypeCode.Integer); codeGenerator.BranchingStack.EmitBreakRuntime(); } break; case Types.Continue: // Emit simple continue; - banch back to the condition of the most inner loop if (expr == null) { codeGenerator.BranchingStack.EmitContinue(); } else if (expr.HasValue) { // We can get the number at compile time and generate the right branch // instruction for continue x; where x is Literal codeGenerator.BranchingStack.EmitContinue(Convert.ObjectToInteger(expr.Value)); } else { // In this case we emit the switch that decides where to branch at runtime. codeGenerator.EmitConversion(expr, PhpTypeCode.Integer); codeGenerator.BranchingStack.EmitContinueRuntime(); } break; case Types.Return: if (codeGenerator.ReturnsPhpReference) EmitReturnPhpReference(codeGenerator); else EmitReturnObject(codeGenerator); break; default: throw null; } }
internal override void Emit(CodeGenerator/*!*/ codeGenerator) { Debug.Assert(codeGenerator.CurrentLabels.ContainsKey(labelName)); Debug.Assert(codeGenerator.CurrentLabels[labelName] is LabelStmt); // marks a sequence point: codeGenerator.MarkSequencePoint( position.FirstLine, position.FirstColumn, position.LastLine, position.LastColumn + 2); codeGenerator.IL.Emit(OpCodes.Br, ((LabelStmt)codeGenerator.CurrentLabels[labelName]).Label); }