cshape 0.2.2__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.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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cshape
3
- Version: 0.2.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
@@ -247,11 +247,12 @@ class CTypeFunction(CType):
247
247
 
248
248
 
249
249
  class CTypeStruct(CType):
250
- def __init__(self, fields, tag, specifiers=None):
250
+ def __init__(self, fields, tag, specifiers=None, attributes=None):
251
251
  super().__init__()
252
252
  self.fields = fields
253
253
  self.tag = tag
254
254
  self.specifiers = specifiers if specifiers != None else []
255
+ self.attributes = attributes
255
256
  self.precedence = 0
256
257
 
257
258
  def to_str(self, text='', with_qualifiers=True):
@@ -282,7 +283,13 @@ class CTypeStruct(CType):
282
283
  else:
283
284
  sstr += 'uint8_t __placeholder;'
284
285
  indent_down()
285
- 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)
286
293
  return sstr
287
294
 
288
295
 
@@ -386,6 +393,14 @@ class KV():
386
393
  self.key = key
387
394
  self.value = value
388
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
389
404
 
390
405
 
391
406
  class CValue():
@@ -535,7 +550,7 @@ class CValueStruct(CValue):
535
550
  if item.nl == 0:
536
551
  s_items += " "
537
552
  s_items += str_nl_indent(item.nl)
538
- s_items += ".%s = %s" % (item.key, str_cvalue(item.value))
553
+ s_items += str_kv(item)
539
554
  i += 1
540
555
 
541
556
  indent_down()
@@ -1090,7 +1105,10 @@ class CValueStringConcat(CValue):
1090
1105
  def str_cvalue(v, ext_precedence=0):
1091
1106
  assert(isinstance(v, CValue))
1092
1107
  y = str(v)
1093
- 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)
1094
1112
  if v.mark != None:
1095
1113
  sstr = '/*%s*/' % v.mark + sstr
1096
1114
  return sstr
@@ -1101,15 +1119,13 @@ def str_cvalue(v, ext_precedence=0):
1101
1119
 
1102
1120
  def str_cstmt(x):
1103
1121
  assert(x != None)
1104
- sstr = ''
1105
- #if x.comment != None:
1106
- # sstr += str_nl_indent(x.comment.nl)
1107
- # print_comment(x.comment)
1108
- #sstr += str_nl_indent(x.nl)
1109
- sstr += str(x)
1122
+ # (!) перевод строки и отступ печатает обертка, а не сам узел: пометка
1123
+ # относится к коду, а не к пустому месту перед ним, и должна встать
1124
+ # между отступом и кодом - иначе она уезжает в конец предыдущей строки
1125
+ sstr = str_nl_indent(x.nl)
1110
1126
  if x.mark != None:
1111
- sstr = '/*%s*/' % x.mark + sstr
1112
- return sstr
1127
+ sstr += '/*%s*/' % x.mark
1128
+ return sstr + str(x)
1113
1129
 
1114
1130
 
1115
1131
  class CStmt():
@@ -1129,7 +1145,6 @@ class CStmtLineComment(CStmt):
1129
1145
 
1130
1146
  def __str__(self):
1131
1147
  sstr = ''
1132
- sstr += str_nl_indent(self.nl)
1133
1148
  n = len(self.lines)
1134
1149
  i = 0
1135
1150
  while i < n:
@@ -1149,8 +1164,7 @@ class CStmtBlockComment(CStmt):
1149
1164
  self.nl = 1
1150
1165
 
1151
1166
  def __str__(self):
1152
- sstr = str_nl_indent(self.nl)
1153
- sstr += "/*%s*/" % self.text
1167
+ sstr = "/*%s*/" % self.text
1154
1168
  return sstr
1155
1169
 
1156
1170
 
@@ -1182,8 +1196,7 @@ class CStmtExpr(CStmt):
1182
1196
  self.nl = 1
1183
1197
 
1184
1198
  def __str__(self):
1185
- sstr = str_nl_indent(self.nl)
1186
- return sstr + str_cvalue(self.value) + ';'
1199
+ return str_cvalue(self.value) + ';'
1187
1200
 
1188
1201
 
1189
1202
  class CStmtAssignment(CStmt):
@@ -1195,8 +1208,7 @@ class CStmtAssignment(CStmt):
1195
1208
  self.rvalue = rvalue
1196
1209
 
1197
1210
  def __str__(self):
1198
- sstr = str_nl_indent(self.nl)
1199
- return sstr + "%s = %s;" % (str_cvalue(self.lvalue), str_cvalue(self.rvalue))
1211
+ return "%s = %s;" % (str_cvalue(self.lvalue), str_cvalue(self.rvalue))
1200
1212
 
1201
1213
 
1202
1214
  class CStmtIncrement(CStmt):
@@ -1206,7 +1218,7 @@ class CStmtIncrement(CStmt):
1206
1218
  self.value = value
1207
1219
 
1208
1220
  def __str__(self):
1209
- return str_nl_indent(self.nl) + "++%s;" % str_cvalue(self.value)
1221
+ return "++%s;" % str_cvalue(self.value)
1210
1222
 
1211
1223
 
1212
1224
  class CStmtDecrement(CStmt):
@@ -1216,7 +1228,7 @@ class CStmtDecrement(CStmt):
1216
1228
  self.value = value
1217
1229
 
1218
1230
  def __str__(self):
1219
- return str_nl_indent(self.nl) + "--%s;" % str_cvalue(self.value)
1231
+ return "--%s;" % str_cvalue(self.value)
1220
1232
 
1221
1233
 
1222
1234
  class CStmtDeclType(CStmt):
@@ -1227,8 +1239,7 @@ class CStmtDeclType(CStmt):
1227
1239
  self.attributes = attributes
1228
1240
 
1229
1241
  def __str__(self):
1230
- sstr = str_nl_indent(self.nl)
1231
- sstr += str_gcc_attributes(self.attributes)
1242
+ sstr = str_gcc_attributes(self.attributes)
1232
1243
  sstr += str_ctype(self.type) + ';'
1233
1244
  return sstr
1234
1245
 
@@ -1243,8 +1254,7 @@ class CStmtDefType(CStmt):
1243
1254
  self.attributes = attributes
1244
1255
 
1245
1256
  def __str__(self):
1246
- sstr = str_nl_indent(self.nl)
1247
- sstr += str_gcc_attributes(self.attributes)
1257
+ sstr = str_gcc_attributes(self.attributes)
1248
1258
  sstr += 'typedef %s;' % self.type.to_str(text=self.id)
1249
1259
  return sstr
1250
1260
 
@@ -1264,11 +1274,10 @@ class CStmtDefVar(CStmt):
1264
1274
  self.attributes = attributes
1265
1275
 
1266
1276
  def __str__(self):
1267
- sstr = str_nl_indent(self.nl)
1268
- sstr += str_gcc_attributes(self.attributes)
1277
+ sstr = str_gcc_attributes(self.attributes)
1269
1278
  if self.storage not in (None, ''):
1270
1279
  sstr += self.storage + ' '
1271
- #mass
1280
+
1272
1281
  sstr += str_ctype(self.type, text=self.id)
1273
1282
  if self.initializer != None:
1274
1283
  sstr += ' = %s' % str_cvalue(self.initializer)
@@ -1292,8 +1301,7 @@ class CStmtDefFunc(CStmt):
1292
1301
  self.nl = 2
1293
1302
 
1294
1303
  def __str__(self):
1295
- sstr = str_nl_indent(self.nl)
1296
- sstr += str_gcc_attributes(self.attributes)
1304
+ sstr = str_gcc_attributes(self.attributes)
1297
1305
  if self.storage not in (None, ''):
1298
1306
  sstr += self.storage + ' '
1299
1307
  sstr += self.type.to_str(text=self.id)
@@ -1320,13 +1328,12 @@ class CStmtIf(CStmt):
1320
1328
  self.else_block = else_block
1321
1329
 
1322
1330
  def __str__(self):
1323
- sstr = str_nl_indent(self.nl)
1324
- sstr += "if (%s)" % str_cvalue(self.condition)
1331
+ sstr = "if (%s)" % str_cvalue(self.condition)
1325
1332
  if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
1326
1333
  sstr += str_nl_indent()
1327
1334
  else:
1328
1335
  sstr += ' '
1329
- sstr += str(self.then_block)
1336
+ sstr += str_cstmt(self.then_block)
1330
1337
  if self.else_block != None:
1331
1338
  if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
1332
1339
  sstr += str_nl_indent()
@@ -1337,7 +1344,7 @@ class CStmtIf(CStmt):
1337
1344
  sstr += str_nl_indent()
1338
1345
  else:
1339
1346
  sstr += ' '
1340
- sstr += str(self.else_block)
1347
+ sstr += str_cstmt(self.else_block)
1341
1348
  return sstr
1342
1349
 
1343
1350
 
@@ -1350,13 +1357,12 @@ class CStmtWhile(CStmt):
1350
1357
  self.block = block
1351
1358
 
1352
1359
  def __str__(self):
1353
- sstr = str_nl_indent(self.nl)
1354
- sstr += "while (%s)" % str_cvalue(self.condition)
1360
+ sstr = "while (%s)" % str_cvalue(self.condition)
1355
1361
  if styleguide['LINE_BREAK_BEFORE_BLOCK_BRACE']:
1356
1362
  sstr += str_nl_indent()
1357
1363
  else:
1358
1364
  sstr += ' '
1359
- sstr += str(self.block)
1365
+ sstr += str_cstmt(self.block)
1360
1366
  return sstr
1361
1367
 
1362
1368
 
@@ -1368,8 +1374,7 @@ class CStmtReturn(CStmt):
1368
1374
  self.return_value = return_value
1369
1375
 
1370
1376
  def __str__(self):
1371
- sstr = str_nl_indent(self.nl)
1372
- sstr += 'return'
1377
+ sstr = 'return'
1373
1378
  if self.return_value != None:
1374
1379
  sstr += ' ' + str_cvalue(self.return_value)
1375
1380
  return sstr + ";"
@@ -1381,8 +1386,7 @@ class CStmtBreak(CStmt):
1381
1386
  pass
1382
1387
 
1383
1388
  def __str__(self):
1384
- sstr = str_nl_indent(self.nl)
1385
- sstr += "break;"
1389
+ sstr = "break;"
1386
1390
  return sstr
1387
1391
 
1388
1392
 
@@ -1392,8 +1396,7 @@ class CStmtContinue(CStmt):
1392
1396
  pass
1393
1397
 
1394
1398
  def __str__(self):
1395
- sstr = str_nl_indent(self.nl)
1396
- sstr += "continue;"
1399
+ sstr = "continue;"
1397
1400
  return sstr
1398
1401
 
1399
1402
 
@@ -1415,8 +1418,7 @@ class CStmtInlineAsm(CStmt):
1415
1418
 
1416
1419
 
1417
1420
  def __str__(self):
1418
- sstr = str_nl_indent(self.nl)
1419
- sstr += "__asm__ volatile ("
1421
+ sstr = "__asm__ volatile ("
1420
1422
  sstr += '"%s" ' % self.text.replace('\n', '\\n\\\n')
1421
1423
 
1422
1424
  sstr += ":"
@@ -1446,6 +1448,7 @@ class CStmtInlineAsm(CStmt):
1446
1448
  class CRawText(CStmt):
1447
1449
  def __init__(self, text):
1448
1450
  super().__init__()
1451
+ self.nl = 0 # сырой текст печатается как есть, без отступа
1449
1452
  self.text = text
1450
1453
  pass
1451
1454
 
@@ -1465,8 +1468,7 @@ class CMacroDef():
1465
1468
  self.mark = None
1466
1469
 
1467
1470
  def __str__(self):
1468
- sstr = str_nl_indent(self.nl)
1469
- sstr += "#define %s" % (self.id)
1471
+ sstr = "#define %s" % (self.id)
1470
1472
  if self.text:
1471
1473
  sstr += ' ' + self.text
1472
1474
  return sstr
@@ -1483,9 +1485,8 @@ class CMacroDefValue():
1483
1485
  self.mark = None
1484
1486
 
1485
1487
  def __str__(self):
1486
- sstr = str_nl_indent(self.nl)
1487
1488
  set_nl_symbol(" \\\n")
1488
- 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))
1489
1490
  set_nl_symbol("\n")
1490
1491
  return sstr
1491
1492
 
@@ -1499,8 +1500,7 @@ class CMacroUndef():
1499
1500
  self.mark = None
1500
1501
 
1501
1502
  def __str__(self):
1502
- sstr = str_nl_indent(self.nl)
1503
- sstr += "#undef %s" % (self.text)
1503
+ sstr = "#undef %s" % (self.text)
1504
1504
  return sstr
1505
1505
 
1506
1506
 
@@ -1515,20 +1515,22 @@ class CInclude():
1515
1515
  self.mark = None
1516
1516
 
1517
1517
  def __str__(self):
1518
- #sstr = str_nl_indent(self.nl)
1519
1518
  if self.is_system:
1520
- return "\n#include <%s>" % self.text
1521
- return "\n#include \"%s\"" % self.text
1519
+ return "#include <%s>" % self.text
1520
+ return "#include \"%s\"" % self.text
1522
1521
 
1523
1522
 
1524
1523
  def str_cdef(x):
1525
- prefix = '/*%s*/' % x.mark if x.mark else ''
1526
- 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)
1527
1528
 
1528
1529
 
1529
1530
  # pairs = ("macro text", [<defs>])
1530
1531
  class CConditionalRegion():
1531
1532
  def __init__(self, pairs, _else=None):
1533
+ self.nl = 1
1532
1534
  self.pairs = pairs
1533
1535
  self._else = _else
1534
1536
  self.mark = None
@@ -1540,7 +1542,8 @@ class CConditionalRegion():
1540
1542
  # if directive == '#if':
1541
1543
  # ss = pair[0].split('()')
1542
1544
  # print(ss)
1543
- sstr += "\n%s %s" % (directive, pair[0])
1545
+ # ведущий перевод строки печатает обертка, как и у всех узлов
1546
+ sstr += "%s%s %s" % ('' if sstr == '' else '\n', directive, pair[0])
1544
1547
  # if len(pair[1]) > 5:
1545
1548
  # sstr += "\n"
1546
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.2"
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"
@@ -2,8 +2,8 @@ import unittest
2
2
 
3
3
  from cshape import (
4
4
  CField, CStmtBlock, CStmtDefFunc, CStmtDefVar, CStmtReturn, CTypeArray,
5
- CTypeFunction, CTypeIdentifier, CValueAdd, CValueArray, CValueIdentifier,
6
- CValueInteger, render,
5
+ CTypeFunction, CTypeIdentifier, CTypeStruct, CValueAdd, CValueArray,
6
+ CValueIdentifier, CValueInteger, render,
7
7
  )
8
8
 
9
9
 
@@ -52,6 +52,24 @@ class SmokeTest(unittest.TestCase):
52
52
  'int numbers[] = {\n\t1, 2\n};',
53
53
  )
54
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
+
55
73
 
56
74
  if __name__ == '__main__':
57
75
  unittest.main()
File without changes
File without changes
File without changes