Exemple #1
0
        private ExprData CompileLazy(ElaLazyLiteral exp, LabelMap map, Hints hints)
        {
            var ed = default(ExprData);

            //Try to optimize lazy section for a case
            //when a function application is marked as lazy
            if (!TryOptimizeLazy(exp, map, hints))
            {
                //Regular lazy section compilation
                //Create a closure around section
                ed = CompileLazyExpression(exp.Expression, map, hints);
            }

            if ((hints & Hints.Left) == Hints.Left)
            {
                AddValueNotUsed(map, exp);
            }

            return(ed);
        }
Exemple #2
0
        //This methods tries to optimize lazy section. It would only work when a lazy
        //section if a function application that result in saturation (no partial applications)
        //allowed. In such a case this method eliminates "double" function call (which would be
        //the result of a regular compilation logic). If this method fails than regular compilation
        //logic is used.
        private bool TryOptimizeLazy(ElaLazyLiteral lazy, LabelMap map, Hints hints)
        {
            var body = default(ElaExpression);

            //Only function application is accepted
            if ((body = lazy.Expression).Type != ElaNodeType.Juxtaposition)
            {
                return(false);
            }

            var funCall = (ElaJuxtaposition)body;

            //If a target is not a variable we can't check what is actually called
            if (funCall.Target.Type != ElaNodeType.NameReference)
            {
                return(false);
            }

            var varRef   = (ElaNameReference)funCall.Target;
            var scopeVar = GetVariable(varRef.Name, varRef.Line, varRef.Column);
            var len      = funCall.Parameters.Count;

            //Only one parameter is allowed
            if (len > 1)
            {
                return(false);
            }

            //If a target is not function we can't optimize it
            if ((scopeVar.VariableFlags & ElaVariableFlags.Function) != ElaVariableFlags.Function)
            {
                return(false);
            }

            //Only saturation case is optimized
            if (scopeVar.Data != funCall.Parameters.Count)
            {
                return(false);
            }

            //We can only optimize a thunk if a last parameter (that will be executed in a strict manner)
            //is either a primitive value or an already initialized variable.
            for (var i = 0; i < len; i++)
            {
                var p = funCall.Parameters[i];

                //Need to check if variable is already initialized.
                if (p.Type == ElaNodeType.NameReference)
                {
                    var ssv = GetVariable(p.GetName(), CurrentScope, GetFlags.NoError, 0, 0);

                    if ((ssv.Flags & ElaVariableFlags.NoInit) == ElaVariableFlags.NoInit)
                    {
                        return(false);
                    }
                }
                else if (p.Type != ElaNodeType.Primitive)
                {
                    return(false);
                }
            }

            for (var i = 0; i < len; i++)
            {
                CompileExpression(funCall.Parameters[len - i - 1], map, Hints.None, funCall);
            }

            var sl = len - 1;

            AddLinePragma(varRef);
            PushVar(scopeVar);

            //We partially apply function and create a new function
            for (var i = 0; i < sl; i++)
            {
                cw.Emit(Op.Call);
            }

            AddLinePragma(lazy);

            //LazyCall uses a function provided to create a thunk
            //and remembers last function arguments as ElaFunction.LastParameter
            cw.Emit(Op.LazyCall, len);
            return(true);
        }