Beispiel #1
0
        //Compiles a pattern as lazy by creating a thunk an initializing all pattern names with these thunks.
        private void CompileLazyPattern(int sys, ElaExpression pat, bool allowBang)
        {
            //First we need to obtain a list of all names, that declared in this pattern.
            var names = new List <String>();

            ExtractPatternNames(pat, names);

            //Walk through all names and create thunks
            for (var i = 0; i < names.Count; i++)
            {
                var      n = names[i];
                Label    funSkipLabel;
                int      address;
                LabelMap newMap;

                CompileFunctionProlog(null, 1, pat.Line, pat.Column, out funSkipLabel, out address, out newMap);

                var next = cw.DefineLabel();
                var exit = cw.DefineLabel();

                //As soon as already compiling pattern as lazy, we should enforce strictness even if
                //pattern is declared as lazy. Otherwise everything would crash, because here assume
                //that names are bound in this bound in the same scope.
                CompilePattern(1 | ((sys >> 8) << 8), pat, next, allowBang, true /*forceStrict*/);
                cw.Emit(Op.Br, exit);
                cw.MarkLabel(next);
                cw.Emit(Op.Failwith, (Int32)ElaRuntimeError.MatchFailed);
                cw.MarkLabel(exit);
                cw.Emit(Op.Nop);

                //Here we expect that our target variable is already declared by a pattern in the
                //same physical scope - so we can obtain and push it as a return value.
                var sv = GetVariable(n, pat.Line, pat.Column);
                PushVar(sv);
                CompileFunctionEpilog(null, 1, address, funSkipLabel);
                cw.Emit(Op.Newlazy);

                ScopeVar var;
                if (CurrentScope.Locals.TryGetValue(n, out var))
                {
                    //If it doesn't have a NoInit flag we are not good
                    if ((var.Flags & ElaVariableFlags.NoInit) == ElaVariableFlags.NoInit)
                    {
                        PopVar(var.Address = 0 | var.Address << 8); //Aligning it to local scope
                        CurrentScope.RemoveFlags(n, ElaVariableFlags.NoInit);
                    }
                }
            }
        }
Beispiel #2
0
        //Compile all declarations including function bindings, name bindings and bindings
        //defined by pattern matching.
        private void CompileDeclaration(ElaEquation s, LabelMap map, Hints hints)
        {
            //Check for some errors
            ValidateBinding(s);
            var partial = (s.VariableFlags & ElaVariableFlags.PartiallyApplied) == ElaVariableFlags.PartiallyApplied;
            var fun     = partial || s.IsFunction();

            if ((s.Left.Type != ElaNodeType.NameReference || ((ElaNameReference)s.Left).Uppercase) && !fun)
            {
                if ((hints & Hints.Lazy) == Hints.Lazy)
                {
                    CompileLazyBindingPattern(s, map);
                }
                else
                {
                    CompileBindingPattern(s, map);
                }
            }
            else
            {
                var nm   = default(String);
                var sv   = GetNoInitVariable(s, out nm);
                var addr = sv.Address;

                if (sv.IsEmpty())
                {
                    addr = AddVariable(s.Left.GetName(), s, s.VariableFlags, -1);
                }
                else
                {
                    CurrentScope.AddFlags(nm, ElaVariableFlags.Self);
                }

                //Compile expression and write it to a variable
                if (fun)
                {
                    //*****CURRENTLY NOT USED!
                    //Here we automatically eta expand functions defined through partial application
                    if (partial)
                    {
                        EtaExpand(s.Left.GetName(), s.Right, map, s.Arguments);
                    }
                    else if (CompileFunction(s, map))
                    {
                        CurrentScope.AddFlags(nm, ElaVariableFlags.Clean); //A function is clean
                    }
                }
                else
                {
                    map.BindingName = s.Left.GetName();

                    if ((hints & Hints.Lazy) == Hints.Lazy)
                    {
                        CompileLazyExpression(s.Right, map, Hints.None);
                    }
                    else
                    {
                        var ed = CompileExpression(s.Right, map, Hints.None, s);

                        if (ed.Type == DataKind.Builtin)
                        {
                            CurrentScope.AddFlagsAndData(nm, ElaVariableFlags.Builtin, ed.Data);
                        }
                    }
                }

                //Now, when done initialization, when can remove NoInit flags.
                if (!sv.IsEmpty())
                {
                    CurrentScope.RemoveFlags(nm, ElaVariableFlags.NoInit | ElaVariableFlags.Self);
                }

                AddLinePragma(s);
                PopVar(addr);
            }
        }