yapcad.dsl package

Subpackages

Submodules

yapcad.dsl.ast module

Abstract Syntax Tree (AST) node definitions for the yapCAD DSL v2 (Pythonic Syntax).

The AST represents the structure of a parsed DSL program, which can then be type-checked and compiled/interpreted.

Changes from v1: - FunctionDef replaces Command (uses ‘def’ keyword) - VarDecl replaces LetStatement (no ‘let’ keyword, optional type annotation) - AssertStatement replaces RequireStatement - NativeFunction for @native decorated functions - Added PassStatement, WhileStatement, ElifBranch

class yapcad.dsl.ast.AssertStatement(span: SourceSpan, condition: Expression, message: Expression | None = None)[source]

Bases: Statement

An assert statement (e.g., assert x > 0, “x must be positive”).

condition: Expression
message: Expression | None = None
class yapcad.dsl.ast.AssignmentStatement(span: SourceSpan, target: Expression, value: Expression)[source]

Bases: Statement

An assignment to an existing variable (e.g., x = 5).

target: Expression
value: Expression
class yapcad.dsl.ast.AstNode(span: SourceSpan)[source]

Bases: ABC

Base class for all AST nodes.

accept(visitor: AstVisitor) Any[source]

Accept a visitor for traversal.

span: SourceSpan
class yapcad.dsl.ast.AstVisitor[source]

Bases: ABC

Base class for AST visitors.

generic_visit(node: AstNode) Any[source]

Default visit method.

class yapcad.dsl.ast.BinaryOp(span: SourceSpan, left: Expression, operator: TokenType, right: Expression)[source]

Bases: Expression

A binary operation (e.g., a + b, x and y).

left: Expression
operator: TokenType
right: Expression
class yapcad.dsl.ast.Block(span: SourceSpan, statements: List[Statement], final_expression: Expression | None = None)[source]

Bases: AstNode

A block of statements (indented block).

In Pythonic syntax, blocks are delimited by indentation (INDENT/DEDENT) rather than braces.

final_expression: Expression | None = None
statements: List[Statement]
yapcad.dsl.ast.Command

alias of FunctionDef

class yapcad.dsl.ast.ComprehensionClause(span: SourceSpan, variable: str, iterable: Expression, conditions: List[Expression] = <factory>)[source]

Bases: AstNode

A single for clause in a list comprehension.

Represents: for variable in iterable [if condition1] [if condition2] …

Multiple if conditions are allowed per clause, all must be true.

conditions: List[Expression]
iterable: Expression
variable: str
class yapcad.dsl.ast.ConditionalExpr(span: SourceSpan, condition: Expression, true_branch: Expression, false_branch: Expression)[source]

Bases: Expression

A ternary conditional expression (e.g., x if condition else y).

Unlike IfExpr (which uses blocks), this is for inline expressions:

value: float = a if condition else b

Both branches must be expressions and the else is required.

condition: Expression
false_branch: Expression
true_branch: Expression
class yapcad.dsl.ast.Decorator(span: SourceSpan, name: str, arguments: List[Expression] = <factory>)[source]

Bases: AstNode

A decorator (e.g., @native).

arguments: List[Expression]
name: str
class yapcad.dsl.ast.DictLiteral(span: SourceSpan, entries: dict[str, Expression])[source]

Bases: Expression

A dictionary literal (e.g., {“key”: value, …}).

entries: dict[str, Expression]
class yapcad.dsl.ast.ElifBranch(span: SourceSpan, condition: Expression, body: Block)[source]

Bases: AstNode

An elif branch in an if expression/statement.

body: Block
condition: Expression
class yapcad.dsl.ast.EmitStatement(span: SourceSpan, value: Expression, metadata: dict[str, ~yapcad.dsl.ast.Expression]=<factory>)[source]

Bases: Statement

An emit statement with optional metadata kwargs.

Syntax:

emit gear # Simple emit emit gear, name=”spur”, material=”steel” # With metadata

metadata: dict[str, Expression]
value: Expression
class yapcad.dsl.ast.ExportStatement(span: SourceSpan, name: str)[source]

Bases: AstNode

An export statement (e.g., export function_name).

name: str
class yapcad.dsl.ast.ExportUseStatement(span: SourceSpan, module_path: List[str])[source]

Bases: AstNode

An export use statement (e.g., export use other.module).

module_path: List[str]
class yapcad.dsl.ast.Expression(span: SourceSpan)[source]

Bases: AstNode

Base class for all expressions.

class yapcad.dsl.ast.ExpressionStatement(span: SourceSpan, expression: Expression)[source]

Bases: Statement

An expression used as a statement.

expression: Expression
class yapcad.dsl.ast.ForStatement(span: SourceSpan, variable: str, iterable: Expression, body: Block)[source]

Bases: Statement

A for loop (e.g., for i in range(n):).

body: Block
iterable: Expression
variable: str
class yapcad.dsl.ast.FunctionCall(span: ~yapcad.dsl.tokens.SourceSpan, callee: ~yapcad.dsl.ast.Expression, arguments: ~typing.List[~yapcad.dsl.ast.Expression], named_arguments: dict[str, ~yapcad.dsl.ast.Expression] = <factory>)[source]

Bases: Expression

A function or constructor call (e.g., point(1, 2, 3)).

arguments: List[Expression]
callee: Expression
named_arguments: dict[str, Expression]
class yapcad.dsl.ast.FunctionDef(span: ~yapcad.dsl.tokens.SourceSpan, name: str, parameters: ~typing.List[~yapcad.dsl.ast.Parameter], return_type: ~yapcad.dsl.ast.TypeNode | None, body: ~yapcad.dsl.ast.Block, decorators: ~typing.List[~yapcad.dsl.ast.Decorator] = <factory>, meta_hint: dict | None = None)[source]

Bases: AstNode

A function definition (uses ‘def’ keyword).

Syntax:
def function_name(param1: type1, param2: type2) -> return_type:

Replaces the old ‘command’ syntax.

body: Block
decorators: List[Decorator]
meta_hint: dict | None = None
name: str
parameters: List[Parameter]
return_type: TypeNode | None
class yapcad.dsl.ast.GenericType(span: SourceSpan, name: str, type_args: List[TypeNode])[source]

Bases: TypeNode

A generic type like ‘list[point3d]’ or ‘dict[str, int]’.

name: str
type_args: List[TypeNode]
class yapcad.dsl.ast.Identifier(span: SourceSpan, name: str)[source]

Bases: Expression

A variable or function name reference.

name: str
class yapcad.dsl.ast.IdentifierPattern(span: SourceSpan, name: str)[source]

Bases: Pattern

A binding pattern (e.g., ‘match x { case n: … }’).

name: str
class yapcad.dsl.ast.IfExpr(span: SourceSpan, condition: Expression, then_branch: Block, elif_branches: List[ElifBranch] = <factory>, else_branch: Block | None = None)[source]

Bases: Expression

An if-else expression (returns a value).

condition: Expression
elif_branches: List[ElifBranch]
else_branch: Block | None = None
then_branch: Block
class yapcad.dsl.ast.IfStatement(span: SourceSpan, condition: Expression, then_branch: Block, elif_branches: List[ElifBranch] = <factory>, else_branch: Block | None = None)[source]

Bases: Statement

An if statement (doesn’t return a value).

Syntax:
if condition:

elif condition:

else:

condition: Expression
elif_branches: List[ElifBranch]
else_branch: Block | None = None
then_branch: Block
class yapcad.dsl.ast.IndexAccess(span: SourceSpan, object: Expression, index: Expression)[source]

Bases: Expression

Index access (e.g., list[0]).

index: Expression
object: Expression
class yapcad.dsl.ast.LambdaExpr(span: SourceSpan, parameters: List[str], body: Expression)[source]

Bases: Expression

A lambda/anonymous function (e.g., (x) => x * 2).

body: Expression
parameters: List[str]
yapcad.dsl.ast.LetStatement

alias of VarDecl

class yapcad.dsl.ast.ListComprehension(span: SourceSpan, element_expr: Expression, clauses: List[ComprehensionClause] = <factory>)[source]

Bases: Expression

A list comprehension with one or more for clauses.

Single clause (original):

[f(x) for x in items if cond]

Multiple clauses (nested):

[f(x, y) for x in xs for y in ys] [f(x, y) for x in xs for y in ys if x < y] [f(x, y) for x in xs if x > 0 for y in ys if y < 10]

The clauses are evaluated left-to-right as nested loops.

clauses: List[ComprehensionClause]
property condition: Expression | None

Get first condition (for single-clause compatibility).

element_expr: Expression
classmethod from_single(span: SourceSpan, element_expr: Expression, variable: str, iterable: Expression, condition: Expression | None = None) ListComprehension[source]

Create a single-clause comprehension (backward compatibility).

property iterable: Expression

Get iterable (for single-clause compatibility).

property variable: str

Get variable name (for single-clause compatibility).

class yapcad.dsl.ast.ListLiteral(span: SourceSpan, elements: List[Expression])[source]

Bases: Expression

A list literal (e.g., [1, 2, 3]).

elements: List[Expression]
class yapcad.dsl.ast.Literal(span: SourceSpan, value: int | float | str | bool, literal_type: TokenType)[source]

Bases: Expression

A literal value (int, float, string, bool).

literal_type: TokenType
value: int | float | str | bool
class yapcad.dsl.ast.LiteralPattern(span: SourceSpan, value: Literal)[source]

Bases: Pattern

A literal pattern (e.g., ‘match x { case 42: … }’).

value: Literal
class yapcad.dsl.ast.MatchArm(span: SourceSpan, pattern: Pattern, body: Expression)[source]

Bases: AstNode

A single arm of a match expression.

body: Expression
pattern: Pattern
class yapcad.dsl.ast.MatchExpr(span: SourceSpan, subject: Expression, arms: List[MatchArm])[source]

Bases: Expression

A match expression.

arms: List[MatchArm]
subject: Expression
class yapcad.dsl.ast.MemberAccess(span: SourceSpan, object: Expression, member: str)[source]

Bases: Expression

Member access (e.g., point.x).

member: str
object: Expression
class yapcad.dsl.ast.MethodCall(span: ~yapcad.dsl.tokens.SourceSpan, object: ~yapcad.dsl.ast.Expression, method: str, arguments: ~typing.List[~yapcad.dsl.ast.Expression], named_arguments: dict[str, ~yapcad.dsl.ast.Expression] = <factory>)[source]

Bases: Expression

A method call (e.g., curve.at(0.5)).

arguments: List[Expression]
method: str
named_arguments: dict[str, Expression]
object: Expression
class yapcad.dsl.ast.Module(span: SourceSpan, name: str | None, uses: List[UseStatement | ExportUseStatement] = <factory>, native_blocks: List[NativeBlock] = <factory>, native_functions: List[NativeFunction] = <factory>, functions: List[FunctionDef] = <factory>, exports: List[ExportStatement] = <factory>)[source]

Bases: AstNode

A complete DSL module.

Syntax:

module module_name

use other.module

@native def native_func(…):

def my_function(…):

property commands: List[FunctionDef]

Backward compatibility alias for functions.

exports: List[ExportStatement]
functions: List[FunctionDef]
name: str | None
native_blocks: List[NativeBlock]
native_functions: List[NativeFunction]
uses: List[UseStatement | ExportUseStatement]
class yapcad.dsl.ast.NativeBlock(span: SourceSpan, code: str, exports: List[NativeFunctionDecl])[source]

Bases: AstNode

A native Python block with exported function declarations (legacy).

Syntax:
native python {

# Python code here

} exports {

fn func_name(param: type) -> return_type;

}

The Python code is executed to define functions, which are then made available to the DSL with the declared type signatures.

Note: This is the legacy syntax. New code should use @native decorator.

code: str
exports: List[NativeFunctionDecl]
class yapcad.dsl.ast.NativeFunction(span: SourceSpan, name: str, parameters: List[Parameter], return_type: TypeNode, python_code: str)[source]

Bases: AstNode

A native function (Python code with DSL type signature).

Syntax:

@native def function_name(param1: type1, param2: type2) -> return_type:

‘’’Python code here’’’ …

The function body contains Python code that is executed directly.

name: str
parameters: List[Parameter]
python_code: str
return_type: TypeNode
class yapcad.dsl.ast.NativeFunctionDecl(span: SourceSpan, name: str, parameters: List[Parameter], return_type: TypeNode)[source]

Bases: AstNode

A function declaration in a native block’s exports section (legacy).

Represents: fn name(param1: type1, param2: type2) -> return_type;

name: str
parameters: List[Parameter]
return_type: TypeNode
class yapcad.dsl.ast.OptionalType(span: SourceSpan, inner: TypeNode)[source]

Bases: TypeNode

An optional type, e.g., ‘point3d?’.

inner: TypeNode
class yapcad.dsl.ast.Parameter(span: SourceSpan, name: str, type_annotation: TypeNode | None = None, default_value: Expression | None = None, ui_hint: dict | None = None)[source]

Bases: AstNode

A function parameter.

default_value: Expression | None = None
name: str
type_annotation: TypeNode | None = None
ui_hint: dict | None = None
class yapcad.dsl.ast.PassStatement(span: SourceSpan)[source]

Bases: Statement

A pass statement (placeholder for empty blocks).

class yapcad.dsl.ast.Pattern(span: SourceSpan)[source]

Bases: AstNode

Base class for match patterns.

class yapcad.dsl.ast.PrintVisitor(indent: int = 0)[source]

Bases: AstVisitor

Debug visitor that prints the AST structure.

generic_visit(node: AstNode) None[source]

Default visit method.

class yapcad.dsl.ast.PythonBlock(span: SourceSpan, code: str)[source]

Bases: Statement

An inline Python block (legacy support).

code: str
class yapcad.dsl.ast.PythonExpr(span: SourceSpan, code: str, return_type: TypeNode)[source]

Bases: Expression

A python block that returns a value (legacy support).

code: str
return_type: TypeNode
class yapcad.dsl.ast.RangeExpr(span: SourceSpan, start: Expression, end: Expression, step: Expression | None = None)[source]

Bases: Expression

A range expression (e.g., 0..10 or range(10)).

end: Expression
start: Expression
step: Expression | None = None
yapcad.dsl.ast.RequireStatement

alias of AssertStatement

class yapcad.dsl.ast.ReturnStatement(span: SourceSpan, value: Expression | None = None)[source]

Bases: Statement

A return statement.

value: Expression | None = None
class yapcad.dsl.ast.SimpleType(span: SourceSpan, name: str)[source]

Bases: TypeNode

A simple type like ‘int’, ‘float’, ‘solid’, etc.

name: str
class yapcad.dsl.ast.Statement(span: SourceSpan)[source]

Bases: AstNode

Base class for all statements.

class yapcad.dsl.ast.TypeNode(span: SourceSpan)[source]

Bases: AstNode

Base class for type annotations.

class yapcad.dsl.ast.UnaryOp(span: SourceSpan, operator: TokenType, operand: Expression)[source]

Bases: Expression

A unary operation (e.g., not x, -n).

operand: Expression
operator: TokenType
class yapcad.dsl.ast.UseStatement(span: SourceSpan, module_path: List[str], alias: str | None = None)[source]

Bases: AstNode

A use/import statement (e.g., use yapcad.stdlib.transforms).

Syntax:

use module.path use module.path as alias use module.path.{item1, item2} # (future: selective imports)

alias: str | None = None
module_path: List[str]
class yapcad.dsl.ast.VarDecl(span: SourceSpan, name: str, type_annotation: TypeNode | None, initializer: Expression | None)[source]

Bases: Statement

A variable declaration (Pythonic style, no ‘let’ keyword).

Syntax options:

x = 42 # Type inferred x: int = 42 # Explicit type x: int # Declaration without initialization (rare)

initializer: Expression | None
name: str
type_annotation: TypeNode | None
class yapcad.dsl.ast.WhileStatement(span: SourceSpan, condition: Expression, body: Block)[source]

Bases: Statement

A while loop (e.g., while condition:).

body: Block
condition: Expression
class yapcad.dsl.ast.WildcardPattern(span: SourceSpan)[source]

Bases: Pattern

The wildcard pattern ‘_’.

yapcad.dsl.ast.print_ast(node: AstNode) None[source]

Print an AST node for debugging.

yapcad.dsl.checker module

Type checker for the yapCAD DSL.

Traverses the AST and validates types, collecting diagnostics for type errors, undefined identifiers, and other semantic issues.

class yapcad.dsl.checker.CheckResult(diagnostics: List[Diagnostic], has_errors: bool, has_warnings: bool, has_python_blocks: bool)[source]

Bases: object

Result of type checking a module.

diagnostics: List[Diagnostic]
has_errors: bool
has_python_blocks: bool
has_warnings: bool
class yapcad.dsl.checker.TypeChecker(max_errors: int = 20)[source]

Bases: object

Type checker for the yapCAD DSL.

Traverses the AST and validates: - Type compatibility in assignments and function calls - Return type matching - Require expression boolean constraint - Emit target type matching command return type - Undefined identifier detection - Python block flagging

check(module: Module) CheckResult[source]

Type check a complete module.

yapcad.dsl.checker.check(module: Module, max_errors: int = 20) CheckResult[source]

Convenience function to type check a module.

Parameters:
  • module – The parsed module AST

  • max_errors – Maximum errors before stopping (default 20)

Returns:

CheckResult with diagnostics

yapcad.dsl.errors module

DSL-specific exceptions and error handling.

Error code ranges (from Phase 3 roadmap): - E0xx: Lexer errors - E1xx: Parser errors - E2xx: Type errors - E3xx: Semantic errors

class yapcad.dsl.errors.Diagnostic(code: str, message: str, severity: ErrorSeverity, span: SourceSpan, source_line: str | None = None, hints: List[str] = <factory>, related: List[Diagnostic] = <factory>)[source]

Bases: object

A single diagnostic message (error, warning, etc.).

code: str
format(show_source: bool = True) str[source]

Format the diagnostic for display.

hints: List[str]
message: str
related: List[Diagnostic]
severity: ErrorSeverity
source_line: str | None = None
span: SourceSpan
to_json() dict[source]

Convert to JSON-serializable dict for tooling integration.

class yapcad.dsl.errors.DiagnosticCollector(max_errors: int = 20)[source]

Bases: object

Collects diagnostics during compilation.

add(diagnostic: Diagnostic) None[source]

Add a diagnostic.

add_error(error: DslError) None[source]

Add an error exception as a diagnostic.

diagnostics: List[Diagnostic]
property error_count: int
format_all(show_source: bool = True) str[source]

Format all diagnostics for display.

property has_errors: bool
property has_warnings: bool
property should_stop: bool

Check if we’ve hit the max error limit.

to_json() dict[source]

Convert all diagnostics to JSON format.

property warning_count: int
exception yapcad.dsl.errors.DslError(diagnostic: Diagnostic)[source]

Bases: Exception

Base exception for DSL errors.

class yapcad.dsl.errors.ErrorSeverity(*values)[source]

Bases: Enum

Severity levels for diagnostics.

ERROR = 'error'
HINT = 'hint'
INFO = 'info'
WARNING = 'warning'
exception yapcad.dsl.errors.LexerError(diagnostic: Diagnostic)[source]

Bases: DslError

Error during lexical analysis (E0xx).

exception yapcad.dsl.errors.ParserError(diagnostic: Diagnostic)[source]

Bases: DslError

Error during parsing (E1xx).

exception yapcad.dsl.errors.SemanticError(diagnostic: Diagnostic)[source]

Bases: DslError

Error during semantic analysis (E3xx).

exception yapcad.dsl.errors.TypeError(diagnostic: Diagnostic)[source]

Bases: DslError

Error during type checking (E2xx).

yapcad.dsl.errors.error_invalid_binary_literal(text: str, span: SourceSpan, source_line: str = None) LexerError[source]

E008: Invalid binary literal.

yapcad.dsl.errors.error_invalid_escape_sequence(seq: str, span: SourceSpan, source_line: str = None) LexerError[source]

E005: Invalid escape sequence in string.

yapcad.dsl.errors.error_invalid_expression(span: SourceSpan, source_line: str = None) ParserError[source]

E103: Invalid expression.

yapcad.dsl.errors.error_invalid_hex_literal(text: str, span: SourceSpan, source_line: str = None) LexerError[source]

E007: Invalid hexadecimal literal.

yapcad.dsl.errors.error_invalid_number_literal(text: str, span: SourceSpan, source_line: str = None) LexerError[source]

E006: Invalid number literal.

yapcad.dsl.errors.error_require_failed(message: str, span: SourceSpan, source_line: str = None) SemanticError[source]

E301: Require constraint failed.

yapcad.dsl.errors.error_type_mismatch(expected: str, found: str, span: SourceSpan, source_line: str = None) TypeError[source]

E201: Type mismatch.

yapcad.dsl.errors.error_undefined_identifier(name: str, span: SourceSpan, source_line: str = None) TypeError[source]

E202: Undefined identifier.

yapcad.dsl.errors.error_unexpected_character(char: str, span: SourceSpan, source_line: str = None) LexerError[source]

E001: Unexpected character.

yapcad.dsl.errors.error_unexpected_eof(expected: str, span: SourceSpan) ParserError[source]

E102: Unexpected end of file.

yapcad.dsl.errors.error_unexpected_token(expected: str, found: str, span: SourceSpan, source_line: str = None) ParserError[source]

E101: Unexpected token.

yapcad.dsl.errors.error_unterminated_comment(span: SourceSpan, source_line: str = None) LexerError[source]

E004: Unterminated multi-line comment.

yapcad.dsl.errors.error_unterminated_multiline_string(span: SourceSpan, source_line: str = None) LexerError[source]

E003: Unterminated multi-line string.

yapcad.dsl.errors.error_unterminated_string(span: SourceSpan, source_line: str = None) LexerError[source]

E002: Unterminated string literal.

yapcad.dsl.errors.warning_python_block(span: SourceSpan, source_line: str = None) Diagnostic[source]

W001: Python block requires manual approval.

yapcad.dsl.introspection module

DSL Introspection API for agentic engineering tools.

This module provides programmatic access to the yapCAD DSL’s type system, built-in functions, and methods. It’s designed to be queried by AI agents and other tools that need to understand the DSL’s capabilities.

Usage:
from yapcad.dsl.introspection import (

get_api_reference, get_function_info, get_type_info, list_functions, list_types, describe_function,

)

# Get complete API reference as a dictionary api = get_api_reference()

# Get info about a specific function info = get_function_info(“box”) print(info[“signature”]) # “box(width: float, depth: float, height: float) -> solid”

# List all available functions for name in list_functions():

print(name)

yapcad.dsl.introspection.describe_function(name: str) str[source]

Get a human-readable description of a function.

Parameters:

name – The function name

Returns:

Formatted description string

yapcad.dsl.introspection.get_api_as_json() str[source]

Get the complete API reference as a JSON string.

Useful for tools that prefer to parse JSON directly.

yapcad.dsl.introspection.get_api_reference() Dict[str, Any][source]

Get the complete API reference as a dictionary.

Returns a dictionary with: - types: All available types with descriptions - functions: All built-in functions with signatures and descriptions - methods: Type-specific methods organized by receiver type

This is the primary entry point for agentic tools to understand the DSL’s capabilities.

yapcad.dsl.introspection.get_common_pattern(name: str) str | None[source]

Get a common DSL pattern/example.

Parameters:

name – Pattern name (e.g., “boolean_subtraction”, “gear_creation”)

Returns:

DSL code example or None if pattern not found

yapcad.dsl.introspection.get_function_info(name: str) Dict[str, Any] | None[source]

Get detailed information about a specific function.

Parameters:

name – The function name

Returns:

Dictionary with signature, description, example, etc. Returns None if function not found.

yapcad.dsl.introspection.get_methods_for_type(type_name: str) Dict[str, Dict[str, Any]][source]

Get all methods available on a given type.

Parameters:

type_name – The type name (e.g., “solid”, “curve”, “region2d”)

Returns:

Dictionary mapping method names to their signatures

yapcad.dsl.introspection.get_type_info(name: str) Dict[str, Any] | None[source]

Get information about a type.

Parameters:

name – The type name

Returns:

Dictionary with tier, description, constructor info. Returns None if type not found.

yapcad.dsl.introspection.list_common_patterns() List[str][source]

List all available common pattern names.

yapcad.dsl.introspection.list_functions(category: str | None = None) List[str][source]

List all available built-in function names.

Parameters:

category – Optional filter by category (e.g., “solid”, “math”, “curve”)

Returns:

Sorted list of function names

yapcad.dsl.introspection.list_types(tier: int | None = None) List[str][source]

List all available types.

Parameters:

tier – Optional filter by tier (0-5)

Returns:

List of type names

yapcad.dsl.lexer module

Lexer for the yapCAD DSL v2 (Pythonic Syntax).

Converts source text into a stream of tokens for the parser. Supports: - Python-style indentation (INDENT/DEDENT tokens) - Significant newlines (NEWLINE tokens) - Implicit line continuation inside brackets - Single-line comments (#) - Multi-line comments (/* */) - String literals with escape sequences - Multi-line strings (triple quotes) - Integer literals (decimal, hex, binary) - Float literals (including scientific notation) - All DSL keywords and operators

class yapcad.dsl.lexer.Lexer(source: str, filename: str | None = None)[source]

Bases: object

Tokenizer for the yapCAD DSL v2 with Python-style indentation.

This lexer generates INDENT and DEDENT tokens based on changes in leading whitespace, similar to Python’s tokenizer.

Usage:

lexer = Lexer(source_code) tokens = lexer.tokenize()

Or for streaming:

lexer = Lexer(source_code) for token in lexer:

process(token)

get_source_line(line_num: int) str | None[source]

Get a specific line of source (1-indexed).

property lines: List[str]

Lazy-load line list for error reporting.

tokenize() List[Token][source]

Tokenize the entire source, returning a list of tokens.

yapcad.dsl.lexer.tokenize(source: str, filename: str | None = None) List[Token][source]

Convenience function to tokenize source code.

Parameters:
  • source – The source code to tokenize

  • filename – Optional filename for error messages

Returns:

List of tokens

Raises:

LexerError – If tokenization fails

yapcad.dsl.meta_apply module

Apply @meta decorator hints from the DSL to yapCAD geometry metadata.

This module bridges the gap between the DSL’s @meta(...) command decorator (which produces a flat meta_hint dict on a FunctionDef node) and the v1.1 metadata namespace helpers in yapcad.metadata.

Typical usage — called by the DSL evaluator or service layer after a command emits a solid:

from yapcad.dsl.meta_apply import apply_meta_hint

if fn.meta_hint:
    apply_meta_hint(solid, fn.meta_hint)

The function is idempotent and additive: calling it multiple times with the same hints merges cleanly because the underlying namespace helpers use setdefault / field-level writes, not wholesale replacement.

Namespace routing

Dotted keys in the hint dict are split on the first dot to determine the namespace, then the remainder becomes the field name:

assembly.joint_kind → assembly namespace, field joint_kind operation.kind → operation namespace, field kind layer → root metadata field layer tags → root metadata tags list (value appended)

Unknown namespaces or unrecognised field names within a known namespace are stored verbatim in the namespace dict rather than raising an error. This keeps the DSL forward-compatible: a field defined in a future v1.2 spec won’t break existing parsers.

List-of-dict assembly fields

The @meta decorator additionally accepts the four structured assembly list fields as lists of dict literals. Each entry is forwarded to the corresponding yapcad.metadata helper, so the same validation (enum checks, required-key checks, vector length checks) applies whether the caller writes Python or DSL:

@meta(
    assembly.datums=[
        {id="neck_face", kind="axis", ring="upper", R_mm=151.9, z_mm=330.0},
        {id="bore",      kind="axis", ring="upper", R_mm=151.9, z_mm=325.0},
    ],
    assembly.bolt_patterns=[
        {id="primary", ring="upper", R_mm=149.4, z_mm=317.3, count=8,
         fastener={kind="heatset", size="1/4-20"}},
    ],
    assembly.surfaces=[{id="mate_top", kind="mating", mate_to="nosecone.base_bore"}],
    assembly.keepouts=[{id="clearance_zone", kind="volume", reason="approach"}],
)
command FORWARD_BULKHEAD(...) -> solid:
    ...

Known unsupported field shapes still raise ValueError with the name of the field so callers can fall back to the Python helpers.

yapcad.dsl.meta_apply.apply_meta_hint(solid: list, meta_hint: Dict[str, Any]) None[source]

Apply a FunctionDef.meta_hint dict to a yapCAD solid’s metadata.

Parameters:
  • solid – A yapCAD solid (list representation from geom3d).

  • meta_hint – The flat dict produced by one or more @meta(...) decorators. Keys are plain strings or dotted namespace paths ("assembly.joint_kind", "operation.kind", "layer", etc.).

Raises:
  • TypeError – If solid is not a solid or meta_hint is not a dict.

  • ValueError – If a structured list field (bolt_patterns, datums, …) is attempted via the flat interface.

Example:

@meta(assembly.joint_kind="revolute", layer="kinematics")
@meta(operation.kind="subtract", operation.feature_kind="pocket")
command MAKE_POCKET(depth: float = 10.0) -> solid:
    ...

# After evaluation:
apply_meta_hint(result_solid, fn.meta_hint)
# → assembly.joint_kind = "revolute"
# → operation.kind = "subtract", operation.feature_kind = "pocket"
# → root layer = "kinematics"
yapcad.dsl.meta_apply.apply_meta_hint_to_raw(meta: Dict[str, Any], meta_hint: Dict[str, Any]) None[source]

Apply a meta_hint dict directly to an already-extracted metadata dict.

Convenience variant for callers that have already retrieved the metadata dict (e.g. via get_solid_metadata) rather than the raw solid.

Parameters:
  • meta – Metadata dict (mutable, modified in place).

  • meta_hint – Flat hint dict from @meta decorators.

yapcad.dsl.packaging module

DSL-to-Package integration.

Provides functions to compile DSL source, execute commands, and package the resulting geometry with full provenance tracking.

class yapcad.dsl.packaging.PackageResult(*, success: bool, manifest: 'PackageManifest' | None = None, execution_result: ExecutionResult | None = None, error_message: str | None = None)[source]

Bases: object

Result of DSL-to-package operation.

yapcad.dsl.packaging.package_from_dsl(source: str, command_name: str, parameters: Dict[str, Any], target_dir: Path | str, *, name: str, version: str, description: str | None = None, author: str | None = None, units: str | None = None, materials: Dict[str, Dict[str, Any]] | None = None, overwrite: bool = False) PackageResult[source]

Compile DSL source, execute a command, and package the result.

This is a high-level function that combines DSL compilation, execution, and packaging into a single workflow. The resulting package includes full provenance metadata linking it to the original DSL source.

Parameters:
  • source – DSL source code containing the module and command definitions.

  • command_name – Name of the command to execute (e.g., “MAKE_GEAR”).

  • parameters – Dictionary of parameter values for the command.

  • target_dir – Directory where the package will be created.

  • name – Name for the package (used in manifest).

  • version – Version string for the package.

  • description – Optional description for the package.

  • author – Optional author name.

  • units – Unit system (default “mm”).

  • materials – Optional materials dictionary for the package.

  • overwrite – If True, overwrite existing package directory.

Returns:

PackageResult with success status, manifest, and any error info.

Example

>>> source = '''
... module gear_design;
...
... command MAKE_GEAR(teeth: int, module_mm: float) -> solid {
...     let pitch_diameter: float = teeth * module_mm;
...     let gear: solid = cylinder(pitch_diameter / 2.0, 10.0);
...     emit gear;
... }
... '''
>>> result = package_from_dsl(
...     source,
...     "MAKE_GEAR",
...     {"teeth": 24, "module_mm": 2.0},
...     "output/gear_pkg",
...     name="gear_24t",
...     version="1.0.0",
... )
>>> if result.success:
...     print(f"Package created at {result.manifest.root}")

yapcad.dsl.parser module

Recursive descent parser for the yapCAD DSL v2 (Pythonic Syntax).

Converts a token stream into an Abstract Syntax Tree (AST). Supports Python-style indentation-based blocks.

class yapcad.dsl.parser.Parser(tokens: List[Token], filename: str | None = None, source: str | None = None)[source]

Bases: object

Recursive descent parser for the yapCAD DSL v2 with Python-style indentation.

Usage:

parser = Parser(tokens) module = parser.parse_module()

The parser implements standard precedence climbing for expressions:
Lowest: or

and == != < > <= >= + - * / // %

Highest: ** (power, right-associative)

unary (not -)

PRECEDENCE = {TokenType.AND: 2, TokenType.DOUBLE_SLASH: 6, TokenType.DOUBLE_STAR: 7, TokenType.EQ: 3, TokenType.GE: 4, TokenType.GT: 4, TokenType.LE: 4, TokenType.LT: 4, TokenType.MINUS: 5, TokenType.NE: 3, TokenType.OR: 1, TokenType.PERCENT: 6, TokenType.PLUS: 5, TokenType.SLASH: 6, TokenType.STAR: 6}
RIGHT_ASSOCIATIVE = {TokenType.DOUBLE_STAR}
parse_module() Module[source]

Parse a complete module.

yapcad.dsl.parser.parse(tokens: List[Token], filename: str | None = None, source: str | None = None) Module[source]

Convenience function to parse tokens into a module.

Parameters:
  • tokens – List of tokens from the lexer

  • filename – Optional filename for error messages

  • source – Optional original source code for extracting raw text

Returns:

Parsed Module AST

Raises:

ParserError – If parsing fails

yapcad.dsl.symbols module

Symbol table management for the yapCAD DSL type checker.

Provides scoped symbol tables for tracking variable definitions, function signatures, and type information during type checking.

class yapcad.dsl.symbols.FunctionSignature(name: str, params: List[Tuple[str, Type, Any | None]], return_type: Type, is_method: bool = False, is_variadic: bool = False)[source]

Bases: object

Type signature for a function or built-in.

is_method: bool = False
is_variadic: bool = False
name: str
params: List[Tuple[str, Type, Any | None]]
return_type: Type
class yapcad.dsl.symbols.Scope(symbols: Dict[str, ~yapcad.dsl.symbols.Symbol]=<factory>, parent: Scope | None = None, name: str = '')[source]

Bases: object

A single scope in the scope stack.

define(symbol: Symbol) None[source]

Define a symbol in this scope.

lookup(name: str) Symbol | None[source]

Look up a symbol in this scope or any parent scope.

lookup_local(name: str) Symbol | None[source]

Look up a symbol in this scope only.

name: str = ''
parent: Scope | None = None
symbols: Dict[str, Symbol]
class yapcad.dsl.symbols.Symbol(name: str, kind: SymbolKind, type: Type, span: SourceSpan | None = None, is_mutable: bool = False, has_python_block: bool = False)[source]

Bases: object

A symbol in the symbol table.

has_python_block: bool = False
is_mutable: bool = False
kind: SymbolKind
name: str
span: SourceSpan | None = None
type: Type
class yapcad.dsl.symbols.SymbolKind(*values)[source]

Bases: Enum

The kind of symbol being tracked.

COMMAND = 4
FUNCTION = 3
MODULE = 5
PARAMETER = 2
VARIABLE = 1
class yapcad.dsl.symbols.SymbolTable[source]

Bases: object

Manages scopes and symbol definitions for type checking.

Provides: - Nested scope management (push/pop) - Symbol definition and lookup - Built-in function registry

current_scope_name() str[source]

Get the name of the current scope (for debugging).

define(symbol: Symbol) bool[source]

Define a symbol in the current scope.

Returns True if successful, False if already defined in current scope.

get_all_builtins() Dict[str, FunctionSignature][source]

Get all registered built-in functions.

is_builtin(name: str) bool[source]

Check if a name is a built-in function.

lookup(name: str) Symbol | None[source]

Look up a symbol in the current scope chain.

lookup_builtin(name: str) FunctionSignature | None[source]

Look up a built-in function signature.

pop_scope() None[source]

Pop the current scope.

push_scope(name: str = '') None[source]

Push a new scope onto the stack.

yapcad.dsl.symbols.get_method_signature(obj_type: Type, method_name: str) FunctionSignature | None[source]

Get the method signature for a type, if it exists.

yapcad.dsl.tokens module

Token types for the yapCAD DSL lexer.

yapCAD DSL v2 - Pythonic Syntax

Token type categories follow error code ranges from the roadmap: - E0xx: Lexer errors - E1xx: Parser errors - E2xx: Type errors - E3xx: Semantic errors

class yapcad.dsl.tokens.SourceLocation(line: int, column: int, offset: int, filename: str | None = None)[source]

Bases: object

Represents a position in source code.

column: int
filename: str | None = None
line: int
offset: int
class yapcad.dsl.tokens.SourceSpan(start: SourceLocation, end: SourceLocation)[source]

Bases: object

Represents a range in source code.

end: SourceLocation
start: SourceLocation
class yapcad.dsl.tokens.Token(type: TokenType, value: Any, lexeme: str, span: SourceSpan)[source]

Bases: object

A single token from the lexer.

lexeme: str
span: SourceSpan
type: TokenType
value: Any
class yapcad.dsl.tokens.TokenType(*values)[source]

Bases: Enum

All token types recognized by the DSL lexer.

AND = 76
ARROW = 92
AS = 19
ASSERT = 17
ASSIGN = 79
AT = 97
BOOL_LITERAL = 4
CLOSE = 30
CLOSE_C0 = 31
CLOSE_C1 = 32
COLON = 88
COMMA = 90
COMMAND = 23
DEDENT = 100
DEF = 8
DOT = 91
DOUBLE_ARROW = 93
DOUBLE_SLASH = 67
DOUBLE_STAR = 69
ELIF = 12
ELSE = 13
EMIT = 10
EOF = 102
EQ = 74
EXPORT = 21
EXPORTS = 29
FLOAT_LITERAL = 2
FN = 28
FOR = 14
GE = 73
GT = 71
HASH = 98
IDENTIFIER = 5
IF = 11
IN = 15
INDENT = 99
INT_LITERAL = 1
LBRACE = 82
LBRACKET = 86
LE = 72
LET = 24
LPAREN = 84
LT = 70
MATCH = 20
MINUS = 64
MINUS_ASSIGN = 81
MODULE = 6
NATIVE = 22
NATIVE_BLOCK = 103
NE = 75
NEWLINE = 101
NOT = 78
OR = 77
PASS = 18
PERCENT = 68
PLUS = 63
PLUS_ASSIGN = 80
PYTHON = 27
QUESTION = 95
RANGE = 94
RBRACE = 83
RBRACKET = 87
REQUIRE = 25
RETURN = 9
RPAREN = 85
SEMICOLON = 89
SLASH = 66
STAR = 65
STRING_LITERAL = 3
TYPE_ARC = 45
TYPE_BEZIER = 52
TYPE_BOOL = 36
TYPE_CATMULLROM = 50
TYPE_CIRCLE = 46
TYPE_DICT = 62
TYPE_ELLIPSE = 47
TYPE_FLOAT = 34
TYPE_HYPERBOLA = 49
TYPE_INT = 33
TYPE_LINE_SEGMENT = 44
TYPE_LIST = 61
TYPE_LOOP3D = 57
TYPE_NURBS = 51
TYPE_PARABOLA = 48
TYPE_PATH2D = 53
TYPE_PATH3D = 54
TYPE_POINT = 37
TYPE_POINT2D = 38
TYPE_POINT3D = 39
TYPE_PROFILE2D = 55
TYPE_REGION2D = 56
TYPE_SHELL = 59
TYPE_SOLID = 60
TYPE_STRING = 35
TYPE_SURFACE = 58
TYPE_TRANSFORM = 43
TYPE_VECTOR = 40
TYPE_VECTOR2D = 41
TYPE_VECTOR3D = 42
UNDERSCORE = 96
USE = 7
WHILE = 16
WITH = 26
yapcad.dsl.tokens.get_deprecation_message(keyword: str) str | None[source]

Get the deprecation message for a keyword, if any.

yapcad.dsl.tokens.is_deprecated_keyword(keyword: str) bool[source]

Check if a keyword is deprecated.

yapcad.dsl.tokens.is_type_token(token_type: TokenType) bool[source]

Check if a token type represents a type keyword.

yapcad.dsl.types module

Type system definitions for the yapCAD DSL.

The type system is organized into five tiers:

Tier 1: Primitives (int, float, bool, string, point, vector, transform) Tier 2: Curve Primitives (line_segment, arc, circle, bezier, nurbs, etc.) Tier 3: Compound Curves (path2d, path3d, profile2d, region2d, loop3d) Tier 4: Surfaces (surface, shell) Tier 5: Solids (solid)

Plus generic types: list<T>, dict

class yapcad.dsl.types.CompoundCurveType(_name: str)[source]

Bases: Type

A Tier 3 compound curve type (paths, profiles, regions).

is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.CurveType(_name: str)[source]

Bases: Type

A Tier 2 curve primitive type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.DictType[source]

Bases: Type

A dictionary type (string keys).

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.ErrorType[source]

Bases: Type

A type representing a type error (prevents cascading errors).

is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.FunctionType(param_types: Tuple[Type, ...], return_type: Type)[source]

Bases: Type

A function type for lambdas and built-in functions.

property name: str

The type name for display/errors.

param_types: Tuple[Type, ...]
return_type: Type
property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.GeometricPrimitiveType(_name: str, dimension: int | None = None)[source]

Bases: Type

A geometric primitive type (point, vector, transform).

Points and vectors are dimensionally polymorphic - they can be 2D or 3D. point2d/point3d and vector2d/vector3d are specific variants.

dimension: int | None = None
is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.ListType(element_type: Type)[source]

Bases: Type

A generic list type: list<T>.

element_type: Type
is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.NoneType[source]

Bases: Type

The none/null type (only valid for optional types).

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.OptionalTypeWrapper(inner_type: Type)[source]

Bases: Type

An optional type: T?

inner_type: Type
is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.PrimitiveType(_name: str)[source]

Bases: Type

A primitive type (int, float, bool, string).

is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.SolidType(_name: str = 'solid')[source]

Bases: Type

A Tier 5 solid type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.SurfaceType(_name: str)[source]

Bases: Type

A Tier 4 surface type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.Type[source]

Bases: ABC

Base class for all DSL types.

is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

abstract property name: str

The type name for display/errors.

abstract property tier: TypeTier

The tier this type belongs to.

class yapcad.dsl.types.TypeTier(*values)[source]

Bases: Enum

Tier classification for types in the hierarchy.

COMPOUND_CURVE = 3
CURVE = 2
GENERIC = 0
PRIMITIVE = 1
SOLID = 5
SURFACE = 4
class yapcad.dsl.types.UnknownType[source]

Bases: Type

A placeholder for type inference or error recovery.

is_assignable_from(other: Type) bool[source]

Check if this type can accept a value of the other type.

property name: str

The type name for display/errors.

property tier: TypeTier

The tier this type belongs to.

yapcad.dsl.types.common_type(t1: Type, t2: Type) Type | None[source]

Find the common type that both t1 and t2 can be assigned to.

Returns None if no common type exists.

yapcad.dsl.types.is_compound_curve(t: Type) bool[source]

Check if type is a compound curve (Tier 3).

yapcad.dsl.types.is_curve(t: Type) bool[source]

Check if type is a curve (Tier 2).

yapcad.dsl.types.is_geometric_primitive(t: Type) bool[source]

Check if type is a geometric primitive (point, vector, transform).

yapcad.dsl.types.is_geometry(t: Type) bool[source]

Check if type is any geometric type (Tier 1 geometric through Tier 5).

yapcad.dsl.types.is_numeric(t: Type) bool[source]

Check if type is numeric (int or float).

yapcad.dsl.types.is_solid(t: Type) bool[source]

Check if type is a solid (Tier 5).

yapcad.dsl.types.is_surface(t: Type) bool[source]

Check if type is a surface (Tier 4).

yapcad.dsl.types.make_list_type(element_type: Type) ListType[source]

Create a list type with the given element type.

yapcad.dsl.types.make_optional_type(inner_type: Type) OptionalTypeWrapper[source]

Create an optional type wrapping the given type.

yapcad.dsl.types.resolve_type_name(name: str) Type | None[source]

Look up a type by name.

Module contents

yapCAD Domain-Specific Language (DSL) compiler.

This module provides: - Lexer: Tokenizes DSL source code - Parser: Builds AST from tokens - Type checker: Validates types and constraints - Interpreter: Executes DSL commands to generate geometry - Transforms: AST transformations for optimization

Usage:

from yapcad.dsl import tokenize, parse, check, Lexer, Parser, TypeChecker

# Simple parsing tokens = tokenize(‘let x: int = 42;’)

# Or parse and type check a complete module source = ‘’’ module my_design;

command MAKE_BOX(width: float, height: float) -> solid {

let box: solid = box(width, height, 10.0); emit box;

tokens = tokenize(source) module = parse(tokens) result = check(module) if result.has_errors:

for diag in result.diagnostics:

print(diag)