using PascalABCCompiler.Parsers; using PascalABCCompiler.ParserTools.Directives; using PascalABCCompiler.SyntaxTree; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace Languages.SPython.Frontend.Data { internal class SPythonLanguageInformation : BaseLanguageInformation { public override BaseKeywords KeywordsStorage { get; } = new SPythonParser.SPythonKeywords(); public override Dictionary ValidDirectives { get; protected set; } public override string BodyStartBracket => null; public override string BodyEndBracket => null; public override string ParameterDelimiter => ","; public override string ResultVariableName => null; public override string ProcedureName => null; public override string FunctionName => "def"; public override string GenericTypesStartBracket => "["; public override string GenericTypesEndBracket => "]"; public override string ReturnTypeDelimiter => "->"; public override bool CaseSensitive => true; public override bool IncludeDotNetEntities => true; public override bool AddStandardUnitNamesToUserScope => false; public override bool AddStandardNetNamespacesToUserScope => false; public override bool UsesFunctionsOverlappingSourceContext => true; private readonly Dictionary renamings = new Dictionary { ["biginteger"] = "bigint" }; private readonly HashSet exclutions = new HashSet { "__NewSetCreatorInternal" }; private readonly Dictionary specialModulesAliases = new Dictionary { { "time", "time1" }, { "random", "random1" }, }; public override Dictionary SpecialModulesAliases => specialModulesAliases; public override void RenameOrExcludeSpecialNames(SymInfo[] symInfos) { for (var i = 0; i < symInfos.Length; i++) { if (symInfos[i] == null) continue; if (renamings.TryGetValue(symInfos[i].name, out var newName)) { // копирование на всякий случай symInfos[i] = new SymInfo(symInfos[i]); symInfos[i].name = newName; } else if (exclutions.Contains(symInfos[i].name)) { symInfos[i] = new SymInfo(symInfos[i]); symInfos[i].not_include = true; } } } public override string ConstructHeader(string meth, IProcScope scope, int tabCount) { throw new NotImplementedException(); } public override string ConstructHeader(IProcRealizationScope scope, int tabCount) { throw new NotImplementedException(); } public override string ConstructOverridedMethodHeader(IProcScope scope, out int off) { throw new NotImplementedException(); } public override string FindExpression(int off, string Text, int line, int col, out KeywordKind keyw) { int i = off - 1; int bound = 0; bool punkt_sym = false; keyw = KeywordKind.None; System.Text.StringBuilder sb = new StringBuilder(); Stack tokens = new Stack(); Stack kav = new Stack(); Stack ugl_skobki = new Stack(); int num_in_ident = -1; keyw = TestForKeyword(Text, i); if (keyw == KeywordKind.Punkt) return ""; while (i >= bound) { bool end = false; char ch = Text[i]; if (kav.Count == 0 && (char.IsLetterOrDigit(ch) || ch == '_' || ch == '&' || ch == '\'' || ch == '!')) { num_in_ident = i; if (kav.Count == 0 && tokens.Count == 0) { int tmp = i; if (ch == '\'') { i--; if (kav.Count == 0) kav.Push('\''); while (i >= 0) { if (Text[i] != '\'') i--; else { if (i >= 1 && Text[i - 1] == '\'') i -= 2; else break; } } if (i >= 0) i--; } else while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!')) { i--; } while (i >= 0 && (Text[i] == ' ' || char.IsControl(Text[i]) || Text[i] == '}')) { if (Text[i] != '}') i--; else { while (i >= 0 && Text[i] != '{') //propusk kommentariev i--; if (i >= 0) i--; } } if (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!')) { bound = i + 1; TestForKeyword(Text, i, ref bound, punkt_sym, out keyw); for (int j = tmp; j > bound; j--) { sb.Insert(0, Text[j]); } if (sb.ToString().Trim() == "new") return ""; i = bound; continue; } else if (i >= 0 && Text[i] == '\'') return ""; i = tmp; } else if (ch == '\'') kav.Push('\''); sb.Insert(0, ch);//.Append(Text[i]); } else if (ch == '.' || ch == '^' || ch == '&' || ch == '?' && IsPunctuation(Text, i + 1)) { if (ch == '.' && i >= 1 && Text[i - 1] == '.' && tokens.Count == 0) end = true; else if (ch == '?' && i + 1 < Text.Length && Text[i + 1] != '.') end = true; else sb.Insert(0, ch); if (ch != '.') punkt_sym = true; } else if (ch == '}') { if (kav.Count == 0) { while (i >= 0 && Text[i] != '{') { if (Text[i] != '$')//skip {$ sb.Insert(0, Text[i]); i--; } if (i < 0) { break; } else if (Text[i] == '{') { sb.Insert(0, '{'); } } else sb.Insert(0, ch); } else if (ch == '{') { if (kav.Count == 0) { if (keyw == KeywordKind.None) return sb.ToString(); sb.Insert(0, ch); break; } else sb.Insert(0, ch); } else switch (ch) { case ')': case ']': if (kav.Count == 0) { string tmps = sb.ToString().Trim(' ', '\r', '\t', '\n'); if (tmps.Length >= 1 && (char.IsLetter(tmps[0]) || tmps[0] == '_' || tmps[0] == '&' || tmps[0] == '?' || tmps[0] == '!') && tokens.Count == 0) end = true; else tokens.Push(ch); } if (!end) { sb.Insert(0, ch); punkt_sym = true; } break; case '>': if (tokens.Count == 0) { int j = i + 1; while (j < Text.Length && char.IsWhiteSpace(Text[j])) j++; if (ugl_skobki.Count > 0 || i == off - 1 || j == off && off == Text.Length || j < Text.Length && Text[i - 1] != '-' && (Text[j] == '.' || Text[j] == '(')) { ugl_skobki.Push('>'); sb.Insert(0, ch); } else if (i >= 1 && Text[i - 1] == '-') { if (!(kav.Count == 0 && tokens.Count == 0)) sb.Insert(0, ch); } else end = true; } else sb.Insert(0, ch); break; case '<': if (tokens.Count == 0) { if (ugl_skobki.Count > 0) { ugl_skobki.Pop(); sb.Insert(0, ch); } else end = true; } else sb.Insert(0, ch); break; case '[': case '(': case '|': if (ch == '|' && ((tokens.Count == 0) || (tokens.Peek() == ']') || (tokens.Peek() == ')') || (tokens.Peek() == ','))) // Закрывающий | - после него (tokens.Pop()) - пусто или ] ) , { if (kav.Count == 0) { string tmps = sb.ToString().Trim(' ', '\r', '\t', '\n'); if (tmps.Length >= 1 && (char.IsLetter(tmps[0]) || tmps[0] == '_' || tmps[0] == '&' || tmps[0] == '?' || tmps[0] == '!') && tokens.Count == 0) end = true; else tokens.Push(ch); } if (!end) { sb.Insert(0, ch); punkt_sym = true; } } else { if (kav.Count == 0) // в т.ч. открывающий | { if (tokens.Count > 0) { tokens.Pop(); punkt_sym = true; sb.Insert(0, ch); if (ch == '(') { int tmp = i--; /*while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&')) { i--; }*/ while (i >= 0 && (Text[i] == ' ' || char.IsControl(Text[i]) || Text[i] == '}')) { if (Text[i] != '}') i--; else { while (i >= 0 && Text[i] != '{') //propusk kommentariev i--; if (i >= 0) i--; } } if (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!' || Text[i] == '?' && IsPunctuation(Text, i + 1))) { bound = i + 1; TestForKeyword(Text, i, ref bound, punkt_sym, out keyw); if (keyw != KeywordKind.None && tokens.Count == 0) { end = true; } else bound = 0; } else if (i >= 0 && Text[i] == '\'') return ""; i = tmp; } } else { end = true; if (ch == '[') { keyw = KeywordKind.SquareBracket; } } } else sb.Insert(0, ch); punkt_sym = true; } break; case '\'': if (kav.Count == 0) kav.Push(ch); else kav.Pop(); sb.Insert(0, ch); punkt_sym = true; break; default: if (!(ch == ' ' || char.IsControl(ch))) { if (kav.Count == 0) { if (ch == ',' && ugl_skobki.Count > 0) sb.Insert(0, ch); else if (tokens.Count == 0) end = true; else sb.Insert(0, ch); } else sb.Insert(0, ch); } else { if (Text[i] == '\n') { bool one_line_comment = false; int comment_position = -1; if (CheckForComment(Text, i - 1, out comment_position, out one_line_comment)) { if (!one_line_comment) end = true; else { sb.Insert(0, ch); i = comment_position; } } else sb.Insert(0, ch); } else sb.Insert(0, ch); } punkt_sym = true; break; } if (end) { bool one_line_comment = false; int comment_position = -1; if (CheckForComment(Text, i, out comment_position, out one_line_comment)) { int new_line_ind = sb.ToString().IndexOf('\n'); if (new_line_ind != -1) sb = sb.Remove(0, new_line_ind + 1); else sb = sb.Remove(0, sb.Length); } break; } i--; } //return RemovePossibleKeywords(sb); if (sb.Length > 0 && sb[sb.Length - 1] == '?') sb.Remove(sb.Length - 1, 1); return sb.ToString().Trim(); } private bool CheckForComment(string Text, int off, out int comment_position, out bool one_line_comment) { int i = off; one_line_comment = false; comment_position = -1; Stack kav = new Stack(); bool is_comm = false; while (i >= 0 && !is_comm && Text[i] != '\n' && Text[i] != '\r') { if (Text[i] == '\'' || Text[i] == '"') { if (kav.Count == 0) kav.Push('\''); else kav.Pop(); } else if (Text[i] == '{') { if (kav.Count == 0) { comment_position = i; while (i >= 0 && Text[i] != '\'' && Text[i] != '"') i--; if (i >= 1 && Text[i - 1] == '$') return false; is_comm = true; return is_comm; } } else if (Text[i] == '}') { return false; } else if (Text[i] == '#') if (kav.Count == 0) { is_comm = true; one_line_comment = true; comment_position = i - 1; } i--; } return is_comm; } public override string FindExpressionForMethod(int off, string Text, int line, int col, char pressed_key, ref int num_param) { int i = off - 1; string pattern = null; int bound = 0; System.Text.StringBuilder sb = new System.Text.StringBuilder(); Stack tokens = new Stack(); Stack kav = new Stack(); Stack skobki = new Stack(); Stack ugl_skobki = new Stack(); bool comma_pressed = pressed_key == ','; int num_in_ident = -1; bool punkt_sym = false; int next; KeywordKind keyw = TestForKeyword(Text, i); bool on_brace = false; if (keyw == KeywordKind.Punkt) return ""; try { while (i >= bound) { bool end = false; char ch = Text[i]; if ((char.IsLetterOrDigit(ch) || ch == '_' || ch == '&' || ch == '!') && !isOperator(Text, i, out next)) { num_in_ident = i; if (kav.Count == 0 && tokens.Count == 0) { int tmp = i; while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!') && !isOperator(Text, i, out next)) { i--; } while (i >= 0 && (Text[i] == ' ' || char.IsControl(Text[i]) || Text[i] == '}')) { if (Text[i] != '}') i--; else { while (i >= 0 && Text[i] != '{') //propusk kommentariev i--; if (i >= 0) i--; } } if (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!') && !isOperator(Text, i, out next)) { bound = i + 1; TestForKeyword(Text, i, ref bound, punkt_sym, out keyw); if (keyw == KeywordKind.New && comma_pressed) bound = 0; if (keyw == KeywordKind.Function || keyw == KeywordKind.Constructor || keyw == KeywordKind.Destructor) return ""; } else if (i >= 0 && (Text[i] == '\'' || Text[i] == '"')) return ""; i = tmp; } sb.Insert(0, ch);//.Append(Text[i]); } else if (ch == '.') sb.Insert(0, ch); else if (ch == '}') { if (kav.Count == 0) { while (i >= 0 && Text[i] != '{') { sb.Insert(0, Text[i]); i--; } if (i < 0) { break; } else if (Text[i] == '{') { sb.Insert(0, '{'); } } else sb.Insert(0, ch); } else if (ch == '{') { if (kav.Count == 0) { sb.Insert(0, ch); break; } else sb.Insert(0, ch); } else switch (ch) { case ')': case ']': case '>': // Добавил это условие для питона EVA if (pressed_key == '(' && ch == ')' && !sb.ToString().Contains(".") && tokens.Count == 0) { end = true; break; } if (kav.Count == 0) { int j = i + 1; while (j < Text.Length && char.IsWhiteSpace(Text[j])) j++; if (ch != '>') tokens.Push(ch); if (ch == ')') skobki.Push(ch); if (tokens.Count > 0 || pressed_key == ',') sb.Insert(0, ch); else if (i == off - 1 || j == off && off == Text.Length || ugl_skobki.Count > 0 || j < Text.Length && Text[i - 1] != '-' && (Text[j] == '.' || Text[j] == '(')) { tokens.Push(ch); ugl_skobki.Push(ch); sb.Insert(0, ch); } else end = true; } else sb.Insert(0, ch); break; case '[': case '<': case '(': if (kav.Count == 0)//esli ne v kavychkah { if (ch == '(') if (skobki.Count > 0) skobki.Pop(); else skobki.Push('('); //esli byli zakryvaushie tokeny (polagaem, chto skobki korrektny, esli net, to parser v lubom sluchae ne proparsit if (tokens.Count > 0) { if (ch != '<') tokens.Pop(); else if (ugl_skobki.Count > 0) { tokens.Pop(); ugl_skobki.Pop(); } sb.Insert(0, ch);//dobavljaem k stroke if (ch == '(') { int tmp = i--; /*while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&')) { i--; }*/ while (i >= 0 && (Text[i] == ' ' || char.IsControl(Text[i]) || Text[i] == '}')) { if (Text[i] != '}') { i--; } else { while (i >= 0 && Text[i] != '{') { //propusk kommentariev i--; } if (i >= 0) i--; } } if (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '!')) { bound = i + 1; TestForKeyword(Text, i, ref bound, punkt_sym, out keyw); if (keyw == KeywordKind.New) bound = 0; else if (keyw != KeywordKind.None && tokens.Count == 0) end = true; else bound = 0; } else if (i >= 0 && (Text[i] == '\'' || Text[i] == '"')) return ""; i = tmp; } } else if (ch == '<' || ch == '>') { if (tokens.Count > 0 || pressed_key == ',') sb.Insert(0, ch); else end = true; } else if (!comma_pressed) //esli my ne v parametrah end = true; //zakonchili, tak kak doshli do pervoj skobki else { sb.Remove(0, sb.Length);//doshli do skobki, byla nazhata zapjataja, poetomu udaljaem vse parametry if (ch == '(') on_brace = true; //on_skobka = true; comma_pressed = false; } } else sb.Insert(0, ch); break; case '\'': case '"': if (kav.Count == 0) kav.Push(ch); else kav.Pop(); sb.Insert(0, ch); if (kav.Count == 0 && tokens.Count == 0) end = true; break; default: if (!(ch == ' ' || char.IsControl(ch))) { if (ch == '^') sb.Insert(0, ch); else if (kav.Count == 0)//ne v kavychkah { if (tokens.Count == 0) { if (ch != ',' && !comma_pressed) end = true;//esli ne na zapjatoj i ne v parametrah, to finish else if (ch == ',' && !comma_pressed) end = true; else if (ch == ',' && (pressed_key == '(' || pressed_key == '[')) end = true; else { sb.Insert(0, ch);//prodolzhaem if (isOperator(Text, i, out next)) { i = next; continue; } } } else sb.Insert(0, ch);//esli est skobki, prodolzhaem if (!end && ch == ',') { if (tokens.Count == 0) num_param++;//esli na zapjatoj, uvelichivaem nomer parametra } } else sb.Insert(0, ch);//prodolzhaem } else if (Text[i] == '\n') { bool one_line_comment = false; int comment_position = -1; if (CheckForComment(Text, i - 1, out comment_position, out one_line_comment)) //proverjaem, net li kommenta ne predydushej stroke { if (!one_line_comment) end = true; else { sb.Insert(0, ch); i = comment_position; } } else sb.Insert(0, ch);//a inache vyrazhenie na neskolkih strokah } else sb.Insert(0, ch); break; } if (end) { if (comma_pressed && !on_brace) return ""; bool one_line_comment = false; int comment_position = -1; if (CheckForComment(Text, i, out comment_position, out one_line_comment))//proverka na kommentarii { int new_line_ind = sb.ToString().IndexOf('\n'); if (new_line_ind != -1) sb = sb.Remove(0, new_line_ind + 1); else sb = sb.Remove(0, sb.Length); } break; } i--; } if (pressed_key == ',') num_param++; } catch (Exception e) { } if (pressed_key == ',' && (!on_brace || skobki.Count == 0)) return ""; //return RemovePossibleKeywords(sb); return sb.ToString().Trim(); } private bool isOperator(string Text, int i, out int next) { next = i; if (i >= 3) { string op = Text.Substring(i - 2, 3).ToLower().Trim(); if (op == "and" || op == "div" || op == "mod" || op == "xor") { if (!char.IsLetterOrDigit(Text[i - 3]) && Text[i - 3] != '_' && Text[i - 3] != '&' && !(i + 1 < Text.Length && char.IsLetterOrDigit(Text[i + 1]))) { next = i - 3; return true; } return false; } } if (i >= 2) { string op = Text.Substring(i - 1, 2).ToLower().Trim(); if (op == "or") { if (!char.IsLetterOrDigit(Text[i - 2]) && Text[i - 2] != '_' && Text[i - 2] != '&' && !(i + 1 < Text.Length && char.IsLetterOrDigit(Text[i + 1]))) { next = i - 2; return true; } return false; } } return false; } public override string FindExpressionFromAnyPosition(int off, string Text, int line, int col, out string expr_without_brackets) { int i = off - 1; // это например вызов метода без параметров expr_without_brackets = null; var keyw = KeywordKind.None; if (i < 0) return ""; bool is_char = false; // идем в обе стороны от off System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (Text[i] != ' ' && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '?' && IsPunctuation(Text, i + 1) || Text[i] == '!')) { //sb.Remove(0,sb.Length); while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '?' && IsPunctuation(Text, i + 1) || Text[i] == '!')) { //sb.Insert(0,Text[i]);//.Append(Text[i]); i--; } is_char = true; } i = off; if (i < Text.Length && Text[i] != ' ' && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '&' || Text[i] == '?' && IsPunctuation(Text, i + 1) || Text[i] == '!')) { while (i < Text.Length && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '!')) { //sb.Append(Text[i]);//.Append(Text[i]); i++; } is_char = true; } if (is_char) { expr_without_brackets = FindExpression(i, Text, line, col, out keyw); } bool is_new = keyw == KeywordKind.New; bool meth_call = false; KeywordKind new_keyw = KeywordKind.None; int j = i; bool in_comment = false; bool brackets = false; while (j < Text.Length) { char c = Text[j]; if (c == '(' && !in_comment) { Stack sk_stack = new Stack(); in_comment = false; bool in_kav = false; sk_stack.Push('('); j++; while (j < Text.Length) { c = Text[j]; if (c == '(' && !in_kav) sk_stack.Push('('); else if (c == ')' && !in_kav) { if (sk_stack.Count == 0) { break; } else { sk_stack.Pop(); if (sk_stack.Count == 0) { i = j + 1; meth_call = true; break; } } } else if ((c == '\'' || c == '"') && !in_comment) { in_kav = !in_kav; } else if (c == '{' && !in_kav) { in_comment = true; } else if (c == '}' && !in_kav) { in_comment = false; } else if (c == '#' && !in_kav && !in_comment) { break; } j++; } break; } else if ((c == '<' || c == '&' && j < Text.Length - 1 && Text[j + 1] == '<') && !in_comment) { Stack sk_stack = new Stack(); if (c == '&') j++; sk_stack.Push('<'); j++; bool generic = false; while (j < Text.Length) { c = Text[j]; if (c == '>') { sk_stack.Pop(); if (sk_stack.Count == 0) { i = j + 1; generic = true; break; } } else if (c == '<') { sk_stack.Push('<'); } else if (!char.IsLetterOrDigit(c) && c != '?' && c != '&' && c != '.' && c != ' ' && c != '\t' && c != '\n' && c != ',' && c != '!') { break; } j++; } if (generic) { //break; } } else if (c == '[' && !in_comment) { brackets = true; break; } else if (c == '{') { in_comment = true; } else if (c == '}') { if (!in_comment) break; else in_comment = false; } else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { } else { if (!in_comment) break; } j++; } if (is_new && string.Compare(expr_without_brackets.Trim(' ', '\n', '\t', '\r'), "new", true) == 0 && !meth_call) { expr_without_brackets = null; return null; } if (is_char) { string ss = FindExpression(i, Text, line, col, out new_keyw); if (brackets && is_new) { int ind = ss.ToLower().IndexOf("new"); if (ind != -1) return ss.Substring(ind + 3); } if (is_new && ss != null && ss.IndexOf("new") == -1 && ss.IndexOf(":") != -1) return expr_without_brackets + "(true?" + ss; return ss; } return null; } // TODO: Реализовать EVA public override string GetArrayDescription(string elementType, int rank) { return ""; } public override string GetClassKeyword(class_keyword keyw) { switch (keyw) { case class_keyword.Class: return "class"; case class_keyword.TemplateClass: return "template class"; } return null; } // TODO: Реализовать EVA public override string GetCompiledTypeRepresentation(Type t, MemberInfo mi, ref int line, ref int col) { return ""; } public override string GetDescription(IBaseScope scope) { switch (scope.Kind) { case ScopeKind.Type: return GetDescriptionForType(scope as ITypeScope); case ScopeKind.CompiledType: return GetDescriptionForCompiledType(scope as ICompiledTypeScope); case ScopeKind.Procedure: return GetDescriptionForProcedure(scope as IProcScope); case ScopeKind.ElementScope: return GetDescriptionForElementScope(scope as IElementScope); case ScopeKind.TypeSynonim: return GetSynonimDescription(scope as ITypeSynonimScope); case ScopeKind.Namespace: return GetDescriptionForNamespace(scope as INamespaceScope); case ScopeKind.CompiledMethod: return GetDescriptionForCompiledMethod(scope as ICompiledMethodScope); /*case ScopeKind.Array: return GetDescriptionForArray(scope as IArrayScope); case ScopeKind.Enum: return GetDescriptionForEnum(scope as IEnumScope); case ScopeKind.Set: return GetDescriptionForSet(scope as ISetScope); case ScopeKind.CompiledField: return GetDescriptionForCompiledField(scope as ICompiledFieldScope); case ScopeKind.CompiledProperty: return GetDescriptionForCompiledProperty(scope as ICompiledPropertyScope); case ScopeKind.CompiledConstructor: return GetDescriptionForCompiledConstructor(scope as ICompiledConstructorScope);*/ } return ""; } protected string GetDescriptionForProcedure(IProcScope scope) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); string extensionType = null; if (scope.IsExtension && scope.Parameters.Length > 0) { extensionType = GetSimpleDescription(scope.Parameters[0].Type); } if (scope.IsExtension) { if (extensionType != null && extensionType.IndexOf(' ') != -1) { sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION") + " " + extensionType + ") "); extensionType = null; } else { sb.Append("(" + PascalABCCompiler.StringResources.Get("CODE_COMPLETION_EXTENSION") + ") "); } } if (scope.IsStatic) sb.Append("static "); if (scope.IsConstructor()) sb.Append("constructor "); else sb.Append("def "); /*if (scope.ReturnType == null) sb.Append("procedure "); else sb.Append("function ");*/ if (!scope.IsConstructor()) { if (extensionType != null) { sb.Append(extensionType + "."); sb.Append(scope.Name); } else { sb.Append(GetTopScopeName(scope.TopScope)); sb.Append(scope.Name); } } else { sb.Append(GetTopScopeNameWithoutDot(scope.TopScope)); } sb.Append(GetGenericString(scope.TemplateParameters)); sb.Append('('); IElementScope[] parameters = scope.Parameters; for (int i = 0; i < parameters.Length; i++) { if (scope.IsExtension && i == 0) continue; sb.Append(GetSimpleDescription(parameters[i])); if (i < parameters.Length - 1) { sb.Append("; "); } } sb.Append(')'); if (scope.ReturnType != null && !scope.IsConstructor() && !(scope.ReturnType is IProcType && (scope.ReturnType as IProcType).Target == scope)) sb.Append(" " + ReturnTypeDelimiter + " " + GetSimpleDescription(scope.ReturnType)); //if (scope.IsStatic) sb.Append("; static"); if (scope.IsVirtual) sb.Append("; "); else if (scope.IsAbstract) sb.Append("; abstract"); else if (scope.IsOverride) sb.Append("; override"); else if (scope.IsReintroduce) sb.Append("; reintroduce"); sb.Append(';'); return sb.ToString(); } protected string GetDescriptionForElementScope(IElementScope scope) { string type_name = null; StringBuilder sb = new StringBuilder(); if (scope.Type == null) type_name = ""; else type_name = GetSimpleDescription(scope.Type); if (type_name.StartsWith("$")) type_name = type_name.Substring(1, type_name.Length - 1); switch (scope.ElemKind) { case SymbolKind.Variable: sb.Append("var " + GetTopScopeName(scope.TopScope) + scope.Name + ((type_name != "") ? ": " + type_name : "")); break; case SymbolKind.Parameter: sb.Append(kind_of_param(scope) + "parameter " + scope.Name + ": " + type_name + (scope.ConstantValue != null ? (":=" + scope.ConstantValue.ToString()) : "")); break; case SymbolKind.Field: if (scope.IsStatic) sb.Append("static "); else sb.Append("var "); sb.Append(GetTopScopeName(scope.TopScope) + scope.Name + ": " + type_name); // append_modifiers(sb, scope); //if (scope.IsStatic) sb.Append("; static"); if (scope.IsReadOnly) sb.Append("; readonly"); break; } sb.Append(';'); return sb.ToString(); } protected override string kind_of_param(IElementScope scope) { switch (scope.ParamKind) { case PascalABCCompiler.SyntaxTree.parametr_kind.const_parametr: return "const "; case PascalABCCompiler.SyntaxTree.parametr_kind.var_parametr: return "var "; case PascalABCCompiler.SyntaxTree.parametr_kind.params_parametr: return "params "; case PascalABCCompiler.SyntaxTree.parametr_kind.out_parametr: return "out "; } return ""; } protected override string GetFullTypeName(Type ctn, bool no_alias = true) { TypeCode tc = Type.GetTypeCode(ctn); if (ctn.FullName == null && !ctn.IsArray && !ctn.IsGenericTypeDefinition && ctn.IsGenericParameter) return ctn.Name; if (!ctn.IsEnum) { switch (tc) { case TypeCode.Int32: return "int"; case TypeCode.Double: return "float"; case TypeCode.Boolean: return "bool"; case TypeCode.String: return "str"; case TypeCode.Char: return "char"; } /*if (ctn.IsPointer) if (ctn.FullName == "System.Void*") return "pointer"; else return "^" + GetFullTypeName(ctn.GetElementType());*/ } else return ctn.FullName; if (!no_alias) { if (ctn.Name.Contains("Func`") || ctn.Name.Contains("Predicate`")) return getLambdaRepresentation(ctn, true, new List()); else if (ctn.Name.Contains("Action`")) return getLambdaRepresentation(ctn, false, new List()); else if (ctn.Name == "IEnumerable`1") return "sequence of " + GetShortTypeName(ctn.GetGenericArguments()[0], false); else if (ctn.Name.Contains("Tuple`")) return get_tuple_string(ctn); } int gen_pos = ctn.Name.IndexOf("`"); if (gen_pos != -1 || ctn.IsGenericType) { int len = ctn.GetGenericArguments().Length; Type[] gen_ps = ctn.GetGenericArguments(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (gen_pos != -1) sb.Append(ctn.Namespace + "." + ctn.Name.Substring(0, gen_pos)); else sb.Append(ctn.Namespace + "." + ctn.Name); sb.Append(GenericTypesStartBracket); for (int i = 0; i < len; i++) { sb.Append(gen_ps[i].Name); if (i < len - 1) sb.Append(", "); } sb.Append(GenericTypesEndBracket); return sb.ToString(); } if (ctn.IsArray) { var rank = ctn.GetArrayRank(); var strrank = rank > 1 ? "[" + new string(',', rank - 1) + "]" : ""; return $"array{strrank}" + " of " + GetFullTypeName(ctn.GetElementType()); } if (ctn == Type.GetType("System.Void*")) return "pointer"; if (ctn.IsNested) return ctn.Name; return ctn.FullName; } public override string GetKeyword(SymbolKind kind) { switch (kind) { case SymbolKind.Class: return "class"; case SymbolKind.Enum: return "enum"; case SymbolKind.Null: return "None"; } return ""; } public override string GetShortName(ICompiledConstructorScope scope) { return "create"; } public override string GetShortTypeName(Type ctn, bool noalias = true) { TypeCode tc = Type.GetTypeCode(ctn); if (ctn.FullName == null && !ctn.IsArray && !ctn.IsGenericTypeDefinition && ctn.IsGenericParameter) return ctn.Name; if (!ctn.IsEnum) { switch (tc) { case TypeCode.Int32: return "int"; case TypeCode.Double: return "float"; case TypeCode.Boolean: return "bool"; case TypeCode.String: return "str"; case TypeCode.Char: return "char"; } /*if (ctn.IsPointer) if (ctn.FullName == "System.Void*") return "pointer"; else return "^" + GetShortTypeName(ctn.GetElementType(), noalias);*/ } else return ctn.Name; if (ctn.Name.Contains("`")) { if (!noalias) { if (ctn.Name.Contains("Func`") || ctn.Name.Contains("Predicate`")) return getLambdaRepresentation(ctn, true, new List()); else if (ctn.Name.Contains("Action`")) return getLambdaRepresentation(ctn, false, new List()); else if (ctn.Name == "IEnumerable`1") return "sequence of " + GetShortTypeName(ctn.GetGenericArguments()[0], false); else if (ctn.Name.Contains("Tuple`")) return get_tuple_string(ctn); } int len = ctn.GetGenericArguments().Length; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(ctn.Name.Substring(0, ctn.Name.IndexOf('`'))); sb.Append('['); if (!noalias) { Type[] gen_ps = ctn.GetGenericArguments(); for (int i = 0; i < len; i++) { sb.Append(gen_ps[i].Name); if (i < len - 1) sb.Append(", "); } } sb.Append(']'); return sb.ToString(); } if (ctn.IsArray) { var rank = ctn.GetArrayRank(); var strrank = rank > 1 ? "[" + new string(',', rank - 1) + "]" : ""; return $"array{strrank}" + " of " + GetShortTypeName(ctn.GetElementType()); } //if (ctn == Type.GetType("System.Void*")) return PascalABCCompiler.StringConstants.pointer_type_name; return ctn.Name; } public override string GetSimpleDescription(IBaseScope scope) { if (scope == null) return ""; switch (scope.Kind) { case ScopeKind.Array: case ScopeKind.Enum: case ScopeKind.Set: if (scope is ITypeScope && (scope as ITypeScope).Aliased) return scope.Name; break; case ScopeKind.TypeSynonim: case ScopeKind.Type: if (scope.Name == "biginteger") return "bigint"; break; } switch (scope.Kind) { case ScopeKind.Type: return GetSimpleDescriptionForType(scope as ITypeScope); case ScopeKind.CompiledType: return GetSimpleDescriptionForCompiledType(scope as ICompiledTypeScope, false); case ScopeKind.Procedure: return GetSimpleDescriptionForProcedure(scope as IProcScope); case ScopeKind.ElementScope: return GetSimpleDescriptionForElementScope(scope as IElementScope); case ScopeKind.TypeSynonim: return GetSimpleSynonimDescription(scope as ITypeSynonimScope); case ScopeKind.Array: return GetDescriptionForArray(scope as IArrayScope); case ScopeKind.UnitInterface: return GetDescriptionForModule(scope as IInterfaceUnitScope); case ScopeKind.Namespace: return GetDescriptionForNamespace(scope as INamespaceScope); case ScopeKind.CompiledMethod: return GetDescriptionForCompiledMethod(scope as ICompiledMethodScope); /*case ScopeKind.Enum: return GetDescriptionForEnum(scope as IEnumScope); case ScopeKind.Set: return GetDescriptionForSet(scope as ISetScope); case ScopeKind.CompiledField: return GetDescriptionForCompiledField(scope as ICompiledFieldScope); case ScopeKind.CompiledProperty: return GetDescriptionForCompiledProperty(scope as ICompiledPropertyScope); case ScopeKind.CompiledConstructor: return GetDescriptionForCompiledConstructor(scope as ICompiledConstructorScope);*/ } return ""; } private string GetDescriptionForModule(IInterfaceUnitScope scope) { var p = specialModulesAliases.FirstOrDefault(kv => kv.Value == scope.Name); if (!p.Equals(default(KeyValuePair))) return "unit " + p.Key; return "unit " + scope.Name; } private string GetDescriptionForNamespace(INamespaceScope scope) { return "namespace " + scope.Name; } private string GetSimpleSynonimDescription(ITypeSynonimScope scope) { return scope.Name; } protected string GetDescriptionForArray(IArrayScope scope) { StringBuilder sb = new StringBuilder(); sb.Append("array"); ITypeScope[] inds = scope.Indexers; if (!scope.IsDynamic) { sb.Append('['); for (int i = 0; i < inds.Length; i++) { sb.Append(GetSimpleDescription(inds[i])); if (i < inds.Length - 1) sb.Append(','); } sb.Append(']'); } if (scope.ElementType != null) { string s = GetSimpleDescription(scope.ElementType); if (s.Length > 0 && s[0] == '$') s = s.Substring(1, s.Length - 1); sb.Append(" of " + s); } return sb.ToString(); } private string GetSimpleDescriptionForCompiledType(ICompiledTypeScope scope, bool fullName) { if (scope.CompiledType.Name != null && scope.CompiledType.Name.Contains("Func`")) { return getLambdaRepresentation(scope, true); } else if (scope.CompiledType.Name != null && scope.CompiledType.Name.Contains("Action`")) { return getLambdaRepresentation(scope, false); } else if (scope.CompiledType.Name != null && scope.CompiledType.Name.Contains("Predicate`1")) { return getLambdaRepresentation(scope, false); } if (scope.CompiledType.Name == "IEnumerable`1") { ITypeScope[] instances = scope.GenericInstances; if (instances != null && instances.Length > 0) { return "sequence of " + GetSimpleDescriptionWithoutNamespace(instances[0]); } else return "sequence of T"; } else if (scope.CompiledType.Name != null && scope.CompiledType.Name.Contains("Tuple`")) { ITypeScope[] instances = scope.GenericInstances; if (instances != null && instances.Length > 0) { return get_tuple_string(instances); } else return "(T1,...)"; } else { string s = !fullName ? GetShortTypeName(scope.CompiledType) : GetFullTypeName(scope.CompiledType); ITypeScope[] instances = scope.GenericInstances; if (instances != null && instances.Length > 0) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); int ind = s.IndexOf(GenericTypesStartBracket); if (ind != -1) sb.Append(s.Substring(0, ind)); else sb.Append(s); sb.Append(GenericTypesStartBracket); for (int i = 0; i < instances.Length; i++) { sb.Append(GetSimpleDescriptionWithoutNamespace(instances[i])); if (i < instances.Length - 1) sb.Append(", "); } sb.Append(GenericTypesEndBracket); s = sb.ToString(); } return s; } } public override string GetStandardTypeByKeyword(KeywordKind keyw) { switch (keyw) { case KeywordKind.IntType: return "int"; case KeywordKind.DoubleType: return "float"; case KeywordKind.CharType: return "char"; case KeywordKind.BoolType: return "bool"; case KeywordKind.StringType: return "str"; } return null; } public override string GetStringForChar(char c) { return "'" + c.ToString() + "'"; } public override string GetStringForSharpChar(int num) { return "#" + num.ToString(); } public override string GetStringForString(string s) { return "'" + s + "'"; } public override string GetSynonimDescription(ITypeScope scope) { return "type " + scope.Name + GetGenericString(scope.TemplateArguments) + " = " + scope.Description; } public override string GetSynonimDescription(ITypeSynonimScope scope) { if (scope.ActType is ICompiledTypeScope && !(scope.ActType as ICompiledTypeScope).Aliased) return "type " + scope.Name + GetGenericString(scope.TemplateArguments) + " = " + GetSimpleDescriptionForCompiledType(scope.ActType as ICompiledTypeScope, true); else return "type " + scope.Name + GetGenericString(scope.TemplateArguments) + " = " + GetSimpleDescription(scope.ActType); } public override string GetSynonimDescription(IProcScope scope) { return "type " + scope.Name + " = " + scope.Description; } public override bool IsDefinitionIdentifierAfterKeyword(KeywordKind keyw) { if (keyw == KeywordKind.Function || keyw == KeywordKind.Constructor || keyw == KeywordKind.Punkt) return true; return false; } public override bool IsMethodCallParameterSeparator(char key) { return key == ','; } public override bool IsTypeAfterKeyword(KeywordKind keyw) { if (keyw == KeywordKind.Colon) return true; return false; } public override KeywordKind TestForKeyword(string Text, int i) { StringBuilder sb = new StringBuilder(); int orig_i = i; int j = i; bool in_keyw = false; while (j >= 0 && Text[j] != '\n') j--; Stack kav_stack = new Stack(); j++; bool in_format_str = false; while (j <= i) { if (Text[j] == '\'' || Text[j] == '"') { if (kav_stack.Count == 0 && !in_keyw) { if (j == 0 || Text[j - 1] != '$') kav_stack.Push('\''); else { in_keyw = false; in_format_str = true; } } else if (kav_stack.Count > 0) kav_stack.Pop(); } else if (Text[j] == '{' && kav_stack.Count == 0 && !in_format_str) in_keyw = true; else if (Text[j] == '}') in_keyw = false; j++; } j = i; if ((kav_stack.Count != 0 || in_keyw) && !in_format_str) return PascalABCCompiler.Parsers.KeywordKind.Punkt; if (j >= 0 && Text[j] == '.') return PascalABCCompiler.Parsers.KeywordKind.Punkt; while (j >= 0) { //if (Text[j] == '{') return PascalABCCompiler.Parsers.KeywordKind.Punkt; if (!in_keyw && (Text[j] == '\'' || Text[j] == '"' || Text[j] == '\n')) break; if (Text[j] == '}') in_keyw = true; else if (Text[j] == '#' && !in_keyw) return PascalABCCompiler.Parsers.KeywordKind.Punkt; j--; } //if (j>= 0 && Text[j] == '\'') return CodeCompletion.KeywordKind.kw_punkt; while (i >= 0 && (Text[i] == ' ' || char.IsControl(Text[i]))) i--; if (i >= 0 && Text[i] == ':') return PascalABCCompiler.Parsers.KeywordKind.Colon; if (i >= 0 && Text[i] == ',') { while (i >= 0 && Text[i] != '\n') { if (char.IsLetterOrDigit(Text[i])) sb.Insert(0, Text[i]); else { PascalABCCompiler.Parsers.KeywordKind keyw = GetKeywordKind(sb.ToString()); if (keyw == PascalABCCompiler.Parsers.KeywordKind.Uses) return PascalABCCompiler.Parsers.KeywordKind.Uses; else if (keyw == PascalABCCompiler.Parsers.KeywordKind.Var) return PascalABCCompiler.Parsers.KeywordKind.Var; else sb.Remove(0, sb.Length); } i--; } } else while (i >= 0 && (char.IsLetterOrDigit(Text[i]) || Text[i] == '_' || Text[i] == '!')) { sb.Insert(0, Text[i]); i--; } string s = sb.ToString().ToLower(); return GetKeywordKind(s); } private string GetDescriptionForType(ITypeScope scope) { string template_str = GetTemplateString(scope); switch (scope.ElemKind) { case SymbolKind.Class: string mod = ""; if (scope.IsStatic) mod = "static "; if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$")) return mod + "class " + scope.TopScope.Name + "." + scope.Name + template_str; else return mod + "class " + scope.Name + template_str; case SymbolKind.Enum: if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$")) return "enum " + scope.TopScope.Name + "." + scope.Name; else return "enum " + scope.Name; } if (scope.TopScope != null) return scope.TopScope.Name + "." + scope.Name; else return scope.Name; } private string GetDescriptionForCompiledType(ICompiledTypeScope scope) { string s = GetFullTypeName(scope.CompiledType); ITypeScope[] instances = scope.GenericInstances; if (instances.Length > 0) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); int ind = s.IndexOf(GenericTypesStartBracket); if (ind != -1) sb.Append(s.Substring(0, ind)); else sb.Append(s); sb.Append(GenericTypesStartBracket); for (int i = 0; i < instances.Length; i++) { sb.Append(GetSimpleDescriptionWithoutNamespace(instances[i])); //sb.Append(instances[i].Name); if (i < instances.Length - 1) sb.Append(", "); } sb.Append(GenericTypesEndBracket); s = sb.ToString(); } switch (scope.ElemKind) { case SymbolKind.Class: string mod = ""; if (scope.IsStatic) mod = "static "; else { if (scope.IsAbstract) mod = "abstract "; if (scope.IsFinal) mod += "sealed "; } return mod + "class " + s; case SymbolKind.Interface: return "interface " + s; case SymbolKind.Enum: return "enum " + s; case SymbolKind.Delegate: return "delegate " + s; case SymbolKind.Struct: return "record " + s; case SymbolKind.Type: return "type " + s; } return s; } } }