Files
test/sexp_effects/primitive_libs/core.py
gilesb d574d5badd Add modular primitive libraries and fix Symbol class compatibility
- Add primitive_libs/ with modular primitive loading (core, math, image,
  color, color_ops, filters, geometry, drawing, blending, arrays, ascii)
- Effects now explicitly declare dependencies via (require-primitives "...")
- Convert ascii-fx-zone from hardcoded special form to loadable primitive
- Add _is_symbol/_is_keyword helpers for duck typing to support both
  sexp_effects.parser.Symbol and artdag.sexp.parser.Symbol classes
- Auto-inject _interp and _env for primitives that need them
- Remove silent error swallowing in cell_effect evaluation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 09:02:34 +00:00

165 lines
2.5 KiB
Python

"""
Core Primitives - Always available, minimal essential set.
These are the primitives that form the foundation of the language.
They cannot be overridden by libraries.
"""
# Arithmetic
def prim_add(*args):
if len(args) == 0:
return 0
result = args[0]
for arg in args[1:]:
result = result + arg
return result
def prim_sub(a, b=None):
if b is None:
return -a
return a - b
def prim_mul(*args):
if len(args) == 0:
return 1
result = args[0]
for arg in args[1:]:
result = result * arg
return result
def prim_div(a, b):
return a / b
def prim_mod(a, b):
return a % b
# Comparison
def prim_lt(a, b):
return a < b
def prim_gt(a, b):
return a > b
def prim_le(a, b):
return a <= b
def prim_ge(a, b):
return a >= b
def prim_eq(a, b):
if isinstance(a, float) or isinstance(b, float):
return abs(a - b) < 1e-9
return a == b
def prim_ne(a, b):
return not prim_eq(a, b)
# Logic
def prim_not(x):
return not x
def prim_and(*args):
for a in args:
if not a:
return False
return True
def prim_or(*args):
for a in args:
if a:
return True
return False
# Basic data access
def prim_get(obj, key, default=None):
"""Get value from dict or list."""
if isinstance(obj, dict):
return obj.get(key, default)
elif isinstance(obj, (list, tuple)):
try:
return obj[int(key)]
except (IndexError, ValueError):
return default
return default
def prim_length(seq):
return len(seq)
def prim_list(*args):
return list(args)
# Type checking
def prim_is_number(x):
return isinstance(x, (int, float))
def prim_is_string(x):
return isinstance(x, str)
def prim_is_list(x):
return isinstance(x, (list, tuple))
def prim_is_dict(x):
return isinstance(x, dict)
def prim_is_nil(x):
return x is None
# Core primitives dict
PRIMITIVES = {
# Arithmetic
'+': prim_add,
'-': prim_sub,
'*': prim_mul,
'/': prim_div,
'mod': prim_mod,
# Comparison
'<': prim_lt,
'>': prim_gt,
'<=': prim_le,
'>=': prim_ge,
'=': prim_eq,
'!=': prim_ne,
# Logic
'not': prim_not,
'and': prim_and,
'or': prim_or,
# Data access
'get': prim_get,
'length': prim_length,
'len': prim_length,
'list': prim_list,
# Type predicates
'number?': prim_is_number,
'string?': prim_is_string,
'list?': prim_is_list,
'dict?': prim_is_dict,
'nil?': prim_is_nil,
}