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(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;
        }
Exemple #3
0
 void LazyExpr(out ElaExpression exp)
 {
     Expect(63);
     var lazy = new ElaLazyLiteral(t);
     Expr(out exp);
     lazy.Expression = exp;
     exp = lazy;
 }
Exemple #4
0
        private ElaExpression ValidateDoBlock(ElaExpression exp)
        {
            if (exp.Type == ElaNodeType.Juxtaposition && ((ElaJuxtaposition)exp).Parameters[0] == null)
            {
                var ext = ((ElaJuxtaposition)exp).Parameters[1];
                var ctx = default(ElaContext);

                if (ext.Type == ElaNodeType.Context)
                {
                    ctx = (ElaContext)ext;
                    ext = ctx.Expression;
                }

                var eqt = new ElaJuxtaposition { Spec = true };
                eqt.SetLinePragma(exp.Line, exp.Column);
                eqt.Target = new ElaNameReference(t) { Name = ">>=" };
                eqt.Parameters.Add(ext);

                var jux = new ElaJuxtaposition();
                jux.SetLinePragma(exp.Line, exp.Column);
                jux.Target = new ElaNameReference { Name = "point" };
                jux.Parameters.Add(new ElaUnitLiteral());
                eqt.Parameters.Add(new ElaLambda { Left = new ElaPlaceholder(), Right = jux });

                if (ctx != null)
                {
                    ctx.Expression = eqt;
                    exp = ctx;
                }
                else
                    exp = eqt;
            }

            var root = exp;

            while (true)
            {
                if (exp.Type == ElaNodeType.Juxtaposition)
                {
                    var juxta = (ElaJuxtaposition)exp;

                    if (juxta.Parameters.Count == 2)
                    {
                        juxta.Parameters[0] = Reduce(juxta.Parameters[0], juxta);
                        juxta.Parameters[1] = Reduce(juxta.Parameters[1], juxta);
                        exp = juxta.Parameters[1];
                    }
                    else
                        break;
                }
                else if (exp.Type == ElaNodeType.LetBinding)
                {
                    var lb = (ElaLetBinding)exp;
                    lb.Expression = Reduce(lb.Expression, lb);
                    exp = lb.Expression;
                }
                else if (exp.Type == ElaNodeType.Lambda)
                {
                    var lb = (ElaLambda)exp;
                    lb.Right = Reduce(lb.Right, lb);

                    if (lb.Left.Type != ElaNodeType.NameReference &&
                        lb.Left.Type != ElaNodeType.Placeholder)
                    {
                        var em = new ElaMatch();
                        em.SetLinePragma(lb.Left.Line, lb.Left.Column);
                        em.Expression = new ElaNameReference { Name = "$x01" };
                        em.Entries = new ElaEquationSet();

                        var eq1 = new ElaEquation();
                        eq1.SetLinePragma(lb.Left.Line, lb.Left.Column);
                        eq1.Left = lb.Left;
                        eq1.Right = lb.Right;
                        em.Entries.Equations.Add(eq1);

                        var eq2 = new ElaEquation();
                        eq2.SetLinePragma(lb.Left.Line, lb.Left.Column);
                        eq2.Left = new ElaNameReference { Name = "$x02" };
                        var errExp = new ElaJuxtaposition();
                        errExp.SetLinePragma(lb.Left.Line, lb.Left.Column);
                        errExp.Target = new ElaNameReference { Name = "failure" };
                        errExp.Parameters.Add(new ElaNameReference { Name = "$x02" });
                        eq2.Right = errExp;
                        em.Entries.Equations.Add(eq2);

                        lb.Left = new ElaNameReference { Name = "$x01" };
                        lb.Right = em;
                        exp = lb;
                    }
                    else
                        exp = lb.Right;
                }
                else
                    break;
            }

            var ret = new ElaLazyLiteral { Expression = root };
            ret.SetLinePragma(root.Line, root.Column);
            return ret;
        }