openscad-parser 2.4.0__tar.gz → 2.4.1__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: openscad_parser
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: A PEG parser to read OpenSCAD language source code, with optional AST tree generation.
5
5
  Keywords: openscad,openscad parser,parser
6
6
  Author: Revar Desmera
@@ -360,107 +360,129 @@ Parsing Library Files
360
360
  AST Node Types
361
361
  --------------
362
362
 
363
- The AST includes comprehensive node types for all OpenSCAD language constructs:
363
+ The AST includes comprehensive node types for all OpenSCAD language constructs.
364
+ All nodes inherit from ``ASTNode`` and carry ``position: Position`` and ``scope: Scope | None`` attributes.
364
365
 
365
366
  Base Classes
366
367
  ~~~~~~~~~~~~
367
368
 
368
- - ``ASTNode``: Base class for all AST nodes (includes ``position`` attribute)
369
+ - ``ASTNode(position: Position, scope: Scope | None)``: Base class for all AST nodes
369
370
  - ``Expression``: Base class for all expression nodes
370
- - ``Primary``: Base class for atomic value types
371
+ - ``Primary``: Base class for atomic value types (extends ``Expression``)
371
372
  - ``ModuleInstantiation``: Base class for module-related statements
373
+ - ``VectorElement``: Base class for list comprehension elements
372
374
 
373
375
  Literals
374
376
  ~~~~~~~~
375
377
 
376
- - ``Identifier``: Variable, function, or module names
377
- - ``StringLiteral``: String values
378
- - ``NumberLiteral``: Numeric values
379
- - ``BooleanLiteral``: true/false values
380
- - ``UndefinedLiteral``: undef value
381
- - ``RangeLiteral``: Range expressions [start:end:step]
378
+ - ``Identifier(name: str)``: Variable, function, or module names
379
+ - ``StringLiteral(val: str)``: String values
380
+ - ``NumberLiteral(val: float)``: Numeric values
381
+ - ``BooleanLiteral(val: bool)``: true/false values
382
+ - ``UndefinedLiteral``: The ``undef`` value (no additional fields)
383
+ - ``RangeLiteral(start: Expression, end: Expression, step: Expression)``: Range expressions ``[start:step:end]``
382
384
 
383
385
  Operators
384
386
  ~~~~~~~~~
385
387
 
388
+ All operators inherit from ``Expression`` and represent their respective operations with typed fields for operands. The AST preserves operator precedence and associativity as defined in OpenSCAD.
389
+
386
390
  Arithmetic:
387
- - ``AdditionOp``, ``SubtractionOp``, ``MultiplicationOp``, ``DivisionOp``
388
- - ``ModuloOp``, ``ExponentOp``, ``UnaryMinusOp``
391
+
392
+ - ``AdditionOp(left: Expression, right: Expression)``: represents ``left + right``
393
+ - ``SubtractionOp(left: Expression, right: Expression)``: represents ``left - right``
394
+ - ``MultiplicationOp(left: Expression, right: Expression)``: represents ``left * right``
395
+ - ``DivisionOp(left: Expression, right: Expression)``: represents ``left / right``
396
+ - ``ModuloOp(left: Expression, right: Expression)``: represents ``left % right``
397
+ - ``ExponentOp(left: Expression, right: Expression)``: represents ``left ^ right``
398
+ - ``UnaryMinusOp(expr: Expression)``: represents ``-expr``
389
399
 
390
400
  Logical:
391
- - ``LogicalAndOp``, ``LogicalOrOp``, ``LogicalNotOp``
401
+
402
+ - ``LogicalAndOp(left: Expression, right: Expression)``: represents ``left && right``
403
+ - ``LogicalOrOp(left: Expression, right: Expression)``: represents ``left || right``
404
+ - ``LogicalNotOp(expr: Expression)``: represents ``!expr``
392
405
 
393
406
  Comparison:
394
- - ``EqualityOp``, ``InequalityOp``
395
- - ``GreaterThanOp``, ``GreaterThanOrEqualOp``
396
- - ``LessThanOp``, ``LessThanOrEqualOp``
407
+
408
+ - ``EqualityOp(left: Expression, right: Expression)``: represents ``left == right``
409
+ - ``InequalityOp(left: Expression, right: Expression)``: represents ``left != right``
410
+ - ``GreaterThanOp(left: Expression, right: Expression)``: represents ``left > right``
411
+ - ``GreaterThanOrEqualOp(left: Expression, right: Expression)``: represents ``left >= right``
412
+ - ``LessThanOp(left: Expression, right: Expression)``: represents ``left < right``
413
+ - ``LessThanOrEqualOp(left: Expression, right: Expression)``: represents ``left <= right``
397
414
 
398
415
  Bitwise:
399
- - ``BitwiseAndOp``, ``BitwiseOrOp``, ``BitwiseNotOp``
400
- - ``BitwiseShiftLeftOp``, ``BitwiseShiftRightOp``
416
+
417
+ - ``BitwiseAndOp(left: Expression, right: Expression)``: represents ``left & right``
418
+ - ``BitwiseOrOp(left: Expression, right: Expression)``: represents ``left | right``
419
+ - ``BitwiseShiftLeftOp(left: Expression, right: Expression)``: represents ``left << right``
420
+ - ``BitwiseShiftRightOp(left: Expression, right: Expression)``: represents ``left >> right``
421
+ - ``BitwiseNotOp(expr: Expression)``: represents ``~expr``
401
422
 
402
423
  Other:
403
- - ``TernaryOp``: condition ? true_expr : false_expr
424
+
425
+ - ``TernaryOp(condition: Expression, true_expr: Expression, false_expr: Expression)``: Represents ``condition ? true_expr : false_expr``
404
426
 
405
427
  Expressions
406
428
  ~~~~~~~~~~~
407
429
 
408
- - ``LetOp``: let(assignments) body
409
- - ``EchoOp``: echo(arguments) body
410
- - ``AssertOp``: assert(arguments) body
411
- - ``FunctionLiteral``: function(parameters) body
412
- - ``PrimaryCall``: function calls
413
- - ``PrimaryIndex``: array indexing [index]
414
- - ``PrimaryMember``: member access .member
430
+ - ``LetOp(assignments: list[Assignment], body: Expression)``: let clause ``let(assignments) body``
431
+ - ``EchoOp(arguments: list[Argument], body: Expression)``: echo clause ``echo(arguments) body``
432
+ - ``AssertOp(arguments: list[Argument], body: Expression)``: assert clause ``assert(arguments) body``
433
+ - ``FunctionLiteral(parameters: list[ParameterDeclaration], body: Expression)``: Anonymous function expression ``function(parameters) body``
434
+ - ``PrimaryCall(left: Expression, arguments: list[Argument])``: Function calls ``left(arguments)``
435
+ - ``PrimaryIndex(left: Expression, index: Expression)``: Array indexing ``left[index]``
436
+ - ``PrimaryMember(left: Expression, member: Identifier)``: Member access ``left.member``
415
437
 
416
438
  List Comprehensions
417
439
  ~~~~~~~~~~~~~~~~~~~
418
440
 
419
- - ``ListComprehension``: Vector/list literals
420
- - ``ListCompFor``: for loops in list comprehensions
421
- - ``ListCompCFor``: C-style for loops
422
- - ``ListCompIf``, ``ListCompIfElse``: Conditionals
423
- - ``ListCompLet``: let expressions
424
- - ``ListCompEach``: each expressions
441
+ - ``ListComprehension(elements: list[VectorElement])``: Vector/list literals ``[elements]``
442
+ - ``ListCompFor(assignments: list[Assignment], body: VectorElement)``: for loops in list comprehensions ``for(assignments) body``
443
+ - ``ListCompCFor(inits: list[Assignment], condition: Expression, incrs: list[Assignment], body: VectorElement)``: C-style for loops in list comprehensions ``for(inits; condition; incrs) body``
444
+ - ``ListCompIf(condition: Expression, true_expr: VectorElement)``: Conditional inclusion without else ``if(condition) true_expr``
445
+ - ``ListCompIfElse(condition: Expression, true_expr: VectorElement, false_expr: VectorElement)``: Conditional inclusion with else ``if(condition) true_expr else false_expr``
446
+ - ``ListCompLet(assignments: list[Assignment], body: VectorElement)``: let expressions in list comprehensions ``let(assignments) body``
447
+ - ``ListCompEach(body: VectorElement)``: each expressions (flattens nested lists) ``each body``
425
448
 
426
449
  Module Instantiations
427
450
  ~~~~~~~~~~~~~~~~~~~~~
428
451
 
429
- - ``ModularCall``: Module calls with arguments and children
430
- - ``ModularFor``: for loops
431
- - ``ModularCFor``: C-style for loops
432
- - ``ModularIntersectionFor``: intersection_for loops
433
- - ``ModularIntersectionCFor``: C-style intersection_for loops
434
- - ``ModularLet``: let statements
435
- - ``ModularEcho``: echo statements
436
- - ``ModularAssert``: assert statements
437
- - ``ModularIf``, ``ModularIfElse``: if/else statements
438
- - ``ModularModifierShowOnly``: ``!`` modifier
439
- - ``ModularModifierHighlight``: ``#`` modifier
440
- - ``ModularModifierBackground``: ``%`` modifier
441
- - ``ModularModifierDisable``: ``*`` modifier
452
+ - ``ModularCall(name: Identifier, arguments: list[Argument], children: list[ModuleInstantiation])``: Module calls ``name(arguments) { children }``
453
+ - ``ModularFor(assignments: list[Assignment], body: ModuleInstantiation)``: for loops in module bodies ``for(assignments) body``
454
+ - ``ModularIntersectionFor(assignments: list[Assignment], body: ModuleInstantiation)``: intersection_for loops ``intersection_for(assignments) body``
455
+ - ``ModularLet(assignments: list[Assignment], children: list[ModuleInstantiation])``: let statements in module bodies ``let(assignments) { children }``
456
+ - ``ModularEcho(arguments: list[Argument], children: list[ModuleInstantiation])``: echo statements in module bodies ``echo(arguments) { children }``
457
+ - ``ModularAssert(arguments: list[Argument], children: list[ModuleInstantiation])``: assert statements in module bodies ``assert(arguments) { children }``
458
+ - ``ModularIf(condition: Expression, true_branch: ModuleInstantiation)``: if statements in module bodies, with no else ``if(condition) true_branch``
459
+ - ``ModularIfElse(condition: Expression, true_branch: ModuleInstantiation, false_branch: ModuleInstantiation)``: if/else statements in module bodies ``if(condition) true_branch else false_branch``
460
+ - ``ModularModifierShowOnly(child: ModuleInstantiation)``: Show-Only modifier ``!child``
461
+ - ``ModularModifierHighlight(child: ModuleInstantiation)``: Highlight modifier ``#child``
462
+ - ``ModularModifierBackground(child: ModuleInstantiation)``: Background modifier ``%child``
463
+ - ``ModularModifierDisable(child: ModuleInstantiation)``: Disabler modifier ``*child``
442
464
 
443
465
  Declarations
444
466
  ~~~~~~~~~~~~
445
467
 
446
- - ``ModuleDeclaration``: module definitions
447
- - ``FunctionDeclaration``: function definitions
448
- - ``ParameterDeclaration``: function/module parameters
449
- - ``Assignment``: variable assignments
468
+ - ``ModuleDeclaration(name: Identifier, parameters: list[ParameterDeclaration], children: list[ModuleInstantiation | Assignment | FunctionDeclaration | ModuleDeclaration])``: Module definitions ``module name(parameters) { children }``
469
+ - ``FunctionDeclaration(name: Identifier, parameters: list[ParameterDeclaration], expr: Expression)``: Function definitions ``function name(parameters) = expr;``
470
+ - ``ParameterDeclaration(name: Identifier, default: Expression | None)``: Function/module parameter with optional default value ``name=default`` or ``name``
471
+ - ``Assignment(name: Identifier, expr: Expression)``: Variable assignments ``name = expr;``
450
472
 
451
473
  Statements
452
474
  ~~~~~~~~~~
453
475
 
454
- - ``UseStatement``: use <filepath>
455
- - ``IncludeStatement``: include <filepath>
456
- - ``PositionalArgument``: Function call positional arguments
457
- - ``NamedArgument``: Function call named arguments (name=value)
476
+ - ``UseStatement(filepath: StringLiteral)``: Represents ``use <filepath>``
477
+ - ``IncludeStatement(filepath: StringLiteral)``: Represents ``include <filepath>``
478
+ - ``PositionalArgument(expr: Expression)``: Function call positional arguments ``expr``
479
+ - ``NamedArgument(name: Identifier, expr: Expression)``: Function call named arguments ``name=expr``
458
480
 
459
481
  Comments
460
482
  ~~~~~~~~
461
483
 
462
- - ``CommentLine``: Single-line comments //
463
- - ``CommentSpan``: Multi-line comments ``/* */``
484
+ - ``CommentLine(text: str)``: Single-line comments ``// str``
485
+ - ``CommentSpan(text: str)``: Multi-line comments ``/* str */``
464
486
 
465
487
  All AST node classes are fully documented with docstrings that include:
466
488
  - Description of what the node represents
@@ -317,107 +317,129 @@ Parsing Library Files
317
317
  AST Node Types
318
318
  --------------
319
319
 
320
- The AST includes comprehensive node types for all OpenSCAD language constructs:
320
+ The AST includes comprehensive node types for all OpenSCAD language constructs.
321
+ All nodes inherit from ``ASTNode`` and carry ``position: Position`` and ``scope: Scope | None`` attributes.
321
322
 
322
323
  Base Classes
323
324
  ~~~~~~~~~~~~
324
325
 
325
- - ``ASTNode``: Base class for all AST nodes (includes ``position`` attribute)
326
+ - ``ASTNode(position: Position, scope: Scope | None)``: Base class for all AST nodes
326
327
  - ``Expression``: Base class for all expression nodes
327
- - ``Primary``: Base class for atomic value types
328
+ - ``Primary``: Base class for atomic value types (extends ``Expression``)
328
329
  - ``ModuleInstantiation``: Base class for module-related statements
330
+ - ``VectorElement``: Base class for list comprehension elements
329
331
 
330
332
  Literals
331
333
  ~~~~~~~~
332
334
 
333
- - ``Identifier``: Variable, function, or module names
334
- - ``StringLiteral``: String values
335
- - ``NumberLiteral``: Numeric values
336
- - ``BooleanLiteral``: true/false values
337
- - ``UndefinedLiteral``: undef value
338
- - ``RangeLiteral``: Range expressions [start:end:step]
335
+ - ``Identifier(name: str)``: Variable, function, or module names
336
+ - ``StringLiteral(val: str)``: String values
337
+ - ``NumberLiteral(val: float)``: Numeric values
338
+ - ``BooleanLiteral(val: bool)``: true/false values
339
+ - ``UndefinedLiteral``: The ``undef`` value (no additional fields)
340
+ - ``RangeLiteral(start: Expression, end: Expression, step: Expression)``: Range expressions ``[start:step:end]``
339
341
 
340
342
  Operators
341
343
  ~~~~~~~~~
342
344
 
345
+ All operators inherit from ``Expression`` and represent their respective operations with typed fields for operands. The AST preserves operator precedence and associativity as defined in OpenSCAD.
346
+
343
347
  Arithmetic:
344
- - ``AdditionOp``, ``SubtractionOp``, ``MultiplicationOp``, ``DivisionOp``
345
- - ``ModuloOp``, ``ExponentOp``, ``UnaryMinusOp``
348
+
349
+ - ``AdditionOp(left: Expression, right: Expression)``: represents ``left + right``
350
+ - ``SubtractionOp(left: Expression, right: Expression)``: represents ``left - right``
351
+ - ``MultiplicationOp(left: Expression, right: Expression)``: represents ``left * right``
352
+ - ``DivisionOp(left: Expression, right: Expression)``: represents ``left / right``
353
+ - ``ModuloOp(left: Expression, right: Expression)``: represents ``left % right``
354
+ - ``ExponentOp(left: Expression, right: Expression)``: represents ``left ^ right``
355
+ - ``UnaryMinusOp(expr: Expression)``: represents ``-expr``
346
356
 
347
357
  Logical:
348
- - ``LogicalAndOp``, ``LogicalOrOp``, ``LogicalNotOp``
358
+
359
+ - ``LogicalAndOp(left: Expression, right: Expression)``: represents ``left && right``
360
+ - ``LogicalOrOp(left: Expression, right: Expression)``: represents ``left || right``
361
+ - ``LogicalNotOp(expr: Expression)``: represents ``!expr``
349
362
 
350
363
  Comparison:
351
- - ``EqualityOp``, ``InequalityOp``
352
- - ``GreaterThanOp``, ``GreaterThanOrEqualOp``
353
- - ``LessThanOp``, ``LessThanOrEqualOp``
364
+
365
+ - ``EqualityOp(left: Expression, right: Expression)``: represents ``left == right``
366
+ - ``InequalityOp(left: Expression, right: Expression)``: represents ``left != right``
367
+ - ``GreaterThanOp(left: Expression, right: Expression)``: represents ``left > right``
368
+ - ``GreaterThanOrEqualOp(left: Expression, right: Expression)``: represents ``left >= right``
369
+ - ``LessThanOp(left: Expression, right: Expression)``: represents ``left < right``
370
+ - ``LessThanOrEqualOp(left: Expression, right: Expression)``: represents ``left <= right``
354
371
 
355
372
  Bitwise:
356
- - ``BitwiseAndOp``, ``BitwiseOrOp``, ``BitwiseNotOp``
357
- - ``BitwiseShiftLeftOp``, ``BitwiseShiftRightOp``
373
+
374
+ - ``BitwiseAndOp(left: Expression, right: Expression)``: represents ``left & right``
375
+ - ``BitwiseOrOp(left: Expression, right: Expression)``: represents ``left | right``
376
+ - ``BitwiseShiftLeftOp(left: Expression, right: Expression)``: represents ``left << right``
377
+ - ``BitwiseShiftRightOp(left: Expression, right: Expression)``: represents ``left >> right``
378
+ - ``BitwiseNotOp(expr: Expression)``: represents ``~expr``
358
379
 
359
380
  Other:
360
- - ``TernaryOp``: condition ? true_expr : false_expr
381
+
382
+ - ``TernaryOp(condition: Expression, true_expr: Expression, false_expr: Expression)``: Represents ``condition ? true_expr : false_expr``
361
383
 
362
384
  Expressions
363
385
  ~~~~~~~~~~~
364
386
 
365
- - ``LetOp``: let(assignments) body
366
- - ``EchoOp``: echo(arguments) body
367
- - ``AssertOp``: assert(arguments) body
368
- - ``FunctionLiteral``: function(parameters) body
369
- - ``PrimaryCall``: function calls
370
- - ``PrimaryIndex``: array indexing [index]
371
- - ``PrimaryMember``: member access .member
387
+ - ``LetOp(assignments: list[Assignment], body: Expression)``: let clause ``let(assignments) body``
388
+ - ``EchoOp(arguments: list[Argument], body: Expression)``: echo clause ``echo(arguments) body``
389
+ - ``AssertOp(arguments: list[Argument], body: Expression)``: assert clause ``assert(arguments) body``
390
+ - ``FunctionLiteral(parameters: list[ParameterDeclaration], body: Expression)``: Anonymous function expression ``function(parameters) body``
391
+ - ``PrimaryCall(left: Expression, arguments: list[Argument])``: Function calls ``left(arguments)``
392
+ - ``PrimaryIndex(left: Expression, index: Expression)``: Array indexing ``left[index]``
393
+ - ``PrimaryMember(left: Expression, member: Identifier)``: Member access ``left.member``
372
394
 
373
395
  List Comprehensions
374
396
  ~~~~~~~~~~~~~~~~~~~
375
397
 
376
- - ``ListComprehension``: Vector/list literals
377
- - ``ListCompFor``: for loops in list comprehensions
378
- - ``ListCompCFor``: C-style for loops
379
- - ``ListCompIf``, ``ListCompIfElse``: Conditionals
380
- - ``ListCompLet``: let expressions
381
- - ``ListCompEach``: each expressions
398
+ - ``ListComprehension(elements: list[VectorElement])``: Vector/list literals ``[elements]``
399
+ - ``ListCompFor(assignments: list[Assignment], body: VectorElement)``: for loops in list comprehensions ``for(assignments) body``
400
+ - ``ListCompCFor(inits: list[Assignment], condition: Expression, incrs: list[Assignment], body: VectorElement)``: C-style for loops in list comprehensions ``for(inits; condition; incrs) body``
401
+ - ``ListCompIf(condition: Expression, true_expr: VectorElement)``: Conditional inclusion without else ``if(condition) true_expr``
402
+ - ``ListCompIfElse(condition: Expression, true_expr: VectorElement, false_expr: VectorElement)``: Conditional inclusion with else ``if(condition) true_expr else false_expr``
403
+ - ``ListCompLet(assignments: list[Assignment], body: VectorElement)``: let expressions in list comprehensions ``let(assignments) body``
404
+ - ``ListCompEach(body: VectorElement)``: each expressions (flattens nested lists) ``each body``
382
405
 
383
406
  Module Instantiations
384
407
  ~~~~~~~~~~~~~~~~~~~~~
385
408
 
386
- - ``ModularCall``: Module calls with arguments and children
387
- - ``ModularFor``: for loops
388
- - ``ModularCFor``: C-style for loops
389
- - ``ModularIntersectionFor``: intersection_for loops
390
- - ``ModularIntersectionCFor``: C-style intersection_for loops
391
- - ``ModularLet``: let statements
392
- - ``ModularEcho``: echo statements
393
- - ``ModularAssert``: assert statements
394
- - ``ModularIf``, ``ModularIfElse``: if/else statements
395
- - ``ModularModifierShowOnly``: ``!`` modifier
396
- - ``ModularModifierHighlight``: ``#`` modifier
397
- - ``ModularModifierBackground``: ``%`` modifier
398
- - ``ModularModifierDisable``: ``*`` modifier
409
+ - ``ModularCall(name: Identifier, arguments: list[Argument], children: list[ModuleInstantiation])``: Module calls ``name(arguments) { children }``
410
+ - ``ModularFor(assignments: list[Assignment], body: ModuleInstantiation)``: for loops in module bodies ``for(assignments) body``
411
+ - ``ModularIntersectionFor(assignments: list[Assignment], body: ModuleInstantiation)``: intersection_for loops ``intersection_for(assignments) body``
412
+ - ``ModularLet(assignments: list[Assignment], children: list[ModuleInstantiation])``: let statements in module bodies ``let(assignments) { children }``
413
+ - ``ModularEcho(arguments: list[Argument], children: list[ModuleInstantiation])``: echo statements in module bodies ``echo(arguments) { children }``
414
+ - ``ModularAssert(arguments: list[Argument], children: list[ModuleInstantiation])``: assert statements in module bodies ``assert(arguments) { children }``
415
+ - ``ModularIf(condition: Expression, true_branch: ModuleInstantiation)``: if statements in module bodies, with no else ``if(condition) true_branch``
416
+ - ``ModularIfElse(condition: Expression, true_branch: ModuleInstantiation, false_branch: ModuleInstantiation)``: if/else statements in module bodies ``if(condition) true_branch else false_branch``
417
+ - ``ModularModifierShowOnly(child: ModuleInstantiation)``: Show-Only modifier ``!child``
418
+ - ``ModularModifierHighlight(child: ModuleInstantiation)``: Highlight modifier ``#child``
419
+ - ``ModularModifierBackground(child: ModuleInstantiation)``: Background modifier ``%child``
420
+ - ``ModularModifierDisable(child: ModuleInstantiation)``: Disabler modifier ``*child``
399
421
 
400
422
  Declarations
401
423
  ~~~~~~~~~~~~
402
424
 
403
- - ``ModuleDeclaration``: module definitions
404
- - ``FunctionDeclaration``: function definitions
405
- - ``ParameterDeclaration``: function/module parameters
406
- - ``Assignment``: variable assignments
425
+ - ``ModuleDeclaration(name: Identifier, parameters: list[ParameterDeclaration], children: list[ModuleInstantiation | Assignment | FunctionDeclaration | ModuleDeclaration])``: Module definitions ``module name(parameters) { children }``
426
+ - ``FunctionDeclaration(name: Identifier, parameters: list[ParameterDeclaration], expr: Expression)``: Function definitions ``function name(parameters) = expr;``
427
+ - ``ParameterDeclaration(name: Identifier, default: Expression | None)``: Function/module parameter with optional default value ``name=default`` or ``name``
428
+ - ``Assignment(name: Identifier, expr: Expression)``: Variable assignments ``name = expr;``
407
429
 
408
430
  Statements
409
431
  ~~~~~~~~~~
410
432
 
411
- - ``UseStatement``: use <filepath>
412
- - ``IncludeStatement``: include <filepath>
413
- - ``PositionalArgument``: Function call positional arguments
414
- - ``NamedArgument``: Function call named arguments (name=value)
433
+ - ``UseStatement(filepath: StringLiteral)``: Represents ``use <filepath>``
434
+ - ``IncludeStatement(filepath: StringLiteral)``: Represents ``include <filepath>``
435
+ - ``PositionalArgument(expr: Expression)``: Function call positional arguments ``expr``
436
+ - ``NamedArgument(name: Identifier, expr: Expression)``: Function call named arguments ``name=expr``
415
437
 
416
438
  Comments
417
439
  ~~~~~~~~
418
440
 
419
- - ``CommentLine``: Single-line comments //
420
- - ``CommentSpan``: Multi-line comments ``/* */``
441
+ - ``CommentLine(text: str)``: Single-line comments ``// str``
442
+ - ``CommentSpan(text: str)``: Multi-line comments ``/* str */``
421
443
 
422
444
  All AST node classes are fully documented with docstrings that include:
423
445
  - Description of what the node represents
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_parser"
7
- version = "2.4.0"
7
+ version = "2.4.1"
8
8
  description = "A PEG parser to read OpenSCAD language source code, with optional AST tree generation."
9
9
  readme = "README.rst"
10
10
  authors = [
@@ -63,9 +63,7 @@ from .nodes import (
63
63
  ModuleInstantiation,
64
64
  ModularCall,
65
65
  ModularFor,
66
- ModularCFor,
67
66
  ModularIntersectionFor,
68
- ModularIntersectionCFor,
69
67
  ModularLet,
70
68
  ModularEcho,
71
69
  ModularAssert,
@@ -6,6 +6,28 @@ from .source_map import SourceMap
6
6
  from .nodes import *
7
7
 
8
8
 
9
+ class _CForParts:
10
+ """Wrapper returned by c_for_inits/c_for_incrs visitors.
11
+
12
+ Always truthy so Arpeggio does not drop it from parent children when
13
+ there are zero assignments, and not a list so Arpeggio does not flatten
14
+ it into the parent's children list.
15
+ """
16
+ __slots__ = ('_items',)
17
+
18
+ def __init__(self, items: list) -> None:
19
+ self._items = items
20
+
21
+ def __iter__(self):
22
+ return iter(self._items)
23
+
24
+ def __len__(self) -> int:
25
+ return len(self._items)
26
+
27
+ def __bool__(self) -> bool: # pragma: no cover
28
+ return True
29
+
30
+
9
31
  @dataclass
10
32
  class Position:
11
33
  """Represents a location in a source origin.
@@ -1051,7 +1073,9 @@ class ASTBuilderVisitor(PTNodeVisitor):
1051
1073
  return ListComprehension(elements=elements, position=self._get_node_position(node))
1052
1074
 
1053
1075
  def visit_funclit_def(self, node, children):
1054
- return FunctionLiteral(arguments=children[0], body=children[1], position=self._get_node_position(node))
1076
+ parameters = [c for c in children if isinstance(c, ParameterDeclaration)]
1077
+ body = next(c for c in children if not isinstance(c, ParameterDeclaration))
1078
+ return FunctionLiteral(parameters=parameters, body=body, position=self._get_node_position(node))
1055
1079
 
1056
1080
  def visit_vector_elements(self, node, children):
1057
1081
  return list(children) if children else []
@@ -1066,24 +1090,43 @@ class ASTBuilderVisitor(PTNodeVisitor):
1066
1090
  return children[0]
1067
1091
 
1068
1092
  def visit_listcomp_let(self, node, children):
1069
- return ListCompLet(assignments=children[0], body=children[1], position=self._get_node_position(node))
1070
-
1093
+ body = children[-1]
1094
+ assignments = [c for c in children[:-1] if isinstance(c, Assignment)]
1095
+ return ListCompLet(assignments=assignments, body=body, position=self._get_node_position(node))
1096
+
1071
1097
  def visit_listcomp_each(self, node, children):
1072
1098
  return ListCompEach(body=children[0], position=self._get_node_position(node))
1073
-
1099
+
1074
1100
  def visit_listcomp_for(self, node, children):
1101
+ body = children[-1]
1102
+ assignments = [c for c in children[:-1] if isinstance(c, Assignment)]
1075
1103
  return ListCompFor(
1076
- assignments=children[0],
1077
- body=children[1],
1104
+ assignments=assignments,
1105
+ body=body,
1078
1106
  position=self._get_node_position(node)
1079
1107
  )
1080
1108
 
1109
+ def visit_c_for_inits(self, node, children):
1110
+ return _CForParts([a for a in children if isinstance(a, Assignment)])
1111
+
1112
+ def visit_c_for_incrs(self, node, children):
1113
+ return _CForParts([a for a in children if isinstance(a, Assignment)])
1114
+
1081
1115
  def visit_listcomp_c_for(self, node, children):
1116
+ idx = 0
1117
+ inits = list(children[idx]) if isinstance(children[idx], _CForParts) else []
1118
+ if isinstance(children[idx], _CForParts):
1119
+ idx += 1
1120
+ condition = children[idx]; idx += 1
1121
+ incrs = list(children[idx]) if idx < len(children) and isinstance(children[idx], _CForParts) else []
1122
+ if idx < len(children) and isinstance(children[idx], _CForParts):
1123
+ idx += 1
1124
+ body = children[idx]
1082
1125
  return ListCompCFor(
1083
- initial=children[0],
1084
- condition=children[1],
1085
- increment=children[2],
1086
- body=children[3],
1126
+ inits=inits,
1127
+ condition=condition,
1128
+ incrs=incrs,
1129
+ body=body,
1087
1130
  position=self._get_node_position(node)
1088
1131
  )
1089
1132
 
@@ -1123,56 +1166,32 @@ class ASTBuilderVisitor(PTNodeVisitor):
1123
1166
  position=self._get_node_position(node)
1124
1167
  )
1125
1168
 
1126
- def visit_modular_c_for(self, node, children):
1127
- initial = children[0] if isinstance(children[0], list) else [children[0]]
1128
- increment = children[2] if isinstance(children[2], list) else [children[2]]
1129
- body = children.get_rule('child_statement')
1130
- return ModularCFor(
1131
- initial=initial,
1132
- condition=children[1],
1133
- increment=increment,
1134
- body=body,
1135
- position=self._get_node_position(node)
1136
- )
1137
-
1138
1169
  def visit_modular_for(self, node, children):
1139
- assignments = children[0] if isinstance(children[0], list) else [children[0]]
1170
+ assignments = [c for c in children if isinstance(c, Assignment)]
1140
1171
  body = children.get_rule('child_statement')
1141
1172
  return ModularFor(
1142
1173
  assignments=assignments,
1143
1174
  body=body,
1144
1175
  position=self._get_node_position(node)
1145
1176
  )
1146
-
1147
- def visit_modular_intersection_c_for(self, node, children):
1148
- initial = children[0] if isinstance(children[0], list) else [children[0]]
1149
- increment = children[2] if isinstance(children[2], list) else [children[2]]
1150
- body = children.get_rule('child_statement')
1151
- return ModularIntersectionCFor(
1152
- initial=initial,
1153
- condition=children[1],
1154
- increment=increment,
1155
- body=body,
1156
- position=self._get_node_position(node)
1157
- )
1158
1177
 
1159
1178
  def visit_modular_intersection_for(self, node, children):
1160
- assignments = children[0] if isinstance(children[0], list) else [children[0]]
1179
+ assignments = [c for c in children if isinstance(c, Assignment)]
1161
1180
  body = children.get_rule('child_statement')
1162
1181
  return ModularIntersectionFor(assignments=assignments, body=body, position=self._get_node_position(node))
1163
-
1182
+
1164
1183
  def visit_modular_let(self, node, children):
1165
- assignments = children[0] if isinstance(children[0], list) else [children[0]]
1184
+ assignments = [c for c in children if isinstance(c, Assignment)]
1166
1185
  mods = children.get_rule('child_statement')
1167
1186
  return ModularLet(assignments=assignments, children=mods, position=self._get_node_position(node))
1168
1187
 
1169
1188
  def visit_modular_echo(self, node, children):
1170
- arguments = children[0] if isinstance(children[0], list) else [children[0]]
1189
+ arguments = [c for c in children if isinstance(c, Argument)]
1171
1190
  mods = children.get_rule('child_statement')
1172
1191
  return ModularEcho(arguments=arguments, children=mods, position=self._get_node_position(node))
1173
-
1192
+
1174
1193
  def visit_modular_assert(self, node, children):
1175
- arguments = children[0] if isinstance(children[0], list) else [children[0]]
1194
+ arguments = [c for c in children if isinstance(c, Argument)]
1176
1195
  mods = children.get_rule('child_statement')
1177
1196
  return ModularAssert(arguments=arguments, children=mods, position=self._get_node_position(node))
1178
1197
 
@@ -1061,35 +1061,30 @@ class LessThanOrEqualOp(Expression):
1061
1061
  @dataclass
1062
1062
  class FunctionLiteral(Expression):
1063
1063
  """Represents an OpenSCAD function literal (anonymous function).
1064
-
1064
+
1065
1065
  Function literals are anonymous functions that can be assigned to variables
1066
1066
  or used directly in expressions. They are defined using the 'function' keyword.
1067
-
1067
+
1068
1068
  Examples:
1069
1069
  x = function(x) x * 2; // Anonymous function assigned to x
1070
1070
  function(a, b) a + b // Function literal in expression
1071
-
1071
+
1072
1072
  Attributes:
1073
- arguments: List of parameter declarations (as Argument nodes).
1073
+ parameters: List of parameter declarations.
1074
1074
  body: The expression body of the function.
1075
1075
  """
1076
- arguments: list[Argument]
1076
+ parameters: list[ParameterDeclaration]
1077
1077
  body: Expression
1078
1078
 
1079
1079
  def __str__(self):
1080
- return f"function({', '.join(str(arg) for arg in self.arguments)}) {self.body}"
1080
+ return f"function({', '.join(str(p) for p in self.parameters)}) {self.body}"
1081
1081
 
1082
1082
  def build_scope(self, parent_scope: "Scope") -> None:
1083
1083
  self.scope = parent_scope
1084
1084
  func_scope = parent_scope.child_scope()
1085
- # Normalize: builder may pass a single ParameterDeclaration for one-param literals
1086
- arguments = self.arguments
1087
- if not isinstance(arguments, (list, tuple)):
1088
- arguments = [arguments] if arguments is not None else []
1089
- for arg in arguments:
1090
- if isinstance(arg, ParameterDeclaration):
1091
- func_scope.define_variable(arg.name.name, arg)
1092
- arg.build_scope(func_scope)
1085
+ for param in self.parameters:
1086
+ func_scope.define_variable(param.name.name, param)
1087
+ param.build_scope(func_scope)
1093
1088
  self.body.build_scope(func_scope)
1094
1089
 
1095
1090
 
@@ -1202,10 +1197,10 @@ class ListCompLet(VectorElement):
1202
1197
 
1203
1198
  Attributes:
1204
1199
  assignments: List of local variable assignments.
1205
- body: The expression body that uses the assigned variables.
1200
+ body: The vector element body that uses the assigned variables.
1206
1201
  """
1207
1202
  assignments: list[Assignment]
1208
- body: Expression
1203
+ body: VectorElement
1209
1204
 
1210
1205
  def __str__(self):
1211
1206
  return f"let ({', '.join(str(a) for a in self.assignments)}) {self.body}"
@@ -1213,11 +1208,7 @@ class ListCompLet(VectorElement):
1213
1208
  def build_scope(self, parent_scope: "Scope") -> None:
1214
1209
  self.scope = parent_scope
1215
1210
  let_scope = parent_scope.child_scope()
1216
- # Normalize: builder may pass a single Assignment for one-binding lets
1217
- assignments = self.assignments
1218
- if not isinstance(assignments, (list, tuple)):
1219
- assignments = [assignments] if assignments is not None else []
1220
- for assignment in assignments:
1211
+ for assignment in self.assignments:
1221
1212
  let_scope.define_variable(assignment.name.name, assignment)
1222
1213
  assignment.build_scope(let_scope)
1223
1214
  self.body.build_scope(let_scope)
@@ -1272,11 +1263,7 @@ class ListCompFor(VectorElement):
1272
1263
  def build_scope(self, parent_scope: "Scope") -> None:
1273
1264
  self.scope = parent_scope
1274
1265
  for_scope = parent_scope.child_scope()
1275
- # Normalize: builder may pass a single Assignment for one-variable loops
1276
- assignments = self.assignments
1277
- if not isinstance(assignments, (list, tuple)):
1278
- assignments = [assignments] if assignments is not None else []
1279
- for assignment in assignments:
1266
+ for assignment in self.assignments:
1280
1267
  assignment.scope = for_scope
1281
1268
  for_scope.define_variable(assignment.name.name, assignment)
1282
1269
  assignment.name.build_scope(for_scope)
@@ -1297,34 +1284,27 @@ class ListCompCFor(VectorElement):
1297
1284
  [i*2 for (i=0; i<10; i=i+2)] // With increment step
1298
1285
 
1299
1286
  Attributes:
1300
- initial: List of initialization assignments.
1287
+ inits: List of initialization assignments.
1301
1288
  condition: The loop continuation condition.
1302
- increment: List of increment assignments.
1289
+ incrs: List of increment assignments.
1303
1290
  body: The expression to evaluate for each iteration.
1304
1291
  """
1305
- initial: list[Assignment]
1292
+ inits: list[Assignment]
1306
1293
  condition: Expression
1307
- increment: list[Assignment]
1294
+ incrs: list[Assignment]
1308
1295
  body: VectorElement
1309
1296
 
1310
1297
  def __str__(self):
1311
- return f"for ({', '.join(str(a) for a in self.initial)}; {self.condition}; {', '.join(str(a) for a in self.increment)}) {self.body}"
1298
+ return f"for ({', '.join(str(a) for a in self.inits)}; {self.condition}; {', '.join(str(a) for a in self.incrs)}) {self.body}"
1312
1299
 
1313
1300
  def build_scope(self, parent_scope: "Scope") -> None:
1314
1301
  self.scope = parent_scope
1315
1302
  for_scope = parent_scope.child_scope()
1316
- # Normalize: builder may pass single Assignments
1317
- initial = self.initial
1318
- if not isinstance(initial, (list, tuple)):
1319
- initial = [initial] if initial is not None else []
1320
- increment = self.increment
1321
- if not isinstance(increment, (list, tuple)):
1322
- increment = [increment] if increment is not None else []
1323
- for assignment in initial:
1303
+ for assignment in self.inits:
1324
1304
  for_scope.define_variable(assignment.name.name, assignment)
1325
1305
  assignment.build_scope(for_scope)
1326
1306
  self.condition.build_scope(for_scope)
1327
- for assignment in increment:
1307
+ for assignment in self.incrs:
1328
1308
  assignment.build_scope(for_scope)
1329
1309
  self.body.build_scope(for_scope)
1330
1310
 
@@ -1496,46 +1476,6 @@ class ModularFor(ModuleInstantiation):
1496
1476
  node.build_scope(for_scope)
1497
1477
 
1498
1478
 
1499
- @dataclass
1500
- class ModularCFor(ModuleInstantiation):
1501
- """Represents a C-style for loop module instantiation.
1502
-
1503
- C-style for loops have three parts: initialization, condition, and increment.
1504
- Similar to C/Java for loops: for (init; condition; increment) body
1505
-
1506
- Examples:
1507
- for (i=0; i<5; i=i+1) translate([i, 0, 0]) cube(1);
1508
- for (i=0; i<10; i=i+2) rotate([0, 0, i]) cube(1);
1509
-
1510
- Attributes:
1511
- initial: List of initialization assignments.
1512
- condition: The loop continuation condition.
1513
- increment: List of increment assignments.
1514
- body: The module instantiation to execute for each iteration.
1515
- """
1516
- initial: list[Assignment]
1517
- condition: Expression
1518
- increment: list[Assignment]
1519
- body: ModuleInstantiation
1520
-
1521
- def __str__(self):
1522
- return f"for ({'; '.join(str(a) for a in self.initial)}; {self.condition}; {', '.join(str(a) for a in self.increment)}) {self.body}"
1523
-
1524
- def build_scope(self, parent_scope: "Scope") -> None:
1525
- self.scope = parent_scope
1526
- for_scope = parent_scope.child_scope()
1527
- for assignment in self.initial:
1528
- for_scope.define_variable(assignment.name.name, assignment)
1529
- assignment.build_scope(for_scope)
1530
- self.condition.build_scope(for_scope)
1531
- for assignment in self.increment:
1532
- assignment.build_scope(for_scope)
1533
- body = self.body if isinstance(self.body, list) else [self.body]
1534
- _collect_hoisted_declarations(body, for_scope)
1535
- for node in body:
1536
- node.build_scope(for_scope)
1537
-
1538
-
1539
1479
  @dataclass
1540
1480
  class ModularIntersectionFor(ModuleInstantiation):
1541
1481
  """Represents an intersection_for loop module instantiation.
@@ -1570,52 +1510,6 @@ class ModularIntersectionFor(ModuleInstantiation):
1570
1510
  node.build_scope(for_scope)
1571
1511
 
1572
1512
 
1573
- @dataclass
1574
- class ModularIntersectionCFor(ModuleInstantiation):
1575
- """Represents an intersection_for C-style loop module instantiation.
1576
-
1577
- Similar to a C-style for loop, but computes the intersection of all
1578
- iterations rather than the union. Used for creating complex intersections
1579
- that use explicit initialization, condition, and increment.
1580
-
1581
- Examples:
1582
- intersection_for(i = 0; i < 3; i = i + 1) rotate([0,0,i*90]) cube(10);
1583
-
1584
- Attributes:
1585
- initial: List of initialization assignments.
1586
- condition: The loop continuation condition.
1587
- increment: List of increment assignments.
1588
- body: The module instantiation to execute for each iteration.
1589
- """
1590
- initial: list[Assignment]
1591
- condition: Expression
1592
- increment: list[Assignment]
1593
- body: ModuleInstantiation
1594
-
1595
- def __str__(self):
1596
- return (
1597
- f"intersection_for ("
1598
- f"{'; '.join(str(a) for a in self.initial)}; "
1599
- f"{self.condition}; "
1600
- f"{', '.join(str(a) for a in self.increment)}"
1601
- f") {self.body}"
1602
- )
1603
-
1604
- def build_scope(self, parent_scope: "Scope") -> None:
1605
- self.scope = parent_scope
1606
- for_scope = parent_scope.child_scope()
1607
- for assignment in self.initial:
1608
- for_scope.define_variable(assignment.name.name, assignment)
1609
- assignment.build_scope(for_scope)
1610
- self.condition.build_scope(for_scope)
1611
- for assignment in self.increment:
1612
- assignment.build_scope(for_scope)
1613
- body = self.body if isinstance(self.body, list) else [self.body]
1614
- _collect_hoisted_declarations(body, for_scope)
1615
- for node in body:
1616
- node.build_scope(for_scope)
1617
-
1618
-
1619
1513
  @dataclass
1620
1514
  class ModularLet(ModuleInstantiation):
1621
1515
  """Represents a let statement for module instantiations.
@@ -4,8 +4,8 @@ from .nodes import (
4
4
  ASTNode, Assignment, FunctionDeclaration, ModuleDeclaration,
5
5
  UseStatement, IncludeStatement,
6
6
  ModuleInstantiation,
7
- ModularCall, ModularFor, ModularCFor,
8
- ModularIntersectionFor, ModularIntersectionCFor,
7
+ ModularCall, ModularFor,
8
+ ModularIntersectionFor,
9
9
  ModularLet, ModularEcho, ModularAssert,
10
10
  ModularIf, ModularIfElse,
11
11
  ModularModifierShowOnly, ModularModifierHighlight,
@@ -72,7 +72,7 @@ def _fmt_node(node: ASTNode, indent: int, w: int) -> str:
72
72
  return f"{pad}module {node.name}({params}) {block}"
73
73
  if isinstance(node, ModuleInstantiation):
74
74
  return _fmt_inst(node, indent, w)
75
- return f"{pad}{node}"
75
+ return f"{pad}{node}" # pragma: no cover
76
76
 
77
77
 
78
78
  def _fmt_block(nodes: list, indent: int, w: int) -> str:
@@ -129,20 +129,10 @@ def _fmt_inst(node: ModuleInstantiation, indent: int, w: int, prefix: str = "")
129
129
  assigns = _join_str(_as_list(node.assignments))
130
130
  return f"{pad}{prefix}for ({assigns})" + _fmt_child(node.body, indent, w)
131
131
 
132
- if isinstance(node, ModularCFor):
133
- init = _join_str(_as_list(node.initial))
134
- inc = _join_str(_as_list(node.increment))
135
- return f"{pad}{prefix}for ({init}; {node.condition}; {inc})" + _fmt_child(node.body, indent, w)
136
-
137
132
  if isinstance(node, ModularIntersectionFor):
138
133
  assigns = _join_str(_as_list(node.assignments))
139
134
  return f"{pad}{prefix}intersection_for ({assigns})" + _fmt_child(node.body, indent, w)
140
135
 
141
- if isinstance(node, ModularIntersectionCFor):
142
- init = _join_str(_as_list(node.initial))
143
- inc = _join_str(_as_list(node.increment))
144
- return f"{pad}{prefix}intersection_for ({init}; {node.condition}; {inc})" + _fmt_child(node.body, indent, w)
145
-
146
136
  if isinstance(node, ModularLet):
147
137
  assigns = _join_str(_as_list(node.assignments))
148
138
  return f"{pad}{prefix}let ({assigns})" + _fmt_child(node.children, indent, w)
@@ -166,4 +156,4 @@ def _fmt_inst(node: ModuleInstantiation, indent: int, w: int, prefix: str = "")
166
156
  connector = " else" if true_tail.startswith(" {") else f"\n{pad}else"
167
157
  return header + true_tail + connector + false_tail
168
158
 
169
- return f"{pad}{prefix}{node};"
159
+ return f"{pad}{prefix}{node};" # pragma: no cover
@@ -76,9 +76,7 @@ from .nodes import (
76
76
  ModuleInstantiation,
77
77
  ModularCall,
78
78
  ModularFor,
79
- ModularCFor,
80
79
  ModularIntersectionFor,
81
- ModularIntersectionCFor,
82
80
  ModularLet,
83
81
  ModularEcho,
84
82
  ModularAssert,
@@ -157,9 +155,7 @@ _NODE_REGISTRY: dict[str, type[ASTNode]] = {
157
155
  # Module instantiations
158
156
  ModularCall,
159
157
  ModularFor,
160
- ModularCFor,
161
158
  ModularIntersectionFor,
162
- ModularIntersectionCFor,
163
159
  ModularLet,
164
160
  ModularEcho,
165
161
  ModularAssert,
@@ -72,7 +72,7 @@ def main():
72
72
  elif args.yaml:
73
73
  try:
74
74
  from openscad_parser.ast import ast_to_yaml
75
- except ImportError:
75
+ except ImportError: # pragma: no cover
76
76
  print("openscad-parser: --yaml requires PyYAML (pip install openscad_parser[yaml])", file=sys.stderr)
77
77
  sys.exit(1)
78
78
  print(ast_to_yaml(ast))
@@ -80,5 +80,5 @@ def main():
80
80
  print(ast_to_json(ast, indent=args.indent))
81
81
 
82
82
 
83
- if __name__ == "__main__":
83
+ if __name__ == "__main__": # pragma: no cover
84
84
  main()
@@ -384,9 +384,7 @@ def ifelse_statement():
384
384
 
385
385
  def single_module_instantiation():
386
386
  return [
387
- modular_c_for,
388
387
  modular_for,
389
- modular_intersection_c_for,
390
388
  modular_intersection_for,
391
389
  modular_let,
392
390
  modular_assert,
@@ -409,36 +407,16 @@ def modular_for():
409
407
  return (KWD_FOR, TOK_PAREN, assignments_expr, TOK_ENDPAREN, child_statement)
410
408
 
411
409
 
412
- def modular_c_for():
413
- return (
414
- KWD_FOR,
415
- TOK_PAREN,
416
- assignments_expr,
417
- TOK_SEMICOLON,
418
- expr,
419
- TOK_SEMICOLON,
420
- assignments_expr,
421
- TOK_ENDPAREN,
422
- child_statement
423
- )
410
+ def c_for_inits():
411
+ return assignments_expr
424
412
 
425
413
 
426
- def modular_intersection_for():
427
- return (KWD_INTERSECTION_FOR, TOK_PAREN, assignments_expr, TOK_ENDPAREN, child_statement)
414
+ def c_for_incrs():
415
+ return assignments_expr
428
416
 
429
417
 
430
- def modular_intersection_c_for():
431
- return (
432
- KWD_INTERSECTION_FOR,
433
- TOK_PAREN,
434
- assignments_expr,
435
- TOK_SEMICOLON,
436
- expr,
437
- TOK_SEMICOLON,
438
- assignments_expr,
439
- TOK_ENDPAREN,
440
- child_statement
441
- )
418
+ def modular_intersection_for():
419
+ return (KWD_INTERSECTION_FOR, TOK_PAREN, assignments_expr, TOK_ENDPAREN, child_statement)
442
420
 
443
421
 
444
422
  def modular_let():
@@ -686,7 +664,7 @@ def listcomp_for():
686
664
 
687
665
 
688
666
  def listcomp_c_for():
689
- return (KWD_FOR, TOK_PAREN, assignments_expr, TOK_SEMICOLON, expr, TOK_SEMICOLON, assignments_expr, TOK_ENDPAREN, vector_element)
667
+ return (KWD_FOR, TOK_PAREN, c_for_inits, TOK_SEMICOLON, expr, TOK_SEMICOLON, c_for_incrs, TOK_ENDPAREN, vector_element)
690
668
 
691
669
 
692
670
  def listcomp_ifonly():