Add JAX typography, xector primitives, deferred effect chains, and GPU streaming
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m28s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m28s
- Add JAX text rendering with font atlas, styled text placement, and typography primitives - Add xector (element-wise/reduction) operations library and sexp effects - Add deferred effect chain fusion for JIT-compiled effect pipelines - Expand drawing primitives with font management, alignment, shadow, and outline - Add interpreter support for function-style define and require - Add GPU persistence mode and hardware decode support to streaming - Add new sexp effects: cell_pattern, halftone, mosaic, and derived definitions - Add path registry for asset resolution - Add integration, primitives, and xector tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -156,11 +156,21 @@ class Interpreter:
|
||||
if form == 'define':
|
||||
name = expr[1]
|
||||
if _is_symbol(name):
|
||||
# Simple define: (define name value)
|
||||
value = self.eval(expr[2], env)
|
||||
self.global_env.set(name.name, value)
|
||||
return value
|
||||
elif isinstance(name, list) and len(name) >= 1 and _is_symbol(name[0]):
|
||||
# Function define: (define (fn-name args...) body)
|
||||
# Desugars to: (define fn-name (lambda (args...) body))
|
||||
fn_name = name[0].name
|
||||
params = [p.name if _is_symbol(p) else p for p in name[1:]]
|
||||
body = expr[2]
|
||||
fn = Lambda(params, body, env)
|
||||
self.global_env.set(fn_name, fn)
|
||||
return fn
|
||||
else:
|
||||
raise SyntaxError(f"define requires symbol, got {name}")
|
||||
raise SyntaxError(f"define requires symbol or (name args...), got {name}")
|
||||
|
||||
# Define-effect
|
||||
if form == 'define-effect':
|
||||
@@ -276,6 +286,10 @@ class Interpreter:
|
||||
if form == 'require-primitives':
|
||||
return self._eval_require_primitives(expr, env)
|
||||
|
||||
# require - load .sexp file into current scope
|
||||
if form == 'require':
|
||||
return self._eval_require(expr, env)
|
||||
|
||||
# Function call
|
||||
fn = self.eval(head, env)
|
||||
args = [self.eval(arg, env) for arg in expr[1:]]
|
||||
@@ -488,6 +502,61 @@ class Interpreter:
|
||||
from .primitive_libs import load_primitive_library
|
||||
return load_primitive_library(name, path)
|
||||
|
||||
def _eval_require(self, expr: Any, env: Environment) -> Any:
|
||||
"""
|
||||
Evaluate require: load a .sexp file and evaluate its definitions.
|
||||
|
||||
Syntax:
|
||||
(require "derived") ; loads derived.sexp from sexp_effects/
|
||||
(require "path/to/file.sexp") ; loads from explicit path
|
||||
|
||||
Definitions from the file are added to the current environment.
|
||||
"""
|
||||
for lib_expr in expr[1:]:
|
||||
if _is_symbol(lib_expr):
|
||||
lib_name = lib_expr.name
|
||||
else:
|
||||
lib_name = lib_expr
|
||||
|
||||
# Find the .sexp file
|
||||
sexp_path = self._find_sexp_file(lib_name)
|
||||
if sexp_path is None:
|
||||
raise ValueError(f"Cannot find sexp file: {lib_name}")
|
||||
|
||||
# Parse and evaluate the file
|
||||
content = parse_file(sexp_path)
|
||||
|
||||
# Evaluate all top-level expressions
|
||||
if isinstance(content, list) and content and isinstance(content[0], list):
|
||||
for e in content:
|
||||
self.eval(e, env)
|
||||
else:
|
||||
self.eval(content, env)
|
||||
|
||||
return None
|
||||
|
||||
def _find_sexp_file(self, name: str) -> Optional[str]:
|
||||
"""Find a .sexp file by name."""
|
||||
# Try various locations
|
||||
candidates = [
|
||||
# Explicit path
|
||||
name,
|
||||
name + '.sexp',
|
||||
# In sexp_effects directory
|
||||
Path(__file__).parent / f'{name}.sexp',
|
||||
Path(__file__).parent / name,
|
||||
# In effects directory
|
||||
Path(__file__).parent / 'effects' / f'{name}.sexp',
|
||||
Path(__file__).parent / 'effects' / name,
|
||||
]
|
||||
|
||||
for path in candidates:
|
||||
p = Path(path) if not isinstance(path, Path) else path
|
||||
if p.exists() and p.is_file():
|
||||
return str(p)
|
||||
|
||||
return None
|
||||
|
||||
def _eval_ascii_fx_zone(self, expr: Any, env: Environment) -> Any:
|
||||
"""
|
||||
Evaluate ascii-fx-zone special form.
|
||||
@@ -876,8 +945,8 @@ class Interpreter:
|
||||
for pname, pdefault in effect.params.items():
|
||||
value = params.get(pname)
|
||||
if value is None:
|
||||
# Evaluate default if it's an expression (list)
|
||||
if isinstance(pdefault, list):
|
||||
# Evaluate default if it's an expression (list) or a symbol (like 'nil')
|
||||
if isinstance(pdefault, list) or _is_symbol(pdefault):
|
||||
value = self.eval(pdefault, env)
|
||||
else:
|
||||
value = pdefault
|
||||
|
||||
Reference in New Issue
Block a user