discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Bizarre OpenSCAD Syntax, and a Python library to parse OpenSCAD

RD
Revar Desmera
Mon, May 18, 2026 2:03 AM

I'm in the process of testing my Python openscad_parser library (https://github.com/BelfrySCAD/openscad_parser), and comparing it to how OpenSCAD itself parses the language.  I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing.

You can do a C-style for loop in a list comprehension like x = [for (i = 0; i < 10; i=i+1) i];, but you CANNOT do a C-style for() in modular form.  Also, intersection_for() will not take C-style syntax.

You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like i=0; x = [for (;i<10;) i];. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded.

Modular for() echo(42); will do nothing.  It's a No-Op.  Same for intersection_for() echo(42);.

For some reason, i=42; echo([for() i]); echoes 42 to the console.  I expected an empty list.

The let() in x = let() 42; acts like a No-op.  x just gets set to 42.

I'm sure there are more oddities in there.  In any case, the parser is live, with Abstract Syntax Tree generation, a command-line code reformatter, and 850+ unit tests. It's probably usable now.

  • Revar
I'm in the process of testing my Python openscad_parser library (https://github.com/BelfrySCAD/openscad_parser), and comparing it to how OpenSCAD itself parses the language. I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing. You can do a C-style for loop in a list comprehension like `x = [for (i = 0; i < 10; i=i+1) i];`, but you CANNOT do a C-style `for()` in modular form. Also, `intersection_for()` will not take C-style syntax. You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like `i=0; x = [for (;i<10;) i];`. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded. Modular `for() echo(42);` will do nothing. It's a No-Op. Same for `intersection_for() echo(42);`. For some reason, `i=42; echo([for() i]);` echoes 42 to the console. I expected an empty list. The `let()` in `x = let() 42;` acts like a No-op. `x` just gets set to 42. I'm sure there are more oddities in there. In any case, the parser is live, with Abstract Syntax Tree generation, a command-line code reformatter, and 850+ unit tests. It's probably usable now. - Revar
CM
Curt McDowell
Mon, May 18, 2026 4:47 PM

Bizarre syntax is old news. ;)

A couple notes on the --format option, from what little I've tried:

  • It doesn't add parenthesis or take operator precedence into account.
    Input (3+5)/2 gets formatted as 3+5/2.
  • It uses /True /and /False /for booleans instead of /true /and /false/.

Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe
a translation to PythonSCAD could be integrated into OpenSCAD itself, as
it has its own AST.)

Regards,
-Curt

On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote:

I'm in the process of testing my Python openscad_parser library
(https://github.com/BelfrySCAD/openscad_parser), and comparing it to
how OpenSCAD itself parses the language.  I've found a few oddities in
what OpenSCAD allows syntactically, that I find amusing.

You can do a C-style for loop in a list comprehension like x = [for (i = 0; i < 10; i=i+1) i];, but you CANNOT do a C-style for() in
modular form.  Also, intersection_for() will not take C-style syntax.

You do NOT need to specify initializer or incrementer in a C-style
list comprehension for loop like i=0; x = [for (;i<10;) i];.
However, if you don't have an incrementer, it will ALWAYS error out
with loop counter exceeded.

Modular for() echo(42); will do nothing.  It's a No-Op.  Same for
intersection_for() echo(42);.

For some reason, |i=42; echo([for() i]); echoes 42 to the console. I
expected an empty list.|
||
The let() in x = let() 42; acts like a No-op.  x just gets set
to 42.

I'm sure there are more oddities in there.  In any case, the parser is
live, with Abstract Syntax Tree generation, a command-line code
reformatter, and 850+ unit tests. It's probably usable now.

  • Revar
Bizarre syntax is old news. ;) A couple notes on the --format option, from what little I've tried: * It doesn't add parenthesis or take operator precedence into account. Input (3+5)/2 gets formatted as 3+5/2. * It uses /True /and /False /for booleans instead of /true /and /false/. Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe a translation to PythonSCAD could be integrated into OpenSCAD itself, as it has its own AST.) Regards, -Curt On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote: > I'm in the process of testing my Python openscad_parser library > (https://github.com/BelfrySCAD/openscad_parser), and comparing it to > how OpenSCAD itself parses the language.  I've found a few oddities in > what OpenSCAD allows syntactically, that I find amusing. > > You can do a C-style for loop in a list comprehension like `x = [for > (i = 0; i < 10; i=i+1) i];`, but you CANNOT do a C-style `for()` in > modular form.  Also, `intersection_for()` will not take C-style syntax. > > You do NOT need to specify initializer or incrementer in a C-style > list comprehension for loop like `i=0; x = [for (;i<10;) i];`. > However, if you don't have an incrementer, it will ALWAYS error out > with loop counter exceeded. > > Modular `for() echo(42);` will do nothing.  It's a No-Op.  Same for > `intersection_for() echo(42);`. > > For some reason, `|i=42; echo([for() i]);` echoes 42 to the console. I > expected an empty list.| > || > The `let()` in `x = let() 42;` acts like a No-op.  `x` just gets set > to 42. > > I'm sure there are more oddities in there.  In any case, the parser is > live, with Abstract Syntax Tree generation, a command-line code > reformatter, and 850+ unit tests. It's probably usable now. > > - Revar
JB
Jordan Brown
Mon, May 18, 2026 5:13 PM

I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing.

Yep. Some degenerate cases, and in my opinion one missing feature, one bug.

You can do a C-style for loop in a list comprehension like x = [for (i = 0; i < 10; i=i+1) i];, but you CANNOT do a C-style for() in modular form.  Also, intersection_for() will not take C-style syntax.

Missing feature.

You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like i=0; x = [for (;i<10;) i];. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded.

Totally useless degenerate case, probably should require an incrementer.  (If the condition fails then it doesn’t error out.)

Modular for() echo(42); will do nothing.  It's a No-Op.  Same for intersection_for() echo(42);.

For some reason, i=42; echo([for() i]); echoes 42 to the console.  I expected an empty list.

Bug.  For some reason the two module variants specifically check for an empty list and do nothing; the LC variant does not. That one runs the child once, times the number of cases in the first assignment, times the number in the se on assignment, et cetera. I don’t really care which it does, or if an empty list is considered an error, but it seems wrong that they are different.

The let() in x = let() 42; acts like a No-op.  x just gets set to 42.

Degenerate case: the let() does every assignment listed. If that’s none, it’s none. That might actually be useful; it would let you comment out all of the assignments in the list without commenting out the let() itself.

I'm sure there are more oddities in there.

Absolutely.

> I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing. Yep. Some degenerate cases, and in my opinion one missing feature, one bug. > You can do a C-style for loop in a list comprehension like `x = [for (i = 0; i < 10; i=i+1) i];`, but you CANNOT do a C-style `for()` in modular form. Also, `intersection_for()` will not take C-style syntax. Missing feature. > You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like `i=0; x = [for (;i<10;) i];`. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded. Totally useless degenerate case, probably should require an incrementer. (If the condition fails then it doesn’t error out.) > Modular `for() echo(42);` will do nothing. It's a No-Op. Same for `intersection_for() echo(42);`. > > For some reason, `i=42; echo([for() i]);` echoes 42 to the console. I expected an empty list. Bug. For some reason the two module variants specifically check for an empty list and do nothing; the LC variant does not. That one runs the child once, times the number of cases in the first assignment, times the number in the se on assignment, et cetera. I don’t really care which it does, or if an empty list is considered an error, but it seems wrong that they are different. > The `let()` in `x = let() 42;` acts like a No-op. `x` just gets set to 42. Degenerate case: the let() does every assignment listed. If that’s none, it’s none. That might actually be useful; it would let you comment out all of the assignments in the list without commenting out the let() itself. > I'm sure there are more oddities in there. Absolutely.
GS
Guenther Sohler
Mon, May 18, 2026 6:05 PM

No Need for that.

One of the PythonSCAD goals is to stay 100% compatible with SCAD code.
And once  you successfully parsed SCAD code, there is a small helper in the
Design Menu.
When you choose "Display Python Conversion" , it actually uses the AST Tree
to display the Model in Python Format.
It's not perfect, but it can aid as a great step ahead.

On Mon, May 18, 2026 at 6:48 PM Curt McDowell via Discuss <
discuss@lists.openscad.org> wrote:

Bizarre syntax is old news. ;)

A couple notes on the --format option, from what little I've tried:

- It doesn't add parenthesis or take operator precedence into account.
Input (3+5)/2 gets formatted as 3+5/2.
- It uses *True *and *False *for booleans instead of *true *and *false*
.

Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe a
translation to PythonSCAD could be integrated into OpenSCAD itself, as it
has its own AST.)

Regards,
-Curt
On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote:

I'm in the process of testing my Python openscad_parser library (
https://github.com/BelfrySCAD/openscad_parser), and comparing it to how
OpenSCAD itself parses the language.  I've found a few oddities in what
OpenSCAD allows syntactically, that I find amusing.

You can do a C-style for loop in a list comprehension like x = [for (i = 0; i < 10; i=i+1) i];, but you CANNOT do a C-style for() in modular
form.  Also, intersection_for() will not take C-style syntax.

You do NOT need to specify initializer or incrementer in a C-style list
comprehension for loop like i=0; x = [for (;i<10;) i];. However, if you
don't have an incrementer, it will ALWAYS error out with loop counter
exceeded.

Modular for() echo(42); will do nothing.  It's a No-Op.  Same for
intersection_for() echo(42);.

For some reason, i=42; echo([for() i]); echoes 42 to the console. I
expected an empty list.
The let() in x = let() 42; acts like a No-op.  x just gets set to 42.

I'm sure there are more oddities in there.  In any case, the parser is
live, with Abstract Syntax Tree generation, a command-line code
reformatter, and 850+ unit tests. It's probably usable now.

  • Revar

OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

No Need for that. One of the PythonSCAD goals is to stay 100% compatible with SCAD code. And once you successfully parsed SCAD code, there is a small helper in the Design Menu. When you choose "Display Python Conversion" , it actually uses the AST Tree to display the Model in Python Format. It's not perfect, but it can aid as a great step ahead. On Mon, May 18, 2026 at 6:48 PM Curt McDowell via Discuss < discuss@lists.openscad.org> wrote: > Bizarre syntax is old news. ;) > > A couple notes on the --format option, from what little I've tried: > > - It doesn't add parenthesis or take operator precedence into account. > Input (3+5)/2 gets formatted as 3+5/2. > - It uses *True *and *False *for booleans instead of *true *and *false* > . > > Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe a > translation to PythonSCAD could be integrated into OpenSCAD itself, as it > has its own AST.) > > Regards, > -Curt > On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote: > > I'm in the process of testing my Python openscad_parser library ( > https://github.com/BelfrySCAD/openscad_parser), and comparing it to how > OpenSCAD itself parses the language. I've found a few oddities in what > OpenSCAD allows syntactically, that I find amusing. > > You can do a C-style for loop in a list comprehension like `x = [for (i = > 0; i < 10; i=i+1) i];`, but you CANNOT do a C-style `for()` in modular > form. Also, `intersection_for()` will not take C-style syntax. > > You do NOT need to specify initializer or incrementer in a C-style list > comprehension for loop like `i=0; x = [for (;i<10;) i];`. However, if you > don't have an incrementer, it will ALWAYS error out with loop counter > exceeded. > > Modular `for() echo(42);` will do nothing. It's a No-Op. Same for > `intersection_for() echo(42);`. > > For some reason, `i=42; echo([for() i]);` echoes 42 to the console. I > expected an empty list. > The `let()` in `x = let() 42;` acts like a No-op. `x` just gets set to 42. > > I'm sure there are more oddities in there. In any case, the parser is > live, with Abstract Syntax Tree generation, a command-line code > reformatter, and 850+ unit tests. It's probably usable now. > > - Revar > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
RD
Revar Desmera
Mon, May 18, 2026 7:13 PM

The command-line openscad-parser command is a recent low effort low-hanging fruit feature. I am not surprised that the --format pretty-printer has bugs.  Luckily, the YAML and JSON outputs should correctly have precedence handled, as they present the full AST structure.  I'll poke at the code to fix the --format precedence and booleans output.  Thanks for the catch.

  • Revar

On May 18, 2026, at 9:47 AM, Curt McDowell via Discuss discuss@lists.openscad.org wrote:

Bizarre syntax is old news. ;)

A couple notes on the --format option, from what little I've tried:

It doesn't add parenthesis or take operator precedence into account. Input (3+5)/2 gets formatted as 3+5/2.
It uses True and False for booleans instead of true and false.
Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe a translation to PythonSCAD could be integrated into OpenSCAD itself, as it has its own AST.)

Regards,
-Curt

On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote:

I'm in the process of testing my Python openscad_parser library (https://github.com/BelfrySCAD/openscad_parser), and comparing it to how OpenSCAD itself parses the language.  I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing.

You can do a C-style for loop in a list comprehension like x = [for (i = 0; i < 10; i=i+1) i];, but you CANNOT do a C-style for() in modular form.  Also, intersection_for() will not take C-style syntax.

You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like i=0; x = [for (;i<10;) i];. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded.

Modular for() echo(42); will do nothing.  It's a No-Op.  Same for intersection_for() echo(42);.

For some reason, i=42; echo([for() i]); echoes 42 to the console.  I expected an empty list.

The let() in x = let() 42; acts like a No-op.  x just gets set to 42.

I'm sure there are more oddities in there.  In any case, the parser is live, with Abstract Syntax Tree generation, a command-line code reformatter, and 850+ unit tests. It's probably usable now.

  • Revar

OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

The command-line `openscad-parser` command is a recent low effort low-hanging fruit feature. I am not surprised that the --format pretty-printer has bugs. Luckily, the YAML and JSON outputs should correctly have precedence handled, as they present the full AST structure. I'll poke at the code to fix the --format precedence and booleans output. Thanks for the catch. - Revar > On May 18, 2026, at 9:47 AM, Curt McDowell via Discuss <discuss@lists.openscad.org> wrote: > > Bizarre syntax is old news. ;) > > A couple notes on the --format option, from what little I've tried: > > It doesn't add parenthesis or take operator precedence into account. Input (3+5)/2 gets formatted as 3+5/2. > It uses True and False for booleans instead of true and false. > Maybe this could be used to translate OpenSCAD to PythonSCAD? (Or, maybe a translation to PythonSCAD could be integrated into OpenSCAD itself, as it has its own AST.) > > Regards, > -Curt > > On 5/17/2026 7:03 PM, Revar Desmera via Discuss wrote: >> I'm in the process of testing my Python openscad_parser library (https://github.com/BelfrySCAD/openscad_parser), and comparing it to how OpenSCAD itself parses the language. I've found a few oddities in what OpenSCAD allows syntactically, that I find amusing. >> >> You can do a C-style for loop in a list comprehension like `x = [for (i = 0; i < 10; i=i+1) i];`, but you CANNOT do a C-style `for()` in modular form. Also, `intersection_for()` will not take C-style syntax. >> >> You do NOT need to specify initializer or incrementer in a C-style list comprehension for loop like `i=0; x = [for (;i<10;) i];`. However, if you don't have an incrementer, it will ALWAYS error out with loop counter exceeded. >> >> Modular `for() echo(42);` will do nothing. It's a No-Op. Same for `intersection_for() echo(42);`. >> >> For some reason, `i=42; echo([for() i]);` echoes 42 to the console. I expected an empty list. >> >> The `let()` in `x = let() 42;` acts like a No-op. `x` just gets set to 42. >> >> I'm sure there are more oddities in there. In any case, the parser is live, with Abstract Syntax Tree generation, a command-line code reformatter, and 850+ unit tests. It's probably usable now. >> >> - Revar > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org