/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator) { #if !SILVERLIGHT Debug.Assert(access == AccessType.Read || access == AccessType.None); Statistics.AST.AddNode("ShellEx"); // CALL Execution.ShellExec(<(string) command>); codeGenerator.EmitConversion(command, PhpTypeCode.String); codeGenerator.IL.Emit(OpCodes.Call, Methods.ShellExec); if (access == AccessType.None) { codeGenerator.IL.Emit(OpCodes.Pop); return PhpTypeCode.Void; } #endif // ShellExec returns a string containing the standard output of executed command return PhpTypeCode.String; }
/// <summary> /// Emits dynamic inclusion. /// </summary> private PhpTypeCode EmitDynamicInclusion(CodeGenerator/*!*/ codeGenerator) { // do not generate dynamic auto inclusions: if (InclusionTypesEnum.IsAutoInclusion(inclusionType)) return PhpTypeCode.Void; ILEmitter il = codeGenerator.IL; // CALL context.DynamicInclude(<file name>,<relative includer source path>,variables,self,includer); codeGenerator.EmitLoadScriptContext(); codeGenerator.EmitConversion(fileNameEx, PhpTypeCode.String); il.Emit(OpCodes.Ldstr, codeGenerator.SourceUnit.SourceFile.RelativePath.ToString()); codeGenerator.EmitLoadRTVariablesTable(); codeGenerator.EmitLoadSelf(); codeGenerator.EmitLoadClassContext(); il.LoadLiteral(inclusionType); il.Emit(OpCodes.Call, Methods.ScriptContext.DynamicInclude); return PhpTypeCode.Object; }
/// <summary> /// Emits load of the name to the stack. /// </summary> internal override void EmitName(CodeGenerator codeGenerator) { codeGenerator.ChainBuilder.Create(); codeGenerator.EmitConversion(this.VarNameEx, PhpTypeCode.String); codeGenerator.ChainBuilder.End(); }
/// <summary> /// Emits binary boolean operation (AND or OR). /// </summary> /// <param name="codeGenerator">A code generator.</param> /// <param name="isAnd">Whether to emit AND.</param> /// <returns>A type code of the result.</returns> private PhpTypeCode EmitBinaryBooleanOperation(CodeGenerator codeGenerator, bool isAnd) { ILEmitter il = codeGenerator.IL; Label partial_eval_label = il.DefineLabel(); Label end_label = il.DefineLabel(); // IF [!]<(bool) leftSon> THEN GOTO partial_eval; codeGenerator.EmitConversion(leftExpr, PhpTypeCode.Boolean); il.Emit(isAnd ? OpCodes.Brfalse : OpCodes.Brtrue, partial_eval_label); // LOAD <(bool) leftSon>; codeGenerator.EmitConversion(rightExpr, PhpTypeCode.Boolean); il.Emit(OpCodes.Br, end_label); il.MarkLabel(partial_eval_label, true); il.LdcI4(isAnd ? 0 : 1); il.MarkLabel(end_label, true); return PhpTypeCode.Boolean; }
/// <remarks> /// Nothing is expected at the evaluation stack. If AST node is read by other node, /// the operation result is left at the stack, otherwise it is poped from the stack. /// </remarks> /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override PhpTypeCode Emit(CodeGenerator codeGenerator) { Debug.Assert(access == AccessType.None || access == AccessType.Read); Statistics.AST.AddNode("BinaryEx"); PhpTypeCode returned_typecode; PhpTypeCode lo_typecode; PhpTypeCode ro_typecode; switch (operation) { #region Arithmetic Operations case Operations.Add: // Template: x + y : Operators.Add(x,y) [overloads] switch (lo_typecode = leftExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Add); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Object); break; } break; } break; case Operations.Sub: //Template: "x - y" Operators.Subtract(x,y) [overloads] lo_typecode = leftExpr.Emit(codeGenerator); switch (lo_typecode) { case PhpTypeCode.Integer: codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Int32_Object); break; case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Sub); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); if (ro_typecode == PhpTypeCode.Integer) { returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int); } else { codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object); } break; } break; case Operations.Div: //Template: "x / y" Operators.Divide(x,y) lo_typecode = leftExpr.Emit(codeGenerator); switch (lo_typecode) { case PhpTypeCode.Integer: codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Int32_Object); break; case PhpTypeCode.Double: switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Div); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Double_Object); break; } break; default: codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Object); break; } break; } break; case Operations.Mul: switch (lo_typecode = leftExpr.Emit(codeGenerator)) { case PhpTypeCode.Double: // "x * (double)y" // Operators.Multiply((double)x,(object)y) switch (ro_typecode = rightExpr.Emit(codeGenerator)) { case PhpTypeCode.Integer: codeGenerator.IL.Emit(OpCodes.Conv_R8); goto case PhpTypeCode.Double; // fallback: case PhpTypeCode.Double: codeGenerator.IL.Emit(OpCodes.Mul); returned_typecode = PhpTypeCode.Double; break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Double_Object); break; } break; default: //Template: "x * y" Operators.Multiply((object)x,y) [overloads] codeGenerator.EmitBoxing(lo_typecode); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32); break; case PhpTypeCode.Double: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Double); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Object); break; } break; } break; case Operations.Mod: //Template: "x % y" Operators.Remainder(x,y) codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); ro_typecode = rightExpr.Emit(codeGenerator); switch (ro_typecode) { case PhpTypeCode.Integer: returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32); break; default: codeGenerator.EmitBoxing(ro_typecode); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object); break; } break; case Operations.ShiftLeft: // LOAD Operators.ShiftLeft(box left, box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft); break; case Operations.ShiftRight: // LOAD Operators.ShiftRight(box left, box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight); break; #endregion #region Boolean and Bitwise Operations case Operations.And: returned_typecode = EmitBinaryBooleanOperation(codeGenerator, true); break; case Operations.Or: returned_typecode = EmitBinaryBooleanOperation(codeGenerator, false); break; case Operations.Xor: // LOAD <(bool) leftSon> == <(bool) rightSon>; codeGenerator.EmitConversion(leftExpr, PhpTypeCode.Boolean); codeGenerator.EmitConversion(rightExpr, PhpTypeCode.Boolean); codeGenerator.IL.Emit(OpCodes.Ceq); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.BitAnd: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.And); break; case Operations.BitOr: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Or); break; case Operations.BitXor: returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Xor); break; #endregion #region Comparing Operations case Operations.Equal: // LOAD PhpComparer.Default.CompareEq returned_typecode = EmitComparison(codeGenerator, true); break; case Operations.NotEqual: // LOAD PhpComparer.Default.CompareEq == false EmitComparison(codeGenerator, true); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.GreaterThan: // LOAD PhpComparer.Default.Compare > 0; EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Cgt); returned_typecode = PhpTypeCode.Boolean; break; case Operations.LessThan: // LOAD PhpComparer.Default.Compare < 0; EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Clt); returned_typecode = PhpTypeCode.Boolean; break; case Operations.GreaterThanOrEqual: // LOAD PhpComparer.Default.Compare >= 0 (not less than) EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Clt); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.LessThanOrEqual: // LOAD PhpComparer.Default.Compare >= 0 (not greater than) EmitComparison(codeGenerator, false); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Cgt); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; case Operations.Identical: // LOAD Operators.StrictEquality(box left,box right); codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality); returned_typecode = PhpTypeCode.Boolean; break; case Operations.NotIdentical: // LOAD Operators.StrictEquality(box left,box right) == false; codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator)); codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator)); codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality); codeGenerator.IL.Emit(OpCodes.Ldc_I4_0); codeGenerator.IL.Emit(OpCodes.Ceq); returned_typecode = PhpTypeCode.Boolean; break; #endregion case Operations.Concat: returned_typecode = ConcatEx.EmitConcat(codeGenerator, leftExpr, rightExpr); break; default: throw null; } switch (access) { case AccessType.Read: // Result is read, do nothing. break; case AccessType.None: // Result is not read, pop the result codeGenerator.IL.Emit(OpCodes.Pop); returned_typecode = PhpTypeCode.Void; break; } return returned_typecode; }
internal override PhpTypeCode Emit(CodeGenerator/*!*/ codeGenerator) { LinqBuilder builder = codeGenerator.LinqBuilder; ILEmitter il = builder.IL; codeGenerator.EmitConversion(expression, PhpTypeCode.LinqSource); firstOp.Emit(builder); return PhpTypeCode.LinqSource; }
/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override PhpTypeCode Emit(CodeGenerator codeGenerator) { Statistics.AST.AddNode("TernaryEx"); Debug.Assert(access == AccessType.Read || access == AccessType.None); Label end_label = codeGenerator.IL.DefineLabel(); if (trueExpr != null) // standard ternary operator { Label else_label = codeGenerator.IL.DefineLabel(); // IF (<(bool) condition>) THEN codeGenerator.EmitConversion(condExpr, PhpTypeCode.Boolean); codeGenerator.IL.Emit(OpCodes.Brfalse, else_label); { codeGenerator.EmitBoxing(trueExpr.Emit(codeGenerator)); codeGenerator.IL.Emit(OpCodes.Br, end_label); } // ELSE codeGenerator.IL.MarkLabel(else_label, true); { codeGenerator.EmitBoxing(falseExpr.Emit(codeGenerator)); } } else { // ternary shortcut: var il = codeGenerator.IL; // condExpr ?? rightExpr il.EmitBoxing(condExpr.Emit(codeGenerator)); // IF (<stack>): il.Emit(OpCodes.Dup); il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean); codeGenerator.IL.Emit(OpCodes.Brtrue, end_label); // ELSE: { il.Emit(OpCodes.Pop); il.EmitBoxing(falseExpr.Emit(codeGenerator)); } } // END IF; codeGenerator.IL.MarkLabel(end_label, true); if (access == AccessType.None) { codeGenerator.IL.Emit(OpCodes.Pop); return PhpTypeCode.Void; } 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; } }