Beispiel #1
0
        //Returns a variable from a local scope marked with NoInit flag
        //If such variable couldn't be found returns -1
        private ScopeVar GetNoInitVariable(ElaEquation s, out string name)
        {
            ScopeVar var;

            name = s.Left.GetName();

            if (s.IsFunction())
            {
                name = s.GetFunctionName();
            }

            if (CurrentScope.Locals.TryGetValue(name, out var))
            {
                //If it doesn't have a NoInit flag we are not good
                if ((var.Flags & ElaVariableFlags.NoInit) != ElaVariableFlags.NoInit)
                {
                    return(ScopeVar.Empty);
                }
                else
                {
                    var.Address = 0 | var.Address << 8; //Aligning it to local scope
                    return(var);
                }
            }

            return(ScopeVar.Empty);
        }
Beispiel #2
0
        //Adds a variable with NoInit flag to the current scope
        //This method also calculates additional flags and metadata for variables.
        //If a given binding if defined by pattern matching then all variables from
        //patterns are traversed using AddPatternVariable method.
        private bool AddNoInitVariable(ElaEquation exp)
        {
            var flags = exp.VariableFlags | ElaVariableFlags.NoInit;

            //This binding is not defined by PM
            if (exp.IsFunction())
            {
                var name = exp.GetFunctionName();

                if (name == null || Char.IsUpper(name[0]))
                {
                    AddError(ElaCompilerError.InvalidFunctionDeclaration, exp, FormatNode(exp.Left));
                    return(false);
                }

                AddVariable(name, exp.Left, flags | ElaVariableFlags.Function, exp.GetArgumentNumber());
            }
            else if (exp.Left.Type == ElaNodeType.NameReference && !((ElaNameReference)exp.Left).Uppercase)
            {
                var data = -1;

                if (exp.Right.Type == ElaNodeType.Builtin)
                {
                    //Adding required hints for a built-in
                    data   = (Int32)((ElaBuiltin)exp.Right).Kind;
                    flags |= ElaVariableFlags.Builtin;
                }
                else if (exp.Right.Type == ElaNodeType.Lambda)
                {
                    var fun = (ElaLambda)exp.Right;
                    flags |= ElaVariableFlags.Function;
                    data   = fun.GetParameterCount();
                }
                else if (exp.Right.IsLiteral())
                {
                    flags |= ElaVariableFlags.ObjectLiteral;
                }

                AddVariable(exp.Left.GetName(), exp, flags, data);
            }
            else
            {
                AddPatternVariables(exp.Left);
            }

            return(true);
        }
Beispiel #3
0
        //Compile an instance member. Argument classPrefix (module alias) is null if a class is
        //not prefixed, otherwise it should be used to lookup class members.
        private void CompileInstanceMember(string className, string classPrefix, ElaEquation s, LabelMap map,
                                           string currentTypePrefix, string currentType)
        {
            //Obtain a 'table' function of a class
            var name  = s.GetLeftName();
            var btVar = ObtainClassFunction(classPrefix, className, name, s.Line, s.Column);

            if (btVar.IsEmpty())
            {
                AddError(ElaCompilerError.MemberInvalid, s, name, className);
            }

            var builtin = (btVar.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin;
            var args    = 0;

            //Here we need to understand how many arguments a class function has.
            //If our declaration has less arguments (allowed by Ela) we need to do
            //eta expansion.
            if (builtin)
            {
                args = BuiltinParams((ElaBuiltinKind)btVar.Data);
            }
            else
            {
                args = btVar.Data;
            }

            //First we check if this binding is simply a function reference
            if (!TryResolveInstanceBinding(args, s.Right, map))
            {
                //Eta expansion should be done if a member is not a function literal
                //(it can be a partially applied function) or if a number of arguments
                //doesn't match.
                if (!s.IsFunction())
                {
                    EtaExpand(null, s.Right, map, args);
                }
                else if (s.GetArgumentNumber() < args)
                {
                    EtaExpand(null, s, map, args);
                }
                else
                {
                    CompileFunction(s, map);
                }
            }

            AddLinePragma(s);

            //It is possible if we are compiling a default instance (that can be
            //used to automatically generate instances).
            if (currentType != null)
            {
                //Depending whether this is a built-in class or a different approach is
                //used to add a member function.
                if (!builtin)
                {
                    PushVar(btVar);
                }
                else
                {
                    cw.Emit(Op.PushI4, (Int32)btVar.Data);
                }

                //We need to obtain a 'real' global ID of the type that we are extending. This
                //is done using this helper method.
                EmitSpecName(currentTypePrefix, "$$" + currentType, s, ElaCompilerError.UndefinedType);

                //Finally adding a member function.
                cw.Emit(Op.Addmbr);
            }
            else
            {
                var nm = "$default$" + name;

                //We are double binding the same default member which is not allowed within
                //the same module.
                if (globalScope.Locals.ContainsKey(nm))
                {
                    AddError(ElaCompilerError.DefaultMemberAlreadyExist, s, name, className);
                    globalScope.Locals.Remove(name);
                }

                var flags = ElaVariableFlags.None;
                var data  = -1;

                if (s.Right.Type == ElaNodeType.Builtin)
                {
                    flags = ElaVariableFlags.Builtin;
                    data  = (Int32)((ElaBuiltin)s.Right).Kind;
                }

                var dv = AddVariable(nm, s, flags, data);
                PopVar(dv);
            }
        }
Beispiel #4
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);
            }
        }
Beispiel #5
0
        //**********************************TEMPORARY DISABLED
        //This method checks if a given expression is a regular function definition or a function
        //defined through partial application of another function.
        private bool IsFunction(ElaEquation eq)
        {
            //A simple case - regular function definition
            if (eq.IsFunction())
                return true;

            //This may be a function defined through partial application. Here we only
            //recognize two cases - when the head is an ordinary identifier and if a head is
            //a fully qualified name.
            if (eq.Right != null && eq.Right.Type == ElaNodeType.Juxtaposition)
            {
                var jx = (ElaJuxtaposition)eq.Right;

                //A head is an identifier
                if (jx.Target.Type == ElaNodeType.NameReference)
                {
                    var sv = GetVariable(jx.Target.GetName(), CurrentScope, GetFlags.NoError, 0, 0);

                    //This is a partially applied function, therefore we can "count" this as a function.
                    return IfFunction(eq, sv, jx.Parameters.Count, false);
                }
                else if (jx.Target.Type == ElaNodeType.FieldReference) //This might be a fully qualified name
                {
                    var tr = (ElaFieldReference)jx.Target;

                    //A target can only be a name reference; otherwise we don't see it as a function.
                    if (tr.TargetObject.Type == ElaNodeType.NameReference)
                    {
                        CodeFrame _;
                        var sv = FindByPrefix(tr.TargetObject.GetName(), tr.FieldName, out _);

                        return IfFunction(eq, sv, jx.Parameters.Count, false);
                    }
                }
            }
            else if (eq.Right != null && eq.Right.Type == ElaNodeType.NameReference)
            {
                //This may be a function defined as an alias for another function.
                var sv = GetVariable(eq.Right.GetName(), CurrentScope, GetFlags.NoError, 0, 0);

                //This is an alias, we can "count" this as a function.
                return IfFunction(eq, sv, 0, true);
            }

            return false;
        }
Beispiel #6
0
        //Compile an instance member. Argument classPrefix (module alias) is null if a class is
        //not prefixed, otherwise it should be used to lookup class members.
        private void CompileInstanceMember(string className, string classPrefix, ElaEquation s, LabelMap map, 
            string currentTypePrefix, string currentType)
        {
            //Obtain a 'table' function of a class
            var name = s.GetLeftName();
            var btVar = ObtainClassFunction(classPrefix, className, name, s.Line, s.Column);

            if (btVar.IsEmpty())
                AddError(ElaCompilerError.MemberInvalid, s, name, className);

            var builtin = (btVar.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin;
            var args = 0;

            //Here we need to understand how many arguments a class function has.
            //If our declaration has less arguments (allowed by Ela) we need to do
            //eta expansion.
            if (builtin)
                args = BuiltinParams((ElaBuiltinKind)btVar.Data);
            else
                args = btVar.Data;

            //First we check if this binding is simply a function reference
            if (!TryResolveInstanceBinding(args, s.Right, map))
            {
                //Eta expansion should be done if a member is not a function literal
                //(it can be a partially applied function) or if a number of arguments
                //doesn't match.
                if (!s.IsFunction())
                    EtaExpand(null, s.Right, map, args);
                else if (s.GetArgumentNumber() < args)
                    EtaExpand(null, s, map, args);
                else
                    CompileFunction(s);
            }

            AddLinePragma(s);

            //It is possible if we are compiling a default instance (that can be
            //used to automatically generate instances).
            if (currentType != null)
            {
                //Depending whether this is a built-in class or a different approach is
                //used to add a member function.
                if (!builtin)
                    PushVar(btVar);
                else
                    cw.Emit(Op.PushI4, (Int32)btVar.Data);

                //We need to obtain a 'real' global ID of the type that we are extending. This
                //is done using this helper method.
                EmitSpecName(currentTypePrefix, "$$" + currentType, s, ElaCompilerError.UndefinedType);

                //Finally adding a member function.
                cw.Emit(Op.Addmbr);
            }
            else
            {
                var nm = "$default$" + name;

                //We are double binding the same default member which is not allowed within
                //the same module.
                if (globalScope.Locals.ContainsKey(nm))
                {
                    AddError(ElaCompilerError.DefaultMemberAlreadyExist, s, name, className);
                    globalScope.Locals.Remove(name);
                }

                var flags = ElaVariableFlags.None;
                var data = -1;

                if (s.Right.Type == ElaNodeType.Builtin)
                {
                    flags = ElaVariableFlags.Builtin;
                    data = (Int32)((ElaBuiltin)s.Right).Kind;
                }

                var dv = AddVariable(nm, s, flags, data);
                PopVar(dv);
            }
        }