Example #1
0
		/// <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);
			}
		}
Example #2
0
		/// <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);
		}
Example #3
0
		/// <summary>
		/// Marks a sequence point "default".
		/// </summary>
		internal override void MarkSequencePoint(CodeGenerator/*!*/ codeGenerator)
		{
			codeGenerator.MarkSequencePoint(
			  position.FirstLine,
			  position.FirstColumn,
			  position.LastLine,
			  position.LastColumn + 1);
		}
Example #4
0
		/// <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);
			}
		}
Example #5
0
		/// <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();
			}

		}
Example #6
0
		/// <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);
			}
		}
Example #7
0
		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));
            }
		}
Example #8
0
		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);
                }
            }
		}
Example #9
0
		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
            }
		}
Example #10
0
		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);
		}
Example #11
0
		/// <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);
		}
Example #12
0
        /// <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;
        }
Example #13
0
		/// <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;
			}
		}
Example #14
0
		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);
		}