Exemplo n.º 1
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);
        }
Exemplo n.º 2
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);
            }
        }
Exemplo n.º 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);
            }

            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);
            }
        }