Ejemplo n.º 1
0
        public override void Compile(Compiler compiler, Node node, NodeParent parent)
        {
            if (parent.OfType <MethodDefinition>().Count() > 0)
            {
                throw new FructoseCompileException("Nested methods are not supported.", node);
            }

            if (((MethodDefinition)node).Parameters.Mandatory.Length > ((MethodDefinition)node).Parameters.LeadingMandatoryCount)
            {
                throw new FructoseCompileException("Additional arguments after splats in methods are currently unsupported.", node);
            }

            string visibility = parent.OfType <ClassDefinition>().Count() > 0 ?
                                "public " : "";

            string signature = visibility + "function " + Mangling.RubyMethodToPHP(((MethodDefinition)node).Name) + "(";

            List <string> compiledParams = new List <string>();

            if (((MethodDefinition)node).Name.Contains("__lambda_"))
            {
                compiledParams.Add("$_locals");
            }
            compiledParams.Add("$block");
            foreach (var arg in ((MethodDefinition)node).Parameters.Mandatory)
            {
                compiledParams.Add("$" + Mangling.RubyIdentifierToPHP(arg.ToString()));
            }
            foreach (var arg in ((MethodDefinition)node).Parameters.Optional)
            {
                compiledParams.Add("$" + Mangling.RubyIdentifierToPHP(arg.Left.ToString()) + "=NULL");
            }
            signature += String.Join(", ", compiledParams);

            signature += ")";

            compiler.AppendLine(signature);
            compiler.AppendLine("{");
            compiler.Indent();

            compiler.AppendLine("$_stack = array();");
            compiler.AppendLine("if(!isset($_locals)) $_locals = new stdClass;");
            if (parent.OfType <ClassDefinition>().Count() > 0)
            {
                compiler.AppendLine("if(!isset($_locals->self)) $_locals->self = $this;");
            }
            else
            {
                compiler.AppendLine("global $_gthis;");
                compiler.AppendLine("if(!isset($_locals->self)) $_locals->self = $_gthis;");
            }
            compiler.AppendLine("if(!isset($_locals->block)) $_locals->block = $block;");

            compiler.AppendLine("foreach(array(" + string.Join(", ", ((MethodDefinition)node).Parameters.Mandatory
                                                               .Select(arg => "\"" + Mangling.RubyIdentifierToPHP(arg.ToString()) + "\"")
                                                               .ToArray()) + ") as $parm)");
            compiler.Indent();
            compiler.AppendLine("$_locals->$parm = $$parm;");
            compiler.Dedent();

            foreach (var arg in ((MethodDefinition)node).Parameters.Optional)
            {
                string parm = Mangling.RubyIdentifierToPHP(arg.Left.ToString());
                compiler.AppendLine("if($" + parm + " === NULL) {");
                compiler.Indent();
                compiler.CompileNode(arg.Right, parent.CreateChild(node));
                compiler.AppendLine("$_locals->" + parm + " = array_pop($_stack);");
                compiler.Dedent();
                compiler.AppendLine("} else {");
                compiler.Indent();
                compiler.AppendLine("$_locals->" + parm + " = $" + parm + ";");
                compiler.Dedent();
                compiler.AppendLine("}");
            }

            if (((MethodDefinition)node).Parameters.Unsplat != null)
            {
                compiler.AppendLine("$_locals->" + Mangling.RubyIdentifierToPHP(((MethodDefinition)node).Parameters.Unsplat.ToString()) + " = "
                                    + "F_Array::__from_array(array_slice(func_get_args(), " + compiledParams.Count + "));");
            }

            compiler.AppendLine("global $_lambda_objs;");
            compiler.AppendLine("global $_globals;");

            foreach (var child in ((MethodDefinition)node).Body.Statements)
            {
                compiler.CompileNode(child, parent.CreateChild(node));
            }

            if (((MethodDefinition)node).Name.Contains("__lambda_"))
            {
                compiler.AppendLine("return array( 'locals' => $_locals, 'retval' => array_pop($_stack) );");
            }
            else
            {
                compiler.AppendLine("return array_pop($_stack);");
            }

            compiler.Dedent();
            compiler.AppendLine("}");
        }
Ejemplo n.º 2
0
        public override void Compile(Compiler compiler, IronRuby.Compiler.Ast.Node node, NodeParent parent)
        {
            string mname = Mangling.RubyMethodToPHP(((MethodCall)node).MethodName);

            if (compilerMethods.ContainsKey(mname))
            {
                compilerMethods[mname].Compile(compiler, (MethodCall)node, parent);
                return;
            }

            if (((MethodCall)node).Arguments != null)
            {
                foreach (var arg in ((MethodCall)node).Arguments.Expressions.Reverse())
                {
                    compiler.CompileNode(arg, parent.CreateChild(node));
                }
            }

            bool callStatic = false;

            if (((MethodCall)node).Target == null)
            {
                compiler.AppendLine("$_stack[] = $_locals->self;");
            }
            else
            {
                if (((MethodCall)node).Target.NodeType == NodeTypes.ConstantVariable)
                {
                    callStatic = true;
                }
                else
                {
                    compiler.CompileNode(((MethodCall)node).Target, parent.CreateChild(node));
                }
            }

            if (((MethodCall)node).Block != null)
            {
                compiler.AppendLine("$_lambda_objs_offset = count($_lambda_objs);");
                compiler.AppendLine("$_lambda_objs[] = $_locals;");
            }

            if (((MethodCall)node).Block != null)
            {
                compiler.AppendLine("try");
                compiler.AppendLine("{");
                compiler.Indent();
            }

            string call = callStatic
                ? string.Format("$_stack[] = {0}::S{1}(", Mangling.RubyIdentifierToPHP(((ConstantVariable)((MethodCall)node).Target).Name), mname)
                : string.Format("$_stack[] = array_pop($_stack)->{0}(", mname);

            if (((MethodCall)node).Block != null)
            {
                if (((MethodCall)node).Block.NodeType == NodeTypes.BlockReference)
                {
                    var expr = ((BlockReference)((MethodCall)node).Block).Expression;
                    if (expr.NodeType != NodeTypes.LocalVariable &&
                        parent.OfType <MethodDefinition>().Count() != 1 &&
                        parent.OfType <MethodDefinition>().Single().Parameters != null &&
                        parent.OfType <MethodDefinition>().Single().Parameters.Block != null &&
                        ((LocalVariable)expr).Name != parent.OfType <MethodDefinition>().Single().Parameters.Block.Name)
                    {
                        throw new FructoseCompileException("Block references not referring to a block parameter are not yet supported.", ((MethodCall)node).Block);
                    }

                    call += "$block";
                }
                else
                {
                    var block_mname = compiler.Transformations.RefactoredBlocksToMethods[(BlockDefinition)((MethodCall)node).Block];

                    call += "create_function('',sprintf('global $_lambda_objs; $args = func_get_args(); $offset = %d; $_locals = $_lambda_objs[$offset]; array_unshift($args, $_locals); $r = call_user_func_array(";

                    if (parent.OfType <ClassDefinition>().Count() > 0)
                    {
                        call += "array($_locals->self,\"" + Mangling.RubyIdentifierToPHP(block_mname) + "\")";
                    }
                    else
                    {
                        call += "\"" + Mangling.RubyIdentifierToPHP(block_mname) + "\"";
                    }

                    call += ", $args); $_lambda_objs[$offset] = $r[\"locals\"]; return $r[\"retval\"];',$_lambda_objs_offset))";
                }
            }
            else
            {
                call += "NULL";
            }

            if (((MethodCall)node).Arguments != null)
            {
                for (int i = 0; i < ((MethodCall)node).Arguments.Expressions.Length; i++)
                {
                    call += ", array_pop($_stack)";
                }
            }

            compiler.AppendLine(call + ");");

            if (((MethodCall)node).Block != null)
            {
                compiler.Dedent();
                compiler.AppendLine("}");
                compiler.AppendLine("catch(ReturnFromBlock $rfb)");
                compiler.AppendLine("{");
                compiler.Indent();
                compiler.AppendLine("return $rfb->val;");
                compiler.Dedent();
                compiler.AppendLine("}");
                compiler.AppendLine("$_locals = $_lambda_objs[$_lambda_objs_offset];");
            }
        }
Ejemplo n.º 3
0
        public override void Compile(Compiler compiler, Node node, NodeParent parent)
        {
            if (node is IsDefinedExpression)
            {
                var ide = (IsDefinedExpression)node;
                switch (ide.Expression.NodeType)
                {
                case NodeTypes.MethodCall:
                    compiler.AppendLine("$_stack[] = F_TrueClass::__from_bool(function_exists('{0}'));", Mangling.RubyMethodToPHP(((MethodCall)ide.Expression).MethodName));
                    return;

                case NodeTypes.ConstantVariable:
                    compiler.AppendLine("$_stack[] = F_TrueClass::__from_bool(class_exists('{0}'));", Mangling.RubyMethodToPHP(((ConstantVariable)ide.Expression).Name));
                    return;

                case NodeTypes.ClassVariable:
                case NodeTypes.GlobalVariable:
                case NodeTypes.InstanceVariable:
                case NodeTypes.LocalVariable:
                    compiler.AppendLine("$_stack[] = F_TrueClass::__from_bool(isset({0}));", ((Variable)ide.Expression).ToPHPVariable());
                    return;

                default:
                    throw new FructoseCompileException("Not supported yet: defined?( " + ide.Expression.NodeType.ToString() + " )", ide.Expression);
                }
            }
            else
            {
                throw new FructoseCompileException("Not supported yet: " + node.ToString(), node);
            }
        }
Ejemplo n.º 4
0
        public override void Compile(Compiler compiler, IronRuby.Compiler.Ast.Node node, NodeParent parent)
        {
            var sae = (SimpleAssignmentExpression)node;

            // substitute a method call of []= rather than the crap that ironruby's parser produces:
            switch (sae.Left.NodeType)
            {
            case NodeTypes.ArrayItemAccess:
                var aia = (ArrayItemAccess)sae.Left;
                compiler.CompileNode(new MethodCall(aia.Array, "[]=", new Arguments(aia.Arguments.Expressions.Concat(new[] { sae.Right }).ToArray()), sae.Location), parent.CreateChild(node));
                return;

            case NodeTypes.AttributeAccess:
                var aa = (AttributeAccess)sae.Left;
                compiler.CompileNode(new MethodCall(aa.Qualifier, aa.Name, new Arguments(sae.Right), aa.Location), parent.CreateChild(node));
                return;
            }

            compiler.CompileNode(sae.Right, parent.CreateChild(node));
            if (sae.Operation != null)
            {
                compiler.AppendLine("$_stack[] = {0};", assignmentVar(sae.Left, parent));
                compiler.AppendLine("$_stack[] = array_pop($_stack)->{0}(NULL, array_pop($_stack));", Mangling.RubyMethodToPHP(sae.Operation));
            }
            compiler.AppendLine("{0} = $_stack[count($_stack)-1];", assignmentVar(sae.Left, parent));
        }