public override void Compile(Compiler compiler, Node node, NodeParent parent) { var body = (Body)node; if (body.RescueClauses != null) { for (int i = 0; i < body.RescueClauses.Count; i++) { compiler.AppendLine("try"); compiler.AppendLine("{"); compiler.Indent(); } } foreach (var stmt in body.Statements) { compiler.CompileNode(stmt, parent.CreateChild(node)); } if (body.RescueClauses != null) { foreach (var rescue in body.RescueClauses) { compiler.Dedent(); compiler.AppendLine("}"); compiler.AppendLine("catch(ErrorCarrier $err)"); compiler.AppendLine("{"); compiler.Indent(); StringBuilder clause = new StringBuilder(); bool first = true; foreach (var t in rescue.Types) { if (t.NodeType != NodeTypes.ConstantVariable) { throw new FructoseCompileException("Type constant must be supplied in rescue expression", rescue); } if (!first) { clause.Append(" && "); } first = false; clause.Append(string.Format("!is_a($err->val, '{0}')", Mangling.RubyIdentifierToPHP(((ConstantVariable)t).Name))); } compiler.AppendLine("if({0})", clause.ToString()); compiler.Indent(); compiler.AppendLine("throw $err;"); compiler.Dedent(); compiler.AppendLine("{0} = $err->val;", ((Variable)(rescue.Target ?? new GlobalVariable("!", rescue.Location))).ToPHPVariable()); foreach (var stmt in rescue.Statements) { compiler.CompileNode(stmt, parent.CreateChild(node)); } compiler.Dedent(); compiler.AppendLine("}"); } } }
public override void Compile(Compiler compiler, Node node, NodeParent parent) { if (parent.OfType <ClassDefinition>().Count() > 0) { throw new FructoseCompileException("Nested classes are not supported.", node); } if (((ClassDefinition)node).SuperClass != null && ((ClassDefinition)node).SuperClass.NodeType != NodeTypes.ConstantVariable) { throw new FructoseCompileException("Classes may only inherit from constant expressions", node); } var super = (ConstantVariable)((ClassDefinition)node).SuperClass; var cname = Mangling.RubyIdentifierToPHP(((ClassDefinition)node).QualifiedName.Name); compiler.AppendLine("class {0} extends {1}", cname, super == null ? "F_Object" : Mangling.RubyIdentifierToPHP(super.Name)); compiler.AppendLine("{"); compiler.Indent(); compiler.AppendLine("function __construct() { }"); compiler.AppendLine("public static function SF_new()"); compiler.AppendLine("{"); compiler.Indent(); compiler.AppendLine("$obj = new {0};", cname); compiler.AppendLine("$args = func_get_args();"); compiler.AppendLine("if(method_exists($obj,'F_initialize'))"); compiler.Indent(); compiler.AppendLine("call_user_func_array(array($obj,'F_initialize'), $args);"); compiler.Dedent(); compiler.AppendLine("return $obj;"); compiler.Dedent(); compiler.AppendLine("}"); foreach (var child in ((ClassDefinition)node).Body.Statements) { if (child.NodeType == NodeTypes.MethodDefinition) { compiler.CompileNode(child, parent.CreateChild(node)); continue; } throw new FructoseCompileException("Classes may only contain method declarations at this point", node); } compiler.Dedent(); compiler.AppendLine("}"); }
internal static string assignmentVar(LeftValue lval, NodeParent parent) { if (lval is LocalVariable) { var method = parent.OfType <MethodDefinition>().ToArray(); if (method.Length > 0 && method[0].Parameters != null && method[0].Parameters.Mandatory.Where(p => p.ToString() == ((LocalVariable)lval).Name).Count() > 0) { return("$" + Mangling.RubyIdentifierToPHP(((LocalVariable)lval).Name)); } if (parent.OfType <ClassDefinition>().Count() == 0) { return("$_locals->" + Mangling.RubyIdentifierToPHP(((LocalVariable)lval).Name)); } } return(((Variable)lval).ToPHPVariable()); }
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("}"); }
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); } }
public override void Compile(Compiler compiler, Node node, NodeParent parent) { var method = parent.OfType <MethodDefinition>().ToArray(); if (method.Length > 0 && method[0].Parameters != null && method[0].Parameters.Mandatory.Where(p => p.ToString() == ((LocalVariable)node).Name).Count() > 0) { compiler.AppendLine("$_stack[] = isset(${0}) ? (${0}) : (new F_NilClass);", Mangling.RubyIdentifierToPHP(((Variable)node).Name)); return; } if (parent.OfType <ClassDefinition>().Count() == 0) { compiler.AppendLine("$_stack[] = isset($_locals->{0}) ? ($_locals->{0}) : (new F_NilClass);", Mangling.RubyIdentifierToPHP(((Variable)node).Name)); return; } compiler.AppendLine("$_stack[] = isset({0}) ? ({0}) : (new F_NilClass);", ((Variable)node).ToPHPVariable()); }
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];"); } }
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)); }