# AutoLISP CADCraft runs AutoLISP routines (`.lsp` files). What is here and what is not yet: [gaps.md](gaps.md) (E1). ## Loading and running - **APPLOAD** (Tools > Load Application…, alias `AP`) asks for a `.lsp` file and runs it. Dropping a `.lsp` file on the window does the same. - **`(load "name")`** loads a file by path, with `.lsp` added when the name has none. A file APPLOAD loaded is found again by its name, also on the web where there is no file system. - **`(defun c:NAME …)`** defines a command: type `NAME` at the command line. Built-in commands keep their names. - **At the command line**, `(expression)` evaluates and shows the value, and `!variable` shows a variable. Typed at a command's prompt (not a free-text one), an expression's value answers it: `CIRCLE 0,0 (* 2 r)`. - **Programmatically** (scripts, the control channel, MCP, the CLI): `lisp {code, inputs?}` and `appload {path} | {name, text | data}` run to the end and return `{value, output, error?}`. `inputs` answer `get…` calls in order (numbers, strings, `[x, y]` points); a call with none left gets nil. ### At startup CADCraft loads LISP from its **support folder**, `support` in the settings folder (on Windows `%APPDATA%\CADCraft\support`, on macOS `~/Library/Application Support/CADCraft/support`, on Linux `~/.config/cadcraft/support`; created at first start): - `acad.lsp` once per session, into the first drawing; with `ACADLSPASDOC` set to 1, into every drawing; - `acaddoc.lsp` into every drawing opened or created; - then `S::STARTUP`, when they define it. `(autoload "file" '("CMD1" "CMD2"))` in a startup file makes `CMD1` and `CMD2` commands that load `file` (from the support folder too) the first time they are typed. Startup files run to the end without asking for input. A drawing's own folder is never searched: an `acaddoc.lsp` that came with a downloaded drawing does not run. Each drawing has its own variables and functions. A routine is one undo step, whatever commands it runs. A routine that waits for input (`getpoint`, `pause`) lets the window work meanwhile; Esc stops it with "Function cancelled", which `*error*` receives. A long loop runs a slice per frame, so the window stays live and Esc stops it too. ## The language Integers are 32-bit and wrap as AutoLISP's do; any real makes arithmetic real. Variables are dynamically scoped: a function's arguments and its locals (after `/`) are bound while it runs. Symbols are case-insensitive. Reals print with six significant digits. Nothing a routine does can crash the program: deep recursion is the error "internal stack limit reached", malformed source is a reader error, and every built-in checks its arguments. ## Built-in functions - **Forms:** `quote` `'` `function` `setq` `set` `if` `cond` `while` `repeat` `foreach` `progn` `and` `or` `defun` `defun-q` `lambda` `eval` `apply` `mapcar` `load` `autoload` `exit` `quit` - **Numbers:** `+ - * / rem 1+ 1- abs min max sqrt exp log sin cos atan expt fix float gcd logand logior lsh ~ = /= < > <= >= zerop minusp numberp` - **Lists:** `car cdr` and the `c…r` combinations up to four levels, `cons list append reverse length nth last member assoc subst acad_strlsort`, `vl-position vl-remove vl-sort vl-remove-if vl-remove-if-not vl-member-if vl-every vl-some vl-list-length vl-consp` - **Predicates:** `atom listp null not type eq equal boundp vl-symbolp` - **Strings:** `strcat strlen substr strcase itoa atoi atof chr ascii read wcmatch`, `vl-string-search vl-string-subst vl-string-trim vl-string-left-trim vl-string-right-trim vl-string-translate vl-string->list vl-list->string vl-prin1-to-string vl-princ-to-string vl-symbol-name vl-symbol-value vl-filename-base vl-filename-extension vl-filename-directory` - **Geometry:** `polar distance angle inters trans` (`trans` returns the point: no UCS yet) - **Output and files:** `princ prin1 print prompt terpri alert open close read-line write-line findfile` - **Errors:** `*error*`, `vl-catch-all-apply vl-catch-all-error-p vl-catch-all-error-message` - **Drawing:** `command` (also `command-s`, `vl-cmdf`) with `pause`, a command left open for the next call, and `(command)` to cancel; `getvar setvar`; `entget entmake entmod entdel entlast entnext entupd handent`; `ssget` (modes X, L, P, I, W, C, F, WP, CP, a point, or the user selecting; filters with wildcards and `-4` operators) `ssadd ssdel sslength ssname ssmemb sssetfirst ssgetfirst`; `tblsearch tblnext` (LAYER, LTYPE, STYLE, BLOCK, DIMSTYLE, APPID) - **Input:** `initget getpoint getcorner getdist getangle getorient getreal getint getstring getkword entsel nentsel` - **Units:** `rtos angtos distof angtof` - **No-ops:** `vl-load-com gc redraw`; `ver` Entity lists use the DXF group codes of CADCraft's DXF files: what `entget` returns is what a DXF file holds for the object, plus `-1` (its name) and `410` (its layout). Angles (groups 50–58) are in radians, as in AutoCAD, where the file holds degrees; `entmake`, `entmod` and `ssget` filters take radians too. ## Testing against the corpus The AutoLISP conformance corpus (#648) lives in its own repository. Point `CADCRAFT_LISP_CORPUS` at it and run `cargo test -p cadcraft-engine --test it lisp_corpus::`; without the variable the test says it was skipped.