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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cshape
3
- Version: 0.2.1
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.1
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', newline='\n'):
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) + '}' + with_space(text)
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 += ".%s = %s" % (item.key, str_cvalue(item.value))
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 '(%s)' % str_cvalue(self.value, ext_precedence=self.precedence)
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
- sstr = wrap_if(y, (v.precedence < ext_precedence) or v.mark and (v.precedence < valuePrecedenceMax))
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
- sstr = ''
1132
- #if x.comment != None:
1133
- # sstr += str_nl_indent(x.comment.nl)
1134
- # print_comment(x.comment)
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 = '/*%s*/' % x.mark + 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 = str_nl_indent(self.nl)
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
- sstr = str_nl_indent(self.nl)
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
- sstr = str_nl_indent(self.nl)
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 str_nl_indent(self.nl) + "++%s;" % str_cvalue(self.value)
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 str_nl_indent(self.nl) + "--%s;" % str_cvalue(self.value)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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
- #mass
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 += str(self.then_block)
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 += str(self.else_block)
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 = str_nl_indent(self.nl)
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 += str(self.block)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 = str_nl_indent(self.nl)
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 += "#define %s %s" % (self.id, str_cvalue(self.value, ext_precedence=valuePrecedenceMax))
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 = str_nl_indent(self.nl)
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 "\n#include <%s>" % self.text
1548
- return "\n#include \"%s\"" % self.text
1519
+ return "#include <%s>" % self.text
1520
+ return "#include \"%s\"" % self.text
1549
1521
 
1550
1522
 
1551
1523
  def str_cdef(x):
1552
- prefix = '/*%s*/' % x.mark if x.mark else ''
1553
- return prefix + str(x)
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
- sstr += "\n%s %s" % (directive, pair[0])
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]:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cshape"
7
- version = "0.2.1"
7
+ version = "0.2.3"
8
8
  description = "A dependency-free C AST + printer: build a tree in Python, get C11 source back"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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()
@@ -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