14 import sys |
14 import sys |
15 |
15 |
16 from dataclasses import dataclass |
16 from dataclasses import dataclass |
17 from functools import reduce |
17 from functools import reduce |
18 |
18 |
|
19 from PyQt6.QtCore import QRegularExpression |
|
20 |
19 from eric7 import Utilities |
21 from eric7 import Utilities |
20 from eric7.Utilities import ClassBrowsers |
22 from eric7.Utilities import ClassBrowsers |
21 |
23 |
22 from . import ClbrBaseClasses |
24 from . import ClbrBaseClasses |
23 |
25 |
24 TABWIDTH = 4 |
26 TABWIDTH = 4 |
25 |
27 |
26 SUPPORTED_TYPES = [ClassBrowsers.PY_SOURCE, ClassBrowsers.PTL_SOURCE] |
28 SUPPORTED_TYPES = [ClassBrowsers.PY_SOURCE, ClassBrowsers.PTL_SOURCE] |
27 |
29 |
28 _getnext = re.compile( |
30 _getnext = QRegularExpression( |
29 r""" |
31 r""" |
30 (?P<CodingLine> |
32 (?P<CodingLine> |
31 ^ \# \s* [*_-]* \s* coding[:=] \s* (?P<Coding> [-\w_.]+ ) \s* [*_-]* $ |
33 ^ \# \s* [*_-]* \s* coding[:=] \s* (?P<Coding> [-\w_.]+ ) \s* [*_-]* $ |
32 ) |
34 ) |
33 |
35 |
133 (?P<ImportFromList> |
135 (?P<ImportFromList> |
134 (?: \( \s* .*? \s* \) ) |
136 (?: \( \s* .*? \s* \) ) |
135 | |
137 | |
136 (?: [^#;\\\n]* (?: \\\n )* )* ) |
138 (?: [^#;\\\n]* (?: \\\n )* )* ) |
137 )""", |
139 )""", |
138 re.VERBOSE | re.DOTALL | re.MULTILINE, |
140 QRegularExpression.PatternOption.MultilineOption |
139 ).search |
141 | QRegularExpression.PatternOption.DotMatchesEverythingOption |
|
142 | QRegularExpression.PatternOption.ExtendedPatternSyntaxOption |
|
143 | QRegularExpression.PatternOption.UseUnicodePropertiesOption, |
|
144 ).match |
140 |
145 |
141 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub |
146 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub |
142 |
147 |
143 |
148 |
144 class VisibilityMixin(ClbrBaseClasses.ClbrVisibilityMixinBase): |
149 class VisibilityMixin(ClbrBaseClasses.ClbrVisibilityMixinBase): |
443 i = 0 |
448 i = 0 |
444 modifierType = ClbrBaseClasses.Function.General |
449 modifierType = ClbrBaseClasses.Function.General |
445 modifierIndent = -1 |
450 modifierIndent = -1 |
446 while True: |
451 while True: |
447 m = _getnext(src, i) |
452 m = _getnext(src, i) |
448 if not m: |
453 if not m.hasMatch(): |
449 break |
454 break |
450 start, i = m.span() |
455 start, i = m.capturedStart(), m.capturedEnd() |
451 |
456 |
452 if m.start("MethodModifier") >= 0: |
457 if m.hasCaptured("MethodModifier"): |
453 modifierIndent = _indent(m.group("MethodModifierIndent")) |
458 modifierIndent = _indent(m.captured("MethodModifierIndent")) |
454 modifierType = m.group("MethodModifierType") |
459 modifierType = m.captured("MethodModifierType") |
455 |
460 |
456 elif m.start("Method") >= 0: |
461 elif m.hasCaptured("Method"): |
457 # found a method definition or function |
462 # found a method definition or function |
458 thisindent = _indent(m.group("MethodIndent")) |
463 thisindent = _indent(m.captured("MethodIndent")) |
459 meth_name = m.group("MethodName") |
464 meth_name = m.captured("MethodName") |
460 meth_sig = m.group("MethodSignature") |
465 meth_sig = m.captured("MethodSignature") |
461 meth_sig = meth_sig.replace("\\\n", "") |
466 meth_sig = meth_sig.replace("\\\n", "") |
462 meth_sig = _commentsub("", meth_sig) |
467 meth_sig = _commentsub("", meth_sig) |
463 meth_ret = m.group("MethodReturnAnnotation") |
468 meth_ret = m.captured("MethodReturnAnnotation") |
464 meth_ret = meth_ret.replace("\\\n", "") |
469 meth_ret = meth_ret.replace("\\\n", "") |
465 meth_ret = _commentsub("", meth_ret) |
470 meth_ret = _commentsub("", meth_ret) |
466 lineno += src.count("\n", last_lineno_pos, start) |
471 lineno += src.count("\n", last_lineno_pos, start) |
467 last_lineno_pos = start |
472 last_lineno_pos = start |
468 if modifierType and modifierIndent == thisindent: |
473 if modifierType and modifierIndent == thisindent: |
532 |
537 |
533 # reset the modifier settings |
538 # reset the modifier settings |
534 modifierType = ClbrBaseClasses.Function.General |
539 modifierType = ClbrBaseClasses.Function.General |
535 modifierIndent = -1 |
540 modifierIndent = -1 |
536 |
541 |
537 elif m.start("String") >= 0: |
542 elif m.hasCaptured("String"): |
538 pass |
543 pass |
539 |
544 |
540 elif m.start("Class") >= 0: |
545 elif m.hasCaptured("Class"): |
541 # we found a class definition |
546 # we found a class definition |
542 thisindent = _indent(m.group("ClassIndent")) |
547 thisindent = _indent(m.captured("ClassIndent")) |
543 # close all classes indented at least as much |
548 # close all classes indented at least as much |
544 while classstack and classstack[-1][1] >= thisindent: |
549 while classstack and classstack[-1][1] >= thisindent: |
545 del classstack[-1] |
550 del classstack[-1] |
546 lineno += src.count("\n", last_lineno_pos, start) |
551 lineno += src.count("\n", last_lineno_pos, start) |
547 last_lineno_pos = start |
552 last_lineno_pos = start |
548 class_name = m.group("ClassName") |
553 class_name = m.captured("ClassName") |
549 inherit = m.group("ClassSupers") |
554 inherit = m.captured("ClassSupers") |
550 if inherit: |
555 if inherit: |
551 # the class inherits from other classes |
556 # the class inherits from other classes |
552 inherit = inherit[1:-1].strip() |
557 inherit = inherit[1:-1].strip() |
553 inherit = _commentsub("", inherit) |
558 inherit = _commentsub("", inherit) |
554 names = [] |
559 names = [] |
599 dictionary[class_name] = cur_class |
604 dictionary[class_name] = cur_class |
600 else: |
605 else: |
601 classstack[-1][0]._addclass(class_name, cur_class) |
606 classstack[-1][0]._addclass(class_name, cur_class) |
602 classstack.append((cur_class, thisindent)) |
607 classstack.append((cur_class, thisindent)) |
603 |
608 |
604 elif m.start("Attribute") >= 0: |
609 elif m.hasCaptured("Attribute"): |
605 lineno += src.count("\n", last_lineno_pos, start) |
610 lineno += src.count("\n", last_lineno_pos, start) |
606 last_lineno_pos = start |
611 last_lineno_pos = start |
607 index = -1 |
612 index = -1 |
608 while index >= -len(classstack): |
613 while index >= -len(classstack): |
609 if classstack[index][0] is not None and not isinstance( |
614 if classstack[index][0] is not None and not isinstance( |
610 classstack[index][0], Function |
615 classstack[index][0], Function |
611 ): |
616 ): |
612 attr = Attribute(module, m.group("AttributeName"), file, lineno) |
617 attr = Attribute(module, m.captured("AttributeName"), file, lineno) |
613 classstack[index][0]._addattribute(attr) |
618 classstack[index][0]._addattribute(attr) |
614 break |
619 break |
615 else: |
620 else: |
616 index -= 1 |
621 index -= 1 |
617 |
622 |
618 elif m.start("Main") >= 0: |
623 elif m.hasCaptured("Main"): |
619 # 'main' part of the script, reset class stack |
624 # 'main' part of the script, reset class stack |
620 lineno += src.count("\n", last_lineno_pos, start) |
625 lineno += src.count("\n", last_lineno_pos, start) |
621 last_lineno_pos = start |
626 last_lineno_pos = start |
622 classstack = [] |
627 classstack = [] |
623 |
628 |
624 elif m.start("Variable") >= 0: |
629 elif m.hasCaptured("Variable"): |
625 thisindent = _indent(m.group("VariableIndent")) |
630 thisindent = _indent(m.captured("VariableIndent")) |
626 variable_name = m.group("VariableName") |
631 variable_name = m.captured("VariableName") |
627 lineno += src.count("\n", last_lineno_pos, start) |
632 lineno += src.count("\n", last_lineno_pos, start) |
628 last_lineno_pos = start |
633 last_lineno_pos = start |
629 if thisindent == 0 or not classstack: |
634 if thisindent == 0 or not classstack: |
630 # global variable, reset class stack first |
635 # global variable, reset class stack first |
631 classstack = [] |
636 classstack = [] |
647 classstack[index][0]._addglobal( |
652 classstack[index][0]._addglobal( |
648 Attribute(module, variable_name, file, lineno) |
653 Attribute(module, variable_name, file, lineno) |
649 ) |
654 ) |
650 break |
655 break |
651 |
656 |
652 elif m.start("Publics") >= 0: |
657 elif m.hasCaptured("Publics"): |
653 idents = m.group("Identifiers") |
658 idents = m.captured("Identifiers") |
654 lineno += src.count("\n", last_lineno_pos, start) |
659 lineno += src.count("\n", last_lineno_pos, start) |
655 last_lineno_pos = start |
660 last_lineno_pos = start |
656 pubs = Publics( |
661 pubs = Publics( |
657 module=module, |
662 module=module, |
658 file=file, |
663 file=file, |
662 for e in idents.split(",") |
667 for e in idents.split(",") |
663 ], |
668 ], |
664 ) |
669 ) |
665 dictionary["__all__"] = pubs |
670 dictionary["__all__"] = pubs |
666 |
671 |
667 elif m.start("Import") >= 0: |
672 elif m.hasCaptured("Import"): |
668 # - import module |
673 # - import module |
669 names = [ |
674 names = [ |
670 n.strip() |
675 n.strip() |
671 for n in "".join(m.group("ImportList").splitlines()) |
676 for n in "".join(m.captured("ImportList").splitlines()) |
672 .replace("\\", "") |
677 .replace("\\", "") |
673 .split(",") |
678 .split(",") |
674 ] |
679 ] |
675 lineno += src.count("\n", last_lineno_pos, start) |
680 lineno += src.count("\n", last_lineno_pos, start) |
676 last_lineno_pos = start |
681 last_lineno_pos = start |
677 if "@@Import@@" not in dictionary: |
682 if "@@Import@@" not in dictionary: |
678 dictionary["@@Import@@"] = Imports(module, file) |
683 dictionary["@@Import@@"] = Imports(module, file) |
679 for name in names: |
684 for name in names: |
680 dictionary["@@Import@@"].addImport(name, [], lineno) |
685 dictionary["@@Import@@"].addImport(name, [], lineno) |
681 |
686 |
682 elif m.start("ImportFrom") >= 0: |
687 elif m.hasCaptured("ImportFrom"): |
683 # - from module import stuff |
688 # - from module import stuff |
684 mod = m.group("ImportFromPath") |
689 mod = m.captured("ImportFromPath") |
685 namesLines = ( |
690 namesLines = ( |
686 m.group("ImportFromList") |
691 m.captured("ImportFromList") |
687 .replace("(", "") |
692 .replace("(", "") |
688 .replace(")", "") |
693 .replace(")", "") |
689 .replace("\\", "") |
694 .replace("\\", "") |
690 .strip() |
695 .strip() |
691 .splitlines() |
696 .splitlines() |
696 last_lineno_pos = start |
701 last_lineno_pos = start |
697 if "@@Import@@" not in dictionary: |
702 if "@@Import@@" not in dictionary: |
698 dictionary["@@Import@@"] = Imports(module, file) |
703 dictionary["@@Import@@"] = Imports(module, file) |
699 dictionary["@@Import@@"].addImport(mod, names, lineno) |
704 dictionary["@@Import@@"].addImport(mod, names, lineno) |
700 |
705 |
701 elif m.start("ConditionalDefine") >= 0: |
706 elif m.hasCaptured("ConditionalDefine"): |
702 # a conditional function/method definition |
707 # a conditional function/method definition |
703 thisindent = _indent(m.group("ConditionalDefineIndent")) |
708 thisindent = _indent(m.captured("ConditionalDefineIndent")) |
704 while conditionalsstack and conditionalsstack[-1] >= thisindent: |
709 while conditionalsstack and conditionalsstack[-1] >= thisindent: |
705 del conditionalsstack[-1] |
710 del conditionalsstack[-1] |
706 if deltastack: |
711 if deltastack: |
707 del deltastack[-1] |
712 del deltastack[-1] |
708 conditionalsstack.append(thisindent) |
713 conditionalsstack.append(thisindent) |
709 deltaindentcalculated = False |
714 deltaindentcalculated = False |
710 |
715 |
711 elif m.start("CodingLine") >= 0: |
716 elif m.hasCaptured("CodingLine"): |
712 # a coding statement |
717 # a coding statement |
713 coding = m.group("Coding") |
718 coding = m.captured("Coding") |
714 lineno += src.count("\n", last_lineno_pos, start) |
719 lineno += src.count("\n", last_lineno_pos, start) |
715 last_lineno_pos = start |
720 last_lineno_pos = start |
716 if "@@Coding@@" not in dictionary: |
721 if "@@Coding@@" not in dictionary: |
717 dictionary["@@Coding@@"] = ClbrBaseClasses.Coding( |
722 dictionary["@@Coding@@"] = ClbrBaseClasses.Coding( |
718 module, file, lineno, coding |
723 module, file, lineno, coding |