v3.5: close OpenSCAD-completeness gaps missed by the v3 audit#72
Merged
Conversation
The v3 roadmap checkboxes tracked a specific 33-issue correctness audit, not a full diff against OpenSCAD's builtin/special-variable surface. An independent read-through against the OpenSCAD language reference found several real gaps that slipped through: - PI constant was entirely absent - is_undef/is_bool/is_num/is_string/is_list/is_function type predicates - search() (string/list/table search) - version()/version_num() (fixed compatibility level for version-gated library code) - $preview/$t special variables - parent_module(idx)/$parent_modules (new module-call-name stack, driven by CsgEvaluator, backing Interpreter's lookups) - linear_extrude(slices=...) was parsed but silently dropped - children([vector])/children([range]) — only a bare number index worked - echo(name=value) now formats as "name = value" like real OpenSCAD Deferred and documented in docs/roadmap.md rather than rushed: first-class function literals/closures, $vpr/$vpt/$vpd viewport vars, and the lexer-keyword-vs-identifier deviation for primitive names — each needs its own pass rather than riding along with these point fixes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MnU6afM9zR44X518jofBSY
particlesector
commented
Jul 14, 2026
particlesector
left a comment
Owner
Author
There was a problem hiding this comment.
Reviewed the diff logic in detail (module-name stack scoping for parent_module/$parent_modules, children([...]) vector/range handling, search()'s flat-vs-nested shape, and the slices extrusion fix) against the new tests and existing APIs — all correct. CI is green on both platforms. One sparse nit left inline; otherwise looks good to merge.
Generated by Claude Code
Real OpenSCAD's index_col_num accepts -1 to mean "compare match_value against each entire row" instead of a specific column — the mode that lets a vector match_value be matched as one unit against table rows, e.g. search([3,"y"], table, 0, -1). Previously any negative indexCol made every row resolve to undef, so -1 could never match. Also had to guard the per-element vector-needle decomposition (search() normally treats a vector match_value as one needle per element) so it doesn't fire when indexCol == -1 — in that mode the whole match_value vector is the needle being compared row-by-row, not something to split apart. Addresses PR review comment on #72. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MnU6afM9zR44X518jofBSY
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The v3 roadmap claimed "OpenSCAD Language Completeness," but that checklist tracked a specific 33-issue correctness audit — not a full diff against OpenSCAD's actual builtin/special-variable surface. An independent read-through against the OpenSCAD language reference turned up real gaps that had never been tracked as roadmap items or GitHub issues. This PR closes the tractable ones and documents the rest as explicit follow-up work in
docs/roadmap.md(new "v3.5" section).Fixed:
PIconstant (was entirely absent — scripts had to hard-code3.14159)is_undef()/is_bool()/is_num()/is_string()/is_list()/is_function()type predicatessearch()— string/list/table search, matching OpenSCAD's flat-vs-nested result shape depending onmatch_value's arityversion()/version_num()— reports a fixed OpenSCAD-compatibility level (2019.05) so version-gated library code picks its modern branch$preview/$tspecial variables (fixed defaults — no animation/dual-render-pass distinction exists yet)parent_module(idx)/$parent_modules— new module-call-name stack (Interpreter::pushModuleName/popModuleName, driven byCsgEvaluator::evalModuleCall)linear_extrude(slices=...)— was parsed into the generic params map but silently never read; twist division count now honors an explicitslicesover the$fn-derived defaultchildren([vector])/children([range])— previously only a bare number index worked; vector and range forms silently returned nothingecho(name=value)now formats asname = value, matching real OpenSCAD (previously printed the bare value)Explicitly deferred (documented in roadmap with rationale, not silently dropped):
f = function(x) x*2;, OpenSCAD 2019.05+) — the language has namedfunction foo(x) = expr;defs but no closure value type; adding one touches theValuevariant, parser grammar, and call dispatch broadly enough to deserve its own pass.$vpr/$vpt/$vpdviewport special variables — needs the render layer's camera state plumbed into the interpreter, a cross-subsystem wire that doesn't exist today.cube/sphere/translate/etc. being reserved lexer keywords rather than ordinary identifiers (a script can't shadow one as a variable, unlike real OpenSCAD) — a grammar-level deviation, not a point fix.Test plan
tests/test_interpreter.cpp(PI,$preview/$t, all six type predicates,search()across single-char/multi-char/table forms,version()/version_num())tests/test_csg_evaluator.cpp(children([vector]),children([range]), out-of-range index skipping,echo(name=value)formatting,parent_module/$parent_modulesat various call depths including "no parent",linear_extrude(slices=...)threading into the IR)Note:
MeshEvaluator.cpp(whereslicesis actually consumed to build geometry) isn't linked into thechiselcad_testsbinary today (it pulls inmanifold, which the test target doesn't), so theslicesfix itself is covered only by production-code reading, not a runtime assertion — the test that exists verifies the param survives parsing into the CSG IR, which is the testable half.Generated by Claude Code