Exemple #1
0
        /// <summary>
        /// Return all the members of a class
        /// </summary>
        /// <param name="classIndex"></param>
        /// <param name="si"></param>
        /// <param name="searchingBase">if searchingBase == true, the MemberType.FromBase of the returned members will be set </param>
        /// <param name="isStatic"></param>
        /// <param name="includeConstructor"></param>
        /// <returns></returns>
        private static List <KeyValuePair <MemberType, string> > GetClassMembers(int classIndex, ScopeInfo si, bool searchingBase, bool isStatic, bool includeConstructor)
        {
            List <KeyValuePair <MemberType, string> > members = new List <KeyValuePair <MemberType, string> >();

            ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex];

            // 1. search the member variable
            if (cn.symbols != null && !searchingBase) // when searching base, no need to populate the member variable, it has already been added in code gen
            {
                foreach (ProtoCore.DSASM.SymbolNode sn in cn.symbols.symbolList.Values.Where(x => x.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex))
                {
                    if (GetAccessLevel(si.ClassScope, sn.classScope) >= sn.access &&
                        isStatic == sn.isStatic &&
                        !sn.name.StartsWith("%") /* block the internally generated members*/)
                    {
                        KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Fields | AccessToMemberType(sn.access) | StaticToMemberType(isStatic) | BaseToMemberType(sn.classScope != classIndex), sn.name);
                        members.Add(member);
                    }
                }
            }
            // 2. search the member functions and constructors
            if (cn.vtable != null)
            {
                foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList)
                {
                    // get static members
                    if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access && isStatic == pn.isStatic && pn.isConstructor == false && !pn.name.StartsWith("%") && pn.isAutoGenerated != true)
                    {
                        KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Methods | AccessToMemberType(pn.access) | StaticToMemberType(pn.isStatic) | BaseToMemberType(searchingBase) | ConstructorToMemberType(pn.isConstructor), pn.name);
                        members.Add(member);
                    }
                    // get constructor
                    if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access && true == pn.isConstructor && includeConstructor == true && !pn.name.StartsWith("%") && pn.isAutoGenerated != true)
                    {
                        KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Methods | AccessToMemberType(pn.access) | StaticToMemberType(pn.isStatic) | BaseToMemberType(searchingBase) | ConstructorToMemberType(pn.isConstructor), pn.name);
                        members.Add(member);
                    }
                }
            }

            // 3. search base class
            if (cn.baseList != null) // Note, for nonstatic members it is been copied to the derived class, hence they have been added already
            {
                foreach (int baseIndex in cn.baseList)
                {
                    // searching base will be set to true since we are searching the base class now
                    members.AddRange(GetClassMembers(baseIndex, si, true, isStatic, false));
                }
            }

            return(members);
        }
Exemple #2
0
        private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetConstructors(int classIndex, string function, ScopeInfo si)
        {
            ProtoCore.DSASM.ClassNode       cn     = compileState.ClassTable.ClassNodes[classIndex];
            ProtoCore.DSASM.AccessSpecifier access = GetAccessLevel(si.ClassScope, classIndex);
            List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > functionList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >();

            if (cn.vtable == null)
            {
                return(functionList);
            }
            foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList)
            {
                if (pn.name == function && pn.isConstructor && access >= pn.access)
                {
                    functionList.Add(new KeyValuePair <int, ProtoCore.DSASM.ProcedureNode>(classIndex, pn));
                }
            }

            // no need to search base constructors,

            return(functionList);
        }
Exemple #3
0
 /// <summary>
 /// This is a helper methods, when the IDE passes "A.foo" or "A." we are always expecting both the constructors and static member functions
 /// This method will search them both making use of the existing GetMemberFunctions and GetConstructors method
 /// </summary>
 /// <param name="classIndex"></param>
 /// <param name="function"></param>
 /// <param name="si"></param>
 /// <returns></returns>
 private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetStatisMemberFunctionAndConstructor(int classIndex, string function, ScopeInfo si)
 {
     return(GetMemberFunctions(classIndex, function, si, true).Concat(GetConstructors(classIndex, function, si)).ToList());
 }
Exemple #4
0
        private static ProtoCore.DSASM.SymbolNode GetMemberVariable(int classIndex, string field, ScopeInfo si, bool isStatic)
        {
            if (field.IndexOfAny(new char[] { '[', ']' }) != -1)
            {
                string[] tokens = TokenizeArrayIndexers(field);
                field = tokens[0];
            }

            // one search is enough, because the code gen will copy all the accessible base
            // class member variabs to the current class table, life easier
            ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex];
            if (cn.symbols == null)
            {
                return(null);
            }
            for (int ix = cn.symbols.symbolList.Values.Count - 1; ix >= 0; --ix)
            {
                // we should search in reverse order because in code gen
                // the base class member variable is added first
                // hence we shoud search the its own variable first
                ProtoCore.DSASM.SymbolNode sn = cn.symbols.symbolList[ix];
                if (sn.functionIndex != ProtoCore.DSASM.Constants.kInvalidIndex ||
                    sn.name != field ||
                    isStatic != sn.isStatic)
                {
                    continue;
                }

                // here we have found a variable with the same name
                if (GetAccessLevel(si.ClassScope, sn.classScope) >= sn.access)
                {
                    return(sn);
                }
            }

            return(null);
        }
Exemple #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="classIndex"></param>
        /// <param name="function"></param>
        /// <param name="si"></param>
        /// <param name="isStatic"></param>
        /// <returns>
        /// the key means the function index of thr procedure, not that it may be different from argument classIndex if
        /// the procedure comes from its base class
        /// </returns>
        private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetMemberFunctions(int classIndex, string function, ScopeInfo si, bool isStatic)
        {
            ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex];
            List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > functionList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >();

            // first search its own functions
            if (cn.vtable == null)
            {
                return(functionList);
            }
            foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList)
            {
                if (pn.isConstructor ||
                    pn.name != function ||
                    pn.isStatic != isStatic)
                {
                    continue;
                }

                // here we have found a function with the same name
                // check if it is accessible
                if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access)
                {
                    functionList.Add(new KeyValuePair <int, ProtoCore.DSASM.ProcedureNode>(classIndex, pn));
                }
            }

            // continue to search its base class
            foreach (int baseClass in cn.baseList)
            {
                functionList.AddRange(GetMemberFunctions(baseClass, function, si, isStatic));
            }

            return(functionList);
        }
        /// <summary>
        /// search global methos by name
        /// </summary>
        /// <param name="si"></param>
        /// <param name="function"></param>
        /// <returns>the key value pair is to keep consistent with the return data type from GetMemberFunctions, GetConstructors</returns>
        private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetGlobalMethod(ScopeInfo si, string function)
        {
            // in global scope, just search the global functions
            List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > functionList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >();

            if (si.BlockId == ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                return(functionList);
            }

            ProtoCore.DSASM.CodeBlock cb = core.CodeBlockList[si.BlockId];
            while (cb != null)
            {
                if (null == cb.procedureTable)
                {
                    cb = cb.parent;
                    continue;
                }

                // search by name
                IEnumerable <ProtoCore.DSASM.ProcedureNode> pns = cb.procedureTable.procList.Where(x => x.name == function);
                if (null == pns || (pns.Count() == 0))
                {
                    cb = cb.parent; // search its parent
                    continue;
                }
                foreach (ProtoCore.DSASM.ProcedureNode pn in pns)
                {
                    functionList.Add(new KeyValuePair <int, ProtoCore.DSASM.ProcedureNode>(ProtoCore.DSASM.Constants.kInvalidIndex, pn));
                }
                break;
            }

            return(functionList);
        }
        /// <summary>
        /// Figure out the ClassScope, FunctionIndex, BlockId of a given position represented by the three parameters
        /// </summary>
        /// <param name="line"></param>
        /// <param name="col"></param>
        /// <param name="src">ds file name</param>
        /// <returns></returns>
        private static ScopeInfo GetScopeInfo(ProtoCore.CodeModel.CodePoint cp)
        {
            // initialize scope info to invalid values, -1
            ScopeInfo si = new ScopeInfo()
            {
                BlockId       = ProtoCore.DSASM.Constants.kInvalidIndex,
                FunctionIndex = ProtoCore.DSASM.Constants.kInvalidIndex,
                ClassScope    = ProtoCore.DSASM.Constants.kInvalidIndex,
            };

            // search if it is inside any class scope
            foreach (KeyValuePair <int, ProtoCore.CodeModel.CodeRange> cr in codeRangeTable.ClassBlock.RangeTable)
            {
                if (cr.Value.InsideRange(cp))
                {   // yes, inside a class scope
                    si.ClassScope = cr.Key;

                    // check if it is inside a function
                    foreach (KeyValuePair <int, ProtoCore.CodeModel.CodeRange> cr2 in codeRangeTable.ClassBlock.FunctionTable[si.ClassScope].RangeTable)
                    {
                        if (cr2.Value.InsideRange(cp))
                        {
                            // yes, it is inside a function
                            si.FunctionIndex = cr2.Key;
                            break;
                        }
                    }
                    break;
                }
            }

            // search what is the block id
            //
            // usually when the class scope is not -1, the block id should be always 0 since class is only allowed at global scope
            // However, language block is allowed in an expression, so it is possible that the current scope is inside a language block which is inside
            // a member function of a class
            // eg: class A { def foo : int() { return = [Imperative] { return = 10; } } }
            // it is still necessary to figure out what is the actual block ID
            IEnumerable <KeyValuePair <int, ProtoCore.CodeModel.CodeRange> > blocks = codeRangeTable.CodeBlock.RangeTable.Where(x => x.Value.InsideRange(cp));

            // minCr holds the inner most block range which contais the target position
            ProtoCore.CodeModel.CodeRange minCr = new ProtoCore.CodeModel.CodeRange();
            if (blocks.Count() > 0)
            {
                minCr = blocks.ElementAt(0).Value;
            }
            foreach (KeyValuePair <int, ProtoCore.CodeModel.CodeRange> block in blocks)
            {
                if (minCr.InsideRange(block.Value))
                {
                    // more inner scope found, update minCr and si.BlockId
                    minCr      = block.Value;
                    si.BlockId = block.Key;
                }
            }

            // not inside any class scope, need to figure out which function it is in
            // Note: it is illegal to have a function inside a language block if the language block is inside a function
            // eg: def foo : int() { return = [Imperative] { def foo2 : int() { return = 20 }; return = foo2(); }; }
            // so there is no need to search the fucntion index if it is inside a class
            if (si.ClassScope == ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                Dictionary <int, FunctionRangeTable> functionTable = codeRangeTable.CodeBlock.FunctionTable;
                if (null != functionTable && (si.BlockId >= 0) && (si.BlockId < functionTable.Count))
                {
                    // search its function index
                    foreach (KeyValuePair <int, ProtoCore.CodeModel.CodeRange> cr in codeRangeTable.CodeBlock.FunctionTable[si.BlockId].RangeTable)
                    {
                        if (cr.Value.InsideRange(cp))
                        {
                            si.FunctionIndex = cr.Key;
                            break;
                        }
                    }
                }
            }

            return(si);
        }
        /// <summary>
        /// get the type of an identifier based on its location and name
        /// </summary>
        /// <param name="si">where is the ident</param>
        /// <param name="ident">name of the ident</param>
        /// <param name="cp">
        /// where is the ident, not the same usage as parameter "si",
        /// this is used to see if the ident location is before its definition or after its definition
        /// </param>
        /// <returns></returns>
        private static int GetIdentType(ScopeInfo si, string ident, ProtoCore.CodeModel.CodePoint cp)
        {
            if (si.ClassScope == ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                // Not inside any class
                ProtoCore.DSASM.CodeBlock        cb         = null;
                List <ProtoCore.DSASM.CodeBlock> codeBlocks = core.CodeBlockList;
                if (null != codeBlocks && (si.BlockId >= 0) && (si.BlockId < codeBlocks.Count))
                {
                    cb = codeBlocks[si.BlockId];
                }

                // loop used to search its parent block
                while (cb != null)
                {
                    // search by matching ident name and function index
                    IEnumerable <ProtoCore.DSASM.SymbolNode> sns = cb.symbolTable.symbolList.Values.Where(x =>
                                                                                                          x.name == ident &&
                                                                                                          x.functionIndex == si.FunctionIndex &&
                                                                                                          x.classScope == ProtoCore.DSASM.Constants.kInvalidIndex);

                    if (sns.Count() > 0) // found something
                    {
                        ProtoCore.DSASM.SymbolNode symbolNode = sns.ElementAt(0);

                        // if it is argument, it is visible every where inside the fucntion
                        if (symbolNode.isArgument == true)
                        {
                            return(GetSymbolType(symbolNode));
                        }

                        // check if the variable definition location is before our searching site
                        if (cp.Before(identLocationTable.Table[symbolNode]))
                        {
                            return(GetSymbolType(symbolNode));
                        }

                        // if not argument, check if it is defined some where in the imported files, if yes, it is visible
                        CodeFile file = identLocationTable.Table[symbolNode].SourceLocation;
                        if (importTable.IsImported(cp.SourceLocation.FilePath, file.FilePath))
                        {
                            return(GetSymbolType(symbolNode));
                        }
                    }

                    if (si.FunctionIndex != ProtoCore.DSASM.Constants.kInvalidIndex)
                    {
                        // no name look up inside a fucntion
                        // TODO: This may need to change, since we are now allowing to access global variables inside a fucntion
                        break;
                    }

                    // update cb to its parent block
                    cb = cb.parent;
                }
            }
            else
            {
                // we are inside a function
                // check if it is this keyword
                if (ident == "this")
                {
                    // the type is the class itself
                    return(si.ClassScope);
                }

                // inside a class scope
                ProtoCore.DSASM.CodeBlock  cb = core.CodeBlockList[si.BlockId];
                ProtoCore.DSASM.SymbolNode sn = null;
                while (cb.parent != null)
                {
                    // if it is inside a language block which is inside a function
                    IEnumerable <ProtoCore.DSASM.SymbolNode> sns = cb.symbolTable.symbolList.Values.Where(x => x.name == ident);
                    if (sns.Count() > 0 &&
                        (sns.ElementAt(0).isArgument == true ||
                         importTable.IsImported(cp.SourceLocation.FilePath, identLocationTable.Table[sns.ElementAt(0)].SourceLocation.FilePath) ||
                         cp.Before(identLocationTable.Table[sns.ElementAt(0)])))
                    {
                        sn = sns.ElementAt(0);
                        break;
                    }

                    cb = cb.parent;
                }

                if (sn == null)
                {
                    // search local variables in the funtion
                    IEnumerable <ProtoCore.DSASM.SymbolNode> sns = core.ClassTable.ClassNodes[si.ClassScope].symbols.symbolList.Values.Where(x => x.name == ident && x.functionIndex == si.FunctionIndex);
                    if (sns.Count() > 0)
                    {
                        sn = sns.ElementAt(0);
                    }
                    else
                    {
                        // the final search, search the class member variables
                        sn = GetMemberVariable(si.ClassScope, ident, si, false);
                        //sn = GetClassMemberVariable(si.ClassScope, ident);
                    }
                }

                if (sn != null)
                {
                    return(sn.datatype.UID);
                }
            }

            return(ProtoCore.DSASM.Constants.kInvalidIndex);
        }
        /// <summary>
        /// This method gathers the list of method signatures (overloaded) given a method name.
        /// </summary>
        public static List <MethodSignature> GetMethodParameterList(int line, int col, string identList, string file)
        {
            // This whole method will be made obsolete.
            if (null != CoreCodeGen.AutoCompleteEngine)
            {
                return(new List <MethodSignature>());
            }

            // We need to compile the input source code first.
            System.Diagnostics.Debug.Assert(null != AutoCompletionHelper.core);
            if (string.IsNullOrEmpty(identList) || (null == AutoCompletionHelper.core))
            {
                return(new List <MethodSignature>());
            }

            if (null == CoreCodeGen.CodeRangeTable)
            {
                return(new List <MethodSignature>());
            }

            ProtoCore.CodeModel.CodePoint cp = new ProtoCore.CodeModel.CodePoint()
            {
                LineNo         = line,
                CharNo         = col,
                SourceLocation = new ProtoCore.CodeModel.CodeFile()
                {
                    FilePath = file
                }
            };

            // figure out the function index, class index and block id of the typing site
            // based on the code range table
            ScopeInfo si = GetScopeInfo(cp);

            // split the identifier list
            // a.b.c -> { "a", "b", "c" }
            char[]   seperator = { '.' };
            string[] idents    = identList.Split(seperator, StringSplitOptions.RemoveEmptyEntries);

            if (idents.Length <= 0)
            {
                return(new List <MethodSignature>());
            }

            int  finalType = ProtoCore.DSASM.Constants.kInvalidIndex;
            bool isStatic  = false;

            // this is slightly different from autocompletion
            // a.b.c.e.f.foo, foo is a class name, so we should traverse only up to f, not foo, to get the type of "f"
            if (idents.Length >= 2)
            {
                finalType = TraverseIdentList(idents, idents.Length - 1, si, cp, out isStatic);
                if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex)
                {
                    return(new List <MethodSignature>());
                }
            }

            List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > methodList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >();

            if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex && si.ClassScope == ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                // the IDE has passed us something like "foo" and we are not inside any classes
                // only global function should be searched
                methodList = GetGlobalMethod(si, idents[0]);
            }
            else if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex && si.ClassScope != ProtoCore.DSASM.Constants.kInvalidIndex)
            {
                // the IDE has passed us something like "foo" and we are inside class with index of finalType
                // search the member function of finalType with a name foo
                methodList = GetMemberFunctions(si.ClassScope, idents[idents.Length - 1], si, isStatic);
            }
            else if (isStatic)
            {
                // the IDE has passed us something like "A.foo", "A" is a class name
                // search the static functions and constructors of finalType with a name "foo"
                methodList = GetStatisMemberFunctionAndConstructor(finalType, idents[idents.Length - 1], si);
            }
            else
            {
                // the IDE has passed us something like "a.b.c.f.foo",
                // search the normal member functions of type finalType with a name "foo", Note: finalType is the type of "f"
                methodList = GetMemberFunctions(finalType, idents[idents.Length - 1], si, isStatic);
            }

            // Note, the .NET Distinct method will keep the earlier element and delete the later one,
            // this ensures that if both the derived class and the base class have exactly the same function signature,
            // the base class one will be removed and the derived one will be kept, which is expected
            return(methodList.Distinct(new DeplicateMethodSignatureRemover()).Select(x => new MethodSignature(x.Value, x.Key == ProtoCore.DSASM.Constants.kInvalidIndex ? null : core.ClassTable.ClassNodes[x.Key].name)).ToList());
        }
 internal ScopedArray(ScopeInfo scopeInfo, string name)
 {
     this.arrayName = name;
     this.scopeInfo = scopeInfo;
 }