/// <summary> /// Compile a custom function definition /// </summary> private static void CompileFunctionDefinition(int level, bool debug, Node node, NanCodeWriter wr, Scope parameterNames) { // 1) Compile the func to a temporary string // 2) Inject a new 'def' op-code, that names the function and does an unconditional jump over it. // 3) Inject the compiled func // 4) Inject a new 'return' op-code if (node.Children.Count != 2) { throw new Exception("Function definition must have 3 parts: the name, the parameter list, and the definition.\r\n" + "Call like `def ( myFunc ( param1 param2 ) ( ... statements ... ) )`"); } var bodyNode = node.Children.Last.Value; var definitionNode = node.Children.First.Value; if (definitionNode.Children.Any(c => c.IsLeaf == false)) { throw new Exception("Function parameters must be simple names.\r\n" + "`def ( myFunc ( param1 ) ( ... ) )` is OK,\r\n" + "`def ( myFunc ( (param1) ) ( ... ) )` is not OK"); } if (bodyNode.Text != "()") { throw new Exception("Bare functions not supported. Wrap your function body in (parenthesis)"); } var functionName = definitionNode.Text; var argCount = definitionNode.Children.Count; ParameterPositions(parameterNames, definitionNode.Children.Select(c => c.Text), wr); var subroutine = Compile(bodyNode, level, debug, parameterNames, null, Context.Default); var tokenCount = subroutine.OpCodeCount(); if (debug) { wr.Comment("// Function definition : \"" + functionName + "\" with " + argCount + " parameter(s)"); } wr.FunctionDefine(functionName, argCount, tokenCount); wr.Merge(subroutine); if (subroutine.ReturnsValues) { // Add an invalid return opcode. This will show an error message. wr.InvalidReturn(); } else { // Add the 'return' call wr.Return(0); } // Then the runner will need to interpret both the new op-codes // This would include a return-stack-push for calling functions, // a jump-to-absolute-position by name // a jump-to-absolute-position by return stack & pop }
/// <summary> /// Compile a function call. Returns true if it's a call to return a value /// </summary> private static bool CompileFunctionCall(int level, bool debug, NanCodeWriter wr, Node node, Scope parameterNames) { var funcName = node.Text; if (Desugar.NeedsDesugaring(funcName)) { node = Desugar.ProcessNode(funcName, parameterNames, node); var frag = Compile(node, level + 1, debug, parameterNames, null, Context.Default); wr.Merge(frag); return(frag.ReturnsValues); } wr.Merge(Compile(node, level + 1, debug, parameterNames, null, Context.Default)); if (debug) { wr.Comment("// Function : \"" + funcName + "\" with " + node.Children.Count + " parameter(s)"); } if (funcName == "return") { wr.Return(node.Children.Count); } else { wr.FunctionCall(funcName, node.Children.Count); } return((funcName == "return") && (node.Children.Count > 0)); // is there a value return? }