بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ
In the name of Allah, the Compassionate, the Merciful
OpenSCAD parametric 3D Constructive Solid Geometry (.scad) compiler, WebAssembly GLR parser, fluent method-chaining evaluator, tag_port() boundary port tagger, 9-rule semantic linter (SCAD_*), OpenCascade B-Rep & ISO 10303-21 STEP exporter (compileScadToStep), and ScadPatcher 3D gizmo AST writeback engine for ModelScript.
- WASM GLR Incremental Parser (
getScadParser): Generated by@modelscript/dsl(buildParser) into native WebAssembly (parser.wasm), supporting standard OpenSCAD prefix trees (translate(...) rotate(...) difference() { ... }), modules, functions, control flow (if,for), and ModelScript's fluent CAD extensions. - Fluent Method-Chaining Syntax: Extends standard OpenSCAD primitives (
cube,cylinder,sphere,circle,square,polyhedron,linear_extrude) with fluent postfix transformation and edge-feature chains:- Spatial transforms:
.translate([x, y, z]),.rotate([rx, ry, rz]),.scale([sx, sy, sz]),.mirror([nx, ny, nz]),.color("...") - B-Rep edge features:
.fillet(r)and.chamfer(d)
- Spatial transforms:
tag_port()Physical Boundary Tagging: First-classtag_port("portName", "frame" | "fluid" | "thermal")operator attaching named topological coordinate frames and surface normals to CSG faces for automatic multibody joint alignment, FEA load application, and Modelica/SysML v2 port synthesis.- 9
SCAD_*Semantic Lint Rules (lintScad,lintScadCst): Single-pass lexical scope analyzer with OpenSCAD block declaration hoisting, constant-folded arithmetic evaluation, division-by-zero detection, call arity validation, and strictly positive CSG primitive dimension verification—all reporting exact AST token byte and line/column ranges. - OpenCascade B-Rep & STEP Compiler (
compileScadToStep,compileScadToSolid,extractScadCadComponents): Evaluates CSG trees (ScadEvaluator) into@modelscript/cadSolidrepresentations, tessellates watertight 3D manifold triangle meshes (ManifoldWorker), and compiles exact ISO 10303-21 STEP B-Rep solids (compileToStep). ScadPatcher3D Gizmo AST Writeback (ScadPatcher,scadWriteback): PreservesSolidSourceMetadatalinking 3D viewport meshes back to their originating CST nodes so interactive 3DTransformControlsgizmo drags patch exact vector components (patchTransformArgument,patchVectorComponent,patchVariable,patchNode) in.scadsource code without reformatting surrounding code.- 13 Bidirectional Polyglot TGG Rules: Synchronizes OpenSCAD modules,
tag_port()frames, projected frontal areas, variables, CSG primitives, and boolean composites with SysML v2, ISO 10303 STEP products, and ModelicaMultiBodyvisualizers/frames.
| Path | Description |
|---|---|
src/index.ts |
High-level API (getScadParser, lintScad, compileScadToSolid, compileScadToStep, extractScadCadComponents) |
src/language.ts |
scadLanguage grammar definition, LSP modelscript/getCadComponents handler, actions (preview_csg, export_step), and 13 TGG rules |
src/evaluator.ts |
ScadEvaluator interpreting OpenSCAD ASTs, loops, modules, fluent .translate()/.fillet() chains, and tag_port() tags |
src/linter.ts |
lintScadCst semantic linter implementing all 9 SCAD_* diagnostic rules with constant folding |
src/patcher.ts |
ScadPatcher surgical CST byte-slice mutator (patchNode, patchVariable, patchTransformArgument, patchVectorComponent) |
src/writeback.ts |
scadWriteback integration hook for LSP & 3D CAD viewport synchronization |
build.js |
Compiles src/language.ts into dist/parser.wasm and src-gen/bindings.js |
| Code | Severity | Description |
|---|---|---|
SCAD_INVALID_DIMENSION |
error |
Non-positive (cube, cylinder, sphere, circle, square, linear_extrude, .fillet(), or .chamfer()
|
SCAD_UNDEFINED_VARIABLE |
error |
Referenced variable is not declared in the lexical scope hierarchy or OpenSCAD built-in specials ($fn, PI) |
SCAD_UNDEFINED_FUNCTION |
error |
Called function is neither declared in scope nor an OpenSCAD built-in mathematical/list function |
SCAD_UNDEFINED_MODULE |
error |
Instantiated module is neither declared in scope nor a built-in CSG primitive/operator |
SCAD_UNKNOWN_METHOD |
error |
Unknown fluent postfix method (supported: translate, rotate, scale, mirror, color, fillet, chamfer) |
SCAD_DIVISION_BY_ZERO |
error |
Constant-folded divisor in / or % binary expression evaluates to 0
|
SCAD_ARGUMENT_COUNT |
error / warning
|
Excess positional arguments (error) or missing required parameter without default value (warning) |
SCAD_UNKNOWN_PARAMETER |
error |
Named argument in a user module/function call does not match any declared parameter |
SCAD_DUPLICATE_DECLARATION |
error / warning
|
Duplicate module/function/parameter declaration (error) or shadowed variable assignment (warning) |
@modelscript/scad defines 13 bidirectional TGG rules in scadLanguage.polyglot.rules:
| Rule Name | Source (scad) |
Target (sysml2 / step / modelica) |
Priority |
|---|---|---|---|
ScadProjectedAreaToModelicaParam |
TagPortOp(args: portName) |
modelica: ComponentClause(name: "A", defaultValue: area) |
15 |
ScadProjectedAreaToSysmlAttribute |
TagPortOp(args: portName) |
sysml2: AttributeUsage(declaredName: "totalFrontalArea", defaultValue: area) |
15 |
ScadBooleanOpToStepComposite |
BooleanOp(op: opName, body: children) |
step: ProductDefinition(name: opName, description: "CSGComposite") |
15 |
ScadCylinderToStepProduct |
CylinderPrimitive(args: dims) |
step: ProductDefinition(name: dims, description: "CylinderSolid") |
10 |
ScadCylinderToMultiBodyShape |
CylinderPrimitive(args: dims) |
modelica: ComponentClause(typeSpecifier: "Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape") |
10 |
ScadSphereToStepProduct |
SpherePrimitive(args: dims) |
step: ProductDefinition(name: dims, description: "SphereSolid") |
5 |
ScadCubeToMultiBodyShape |
CubePrimitive(args: dims) |
modelica: ComponentClause(typeSpecifier: "Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape") |
5 |
ScadSphereToMultiBodyShape |
SpherePrimitive(args: dims) |
modelica: ComponentClause(typeSpecifier: "Modelica.Mechanics.MultiBody.Visualizers.Advanced.Shape") |
5 |
ScadModuleToSysmlPart |
ModuleDeclaration(name: modName) |
sysml2: PartDefinition(declaredName: modName) |
0 |
ScadTagPortToSysmlPort |
TagPortOp(args: portName) |
sysml2: PortUsage(declaredName: portName) |
0 |
ScadVariableToSysmlAttribute |
VariableDeclaration(name: varName) |
sysml2: AttributeUsage(declaredName: varName, defaultValue: val) |
0 |
ScadSolidToStepProduct |
CubePrimitive(args: dims) |
step: ProductDefinition(name: dims) |
0 |
ScadTagPortToModelicaFrame |
TagPortOp(args: portName) |
modelica: ComponentClause(name: portName, typeSpecifier: "Modelica.Mechanics.MultiBody.Interfaces.Frame_a") |
0 |
import { compileScadToStep, extractScadCadComponents, getScadParser, lintScad, ScadPatcher } from "@modelscript/scad";
const source = `
arm_length = 180;
cube([arm_length, 24, 6], center = true)
.translate([90, 0, 0])
.fillet(1.5);
tag_port("motor_mount", "frame")
cylinder(h = 12, r = 14).translate([180, 0, 6]);
`;
// 1. Run semantic linter (9 SCAD_* rules)
const diagnostics = await lintScad(source);
// 2. Compile directly to ISO 10303-21 STEP B-Rep solid
const stepFileContent = await compileScadToStep(source);
// 3. Extract interactive 3D mesh components with sourceMetadata
const components = await extractScadCadComponents(source);
// 4. Patch AST transform vector from 3D gizmo drag
const parser = await getScadParser();
const tree = parser.parse(source);
const patched = ScadPatcher.patchTransformArgument(source, tree.rootNode, "translate", 0, [95.0, 0.0, 2.5]);