12 It is based on the Python class browser found in this package. |
12 It is based on the Python class browser found in this package. |
13 """ |
13 """ |
14 |
14 |
15 import re |
15 import re |
16 |
16 |
|
17 from PyQt6.QtCore import QRegularExpression |
|
18 |
17 from eric7 import Utilities |
19 from eric7 import Utilities |
18 from eric7.Utilities import ClassBrowsers |
20 from eric7.Utilities import ClassBrowsers |
19 |
21 |
20 from . import ClbrBaseClasses |
22 from . import ClbrBaseClasses |
21 |
23 |
22 SUPPORTED_TYPES = [ClassBrowsers.RB_SOURCE] |
24 SUPPORTED_TYPES = [ClassBrowsers.RB_SOURCE] |
23 |
25 |
24 _getnext = re.compile( |
26 _getnext = QRegularExpression( |
25 r""" |
27 r""" |
26 (?P<String> |
28 (?P<String> |
27 =begin .*? =end |
29 =begin .*? =end |
28 |
30 |
29 | <<-? (?P<HereMarker1> [a-zA-Z0-9_]+? ) [ \t]* .*? (?P=HereMarker1) |
31 | <<-? (?P<HereMarker1> [a-zA-Z0-9_]+? ) [ \t]* .*? (?P=HereMarker1) |
312 cur_obj = None |
317 cur_obj = None |
313 lastGlobalEntry = None |
318 lastGlobalEntry = None |
314 i = 0 |
319 i = 0 |
315 while True: |
320 while True: |
316 m = _getnext(src, i) |
321 m = _getnext(src, i) |
317 if not m: |
322 if not m.hasMatch(): |
318 break |
323 break |
319 start, i = m.span() |
324 start, i = m.capturedStart(), m.capturedEnd() |
320 |
325 |
321 if m.start("Method") >= 0: |
326 if m.hasCaptured("Method"): |
322 # found a method definition or function |
327 # found a method definition or function |
323 thisindent = indent |
328 thisindent = indent |
324 indent += 1 |
329 indent += 1 |
325 meth_name = ( |
330 meth_name = ( |
326 m.group("MethodName") |
331 m.captured("MethodName") |
327 or m.group("MethodName2") |
332 or m.captured("MethodName2") |
328 or m.group("MethodName3") |
333 or m.captured("MethodName3") |
329 ) |
334 ) |
330 meth_sig = m.group("MethodSignature") |
335 meth_sig = m.captured("MethodSignature") |
331 meth_sig = meth_sig and meth_sig.replace("\\\n", "") or "" |
336 meth_sig = meth_sig and meth_sig.replace("\\\n", "") or "" |
332 meth_sig = _commentsub("", meth_sig) |
337 meth_sig = _commentsub("", meth_sig) |
333 lineno += src.count("\n", last_lineno_pos, start) |
338 lineno += src.count("\n", last_lineno_pos, start) |
334 last_lineno_pos = start |
339 last_lineno_pos = start |
335 if meth_name.startswith("self."): |
340 if meth_name.startswith("self."): |
380 cur_obj.setEndLine(lineno - 1) |
385 cur_obj.setEndLine(lineno - 1) |
381 cur_obj = f |
386 cur_obj = f |
382 classstack.append((f, thisindent)) # Marker for nested fns |
387 classstack.append((f, thisindent)) # Marker for nested fns |
383 |
388 |
384 elif ( |
389 elif ( |
385 m.start("String") >= 0 |
390 m.hasCaptured("String") |
386 or m.start("Comment") >= 0 |
391 or m.hasCaptured("Comment") |
387 or m.start("ClassIgnored") >= 0 |
392 or m.hasCaptured("ClassIgnored") |
388 or m.start("BeginEnd") >= 0 |
393 or m.hasCaptured("BeginEnd") |
389 ): |
394 ): |
390 pass |
395 pass |
391 |
396 |
392 elif m.start("Class") >= 0: |
397 elif m.hasCaptured("Class"): |
393 # we found a class definition |
398 # we found a class definition |
394 thisindent = indent |
399 thisindent = indent |
395 indent += 1 |
400 indent += 1 |
396 lineno += src.count("\n", last_lineno_pos, start) |
401 lineno += src.count("\n", last_lineno_pos, start) |
397 last_lineno_pos = start |
402 last_lineno_pos = start |
399 while classstack and classstack[-1][1] >= thisindent: |
404 while classstack and classstack[-1][1] >= thisindent: |
400 if classstack[-1][0] is not None: |
405 if classstack[-1][0] is not None: |
401 # record the end line |
406 # record the end line |
402 classstack[-1][0].setEndLine(lineno - 1) |
407 classstack[-1][0].setEndLine(lineno - 1) |
403 del classstack[-1] |
408 del classstack[-1] |
404 class_name = m.group("ClassName") or m.group("ClassName2") |
409 class_name = m.captured("ClassName") or m.captured("ClassName2") |
405 inherit = m.group("ClassSupers") |
410 inherit = m.captured("ClassSupers") |
406 if inherit: |
411 if inherit: |
407 # the class inherits from other classes |
412 # the class inherits from other classes |
408 inherit = inherit[1:].strip() |
413 inherit = inherit[1:].strip() |
409 inherit = [_commentsub("", inherit)] |
414 inherit = [_commentsub("", inherit)] |
410 # remember this class |
415 # remember this class |
431 while acstack and acstack[-1][1] >= thisindent: |
436 while acstack and acstack[-1][1] >= thisindent: |
432 del acstack[-1] |
437 del acstack[-1] |
433 acstack.append(["public", thisindent]) |
438 acstack.append(["public", thisindent]) |
434 # default access control is 'public' |
439 # default access control is 'public' |
435 |
440 |
436 elif m.start("Module") >= 0: |
441 elif m.hasCaptured("Module"): |
437 # we found a module definition |
442 # we found a module definition |
438 thisindent = indent |
443 thisindent = indent |
439 indent += 1 |
444 indent += 1 |
440 lineno += src.count("\n", last_lineno_pos, start) |
445 lineno += src.count("\n", last_lineno_pos, start) |
441 last_lineno_pos = start |
446 last_lineno_pos = start |
443 while classstack and classstack[-1][1] >= thisindent: |
448 while classstack and classstack[-1][1] >= thisindent: |
444 if classstack[-1][0] is not None: |
449 if classstack[-1][0] is not None: |
445 # record the end line |
450 # record the end line |
446 classstack[-1][0].setEndLine(lineno - 1) |
451 classstack[-1][0].setEndLine(lineno - 1) |
447 del classstack[-1] |
452 del classstack[-1] |
448 module_name = m.group("ModuleName") |
453 module_name = m.captured("ModuleName") |
449 # remember this class |
454 # remember this class |
450 cur_class = Module(module, module_name, file, lineno) |
455 cur_class = Module(module, module_name, file, lineno) |
451 if not classstack: |
456 if not classstack: |
452 if module_name in dictionary: |
457 if module_name in dictionary: |
453 cur_class = dictionary[module_name] |
458 cur_class = dictionary[module_name] |
470 while acstack and acstack[-1][1] >= thisindent: |
475 while acstack and acstack[-1][1] >= thisindent: |
471 del acstack[-1] |
476 del acstack[-1] |
472 acstack.append(["public", thisindent]) |
477 acstack.append(["public", thisindent]) |
473 # default access control is 'public' |
478 # default access control is 'public' |
474 |
479 |
475 elif m.start("AccessControl") >= 0: |
480 elif m.hasCaptured("AccessControl"): |
476 aclist = m.group("AccessControlList") |
481 aclist = m.captured("AccessControlList") |
477 if aclist is None: |
482 if not aclist: |
478 index = -1 |
483 index = -1 |
479 while index >= -len(acstack): |
484 while index >= -len(acstack): |
480 if acstack[index][1] < indent: |
485 if acstack[index][1] < indent: |
481 actype = ( |
486 actype = ( |
482 m.group("AccessControlType") |
487 m.captured("AccessControlType") |
483 or m.group("AccessControlType2").split("_")[0] |
488 or m.captured("AccessControlType2").split("_")[0] |
484 ) |
489 ) |
485 acstack[index][0] = actype.lower() |
490 acstack[index][0] = actype.lower() |
486 break |
491 break |
487 else: |
492 else: |
488 index -= 1 |
493 index -= 1 |
494 and not isinstance(classstack[index][0], Function) |
499 and not isinstance(classstack[index][0], Function) |
495 and classstack[index][1] < indent |
500 and classstack[index][1] < indent |
496 ): |
501 ): |
497 parent = classstack[index][0] |
502 parent = classstack[index][0] |
498 actype = ( |
503 actype = ( |
499 m.group("AccessControlType") |
504 m.captured("AccessControlType") |
500 or m.group("AccessControlType2").split("_")[0] |
505 or m.captured("AccessControlType2").split("_")[0] |
501 ) |
506 ) |
502 actype = actype.lower() |
507 actype = actype.lower() |
503 for name in aclist.split(","): |
508 for name in aclist.split(","): |
504 name = name.strip()[1:] # get rid of leading ':' |
509 name = name.strip()[1:] # get rid of leading ':' |
505 acmeth = parent._getmethod(name) |
510 acmeth = parent._getmethod(name) |
513 acmeth.setPublic() |
518 acmeth.setPublic() |
514 break |
519 break |
515 else: |
520 else: |
516 index -= 1 |
521 index -= 1 |
517 |
522 |
518 elif m.start("Attribute") >= 0: |
523 elif m.hasCaptured("Attribute"): |
519 lineno += src.count("\n", last_lineno_pos, start) |
524 lineno += src.count("\n", last_lineno_pos, start) |
520 last_lineno_pos = start |
525 last_lineno_pos = start |
521 index = -1 |
526 index = -1 |
522 while index >= -len(classstack): |
527 while index >= -len(classstack): |
523 if ( |
528 if ( |
524 classstack[index][0] is not None |
529 classstack[index][0] is not None |
525 and not isinstance(classstack[index][0], Function) |
530 and not isinstance(classstack[index][0], Function) |
526 and classstack[index][1] < indent |
531 and classstack[index][1] < indent |
527 ): |
532 ): |
528 attr = Attribute(module, m.group("AttributeName"), file, lineno) |
533 attr = Attribute(module, m.captured("AttributeName"), file, lineno) |
529 classstack[index][0]._addattribute(attr) |
534 classstack[index][0]._addattribute(attr) |
530 break |
535 break |
531 else: |
536 else: |
532 index -= 1 |
537 index -= 1 |
533 if lastGlobalEntry: |
538 if lastGlobalEntry: |
534 lastGlobalEntry.setEndLine(lineno - 1) |
539 lastGlobalEntry.setEndLine(lineno - 1) |
535 lastGlobalEntry = None |
540 lastGlobalEntry = None |
536 |
541 |
537 elif m.start("Attr") >= 0: |
542 elif m.hasCaptured("Attr"): |
538 lineno += src.count("\n", last_lineno_pos, start) |
543 lineno += src.count("\n", last_lineno_pos, start) |
539 last_lineno_pos = start |
544 last_lineno_pos = start |
540 index = -1 |
545 index = -1 |
541 while index >= -len(classstack): |
546 while index >= -len(classstack): |
542 if ( |
547 if ( |
543 classstack[index][0] is not None |
548 classstack[index][0] is not None |
544 and not isinstance(classstack[index][0], Function) |
549 and not isinstance(classstack[index][0], Function) |
545 and classstack[index][1] < indent |
550 and classstack[index][1] < indent |
546 ): |
551 ): |
547 parent = classstack[index][0] |
552 parent = classstack[index][0] |
548 if m.group("AttrType") is None: |
553 if not m.captured("AttrType"): |
549 nv = m.group("AttrList").split(",") |
554 nv = m.captured("AttrList").split(",") |
550 if not nv: |
555 if not nv: |
551 break |
556 break |
552 name = nv[0].strip()[1:] # get rid of leading ':' |
557 name = nv[0].strip()[1:] # get rid of leading ':' |
553 attr = ( |
558 attr = ( |
554 parent._getattribute("@" + name) |
559 parent._getattribute("@" + name) |
559 attr.setProtected() |
564 attr.setProtected() |
560 elif nv[1].strip() == "true": |
565 elif nv[1].strip() == "true": |
561 attr.setPublic() |
566 attr.setPublic() |
562 parent._addattribute(attr) |
567 parent._addattribute(attr) |
563 else: |
568 else: |
564 access = m.group("AttrType") |
569 access = m.captured("AttrType") |
565 for name in m.group("AttrList").split(","): |
570 for name in m.captured("AttrList").split(","): |
566 name = name.strip()[1:] # get rid of leading ':' |
571 name = name.strip()[1:] # get rid of leading ':' |
567 attr = ( |
572 attr = ( |
568 parent._getattribute("@" + name) |
573 parent._getattribute("@" + name) |
569 or parent._getattribute("@@" + name) |
574 or parent._getattribute("@@" + name) |
570 or Attribute(module, "@" + name, file, lineno) |
575 or Attribute(module, "@" + name, file, lineno) |
579 parent._addattribute(attr) |
584 parent._addattribute(attr) |
580 break |
585 break |
581 else: |
586 else: |
582 index -= 1 |
587 index -= 1 |
583 |
588 |
584 elif m.start("Begin") >= 0: |
589 elif m.hasCaptured("Begin"): |
585 # a begin of a block we are not interested in |
590 # a begin of a block we are not interested in |
586 indent += 1 |
591 indent += 1 |
587 |
592 |
588 elif m.start("End") >= 0: |
593 elif m.hasCaptured("End"): |
589 # an end of a block |
594 # an end of a block |
590 indent -= 1 |
595 indent -= 1 |
591 if indent < 0: |
596 if indent < 0: |
592 # no negative indent allowed |
597 # no negative indent allowed |
593 if classstack: |
598 if classstack: |
594 # it's a class/module method |
599 # it's a class/module method |
595 indent = classstack[-1][1] |
600 indent = classstack[-1][1] |
596 else: |
601 else: |
597 indent = 0 |
602 indent = 0 |
598 |
603 |
599 elif m.start("CodingLine") >= 0: |
604 elif m.hasCaptured("CodingLine"): |
600 # a coding statement |
605 # a coding statement |
601 coding = m.group("Coding") |
606 coding = m.captured("Coding") |
602 lineno += src.count("\n", last_lineno_pos, start) |
607 lineno += src.count("\n", last_lineno_pos, start) |
603 last_lineno_pos = start |
608 last_lineno_pos = start |
604 if "@@Coding@@" not in dictionary: |
609 if "@@Coding@@" not in dictionary: |
605 dictionary["@@Coding@@"] = ClbrBaseClasses.Coding( |
610 dictionary["@@Coding@@"] = ClbrBaseClasses.Coding( |
606 module, file, lineno, coding |
611 module, file, lineno, coding |