cshape 0.2.1__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cshape-0.2.1 → cshape-0.2.3}/PKG-INFO +10 -1
- {cshape-0.2.1 → cshape-0.2.3}/README.md +9 -0
- {cshape-0.2.1 → cshape-0.2.3}/cshape.egg-info/PKG-INFO +10 -1
- {cshape-0.2.1 → cshape-0.2.3}/cshape.py +97 -121
- {cshape-0.2.1 → cshape-0.2.3}/pyproject.toml +1 -1
- cshape-0.2.3/tests/test_smoke.py +75 -0
- cshape-0.2.1/tests/test_smoke.py +0 -41
- {cshape-0.2.1 → cshape-0.2.3}/LICENSE +0 -0
- {cshape-0.2.1 → cshape-0.2.3}/cshape.egg-info/SOURCES.txt +0 -0
- {cshape-0.2.1 → cshape-0.2.3}/cshape.egg-info/dependency_links.txt +0 -0
- {cshape-0.2.1 → cshape-0.2.3}/cshape.egg-info/top_level.txt +0 -0
- {cshape-0.2.1 → cshape-0.2.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cshape
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A dependency-free C AST + printer: build a tree in Python, get C11 source back
|
|
5
5
|
Author-email: Alex Balan <outsiders.b@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -62,6 +62,12 @@ int add(int a, int b) {
|
|
|
62
62
|
starts with a blank line by default, so `.strip()` if you're printing a
|
|
63
63
|
single node standalone rather than concatenating several.)
|
|
64
64
|
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
- [docs/api.md](docs/api.md) - documentation index
|
|
68
|
+
- [docs/quickstart.md](docs/quickstart.md) - getting started and first example
|
|
69
|
+
- [docs/reference.md](docs/reference.md) - current API reference
|
|
70
|
+
|
|
65
71
|
## What it covers
|
|
66
72
|
|
|
67
73
|
- Types: named types, pointers, arrays, function types, structs/unions, enums
|
|
@@ -77,6 +83,9 @@ single node standalone rather than concatenating several.)
|
|
|
77
83
|
- A `.mark` field on every node: set it to any string and it shows up as a
|
|
78
84
|
`/*mark*/` comment right before that node in the output — useful for
|
|
79
85
|
tracing which part of your own compiler/generator produced which bit of C
|
|
86
|
+
- A `.note` field on every value, printed as a `/* note */` comment *after*
|
|
87
|
+
the value — for saying where a value came from once it no longer shows:
|
|
88
|
+
`3.125 /* totalVolume / elementVolume */`
|
|
80
89
|
|
|
81
90
|
## What it doesn't do
|
|
82
91
|
|
|
@@ -44,6 +44,12 @@ int add(int a, int b) {
|
|
|
44
44
|
starts with a blank line by default, so `.strip()` if you're printing a
|
|
45
45
|
single node standalone rather than concatenating several.)
|
|
46
46
|
|
|
47
|
+
## Documentation
|
|
48
|
+
|
|
49
|
+
- [docs/api.md](docs/api.md) - documentation index
|
|
50
|
+
- [docs/quickstart.md](docs/quickstart.md) - getting started and first example
|
|
51
|
+
- [docs/reference.md](docs/reference.md) - current API reference
|
|
52
|
+
|
|
47
53
|
## What it covers
|
|
48
54
|
|
|
49
55
|
- Types: named types, pointers, arrays, function types, structs/unions, enums
|
|
@@ -59,6 +65,9 @@ single node standalone rather than concatenating several.)
|
|
|
59
65
|
- A `.mark` field on every node: set it to any string and it shows up as a
|
|
60
66
|
`/*mark*/` comment right before that node in the output — useful for
|
|
61
67
|
tracing which part of your own compiler/generator produced which bit of C
|
|
68
|
+
- A `.note` field on every value, printed as a `/* note */` comment *after*
|
|
69
|
+
the value — for saying where a value came from once it no longer shows:
|
|
70
|
+
`3.125 /* totalVolume / elementVolume */`
|
|
62
71
|
|
|
63
72
|
## What it doesn't do
|
|
64
73
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cshape
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A dependency-free C AST + printer: build a tree in Python, get C11 source back
|
|
5
5
|
Author-email: Alex Balan <outsiders.b@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -62,6 +62,12 @@ int add(int a, int b) {
|
|
|
62
62
|
starts with a blank line by default, so `.strip()` if you're printing a
|
|
63
63
|
single node standalone rather than concatenating several.)
|
|
64
64
|
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
- [docs/api.md](docs/api.md) - documentation index
|
|
68
|
+
- [docs/quickstart.md](docs/quickstart.md) - getting started and first example
|
|
69
|
+
- [docs/reference.md](docs/reference.md) - current API reference
|
|
70
|
+
|
|
65
71
|
## What it covers
|
|
66
72
|
|
|
67
73
|
- Types: named types, pointers, arrays, function types, structs/unions, enums
|
|
@@ -77,6 +83,9 @@ single node standalone rather than concatenating several.)
|
|
|
77
83
|
- A `.mark` field on every node: set it to any string and it shows up as a
|
|
78
84
|
`/*mark*/` comment right before that node in the output — useful for
|
|
79
85
|
tracing which part of your own compiler/generator produced which bit of C
|
|
86
|
+
- A `.note` field on every value, printed as a `/* note */` comment *after*
|
|
87
|
+
the value — for saying where a value came from once it no longer shows:
|
|
88
|
+
`3.125 /* totalVolume / elementVolume */`
|
|
80
89
|
|
|
81
90
|
## What it doesn't do
|
|
82
91
|
|
|
@@ -55,13 +55,12 @@ def str_nl_indent(nl=1):
|
|
|
55
55
|
return s
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def render(node, style='legacy', indent='\t'
|
|
58
|
+
def render(node, style='legacy', indent='\t'):
|
|
59
59
|
global indent_level, styleguide, nl_symbol, indent_symbol
|
|
60
60
|
|
|
61
61
|
saved = (indent_level, styleguide, nl_symbol, indent_symbol)
|
|
62
62
|
indent_level = 0
|
|
63
63
|
styleguide = styles[style]
|
|
64
|
-
nl_symbol = newline
|
|
65
64
|
indent_symbol = indent
|
|
66
65
|
|
|
67
66
|
try:
|
|
@@ -141,11 +140,6 @@ def str_gcc_attributes(attributes):
|
|
|
141
140
|
|
|
142
141
|
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
143
|
class CField():
|
|
150
144
|
def __init__(self, id, type, specifiers=None, nl=0):
|
|
151
145
|
#assert(isinstance(type, CType))
|
|
@@ -253,11 +247,12 @@ class CTypeFunction(CType):
|
|
|
253
247
|
|
|
254
248
|
|
|
255
249
|
class CTypeStruct(CType):
|
|
256
|
-
def __init__(self, fields, tag, specifiers=None):
|
|
250
|
+
def __init__(self, fields, tag, specifiers=None, attributes=None):
|
|
257
251
|
super().__init__()
|
|
258
252
|
self.fields = fields
|
|
259
253
|
self.tag = tag
|
|
260
254
|
self.specifiers = specifiers if specifiers != None else []
|
|
255
|
+
self.attributes = attributes
|
|
261
256
|
self.precedence = 0
|
|
262
257
|
|
|
263
258
|
def to_str(self, text='', with_qualifiers=True):
|
|
@@ -288,7 +283,13 @@ class CTypeStruct(CType):
|
|
|
288
283
|
else:
|
|
289
284
|
sstr += 'uint8_t __placeholder;'
|
|
290
285
|
indent_down()
|
|
291
|
-
sstr += str_nl_indent(nl_end) + '}'
|
|
286
|
+
sstr += str_nl_indent(nl_end) + '}'
|
|
287
|
+
# атрибуты типа печатаем после закрывающей скобки, а не перед
|
|
288
|
+
# декларацией: в префиксной позиции компилятор их у struct/union
|
|
289
|
+
# игнорирует ("attribute is ignored, place it after struct"),
|
|
290
|
+
# а эта работает всюду - и в определении, и в typedef, и у поля
|
|
291
|
+
sstr += with_space(str_gcc_attributes(self.attributes).strip())
|
|
292
|
+
sstr += with_space(text)
|
|
292
293
|
return sstr
|
|
293
294
|
|
|
294
295
|
|
|
@@ -392,16 +393,25 @@ class KV():
|
|
|
392
393
|
self.key = key
|
|
393
394
|
self.value = value
|
|
394
395
|
self.nl = nl
|
|
396
|
+
self.mark = None
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def str_kv(x):
|
|
400
|
+
sstr = ".%s = %s" % (x.key, str_cvalue(x.value))
|
|
401
|
+
if x.mark != None:
|
|
402
|
+
sstr = '/*%s*/' % x.mark + sstr
|
|
403
|
+
return sstr
|
|
395
404
|
|
|
396
405
|
|
|
397
406
|
class CValue():
|
|
398
|
-
def __init__(self):
|
|
407
|
+
def __init__(self, nl=0):
|
|
399
408
|
self.mark = None
|
|
409
|
+
self.nl = nl
|
|
400
410
|
|
|
401
411
|
|
|
402
412
|
class CValueIdentifier(CValue):
|
|
403
|
-
def __init__(self, id):
|
|
404
|
-
super().__init__()
|
|
413
|
+
def __init__(self, id, nl=0):
|
|
414
|
+
super().__init__(nl=nl)
|
|
405
415
|
self.id = id
|
|
406
416
|
self.precedence = 15
|
|
407
417
|
|
|
@@ -412,8 +422,8 @@ class CValueIdentifier(CValue):
|
|
|
412
422
|
|
|
413
423
|
|
|
414
424
|
class CValueInteger(CValue):
|
|
415
|
-
def __init__(self, number, as_hex=False, nsigns=0, suffix=''):
|
|
416
|
-
super().__init__()
|
|
425
|
+
def __init__(self, number, as_hex=False, nsigns=0, suffix='', nl=0):
|
|
426
|
+
super().__init__(nl=nl)
|
|
417
427
|
assert(isinstance(number, int))
|
|
418
428
|
assert(isinstance(as_hex, bool))
|
|
419
429
|
self.precedence = 15
|
|
@@ -441,9 +451,9 @@ def string_literal_prefix(width):
|
|
|
441
451
|
|
|
442
452
|
|
|
443
453
|
class CValueString(CValue):
|
|
444
|
-
def __init__(self, string, width):
|
|
454
|
+
def __init__(self, string, width, nl=0):
|
|
445
455
|
assert(isinstance(string, str))
|
|
446
|
-
super().__init__()
|
|
456
|
+
super().__init__(nl=nl)
|
|
447
457
|
self.string = string
|
|
448
458
|
self.width = width
|
|
449
459
|
self.precedence = 15
|
|
@@ -475,9 +485,9 @@ def code_to_char(cc):
|
|
|
475
485
|
|
|
476
486
|
|
|
477
487
|
class CValueChar(CValue):
|
|
478
|
-
def __init__(self, cc, width=8):
|
|
488
|
+
def __init__(self, cc, width=8, nl=0):
|
|
479
489
|
assert(isinstance(cc, int))
|
|
480
|
-
super().__init__()
|
|
490
|
+
super().__init__(nl=nl)
|
|
481
491
|
self.char_code = cc
|
|
482
492
|
self.width = width
|
|
483
493
|
self.precedence = 15
|
|
@@ -488,8 +498,8 @@ class CValueChar(CValue):
|
|
|
488
498
|
|
|
489
499
|
|
|
490
500
|
class CValueArray(CValue):
|
|
491
|
-
def __init__(self, items):
|
|
492
|
-
super().__init__()
|
|
501
|
+
def __init__(self, items, nl=0):
|
|
502
|
+
super().__init__(nl=nl)
|
|
493
503
|
self.items = items
|
|
494
504
|
self.precedence = 15
|
|
495
505
|
|
|
@@ -520,8 +530,8 @@ class CValueArray(CValue):
|
|
|
520
530
|
|
|
521
531
|
|
|
522
532
|
class CValueStruct(CValue):
|
|
523
|
-
def __init__(self, items):
|
|
524
|
-
super().__init__()
|
|
533
|
+
def __init__(self, items, nl=0):
|
|
534
|
+
super().__init__(nl=nl)
|
|
525
535
|
self.items = items
|
|
526
536
|
self.precedence = 15
|
|
527
537
|
|
|
@@ -540,7 +550,7 @@ class CValueStruct(CValue):
|
|
|
540
550
|
if item.nl == 0:
|
|
541
551
|
s_items += " "
|
|
542
552
|
s_items += str_nl_indent(item.nl)
|
|
543
|
-
s_items +=
|
|
553
|
+
s_items += str_kv(item)
|
|
544
554
|
i += 1
|
|
545
555
|
|
|
546
556
|
indent_down()
|
|
@@ -561,14 +571,14 @@ class CValueStruct(CValue):
|
|
|
561
571
|
|
|
562
572
|
|
|
563
573
|
class CValueParen(CValue):
|
|
564
|
-
def __init__(self, value):
|
|
574
|
+
def __init__(self, value, nl=0):
|
|
565
575
|
assert(isinstance(value, CValue))
|
|
566
|
-
super().__init__()
|
|
576
|
+
super().__init__(nl=nl)
|
|
567
577
|
self.value = value
|
|
568
578
|
self.precedence = 15
|
|
569
579
|
|
|
570
580
|
def __str__(self):
|
|
571
|
-
return
|
|
581
|
+
return str_cvalue(self.value, ext_precedence=valuePrecedenceMax)
|
|
572
582
|
|
|
573
583
|
|
|
574
584
|
|
|
@@ -661,28 +671,6 @@ class CValueDereference(CValue):
|
|
|
661
671
|
return '*%s' % str_cvalue(self.value, ext_precedence=self.precedence)
|
|
662
672
|
|
|
663
673
|
|
|
664
|
-
class CValueIncrement(CValue):
|
|
665
|
-
def __init__(self, value):
|
|
666
|
-
assert(isinstance(value, CValue))
|
|
667
|
-
super().__init__()
|
|
668
|
-
self.value = value
|
|
669
|
-
self.precedence = 13
|
|
670
|
-
|
|
671
|
-
def __str__(self):
|
|
672
|
-
return '++%s' % (str_cvalue(self.value, ext_precedence=self.precedence))
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
class CValueDecrement(CValue):
|
|
676
|
-
def __init__(self, value):
|
|
677
|
-
assert(isinstance(value, CValue))
|
|
678
|
-
super().__init__()
|
|
679
|
-
self.value = value
|
|
680
|
-
self.precedence = 13
|
|
681
|
-
|
|
682
|
-
def __str__(self):
|
|
683
|
-
return '--%s' % str_cvalue(self.value, ext_precedence=self.precedence)
|
|
684
|
-
|
|
685
|
-
|
|
686
674
|
class CValueUnaryPlus(CValue):
|
|
687
675
|
def __init__(self, value):
|
|
688
676
|
assert(isinstance(value, CValue))
|
|
@@ -760,7 +748,7 @@ class CValueMul(CValue):
|
|
|
760
748
|
|
|
761
749
|
def __str__(self):
|
|
762
750
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
763
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
751
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
764
752
|
return '%s * %s' % (lx, rx)
|
|
765
753
|
|
|
766
754
|
|
|
@@ -775,7 +763,7 @@ class CValueDiv(CValue):
|
|
|
775
763
|
|
|
776
764
|
def __str__(self):
|
|
777
765
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
778
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
766
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
779
767
|
return '%s / %s' % (lx, rx)
|
|
780
768
|
|
|
781
769
|
|
|
@@ -790,7 +778,7 @@ class CValueMod(CValue):
|
|
|
790
778
|
|
|
791
779
|
def __str__(self):
|
|
792
780
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
793
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
781
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
794
782
|
return '%s %% %s' % (lx, rx)
|
|
795
783
|
|
|
796
784
|
|
|
@@ -805,7 +793,7 @@ class CValueAdd(CValue):
|
|
|
805
793
|
|
|
806
794
|
def __str__(self):
|
|
807
795
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
808
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
796
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
809
797
|
return '%s + %s' % (lx, rx)
|
|
810
798
|
|
|
811
799
|
|
|
@@ -820,7 +808,7 @@ class CValueSub(CValue):
|
|
|
820
808
|
|
|
821
809
|
def __str__(self):
|
|
822
810
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
823
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
811
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
824
812
|
return '%s - %s' % (lx, rx)
|
|
825
813
|
|
|
826
814
|
|
|
@@ -839,7 +827,7 @@ class CValueShiftLeft(CValue):
|
|
|
839
827
|
lprec = self.precedence
|
|
840
828
|
if self.left.precedence == self.precedence + 1:
|
|
841
829
|
lprec = valuePrecedenceMax
|
|
842
|
-
rprec = self.precedence
|
|
830
|
+
rprec = self.precedence + 1
|
|
843
831
|
if self.right.precedence == self.precedence + 1:
|
|
844
832
|
rprec = valuePrecedenceMax
|
|
845
833
|
|
|
@@ -863,7 +851,7 @@ class CValueShiftRight(CValue):
|
|
|
863
851
|
lprec = self.precedence
|
|
864
852
|
if self.left.precedence == self.precedence + 1:
|
|
865
853
|
lprec = valuePrecedenceMax
|
|
866
|
-
rprec = self.precedence
|
|
854
|
+
rprec = self.precedence + 1
|
|
867
855
|
if self.right.precedence == self.precedence + 1:
|
|
868
856
|
rprec = valuePrecedenceMax
|
|
869
857
|
|
|
@@ -883,7 +871,7 @@ class CValueLt(CValue):
|
|
|
883
871
|
|
|
884
872
|
def __str__(self):
|
|
885
873
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
886
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
874
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
887
875
|
return '%s < %s' % (lx, rx)
|
|
888
876
|
|
|
889
877
|
|
|
@@ -898,7 +886,7 @@ class CValueGt(CValue):
|
|
|
898
886
|
|
|
899
887
|
def __str__(self):
|
|
900
888
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
901
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
889
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
902
890
|
return '%s > %s' % (lx, rx)
|
|
903
891
|
|
|
904
892
|
|
|
@@ -913,7 +901,7 @@ class CValueLE(CValue):
|
|
|
913
901
|
|
|
914
902
|
def __str__(self):
|
|
915
903
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
916
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
904
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
917
905
|
return '%s <= %s' % (lx, rx)
|
|
918
906
|
|
|
919
907
|
|
|
@@ -928,7 +916,7 @@ class CValueGE(CValue):
|
|
|
928
916
|
|
|
929
917
|
def __str__(self):
|
|
930
918
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
931
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
919
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
932
920
|
return '%s >= %s' % (lx, rx)
|
|
933
921
|
|
|
934
922
|
|
|
@@ -943,7 +931,7 @@ class CValueEq(CValue):
|
|
|
943
931
|
|
|
944
932
|
def __str__(self):
|
|
945
933
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
946
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
934
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
947
935
|
return '%s == %s' % (lx, rx)
|
|
948
936
|
|
|
949
937
|
|
|
@@ -958,7 +946,7 @@ class CValueNe(CValue):
|
|
|
958
946
|
|
|
959
947
|
def __str__(self):
|
|
960
948
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
961
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
949
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
962
950
|
return '%s != %s' % (lx, rx)
|
|
963
951
|
|
|
964
952
|
|
|
@@ -982,7 +970,7 @@ class CValueBitwiseAnd(CValue):
|
|
|
982
970
|
|
|
983
971
|
def __str__(self):
|
|
984
972
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
985
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
973
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
986
974
|
return '%s & %s' % (lx, rx)
|
|
987
975
|
|
|
988
976
|
|
|
@@ -997,7 +985,7 @@ class CValueBitwiseXor(CValue):
|
|
|
997
985
|
|
|
998
986
|
def __str__(self):
|
|
999
987
|
lx = str_cvalue(self.left, ext_precedence=select_prio_plus(self.precedence, self.left.precedence, n=1))
|
|
1000
|
-
rx = str_cvalue(self.right, ext_precedence=select_prio_plus(self.precedence, self.right.precedence, n=1))
|
|
988
|
+
rx = str_cvalue(self.right, ext_precedence=max(self.precedence + 1, select_prio_plus(self.precedence, self.right.precedence, n=1)))
|
|
1001
989
|
return '%s ^ %s' % (lx, rx)
|
|
1002
990
|
|
|
1003
991
|
|
|
@@ -1012,7 +1000,7 @@ class CValueBitwiseOr(CValue):
|
|
|
1012
1000
|
|
|
1013
1001
|
def __str__(self):
|
|
1014
1002
|
lx = str_cvalue(self.left, ext_precedence=select_prio_plus(self.precedence, self.left.precedence, n=2))
|
|
1015
|
-
rx = str_cvalue(self.right, ext_precedence=select_prio_plus(self.precedence, self.right.precedence, n=2))
|
|
1003
|
+
rx = str_cvalue(self.right, ext_precedence=max(self.precedence + 1, select_prio_plus(self.precedence, self.right.precedence, n=2)))
|
|
1016
1004
|
return '%s | %s' % (lx, rx)
|
|
1017
1005
|
|
|
1018
1006
|
|
|
@@ -1027,7 +1015,7 @@ class CValueLogicalAnd(CValue):
|
|
|
1027
1015
|
|
|
1028
1016
|
def __str__(self):
|
|
1029
1017
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
1030
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
1018
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
1031
1019
|
return '%s && %s' % (lx, rx)
|
|
1032
1020
|
|
|
1033
1021
|
|
|
@@ -1042,7 +1030,7 @@ class CValueLogicalOr(CValue):
|
|
|
1042
1030
|
|
|
1043
1031
|
def __str__(self):
|
|
1044
1032
|
lx = str_cvalue(self.left, ext_precedence=select_prio_plus(self.precedence, self.left.precedence, n=1))
|
|
1045
|
-
rx = str_cvalue(self.right, ext_precedence=select_prio_plus(self.precedence, self.right.precedence, n=1))
|
|
1033
|
+
rx = str_cvalue(self.right, ext_precedence=max(self.precedence + 1, select_prio_plus(self.precedence, self.right.precedence, n=1)))
|
|
1046
1034
|
return '%s || %s' % (lx, rx)
|
|
1047
1035
|
|
|
1048
1036
|
|
|
@@ -1109,7 +1097,7 @@ class CValueStringConcat(CValue):
|
|
|
1109
1097
|
|
|
1110
1098
|
def __str__(self):
|
|
1111
1099
|
lx = str_cvalue(self.left, ext_precedence=self.precedence)
|
|
1112
|
-
rx = str_cvalue(self.right, ext_precedence=self.precedence)
|
|
1100
|
+
rx = str_cvalue(self.right, ext_precedence=self.precedence + 1)
|
|
1113
1101
|
return lx + ' ' + rx
|
|
1114
1102
|
|
|
1115
1103
|
|
|
@@ -1117,7 +1105,10 @@ class CValueStringConcat(CValue):
|
|
|
1117
1105
|
def str_cvalue(v, ext_precedence=0):
|
|
1118
1106
|
assert(isinstance(v, CValue))
|
|
1119
1107
|
y = str(v)
|
|
1120
|
-
|
|
1108
|
+
# (!) mark сам по себе скобок не ставит. Комментарий в C лексически
|
|
1109
|
+
# прозрачен, а скобки - нет: отладочная пометка, меняющая
|
|
1110
|
+
# сгенерированный код, перестает быть наблюдением за ним
|
|
1111
|
+
sstr = wrap_if(y, v.precedence < ext_precedence)
|
|
1121
1112
|
if v.mark != None:
|
|
1122
1113
|
sstr = '/*%s*/' % v.mark + sstr
|
|
1123
1114
|
return sstr
|
|
@@ -1128,15 +1119,13 @@ def str_cvalue(v, ext_precedence=0):
|
|
|
1128
1119
|
|
|
1129
1120
|
def str_cstmt(x):
|
|
1130
1121
|
assert(x != None)
|
|
1131
|
-
|
|
1132
|
-
#
|
|
1133
|
-
#
|
|
1134
|
-
|
|
1135
|
-
#sstr += str_nl_indent(x.nl)
|
|
1136
|
-
sstr += str(x)
|
|
1122
|
+
# (!) перевод строки и отступ печатает обертка, а не сам узел: пометка
|
|
1123
|
+
# относится к коду, а не к пустому месту перед ним, и должна встать
|
|
1124
|
+
# между отступом и кодом - иначе она уезжает в конец предыдущей строки
|
|
1125
|
+
sstr = str_nl_indent(x.nl)
|
|
1137
1126
|
if x.mark != None:
|
|
1138
|
-
sstr
|
|
1139
|
-
return sstr
|
|
1127
|
+
sstr += '/*%s*/' % x.mark
|
|
1128
|
+
return sstr + str(x)
|
|
1140
1129
|
|
|
1141
1130
|
|
|
1142
1131
|
class CStmt():
|
|
@@ -1156,7 +1145,6 @@ class CStmtLineComment(CStmt):
|
|
|
1156
1145
|
|
|
1157
1146
|
def __str__(self):
|
|
1158
1147
|
sstr = ''
|
|
1159
|
-
sstr += str_nl_indent(self.nl)
|
|
1160
1148
|
n = len(self.lines)
|
|
1161
1149
|
i = 0
|
|
1162
1150
|
while i < n:
|
|
@@ -1176,8 +1164,7 @@ class CStmtBlockComment(CStmt):
|
|
|
1176
1164
|
self.nl = 1
|
|
1177
1165
|
|
|
1178
1166
|
def __str__(self):
|
|
1179
|
-
sstr =
|
|
1180
|
-
sstr += "/*%s*/" % self.text
|
|
1167
|
+
sstr = "/*%s*/" % self.text
|
|
1181
1168
|
return sstr
|
|
1182
1169
|
|
|
1183
1170
|
|
|
@@ -1209,8 +1196,7 @@ class CStmtExpr(CStmt):
|
|
|
1209
1196
|
self.nl = 1
|
|
1210
1197
|
|
|
1211
1198
|
def __str__(self):
|
|
1212
|
-
|
|
1213
|
-
return sstr + str_cvalue(self.value) + ';'
|
|
1199
|
+
return str_cvalue(self.value) + ';'
|
|
1214
1200
|
|
|
1215
1201
|
|
|
1216
1202
|
class CStmtAssignment(CStmt):
|
|
@@ -1222,8 +1208,7 @@ class CStmtAssignment(CStmt):
|
|
|
1222
1208
|
self.rvalue = rvalue
|
|
1223
1209
|
|
|
1224
1210
|
def __str__(self):
|
|
1225
|
-
|
|
1226
|
-
return sstr + "%s = %s;" % (str_cvalue(self.lvalue), str_cvalue(self.rvalue))
|
|
1211
|
+
return "%s = %s;" % (str_cvalue(self.lvalue), str_cvalue(self.rvalue))
|
|
1227
1212
|
|
|
1228
1213
|
|
|
1229
1214
|
class CStmtIncrement(CStmt):
|
|
@@ -1233,7 +1218,7 @@ class CStmtIncrement(CStmt):
|
|
|
1233
1218
|
self.value = value
|
|
1234
1219
|
|
|
1235
1220
|
def __str__(self):
|
|
1236
|
-
return
|
|
1221
|
+
return "++%s;" % str_cvalue(self.value)
|
|
1237
1222
|
|
|
1238
1223
|
|
|
1239
1224
|
class CStmtDecrement(CStmt):
|
|
@@ -1243,7 +1228,7 @@ class CStmtDecrement(CStmt):
|
|
|
1243
1228
|
self.value = value
|
|
1244
1229
|
|
|
1245
1230
|
def __str__(self):
|
|
1246
|
-
return
|
|
1231
|
+
return "--%s;" % str_cvalue(self.value)
|
|
1247
1232
|
|
|
1248
1233
|
|
|
1249
1234
|
class CStmtDeclType(CStmt):
|
|
@@ -1254,8 +1239,7 @@ class CStmtDeclType(CStmt):
|
|
|
1254
1239
|
self.attributes = attributes
|
|
1255
1240
|
|
|
1256
1241
|
def __str__(self):
|
|
1257
|
-
sstr =
|
|
1258
|
-
sstr += str_gcc_attributes(self.attributes)
|
|
1242
|
+
sstr = str_gcc_attributes(self.attributes)
|
|
1259
1243
|
sstr += str_ctype(self.type) + ';'
|
|
1260
1244
|
return sstr
|
|
1261
1245
|
|
|
@@ -1270,8 +1254,7 @@ class CStmtDefType(CStmt):
|
|
|
1270
1254
|
self.attributes = attributes
|
|
1271
1255
|
|
|
1272
1256
|
def __str__(self):
|
|
1273
|
-
sstr =
|
|
1274
|
-
sstr += str_gcc_attributes(self.attributes)
|
|
1257
|
+
sstr = str_gcc_attributes(self.attributes)
|
|
1275
1258
|
sstr += 'typedef %s;' % self.type.to_str(text=self.id)
|
|
1276
1259
|
return sstr
|
|
1277
1260
|
|
|
@@ -1291,11 +1274,10 @@ class CStmtDefVar(CStmt):
|
|
|
1291
1274
|
self.attributes = attributes
|
|
1292
1275
|
|
|
1293
1276
|
def __str__(self):
|
|
1294
|
-
sstr =
|
|
1295
|
-
sstr += str_gcc_attributes(self.attributes)
|
|
1277
|
+
sstr = str_gcc_attributes(self.attributes)
|
|
1296
1278
|
if self.storage not in (None, ''):
|
|
1297
1279
|
sstr += self.storage + ' '
|
|
1298
|
-
|
|
1280
|
+
|
|
1299
1281
|
sstr += str_ctype(self.type, text=self.id)
|
|
1300
1282
|
if self.initializer != None:
|
|
1301
1283
|
sstr += ' = %s' % str_cvalue(self.initializer)
|
|
@@ -1319,8 +1301,7 @@ class CStmtDefFunc(CStmt):
|
|
|
1319
1301
|
self.nl = 2
|
|
1320
1302
|
|
|
1321
1303
|
def __str__(self):
|
|
1322
|
-
sstr =
|
|
1323
|
-
sstr += str_gcc_attributes(self.attributes)
|
|
1304
|
+
sstr = str_gcc_attributes(self.attributes)
|
|
1324
1305
|
if self.storage not in (None, ''):
|
|
1325
1306
|
sstr += self.storage + ' '
|
|
1326
1307
|
sstr += self.type.to_str(text=self.id)
|
|
@@ -1347,13 +1328,12 @@ class CStmtIf(CStmt):
|
|
|
1347
1328
|
self.else_block = else_block
|
|
1348
1329
|
|
|
1349
1330
|
def __str__(self):
|
|
1350
|
-
sstr =
|
|
1351
|
-
sstr += "if (%s)" % str_cvalue(self.condition)
|
|
1331
|
+
sstr = "if (%s)" % str_cvalue(self.condition)
|
|
1352
1332
|
if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
|
|
1353
1333
|
sstr += str_nl_indent()
|
|
1354
1334
|
else:
|
|
1355
1335
|
sstr += ' '
|
|
1356
|
-
sstr +=
|
|
1336
|
+
sstr += str_cstmt(self.then_block)
|
|
1357
1337
|
if self.else_block != None:
|
|
1358
1338
|
if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
|
|
1359
1339
|
sstr += str_nl_indent()
|
|
@@ -1364,7 +1344,7 @@ class CStmtIf(CStmt):
|
|
|
1364
1344
|
sstr += str_nl_indent()
|
|
1365
1345
|
else:
|
|
1366
1346
|
sstr += ' '
|
|
1367
|
-
sstr +=
|
|
1347
|
+
sstr += str_cstmt(self.else_block)
|
|
1368
1348
|
return sstr
|
|
1369
1349
|
|
|
1370
1350
|
|
|
@@ -1377,13 +1357,12 @@ class CStmtWhile(CStmt):
|
|
|
1377
1357
|
self.block = block
|
|
1378
1358
|
|
|
1379
1359
|
def __str__(self):
|
|
1380
|
-
sstr =
|
|
1381
|
-
sstr += "while (%s)" % str_cvalue(self.condition)
|
|
1360
|
+
sstr = "while (%s)" % str_cvalue(self.condition)
|
|
1382
1361
|
if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
|
|
1383
1362
|
sstr += str_nl_indent()
|
|
1384
1363
|
else:
|
|
1385
1364
|
sstr += ' '
|
|
1386
|
-
sstr +=
|
|
1365
|
+
sstr += str_cstmt(self.block)
|
|
1387
1366
|
return sstr
|
|
1388
1367
|
|
|
1389
1368
|
|
|
@@ -1395,8 +1374,7 @@ class CStmtReturn(CStmt):
|
|
|
1395
1374
|
self.return_value = return_value
|
|
1396
1375
|
|
|
1397
1376
|
def __str__(self):
|
|
1398
|
-
sstr =
|
|
1399
|
-
sstr += 'return'
|
|
1377
|
+
sstr = 'return'
|
|
1400
1378
|
if self.return_value != None:
|
|
1401
1379
|
sstr += ' ' + str_cvalue(self.return_value)
|
|
1402
1380
|
return sstr + ";"
|
|
@@ -1408,8 +1386,7 @@ class CStmtBreak(CStmt):
|
|
|
1408
1386
|
pass
|
|
1409
1387
|
|
|
1410
1388
|
def __str__(self):
|
|
1411
|
-
sstr =
|
|
1412
|
-
sstr += "break;"
|
|
1389
|
+
sstr = "break;"
|
|
1413
1390
|
return sstr
|
|
1414
1391
|
|
|
1415
1392
|
|
|
@@ -1419,8 +1396,7 @@ class CStmtContinue(CStmt):
|
|
|
1419
1396
|
pass
|
|
1420
1397
|
|
|
1421
1398
|
def __str__(self):
|
|
1422
|
-
sstr =
|
|
1423
|
-
sstr += "continue;"
|
|
1399
|
+
sstr = "continue;"
|
|
1424
1400
|
return sstr
|
|
1425
1401
|
|
|
1426
1402
|
|
|
@@ -1442,8 +1418,7 @@ class CStmtInlineAsm(CStmt):
|
|
|
1442
1418
|
|
|
1443
1419
|
|
|
1444
1420
|
def __str__(self):
|
|
1445
|
-
sstr =
|
|
1446
|
-
sstr += "__asm__ volatile ("
|
|
1421
|
+
sstr = "__asm__ volatile ("
|
|
1447
1422
|
sstr += '"%s" ' % self.text.replace('\n', '\\n\\\n')
|
|
1448
1423
|
|
|
1449
1424
|
sstr += ":"
|
|
@@ -1473,6 +1448,7 @@ class CStmtInlineAsm(CStmt):
|
|
|
1473
1448
|
class CRawText(CStmt):
|
|
1474
1449
|
def __init__(self, text):
|
|
1475
1450
|
super().__init__()
|
|
1451
|
+
self.nl = 0 # сырой текст печатается как есть, без отступа
|
|
1476
1452
|
self.text = text
|
|
1477
1453
|
pass
|
|
1478
1454
|
|
|
@@ -1492,8 +1468,7 @@ class CMacroDef():
|
|
|
1492
1468
|
self.mark = None
|
|
1493
1469
|
|
|
1494
1470
|
def __str__(self):
|
|
1495
|
-
sstr =
|
|
1496
|
-
sstr += "#define %s" % (self.id)
|
|
1471
|
+
sstr = "#define %s" % (self.id)
|
|
1497
1472
|
if self.text:
|
|
1498
1473
|
sstr += ' ' + self.text
|
|
1499
1474
|
return sstr
|
|
@@ -1510,9 +1485,8 @@ class CMacroDefValue():
|
|
|
1510
1485
|
self.mark = None
|
|
1511
1486
|
|
|
1512
1487
|
def __str__(self):
|
|
1513
|
-
sstr = str_nl_indent(self.nl)
|
|
1514
1488
|
set_nl_symbol(" \\\n")
|
|
1515
|
-
sstr
|
|
1489
|
+
sstr = "#define %s %s" % (self.id, str_cvalue(self.value, ext_precedence=valuePrecedenceMax))
|
|
1516
1490
|
set_nl_symbol("\n")
|
|
1517
1491
|
return sstr
|
|
1518
1492
|
|
|
@@ -1526,8 +1500,7 @@ class CMacroUndef():
|
|
|
1526
1500
|
self.mark = None
|
|
1527
1501
|
|
|
1528
1502
|
def __str__(self):
|
|
1529
|
-
sstr =
|
|
1530
|
-
sstr += "#undef %s" % (self.text)
|
|
1503
|
+
sstr = "#undef %s" % (self.text)
|
|
1531
1504
|
return sstr
|
|
1532
1505
|
|
|
1533
1506
|
|
|
@@ -1542,20 +1515,22 @@ class CInclude():
|
|
|
1542
1515
|
self.mark = None
|
|
1543
1516
|
|
|
1544
1517
|
def __str__(self):
|
|
1545
|
-
#sstr = str_nl_indent(self.nl)
|
|
1546
1518
|
if self.is_system:
|
|
1547
|
-
return "
|
|
1548
|
-
return "
|
|
1519
|
+
return "#include <%s>" % self.text
|
|
1520
|
+
return "#include \"%s\"" % self.text
|
|
1549
1521
|
|
|
1550
1522
|
|
|
1551
1523
|
def str_cdef(x):
|
|
1552
|
-
|
|
1553
|
-
|
|
1524
|
+
sstr = str_nl_indent(x.nl)
|
|
1525
|
+
if x.mark != None:
|
|
1526
|
+
sstr += '/*%s*/' % x.mark
|
|
1527
|
+
return sstr + str(x)
|
|
1554
1528
|
|
|
1555
1529
|
|
|
1556
1530
|
# pairs = ("macro text", [<defs>])
|
|
1557
1531
|
class CConditionalRegion():
|
|
1558
1532
|
def __init__(self, pairs, _else=None):
|
|
1533
|
+
self.nl = 1
|
|
1559
1534
|
self.pairs = pairs
|
|
1560
1535
|
self._else = _else
|
|
1561
1536
|
self.mark = None
|
|
@@ -1567,7 +1542,8 @@ class CConditionalRegion():
|
|
|
1567
1542
|
# if directive == '#if':
|
|
1568
1543
|
# ss = pair[0].split('()')
|
|
1569
1544
|
# print(ss)
|
|
1570
|
-
|
|
1545
|
+
# ведущий перевод строки печатает обертка, как и у всех узлов
|
|
1546
|
+
sstr += "%s%s %s" % ('' if sstr == '' else '\n', directive, pair[0])
|
|
1571
1547
|
# if len(pair[1]) > 5:
|
|
1572
1548
|
# sstr += "\n"
|
|
1573
1549
|
for xd in pair[1]:
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from cshape import (
|
|
4
|
+
CField, CStmtBlock, CStmtDefFunc, CStmtDefVar, CStmtReturn, CTypeArray,
|
|
5
|
+
CTypeFunction, CTypeIdentifier, CTypeStruct, CValueAdd, CValueArray,
|
|
6
|
+
CValueIdentifier, CValueInteger, render,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SmokeTest(unittest.TestCase):
|
|
11
|
+
def test_render_function(self):
|
|
12
|
+
func = CStmtDefFunc(
|
|
13
|
+
id='add',
|
|
14
|
+
type=CTypeFunction(
|
|
15
|
+
params=[CField(id='a', type=CTypeIdentifier('int')),
|
|
16
|
+
CField(id='b', type=CTypeIdentifier('int'))],
|
|
17
|
+
to=CTypeIdentifier('int'),
|
|
18
|
+
),
|
|
19
|
+
block=CStmtBlock([
|
|
20
|
+
CStmtReturn(CValueAdd(CValueIdentifier('a'), CValueIdentifier('b'))),
|
|
21
|
+
]),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
self.assertEqual(
|
|
25
|
+
render(func).strip(),
|
|
26
|
+
'int add(int a, int b) {\n\treturn a + b;\n}',
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def test_render_is_reentrant(self):
|
|
30
|
+
# render() must not leak indent/style state between independent calls
|
|
31
|
+
named = CTypeIdentifier('int')
|
|
32
|
+
render(named, style='modern')
|
|
33
|
+
self.assertEqual(render(named, style='legacy'), 'int')
|
|
34
|
+
|
|
35
|
+
def test_mark_shows_up_as_comment(self):
|
|
36
|
+
v = CValueIdentifier('x')
|
|
37
|
+
v.mark = 'debug-note'
|
|
38
|
+
self.assertIn('/*debug-note*/', render(v))
|
|
39
|
+
|
|
40
|
+
def test_value_constructor_accepts_nl_for_array_layout(self):
|
|
41
|
+
array_def = CStmtDefVar(
|
|
42
|
+
id='numbers',
|
|
43
|
+
type=CTypeArray(CTypeIdentifier('int')),
|
|
44
|
+
initializer=CValueArray([
|
|
45
|
+
CValueInteger(1, nl=1),
|
|
46
|
+
CValueInteger(2),
|
|
47
|
+
]),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self.assertEqual(
|
|
51
|
+
render(array_def).strip(),
|
|
52
|
+
'int numbers[] = {\n\t1, 2\n};',
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def test_struct_attributes_follow_the_closing_brace(self):
|
|
56
|
+
# a struct attribute is only read after the body: before the
|
|
57
|
+
# declaration the compiler ignores it
|
|
58
|
+
packed = CStmtDefVar(
|
|
59
|
+
id='',
|
|
60
|
+
type=CTypeStruct(
|
|
61
|
+
fields=[CField(id='tag', type=CTypeIdentifier('uint8_t')),
|
|
62
|
+
CField(id='len', type=CTypeIdentifier('uint32_t'))],
|
|
63
|
+
tag='struct header',
|
|
64
|
+
attributes={'packed': {}},
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
self.assertEqual(
|
|
69
|
+
render(packed).strip(),
|
|
70
|
+
'struct header {uint8_t tag; uint32_t len;} __attribute__((packed));',
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == '__main__':
|
|
75
|
+
unittest.main()
|
cshape-0.2.1/tests/test_smoke.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from cshape import (
|
|
4
|
-
CField, CStmtBlock, CStmtDefFunc, CStmtReturn, CTypeFunction, CTypeIdentifier,
|
|
5
|
-
CValueAdd, CValueIdentifier, render,
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class SmokeTest(unittest.TestCase):
|
|
10
|
-
def test_render_function(self):
|
|
11
|
-
func = CStmtDefFunc(
|
|
12
|
-
id='add',
|
|
13
|
-
type=CTypeFunction(
|
|
14
|
-
params=[CField(id='a', type=CTypeIdentifier('int')),
|
|
15
|
-
CField(id='b', type=CTypeIdentifier('int'))],
|
|
16
|
-
to=CTypeIdentifier('int'),
|
|
17
|
-
),
|
|
18
|
-
block=CStmtBlock([
|
|
19
|
-
CStmtReturn(CValueAdd(CValueIdentifier('a'), CValueIdentifier('b'))),
|
|
20
|
-
]),
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
self.assertEqual(
|
|
24
|
-
render(func).strip(),
|
|
25
|
-
'int add(int a, int b) {\n\treturn a + b;\n}',
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
def test_render_is_reentrant(self):
|
|
29
|
-
# render() must not leak indent/style state between independent calls
|
|
30
|
-
named = CTypeIdentifier('int')
|
|
31
|
-
render(named, style='modern')
|
|
32
|
-
self.assertEqual(render(named, style='legacy'), 'int')
|
|
33
|
-
|
|
34
|
-
def test_mark_shows_up_as_comment(self):
|
|
35
|
-
v = CValueIdentifier('x')
|
|
36
|
-
v.mark = 'debug-note'
|
|
37
|
-
self.assertIn('/*debug-note*/', render(v))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if __name__ == '__main__':
|
|
41
|
-
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|