Пример #1
0
        public override ErlangValue Evaluate(ErlangProcess process)
        {
            ErlangValue last = null;
            ErlangExpressionBlockExpression def    = this;
            ErlangCompiledModule            module = GetModule();
            var  children   = def.GetChildren();
            bool doTailCall = false;

            do
            {
                doTailCall = false; // ensure we're reset from the last loop
                // evaluate each expression
                Debug.Assert(children.Length > 0);
                for (int i = 0; !doTailCall && i < children.Length; i++)
                {
                    var    expression = children[i];
                    string moduleName = null;
                    ErlangFunctionInvocationExpression function = null;
                    ErlangStackFrame tailCallCandidate          = null;
                    if (UseTailCalls && i == children.Length - 1 && expression is ErlangFunctionInvocationExpression && expression.IsLastChild)
                    {
                        // if last expression and it's a function invocation
                        function          = (ErlangFunctionInvocationExpression)expression;
                        moduleName        = function.Module ?? module.Name;
                        tailCallCandidate = process.CallStack.GetTailCallCandidate(
                            moduleName,
                            function.Function,
                            function.Parameters.Length);
                        doTailCall = tailCallCandidate != null;
                    }

                    if (doTailCall)
                    {
                        // evaluate parameters
                        var evaledParams = new ErlangValue[function.Parameters.Length];
                        for (int j = 0; j < function.Parameters.Length; j++)
                        {
                            var value = function.Parameters[j].Evaluate(process);
                            if (value.Kind == ErlangValueKind.Error)
                            {
                                return(value);
                            }
                            evaledParams[j] = value;
                        }

                        // prepare new frame
                        var newFrame = new ErlangStackFrame(tailCallCandidate.Module,
                                                            tailCallCandidate.Function,
                                                            tailCallCandidate.Airity);
                        process.CallStack.RewindForTailCall(newFrame);

                        // find the new definition
                        var group = module.GetFunction(function.Function, evaledParams.Length);
                        def = group.GetFunctionOverload(process, evaledParams);
                        if (def == null)
                        {
                            return(new ErlangAtom("no_such_tailcall_function"));
                        }
                        children = def.GetChildren();
                    }
                    else
                    {
                        // not a tailcall, just invoke normally
                        last = children[i].Evaluate(process);
                        if (last.Kind == ErlangValueKind.Error)
                        {
                            return(last); // decrease scope?
                        }
                    }
                }
            } while (doTailCall);

            return(last);
        }
Пример #2
0
        public static ErlangModule Compile(ErlangModuleSyntax syntax)
        {
            var module = new ErlangCompiledModule();

            // get the module's name
            var atom = syntax.Attributes.OfType <ErlangAttributeSyntax>().Single(at => at.Name.Text == "module").Parameters.Single().Value as ErlangAtomSyntax;

            module.Name = atom.Atom.Text;

            // get visibility
            var publicFunctions = new HashSet <Tuple <string, int> >();
            var exportAll       =
                (from at in syntax.Attributes.OfType <ErlangAttributeSyntax>()
                 where at.Name.Text == "compile" &&
                 at.Parameters.Count == 1
                 let param = at.Parameters[0]
                             where param.Value is ErlangAtomSyntax && ((ErlangAtomSyntax)param.Value).Atom.Text == "export_all"
                             select true).Any(b => b);

            if (!exportAll)
            {
                foreach (var functionReference in
                         from at in syntax.Attributes.OfType <ErlangAttributeSyntax>()
                         where at.Name.Text == "export" && at.Parameters.Count == 1
                         let param = at.Parameters[0]
                                     where param.Value is ErlangListRegularSyntax
                                     let list = (ErlangListRegularSyntax)param.Value
                                                from item in list.Items
                                                where item.Item is ErlangFunctionReferenceSyntax
                                                select(ErlangFunctionReferenceSyntax) item.Item)
                {
                    publicFunctions.Add(Tuple.Create(functionReference.Function.Text, (int)functionReference.Airity.IntegerValue));
                }
            }

            // compile functions
            var functionList      = new List <ErlangTuple>();
            var exportedFunctions = new List <ErlangTuple>();

            foreach (var group in syntax.FunctionGroups)
            {
                var key = Tuple.Create(group.Name, group.Airity);
                functionList.Add(new ErlangTuple(new ErlangAtom(group.Name), new ErlangNumber(group.Airity)));
                var function = (ErlangFunctionGroupExpression)ErlangExpression.Compile(group);
                function.Module   = module;
                function.IsPublic = exportAll || publicFunctions.Contains(key);
                if (function.IsPublic)
                {
                    exportedFunctions.Add(new ErlangTuple(new ErlangAtom(group.Name), new ErlangNumber(group.Airity)));
                }
                module.AddFunction(key.Item1, key.Item2, function);
            }

            functionList.Add(new ErlangTuple(new ErlangAtom("module_info"), new ErlangNumber(0)));
            functionList.Add(new ErlangTuple(new ErlangAtom("module_info"), new ErlangNumber(1)));
            exportedFunctions.Add(new ErlangTuple(new ErlangAtom("module_info"), new ErlangNumber(0)));
            exportedFunctions.Add(new ErlangTuple(new ErlangAtom("module_info"), new ErlangNumber(1)));

            module.AllFunctions = new ErlangList(functionList.ToArray());
            module.ModuleInfo   = new ErlangList(
                new ErlangTuple(new ErlangAtom("exports"), new ErlangList(exportedFunctions.ToArray())),
                new ErlangTuple(new ErlangAtom("imports"), new ErlangList()),    // always empty.  may be removed in future versions
                new ErlangTuple(new ErlangAtom("attributes"), new ErlangList()), // TODO: populate attributes
                new ErlangTuple(new ErlangAtom("compile"), new ErlangList())     // TODO: process compile options
                );

            return(module);
        }