A fast LALR(1) parser for the OpenSCAD language with AST generation, powered by Lark.
Project description
openscad_lalr_parser
A fast LALR(1) parser for the OpenSCAD language with AST generation, powered by Lark.
Overview
openscad_lalr_parser parses OpenSCAD source code using a Lark-based LALR(1) parser and produces
an abstract syntax tree (AST). The AST node classes are identical to those in the
openscad_parser library, making it a drop-in
replacement with significantly better performance.
Why LALR?
- Speed: LALR(1) parsing is O(n) in the input size — no PEG backtracking overhead.
- Predictability: Parse time is always proportional to input size.
- Compatibility: Produces the same AST node types as
openscad_parser.
Installation
pip install openscad-lalr-parser
For YAML output support:
pip install openscad-lalr-parser[yaml]
From Source
git clone https://github.com/BelfrySCAD/openscad_lalr_parser.git
cd openscad_lalr_parser
pip install -e ".[dev]"
Quick Start
Parse a String
from openscad_lalr_parser import getASTfromString
ast = getASTfromString("cube([1, 2, 3]);")
for node in ast:
print(node)
Parse a File
from openscad_lalr_parser import getASTfromFile
ast = getASTfromFile("model.scad")
for node in ast:
print(node)
Files are cached by modification time — repeated calls to getASTfromFile() with the same
unchanged file return instantly. A disk cache is also maintained for persistence across
interpreter sessions.
Include Comments
ast = getASTfromString("""
// A comment
x = 42; /* inline */
""", include_comments=True)
Comments are returned as CommentLine, CommentSpan, and BlankLine nodes at the top level.
Inline comments adjacent to expressions are wrapped in CommentedExpr nodes with
leading_comments and trailing_comments fields.
Scope Analysis
from openscad_lalr_parser import getASTfromString, build_scopes
ast = getASTfromString('''
x = 10;
function double(n) = n * 2;
module box(size) { cube(size); }
''')
root_scope = build_scopes(ast)
print(root_scope.lookup_variable("x"))
print(root_scope.lookup_function("double"))
print(root_scope.lookup_module("box"))
Serialization
from openscad_lalr_parser import getASTfromString, ast_to_json, ast_from_json
ast = getASTfromString("cube(10);")
# Serialize to JSON
json_str = ast_to_json(ast, indent=2)
# Deserialize back to AST nodes
ast2 = ast_from_json(json_str)
YAML serialization is available when PyYAML is installed:
from openscad_lalr_parser import ast_to_yaml, ast_from_yaml
yaml_str = ast_to_yaml(ast)
ast2 = ast_from_yaml(yaml_str)
Pretty-Printing
from openscad_lalr_parser import getASTfromString, to_openscad
ast = getASTfromString("module box(w,h){cube([w,h,1]);}")
print(to_openscad(ast, indent_width=4))
Output:
module box(w, h) {
cube([w, h, 1]);
}
CLI
The openscad-lalr command-line tool parses OpenSCAD files and outputs JSON, YAML, or
reformatted source.
# Parse to JSON (default)
openscad-lalr model.scad
# Pretty-print / reformat
openscad-lalr --format model.scad
# YAML output
openscad-lalr --yaml model.scad
# Read from stdin
echo 'cube(10);' | openscad-lalr -
# Include comments in output
openscad-lalr --with-comments model.scad
# Custom indentation
openscad-lalr --format --indent 2 model.scad
# Skip include resolution
openscad-lalr --no-includes model.scad
API Reference
Parsing Functions
| Function | Description |
|---|---|
getASTfromString(code, include_comments=False, origin="<string>") |
Parse OpenSCAD source code and return its AST. |
getASTfromFile(file, include_comments=False, process_includes=True) |
Parse a file with mtime-based caching and optional include resolution. |
getASTfromLibraryFile(currfile, libfile, ...) |
Find and parse a library file using OpenSCAD's search path rules. |
parse_ast(code, origin="<string>") |
Low-level parse returning AST nodes (no comment processing). |
findLibraryFile(currfile, libfile) |
Find a library file path without parsing it. |
clear_ast_cache() |
Clear the in-memory and on-disk AST caches. |
Serialization Functions
| Function | Description |
|---|---|
ast_to_json(ast, indent=None) |
Serialize AST nodes to a JSON string. |
ast_from_json(json_str) |
Deserialize AST nodes from a JSON string. |
ast_to_dict(ast) |
Convert AST nodes to plain dicts. |
ast_from_dict(data) |
Reconstruct AST nodes from dicts. |
ast_to_yaml(ast) |
Serialize AST nodes to YAML (requires PyYAML). |
ast_from_yaml(yaml_str) |
Deserialize AST nodes from YAML. |
to_openscad(ast, indent_width=4) |
Pretty-print AST back to OpenSCAD source. |
Scope Analysis
| Function / Class | Description |
|---|---|
build_scopes(ast) |
Build scope tree for top-level AST nodes. Returns root Scope. |
Scope |
Lexical scope with lookup_variable(), lookup_function(), lookup_module(). |
AST Node Classes
All AST nodes inherit from ASTNode. The main categories are:
Literals: Identifier, StringLiteral, NumberLiteral, BooleanLiteral, UndefinedLiteral, RangeLiteral
Operators: AdditionOp, SubtractionOp, MultiplicationOp, DivisionOp, ModuloOp, ExponentOp, UnaryMinusOp, LogicalAndOp, LogicalOrOp, LogicalNotOp, BitwiseAndOp, BitwiseOrOp, BitwiseNotOp, BitwiseShiftLeftOp, BitwiseShiftRightOp, EqualityOp, InequalityOp, GreaterThanOp, GreaterThanOrEqualOp, LessThanOp, LessThanOrEqualOp, TernaryOp
Expressions: PrimaryCall, PrimaryIndex, PrimaryMember, LetOp, EchoOp, AssertOp, FunctionLiteral, ListComprehension
List Comprehensions: ListCompFor, ListCompCFor, ListCompIf, ListCompIfElse, ListCompLet, ListCompEach
Declarations: Assignment, FunctionDeclaration, ModuleDeclaration, ParameterDeclaration
Module Instantiations: ModularCall, ModularFor, ModularIntersectionFor, ModularLet, ModularEcho, ModularAssert, ModularIf, ModularIfElse
Modifiers: ModularModifierShowOnly, ModularModifierHighlight, ModularModifierBackground, ModularModifierDisable
Imports: UseStatement, IncludeStatement
Arguments: PositionalArgument, NamedArgument
Comments: CommentLine, CommentSpan, CommentedExpr, BlankLine
Comparison with openscad_parser
| Feature | openscad_parser | openscad_lalr_parser |
|---|---|---|
| Parser type | PEG (Arpeggio) | LALR(1) (Lark) |
| AST nodes | ✓ | ✓ (identical) |
| Scope analysis | ✓ | ✓ |
| Comment preservation | ✓ | ✓ |
| Inline comment attachment | ✓ | ✓ |
| Serialization (JSON/YAML) | ✓ | ✓ |
| Pretty-printing | ✓ | ✓ |
| Source maps | ✓ | ✓ |
| CLI tool | ✓ (openscad-parser) |
✓ (openscad-lalr) |
| Disk caching | ✓ | ✓ |
| Performance | Baseline | Faster (LALR, no backtracking) |
Development
Running Tests
pytest tests/ -v
Running Tests with Coverage
pytest tests/ --cov=src/openscad_lalr_parser --cov-report=term-missing
License
MIT License - Copyright (c) 2025 Belfry OpenSCAD Libraries
See LICENSE for full text.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openscad_lalr_parser-1.0.2.tar.gz.
File metadata
- Download URL: openscad_lalr_parser-1.0.2.tar.gz
- Upload date:
- Size: 30.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
011bb56f96cbac22b0d750c1f4c004ddc2548909bda39bd237e0d8a3a11f7016
|
|
| MD5 |
265dc9b6cd7f1db36de0408f406d76aa
|
|
| BLAKE2b-256 |
55158acfaa01ff7d06c37d56a87b4333fdbb5220dd0faf4949562ff992fed4d8
|
Provenance
The following attestation bundles were made for openscad_lalr_parser-1.0.2.tar.gz:
Publisher:
publish.yml on BelfrySCAD/openscad_lalr_parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openscad_lalr_parser-1.0.2.tar.gz -
Subject digest:
011bb56f96cbac22b0d750c1f4c004ddc2548909bda39bd237e0d8a3a11f7016 - Sigstore transparency entry: 1916843592
- Sigstore integration time:
-
Permalink:
BelfrySCAD/openscad_lalr_parser@f62f00c1617cb1a9c3e086726541b67af15900f8 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/BelfrySCAD
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f62f00c1617cb1a9c3e086726541b67af15900f8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file openscad_lalr_parser-1.0.2-py3-none-any.whl.
File metadata
- Download URL: openscad_lalr_parser-1.0.2-py3-none-any.whl
- Upload date:
- Size: 35.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41f158f04f9c8b46bb448cba757dbb475f64a835291c38f021ddbcbe3d76afeb
|
|
| MD5 |
cca7ec2595148c8872a8a706b7677e18
|
|
| BLAKE2b-256 |
d14a69f6256f4d7f6b4547af6dce532723b2db68afe17ae9b1064d6cb4c44ca9
|
Provenance
The following attestation bundles were made for openscad_lalr_parser-1.0.2-py3-none-any.whl:
Publisher:
publish.yml on BelfrySCAD/openscad_lalr_parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openscad_lalr_parser-1.0.2-py3-none-any.whl -
Subject digest:
41f158f04f9c8b46bb448cba757dbb475f64a835291c38f021ddbcbe3d76afeb - Sigstore transparency entry: 1916843757
- Sigstore integration time:
-
Permalink:
BelfrySCAD/openscad_lalr_parser@f62f00c1617cb1a9c3e086726541b67af15900f8 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/BelfrySCAD
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f62f00c1617cb1a9c3e086726541b67af15900f8 -
Trigger Event:
release
-
Statement type: