Skip to main content

openscad_lalr_parser

A fast LALR(1) parser for the OpenSCAD language with AST generation, powered by Lark.

Tests PyPI version License: MIT

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.
librarySearchDirs(currfile) The directories searched, in order: the including file's, each OPENSCADPATH entry, then the user's OpenSCAD libraries folder (as OpenSCAD orders them).
strict_commas(enabled=True) Context manager: parse as OpenSCAD 2021.01 did, rejecting a trailing comma in call arguments and let/for/intersection_for assignments (cube(1,), let(x=1,)), while list literals, comprehensions and parameter lists keep theirs. Nests, restores on exit, and is part of every cache key. CLI: --strict-commas.
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 (its implicit_step is true for [a:b], whose step node is a synthesized 1)

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, RenderExpression

RenderExpression is render() in expression position, obj = render() { cube(1); };, a language extension of openscad_cpp_evaluator/BelfrySCAD: its children's geometry as a value. The braces are required. To make it parseable, render is a reserved word wherever an expression can start, so it can't be a variable or an argument name; render() cube(1); as a statement is still a ModularCall.

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.

Release files for openscad-lalr-parser 1.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openscad-lalr-parser 1.4.0
File Size Uploaded
openscad_lalr_parser-1.4.0.tar.gz 40.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openscad-lalr-parser 1.4.0
File Interpreter ABI Platform
openscad_lalr_parser-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 86.0 kB

Release files / openscad_lalr_parser-1.4.0.tar.gz

Download URL openscad_lalr_parser-1.4.0.tar.gz
Size 40.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2e203f8a2ead69d5a5dd43aea604805fa8cc940c2244a02957c2ffe6e99e1fd9
BLAKE2b-256 checksum
How to use checksums
043dcc1df88dc9292198c261a13cf5d0a0485db123a41708750dcc381ee65c81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / openscad_lalr_parser-1.4.0-py3-none-any.whl

Download URL openscad_lalr_parser-1.4.0-py3-none-any.whl
Size 45.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c4290b8e371a8016de5e5bb3fc56d2695973461552cd1149179190687c8862dd
BLAKE2b-256 checksum
How to use checksums
60c659ddc6dc0383a51489087ee29110c0b7325f38de007c15d61bbe2c80414a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.4.0 This release

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page