public bool Before(CodePoint cp) { if (cp.SourceLocation != SourceLocation) return false; return (cp.LineNo < LineNo || (cp.LineNo == LineNo && (cp.CharNo < CharNo))); }
public bool InsideRange(CodePoint cp) { // Reject the obvious cases first (codes in different files)... if (cp.SourceLocation != StartInclusive.SourceLocation) { return(false); } if (cp.SourceLocation != EndExclusive.SourceLocation) { return(false); } if (StartInclusive.LineNo <= cp.LineNo && EndExclusive.LineNo >= cp.LineNo) { if (StartInclusive.LineNo == cp.LineNo && StartInclusive.CharNo > cp.CharNo) { return(false); } else if (EndExclusive.LineNo == cp.LineNo && EndExclusive.CharNo < cp.CharNo) { return(false); } return(true); } return(false); }
public bool SetBreakpointAt(ProtoCore.CodeModel.CodePoint breakpoint) { if (null == vmWorker) { return(false); } return(vmWorker.SetBreakpointAt(breakpoint)); }
public bool Before(CodePoint cp) { if (cp.SourceLocation != SourceLocation) { return(false); } return(cp.LineNo < LineNo || (cp.LineNo == LineNo && (cp.CharNo < CharNo))); }
/// <summary> /// API method for autocompletion /// </summary> /// <param name="line"></param> /// <param name="col"></param> /// <param name="src">source code</param> /// <param name="identlist">a.b.c.e.f</param> /// <param name="file">can be null the the file has not been saved</param> /// <returns>a list of class members</returns> public static List <KeyValuePair <MemberType, string> > GetList(int line, int col, string src, string identlist, string file) { List <KeyValuePair <MemberType, string> > members = new List <KeyValuePair <MemberType, string> >(); // This whole method will be made obsolete. if (null != CoreCodeGen.AutoCompleteEngine) { return(members); } // We need to compile the input source code first. AutoCompletionHelper.Reset(); if (AutoCompletionHelper.Compile(src, file) == false) { return(members); } 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(members); } bool isStatic = false; // a.b.c.e -> traverse and get the type of 'e', // isStatic will be true only when the identifier list is "A" and "A" is a class name int finalType = TraverseIdentList(idents, idents.Length, si, cp, out isStatic); if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex) { return(members); } // find out all the class members based on finalType // Distinct method is used to filter away overloaded methods return(GetClassMembers(finalType, si, false, isStatic, isStatic).Distinct(new DuplicateMethodNameRemover()).ToList()); }
public bool InsideRange(CodePoint cp) { // Reject the obvious cases first (codes in different files)... if (cp.SourceLocation != StartInclusive.SourceLocation) return false; if (cp.SourceLocation != EndExclusive.SourceLocation) return false; if (StartInclusive.LineNo <= cp.LineNo && EndExclusive.LineNo >= cp.LineNo) { if (StartInclusive.LineNo == cp.LineNo && StartInclusive.CharNo > cp.CharNo) return false; else if (EndExclusive.LineNo == cp.LineNo && EndExclusive.CharNo < cp.CharNo) return false; return true; } return false; }
internal bool SetBreakpointAt(ProtoCore.CodeModel.CodePoint breakpoint) { if ((null != internalWorker) && internalWorker.IsBusy) { return(false); } // The script is executed without a debugger attached, // therefore this call does not make sense right now. if (null != scriptRunner) { return(false); } if (null == debugRunner) { return(false); // Not debugging, cannot set a breakpoint. } CodePoint location = breakpoint; location.CharNo = location.CharNo + 1; location.LineNo = location.LineNo + 1; return(debugRunner.ToggleBreakpoint(location)); }
internal List<CompletionItem> GetCompletionList(CodePoint location, string idents) { ScopeInfo scopeIdentifier = new ScopeInfo(); if (!GetScopeIdentifier(location, ref scopeIdentifier)) return null; // Unknown scope. bool isStatic = false; int identifierType = GetIdentifierType(scopeIdentifier, location, idents, true, ref isStatic); if (ProtoCore.DSASM.Constants.kInvalidIndex == identifierType) return null; // No identifier of given name found in scope. return (GetClassMembers(identifierType, isStatic, scopeIdentifier)); }
public List<CompletionItem> GetCompletionList(CodePoint location, string idents) { lock (promotionSyncRoot) // Block until progressing promotion is done. { if (null != productionDatabase) return productionDatabase.GetCompletionList(location, idents); return null; } }
/// <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); }
internal List<MethodSignature> GetMethodSignatures(CodePoint location, string idents) { ScopeInfo scopeIdentifier = new ScopeInfo(); if (!GetScopeIdentifier(location, ref scopeIdentifier)) return null; // Unknown scope. // This identifier list traversal is slightly different from the one for // 'GetCompletionList'. For example, "a.b.c.d.e.foo" where the "foo" // identifier is expected to be a method name, so the logic needs only to // traverse up to "e" to resolve its type, disregarding "foo". // bool isStatic = false; int identifierType = GetIdentifierType(scopeIdentifier, location, idents, false, ref isStatic); // If the "search site" is not within any class body/method. if (ProtoCore.DSASM.Constants.kInvalidIndex == scopeIdentifier.ClassScope) { // If the "search target" is in global scope... if (ProtoCore.DSASM.Constants.kInvalidIndex == identifierType) { // Only get those global methods that belong to the same // block as the search site (methods residing in another // block cannot be accessed within the current block). // // GetMethodSignatures(scopeIdentifier) } // If the "search target" is in a class... else { // While looking up methods of a class in a global scope, // it can at most access methods that are made public. // // GetClassMethods(identifierType, false, AccessSpecifier.kPublic, results); } } // If the "search site" is within a class body/method. else { // If user only types "foo" (instead of "a.b.foo") within a class // body/method, then look for "foo" within the current class, or // in any base classes if it can be accessed from the search site. // if (ProtoCore.DSASM.Constants.kInvalidIndex == identifierType) { } // If user types "a.b.foo", then at most public methods can be // accessed. But if user types "this.foo", then a traversal is // required up the class hierarchy to obtain methods with name "foo". else { } } return null; }
/// <summary> /// This method traverses an identifier list, like a.b.c.d and returns the type of "d" /// it also has an out parameter isStatic, this indicates if the type is Static, /// for example: if you are searching for A, A is a class name, then the isStatic will be true /// otherwize it will be false /// </summary> /// <param name="idents">ident list, if you are searching the type of a.b.c, you should pass it { a, b, c }</param> /// <param name="si">the scope of the ident list</param> /// <param name="cp">the location of the ident list</param> /// <param name="isStatic"></param> /// <returns></returns> private static int TraverseIdentList(string[] idents, int depth, ScopeInfo si, ProtoCore.CodeModel.CodePoint cp, out bool isStatic) { isStatic = false; if (idents.Length == 0 || depth > idents.Length) { return(ProtoCore.DSASM.Constants.kInvalidIndex); } string firstIdentifier = idents[0]; int finalType = GetArrayElementType(si, firstIdentifier); if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex) { if (firstIdentifier.IndexOfAny(new char[] { '[', ']' }) != -1) { string[] tokens = TokenizeArrayIndexers(firstIdentifier); firstIdentifier = tokens[0]; } // this will get the type of the first identifier in the identifier list (a in a.b.c.d) // it is special because it is plain variables, ( a is plain variable) // and all the followings are class member variabls ( b, c, and d are all class member variables) finalType = GetIdentType(si, firstIdentifier, cp); } if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex) { // cannot find a variable named "a" // check if there is a class named "a:, // if there is return its class index as final type // and set isStatic to true // we are only interested in its static members and constructors now finalType = compileState.ClassTable.IndexOf(idents[0]); isStatic = true; } if (finalType == ProtoCore.DSASM.Constants.kInvalidIndex) { return(ProtoCore.DSASM.Constants.kInvalidIndex); } // iterate through all the remaining identifiers, (b c and d) for (int ix = 1; ix < depth; ++ix) { ProtoCore.DSASM.SymbolNode sn = GetMemberVariable(finalType, idents[ix], si, isStatic); if (sn == null || sn.datatype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) { return(ProtoCore.DSASM.Constants.kInvalidIndex); } finalType = GetSymbolType(sn); isStatic = false; } return(finalType); }
/// <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 = compileState.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 = compileState.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 = compileState.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.compileState); if (string.IsNullOrEmpty(identList) || (null == AutoCompletionHelper.compileState)) { 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 : compileState.ClassTable.ClassNodes[x.Key].name)).ToList()); }
private int GetIdentifierType(ScopeInfo scopeIdentifier, CodePoint location, string identifier, bool includeLastIdent, ref bool isStatic) { isStatic = false; if (string.IsNullOrEmpty(identifier)) return ProtoCore.DSASM.Constants.kInvalidIndex; // Split the identifier list (e.g. "a.b.c" -> { "a", "b", "c" }) char[] seperator = { '.' }; string[] idents = identifier.Split(seperator, StringSplitOptions.RemoveEmptyEntries); if (null == idents || (idents.Length <= 0)) return ProtoCore.DSASM.Constants.kInvalidIndex; // The caller may choose to drop the last identifier in the list, if // it represents a method name. For example, "a.b.foo", the search // only goes up to determine the type of "b" while disregarding "foo". if (false == includeLastIdent) { List<string> intermediate = idents.ToList(); intermediate.RemoveAt(intermediate.Count - 1); if (intermediate.Count <= 0) return ProtoCore.DSASM.Constants.kInvalidIndex; idents = idents.ToArray(); } // First we need to find out the type of the "root // variable". For example, "a" in the case of "a.b.c". // string rootIdentifier = idents[0]; int rootType = ProtoCore.DSASM.Constants.kInvalidIndex; if (ProtoCore.DSASM.Constants.kInvalidIndex != scopeIdentifier.ClassScope) { // If this symbol is in a language block within a class definition... if (scopeIdentifier.BlockId != 0) rootType = GetBlockMemberType(scopeIdentifier, rootIdentifier); // This identifier is found within a class definition region. if (ProtoCore.DSASM.Constants.kInvalidIndex == rootType) rootType = GetClassMemberType(scopeIdentifier, rootIdentifier, isStatic); } else { // For identifiers found outside of the class definition region... rootType = GetBlockMemberType(scopeIdentifier, rootIdentifier); } // It seems like the identifier does not correspond to a valid variable // name given the scope it resides in. Check to see if it represents the // name of an existing class. if (ProtoCore.DSASM.Constants.kInvalidIndex == rootType) { bool isImported = false; rootType = GetClassScopeFromName(rootIdentifier, ref isImported); if (ProtoCore.DSASM.Constants.kInvalidIndex == rootType) return ProtoCore.DSASM.Constants.kInvalidIndex; // We have found a class with name matching "rootIdentifier", // which means the subsequent identifier(s) is a static member. isStatic = true; } int finalType = ProtoCore.DSASM.Constants.kInvalidIndex; for (int index = 1; index < idents.Length; ++index) { string ident = idents[index]; finalType = GetClassMemberType(scopeIdentifier, ident, isStatic); if (ProtoCore.DSASM.Constants.kInvalidIndex == finalType) return ProtoCore.DSASM.Constants.kInvalidIndex; isStatic = false; // Can't be static after the root level. } return finalType; }
public List<MethodSignature> GetMethodSignatures(CodePoint location, string idents) { lock (promotionSyncRoot) { if (null != productionDatabase) return productionDatabase.GetMethodSignatures(location, idents); return null; } }
protected bool FallsWithinActiveScript(CodePoint codePoint) { if (null == codePoint.SourceLocation || (null == currentScript)) return false; if (string.IsNullOrEmpty(codePoint.SourceLocation.FilePath)) throw new InvalidOperationException("'SourceLocation' not specified!"); IParsedScript parsedScript = currentScript.GetParsedScript(); if (null == parsedScript) return false; string sourcePath = codePoint.SourceLocation.FilePath; string activePath = parsedScript.GetScriptPath(); return (string.Compare(sourcePath, activePath, true) == 0); }
private bool GetScopeIdentifier(CodePoint location, ref ScopeInfo scopeIdentifier) { string[] conditions = { "StartLine <= " + location.LineNo.ToString(), "EndLine >= " + location.LineNo.ToString() }; Dictionary<ScopeInfo, CodeRange> scopeIdentifiers = null; try { string statement = SelectFromStatement(TableNames.ScopeRanges, conditions); SQLiteCommand command = new SQLiteCommand(statement, connection); SQLiteDataReader reader = command.ExecuteReader(); if (null == reader || (false == reader.HasRows)) return false; // No record was found matching. while (reader.Read()) { int startLine = reader.GetInt32(1); int startColumn = reader.GetInt32(2); int endLine = reader.GetInt32(3); int endColumn = reader.GetInt32(4); bool withinRange = true; if (location.LineNo == startLine && (location.CharNo < startColumn)) withinRange = false; else if (location.LineNo == endLine && (location.CharNo >= endColumn)) withinRange = false; if (false == withinRange) continue; if (null == scopeIdentifiers) scopeIdentifiers = new Dictionary<ScopeInfo, CodeRange>(); string path = GetScriptPath(reader.GetInt32(0)); ScopeInfo scope = new ScopeInfo() { BlockId = reader.GetInt32(5), ClassScope = reader.GetInt32(6), FunctionIndex = reader.GetInt32(7) }; CodeRange range = MakeCodeRange(startLine, startColumn, endLine, endColumn, path); scopeIdentifiers.Add(scope, range); } } catch (Exception exception) { HandleException(exception); return false; } if (null == scopeIdentifiers || (scopeIdentifiers.Count <= 0)) return false; // Attempt to find the inner-most scope by seeing // if one scope completely contains another scope. // bool foundInnerMostScope = false; CodeRange innerMostScope = new CodeRange(); foreach (var identifier in scopeIdentifiers) { if (false == foundInnerMostScope) { innerMostScope = identifier.Value; scopeIdentifier = identifier.Key; foundInnerMostScope = true; continue; } if (innerMostScope.InsideRange(identifier.Value)) { innerMostScope = identifier.Value; scopeIdentifier = identifier.Key; } } return foundInnerMostScope; }