• v0.5.1 5c6f8334f4

    tklips v0.5.1 Stable

    michael released this 2026-11-06 10:48:34 +00:00 | 0 commits to master since this release

    tklips v0.5.1: rule priorities, the standard library of releases at the repository's new location, and error lines after the output they follow. The reference PDF documents the language as released.

    Breaking changes

    • The releases' standard library moved with the repository, from experiments/tklips to tklips/tklips-lang. (std name version) gives https://code.thunderk.net/tklips/tklips-lang/raw/tag/<version>/stdlib/<name>.tk, which serves every release, the earlier ones included. Only that location is trusted: a library URL written out under the former experiments/tklips/raw/tag/ prefix is an ordinary URL now, which needs --allow-url, allowUrl or allow_url. Write (std name version) instead, or the new URL.

    Rules

    • (*priority* n) among a rule's conditions orders it among the rules that no *after* or *before* declaration relates to it: higher priorities first, 0 by default, then definition order. *after* and *before* always take precedence. A library's end-of-turn rule can take (*priority* -1000) to come after the rules of the modules that require it. n is an integer as written; errors: rule: missing priority <d>, rule: invalid priority <v>, rule: duplicate marker *priority* and rule: misplaced marker *priority*.

    Command line

    • With stdout and stderr sent to the same place, a form's error line now comes after what the form wrote before the error. It came first when stdout was a pipe.

    SHA-256

    fc2953e24c3fb440c62f52bb34b9e594354176361c38be69ea9d58b443b747b9  tklips-v0.5.1-linux-x86_64
    5fa690e585611bfdaa23317fa36f5ff4d2fb1cea027a87e8cd9f0eabec7ed850  tklips-v0.5.1.mjs
    55f7dc0e8dc2e61052fc34ee105a7df88e45b4f0f877c12a8a242fb4801612cb  tklips-v0.5.1.py
    a4924c4705fafffe7b5866d7d752e8292814532782ff3afa859032bdf25fb429  tklips-v0.5.1-reference.pdf
    
    Downloads
  • v0.5.0 b4b1bfc055

    tklips v0.5.0 Stable

    michael released this 2026-11-05 21:40:57 +00:00 | 5 commits to master since this release

    tklips v0.5.0: files and streams, constants, help in the shell, random draws, and aggregates in rules, which also check much less work again after a change. The reference PDF documents the language as released.

    Breaking changes

    • pi and e are removed. Write the constants &PI and &E instead of (pi) and (e).
    • set returns the value it binds, _ included, instead of _. The shell and batch mode write that value as the result of a top-level set; (and (set o x) ...) goes on when x is true; and set as a fact predicate keeps the facts whose value is true. Where a program relied on the _, write (block (set x v) _).
    • Global variables cannot take a constant's name. (set PI 3) at top level fails with set: cannot shadow constant PI, and so do the other built-in constants: TAU, E, INT-MAX, INT-MIN, STDIN, STDOUT and STDERR. Rename such variables; parameters and variables inside functions and rules may still use these names.

    Language

    • Constants. (const NAME value) defines a constant at top level, with an upper-case name; it cannot be defined again. &NAME reads it everywhere, in function bodies, lambdas and rules included, unless a parameter or local variable shadows it. (const-list) lists them all. The built-in constants are PI, TAU, E, INT-MAX, INT-MIN, STDIN, STDOUT and STDERR. The new error codes are define/constant and define/scope.
    • Help. (? name) writes a function's signature and what it does, and where a user function was defined. It evaluates none of its arguments, so ? can head a call being written: (? text-pad-left 42 5). (?) lists every function and constant. (func-info f) gives the same as an object. The # lines right above a top-level func or const are its doc, and every built-in and standard library function has one.
    • Files, URLs and standard streams.
      • (io-open path fn (.mode read)) opens a resource, calls fn with its integer id, and closes the resource however fn ends, errors and interrupts included. (io-with (in a.txt) (out b.txt (.mode write)) body...) does the same around a body.
      • io-read-line, io-read, io-write and io-print read and write a resource. io-info and io-list inspect the open ones.
      • Ids 0, 1 and 2 are stdin, stdout and stderr. Files are opened inside the current directory, with mode read, write or append. URLs are read only.
      • Errors belong to the new io/ family: io/denied, io/not-found, io/not-accessible, io/closed, io/mode, io/read and io/write.
    • Random draws.
      • (random), (random end) and (random start end) draw a float in [0, 1), or a number in [start, end), an integer unless a bound is a float. (shuffle obj) gives the items of an object in a random order.
      • (seed n) replays the draws of a seed, (seed) sets a fresh one and returns it, and (seed-get) gives the seed in effect.
      • With .key, a draw is fixed by its key and the seed, and leaves the generator as it was.
      • The generators are xoshiro256** and SipHash-1-3, so a seed gives the same draws on every host. They are not cryptographic.
    • Standard library, new libraries:
      • file: file-read, file-write, file-append and file-each-line.
      • enum: enum, enum-str, enum-name, enum-has and enum-check, which builds and checks sets of named constants.
      • random: random-pick and random-sample.

    Facts

    • fact, fact-find, fact-find-read and fact-del-all find facts by their first written value through an index, instead of walking the whole relation.

    Rules

    • Aggregates. (*collect* (name expr) c...) always holds. It binds name to an object holding the values of expr, one for each way facts satisfy c..., or to (obj) when none do. The rule fires again when that object changes, so a rule with a fact upsert keeps an aggregate fact up to date: (fact total (.order &o) > (.sum (+ *prices))). A name already visible fails with rule: already captured <name>.
    • Chance. (*chance* p key...) holds with probability p, drawn with a key made of the rule's name and the keys, or every visible capture when no key is written. A new seed draws every condition again. Unkeyed random and shuffle, and seed, fail in rule conditions with not allowed in a rule condition, as the fact and io- built-ins do.
    • Faster checks. run and run-prepare look at a fired activation or a tracked support again only when a change concerns it. A rule whose relations did not change costs nothing. rule-stats counts these looks as (.checked n).

    Interactive shell

    • A top-level set writes the value it binds (see Breaking changes).

    Command line

    • --seed <n> starts random draws from the seed n. Without an integer after it, it fails with tklips: --seed needs an integer.
    • When the program comes from a file, stdin is the stream 0 that programs read.

    JavaScript module

    • The open(path, mode) option opens resources for io-open, and the stdin(max) option gives what stream 0 reads. The defaults:
      • Node opens files inside the current directory, fetches URLs with allowUrl, and reads its standard input.
      • A browser fetches every path, relative to the page.
    • What a program writes to stream 2 goes to the stderr option.
    • The seed option starts random draws from a seed, and reset goes back to it.
    • reset forgets the program's constants.

    Python module

    • The open, stdin and seed options, as in the JavaScript module. Stream 2 goes to stderr, and reset forgets the program's constants.
    • Evaluations nested 100 deep through Python functions fail with stack overflow, as in the JavaScript module; they could fail with the engine failed instead.

    SHA-256

    5675c463b1b5f767d792533c3db1cbd98b674ce30e55ca0d812851a5f3ebe443  tklips-v0.5.0-linux-x86_64
    0b61bee6a797a3bf86f5376cd6db9093cfdf0d9d0e056e53f5e49bbbdb03beec  tklips-v0.5.0.mjs
    4113a781321a5c3dec57a91e1db2ddcdf256160c951a55278141cd4b8495560c  tklips-v0.5.0.py
    112d0534cb72828fcb478660a9acaf5da8d56afb144dfc96d8daf483e6dd85fc  tklips-v0.5.0-reference.pdf
    
    Downloads
  • v0.4.1 395375bef7

    tklips v0.4.1 Stable

    michael released this 2026-10-27 20:16:36 +00:00 | 14 commits to master since this release

    tklips v0.4.1: fixes to the codes and display of errors raised by JavaScript and Python functions. The language is unchanged otherwise, and the reference PDF is v0.4.0's, which documents it, except for the display described below.

    Breaking changes

    • An error with a code of its own from a JavaScript or Python function displays its code. An error that tklipsFail("not-found", "no user") or fail("not-found", "no user") raises in a function lookup now displays as not-found: lookup: no user, in the shell's error line and in the TklipsError's message, as every error with a code that is not built-in does; it displayed as lookup: no user before, and as not-found: lookup: no user only once a program raised it again with (fail &e). The error object's .message is still lookup: no user. Code that compares the message of such a TklipsError should expect the code first, or compare its code and .message instead.

    Language

    • js/error and py/error are built-in error codes, the codes of errors in JavaScript and Python functions that give none of their own: an error with either displays its message alone, also raised again with (fail &e). A Python function's error raised again displayed as py/error: <name>: <message> before.

    Python module

    • A Python function whose result has no tklips form, or that returns an awaitable in a synchronous Runtime, fails with the code py/error; it was js/error.

    SHA-256

    b19d321b364178612e71618daf5fa3bc7f002b5f9985b4258efa0add4a70e137  tklips-v0.4.1-linux-x86_64
    d20ec86769ab8ef1b97e5a84057116cd9659624ffd66dc2983958c4692ad7618  tklips-v0.4.1.mjs
    8e8b4b39802041770ca0c08f4d44a76fe9298f091431da45abc732514de5c6bf  tklips-v0.4.1.py
    8e1ce33859fee37252c55a4d075b31f17e27112a55a16be34b9be5b72e6ec95b  tklips-v0.4.1-reference.pdf
    
    Downloads
  • v0.4.0 2e3f9a5e88

    tklips v0.4.0 Stable

    michael released this 2026-10-25 22:58:17 +00:00 | 16 commits to master since this release

    tklips v0.4.0: interrupts and a stack limit, rule introspection, faster rules, and a new Python module beside the binary and the JavaScript module. The reference PDF documents the language as released.

    Breaking changes

    • Rule conditions are pure. In a rule's predicates and tests, and in the functions they call, the built-ins that read or change facts or rules fail with <name>: not allowed in a rule condition (code rule/condition): every fact- built-in, run, run-prepare, rule-agenda and rule. Write a condition on other facts as a pattern or a marked condition instead, such as (*none* (q)) in place of (*test* (= (fact-find q) (obj))). How often predicates and tests run is now unspecified, since their results may be reused while the facts they captured from are unchanged.
    • *persist* and *track* on a test fail with rule: misplaced marker <m>: they could change nothing. Drop the marker.
    • JavaScript module in Node: URLs need allowUrl: true. The default resolution refuses a URL other than a file: one with require: URLs need allowUrl, as the binary needs --allow-url. Pass createRuntime({ allowUrl: true }) to fetch them. In a browser, URLs stay allowed unless allowUrl is false.
    • Stdlib trust. A source is trusted as part of the standard library only when what follows the stdlib directory is a plain relative path: non-empty segments, none . or .., with no % and no \. An escaped path such as …/stdlib/%2e%2e/README.md is now an ordinary source, which needs --allow-url (or allowUrl) like any other URL. (require (std name)) is unaffected.

    Language

    • Interrupts. Ctrl-C, or rt.interrupt(), makes the evaluation fail at its next step with interrupted, code system/interrupt; a second one during an interrupted evaluation gives aborted, code system/abort. A catch takes a system/ error only when it names its code or system/, so a bare catch or recovery never swallows one; nothing catches system/abort.
    • Stack limit. An evaluation holds at most 200000 calls of functions, lambdas and run waiting for their result: one more fails with <name>: stack overflow, code limit/stack, which try handles like any other error.
    • Faster calls: a call resolves its function and checks its arguments once per call site, and a function's body finds its variables by slot.
    • Function and rule definitions that are replaced are released once nothing runs them any more.

    Rules

    • Introspection. rule-agenda lists the pending activations in firing order, changing nothing; rule-fired the activations each rule remembers having fired; rule-owned the facts tracked firings own; (rule-firing), in actions, the activation being fired; rule-stats per-rule counters (fired, tried, evaluated); (run-prepare) does what run does before choosing and says what it did. The first three take rule names and a .limit. An undefined rule name fails with <name>: unknown rule <v>, code unknown/rule.
    • Faster matching. Facts are indexed by relation and by joined value, and each rule keeps its pending activations, brought up to date from the facts changed since: a rule nothing changed for tries nothing. Which activations fire, and in which order, is unchanged.

    Interactive shell

    • Ctrl-C interrupts the form being evaluated, and the session goes on with the state it left.

    Command line

    • In batch mode, a system/ error that nothing handles ends the program, with exit status 130.
    • A URL's dot segments written with escaped dots (%2e) are removed like . and .., as browsers and the JavaScript module do.

    JavaScript module

    • rt.interrupt() interrupts every evaluation of the runtime, including one waiting for a JavaScript function's Promise, whose result is then ignored; evaluations let the event loop run every few tens of milliseconds. runProgram returns 130 when a system/ error ended it.
    • A TklipsError that a JavaScript function throws is raised again unchanged, with its code, message, data and trace, as (fail e) raises an error object.
    • Through JavaScript functions that call back into their runtime, evaluations nest at most 100 deep: one more fails with stack overflow.
    • The allowUrl option (see Breaking changes).

    Python module

    • New: tklips-v0.4.0.py, one Python file with the engine inside, for Python 3.10+ with pip install wasmtime (Linux, macOS and Windows). It has the JavaScript module's API in Python form: Runtime, whose methods run to their end, and AsyncRuntime, whose evaluating methods are coroutines and whose Python functions may be async.
    • Values: integers, floats, texts and None for _ convert as themselves; every tklips object is a TklipsObject, a dict with int keys for positions and str keys for names, whose to_list() gives the positions' values. Named arguments cross as keyword arguments both ways: rt.call("str-sub", "hello", end=2), and define(..., named=True) passes them as **kwargs.
    • Errors raise a TklipsError; a Python function's exception becomes <name>: <message>, code py/error unless it has a code, as fail(code, message, **data) gives it. rt.interrupt() works from any thread, and Ctrl-C during an evaluation of a Runtime is an interrupt, raised, if nothing catches it, as a TklipsInterrupt, also a KeyboardInterrupt. URLs are required only with allow_url=True.
    • Run as a script, python tklips-v0.4.0.py behaves as the binary does.

    Known issues

    • Python module: a Python function whose result has no tklips form, or that returns an awaitable in a synchronous Runtime, fails with the code js/error instead of py/error; and py/error is not yet a built-in code, so a caught Python error raised again with (fail &e) displays as py/error: <message>. Both will be fixed in the next release.

    SHA-256

    620a52797cd4be42914e260b30fdd2179f89fe35a27212079bc898712dd5b436  tklips-v0.4.0-linux-x86_64
    100f5ce7bc7e232ab8feb4514df67ab8b0dfb4f8cad0b881473a602a301dbc15  tklips-v0.4.0.mjs
    4dabfba44259b8230446c16855f36fde7be3cd71cc6dfac6878b22b5abf0da8b  tklips-v0.4.0.py
    8e1ce33859fee37252c55a4d075b31f17e27112a55a16be34b9be5b72e6ec95b  tklips-v0.4.0-reference.pdf
    
    Downloads
  • v0.3.0 3661d23321

    tklips v0.3.0 Stable

    michael released this 2026-10-23 16:50:32 +00:00 | 28 commits to master since this release

    tklips v0.3.0 splits programs into sources with a standard library, handles errors as values, names built-in arguments, and gives rules test conditions and simpler patterns; the JavaScript module becomes asynchronous. tklips-v0.3.0-reference.pdf documents the language as released.

    Breaking changes

    • Capture patterns (fact-match, fact-match-read, rule patterns) capture into bare names: write (person name (.age a)) instead of (person &name (.age &a)). .age alone is short for (.age age).
    • No literals in capture patterns: write (person .sex (= &sex M)) instead of (person (.sex M)). A number in a pattern now fails with invalid variable name, and a text is a capture, so an old pattern with text literals matches more facts.
    • Strict functions: a user function or lambda without a rest parameter rejects arguments it has no parameter for, with <f>: expected at most <n> arguments, got <m> and <f>: unknown named argument <name>. Add a rest parameter (*rest) to accept them.
    • New built-in names: require, std, fail, try, catch and recovery. A function of one of these names must be renamed.
    • Error messages and output: built-ins with parameter names report <f>: missing argument <param> and <f>: expected at most <n> arguments, where they reported expected <n> arguments; an error raised inside a function is followed by its trace lines; the shadowing warning writes capture a shadows a variable, without &.
    • JavaScript API: eval, call, apply, run, runProgram, and a session's feed and end return Promises: await them. define, undefine, reset and session() stay synchronous.

    Language

    • (require source) imports a source once, in the scope where it is written, running its forms without echo; errors in it are located as lib.tk:2:1.
    • The standard library, written in tklips: (require (std text)) imports the text library, with text-pad-left, text-pad-right, text-center, text-lines, text-wrap, text-capfirst and text-capwords. (std text v0.3.0) names the copy of a given release.
    • Errors are values with a code (type/not-text, unknown/function, arg/arity…), a message, data and a trace:
      • (fail code message (.name value)…) raises one, its named arguments as data, and (fail e) raises a caught one again;
      • (try expr… (catch e handler…) (catch (e code…) handler…)) handles them, a code ending with / taking a whole family;
      • (recovery value) in a block, a try or a rule's actions ends the rest of the body with value, or a function's result on the error, when an error comes after it.
    • An error nothing handles is written with the calls it went through: in f, called at 3:1.
    • Built-ins take their arguments by position or by name: (str-sub s (.end 3)), (reduce xs &+ (.init 10)), (partial map (.fn f)), (range 10 (.step 3)), (run (.limit 5)), and likewise str-find, str-replace, str-repeat, slice, chunk, repeat, sort, filter, count, any, all, find, find-pos, group-by, partition, for-each, log and atan. str-sub and slice start at 0 by default.

    Rules

    • (*test* expr…) holds when its expressions are true, with the captures of the conditions before it: to compare patterns, (rule bigger (p x) (q y) (*test* (> &x &y)) > …), as an alternative of *either*, or as what every match of *every* satisfies. It can be *persist* or *track*.
    • An error in a rule's test or action can be handled by recovery in its actions, which ends that firing and lets run go on, or by a try around run.

    Command line

    • tklips main.tk runs a program file instead of stdin; tklips -i main.tk runs it, then opens the shell.
    • --allow-url lets require fetch http:// and https:// sources with curl; files are read only inside the current directory.
    • --stdlib <location> takes the standard library from another directory or URL; a release reads its own tagged copy by default.

    JavaScript module

    • A JavaScript function may return a Promise: the evaluation waits for it where the call stands, and the function may call back into its runtime meanwhile.
    • createRuntime({ resolve, read, stdlib }) says where require finds sources and where the standard library is; by default, paths are URLs, and Node reads files of the current directory.
    • TklipsError has code, data, trace and source; tklipsFail(code, message, data) makes an error a JavaScript function can throw with a code.

    SHA-256

    0462340c083f37e115d12f74f00f7926468cafad99ad16a7adc6f48590a34249  tklips-v0.3.0-linux-x86_64
    b9b12f85d113c9640f1bb6adf7a2caa17d91648c991ad3ce4dd695d925ae4674  tklips-v0.3.0.mjs
    8da22559b355325af6ab84af4d20726346f51feb3b1845b275ec229a29068f15  tklips-v0.3.0-reference.pdf
    
    Downloads
  • v0.2.1 a630d66280

    tklips v0.2.1 Stable

    michael released this 2026-10-22 20:32:56 +00:00 | 36 commits to master since this release

    tklips v0.2.1 makes the engine faster and the Linux binary five times smaller, with the same language as v0.2.0. The attached reference PDF, unchanged from v0.2.0, documents the language as released.

    Language

    • Programs run about twice as fast, more on code that calls many functions: (fib 25) takes less than half the time it did, and so do sort with a comparator, map and filter with a function.
    • Calling a function that has a rest parameter, such as (func g *r &r), no longer leaks a value now and then: (mem) reports a steady live count over repeated calls.

    Command line

    • The Linux binary weighs 256 KB instead of 1.3 MB. It is still a single static executable with no dependency, now built against musl instead of glibc.

    JavaScript module

    • The module gets the same speedup, about 2.5 times faster on call-heavy programs.

    SHA-256

    e2dea262399acec6cfe64bf9c957b6c7250e3dea785b8724545685a30b1c7137  tklips-v0.2.1-linux-x86_64
    e295b218c4d92ac45a89c57366da84303b52d4ea6e60e96adb4c180f73722429  tklips-v0.2.1.mjs
    d184f6030d5fbcb2b480dd61f492fa75ccbbb5a73230a93cef8309b152c9fb68  tklips-v0.2.1-reference.pdf
    
    Downloads
  • v0.2.0 2cbcbc4391

    tklips v0.2.0 Stable

    michael released this 2026-10-22 19:24:05 +00:00 | 39 commits to master since this release

    tklips v0.2.0 grows the language with text, number and collection built-ins, gives rules an explicit firing order and fact tracking, and ships the engine as a JavaScript module. The language reference for this version is attached as a PDF.

    Breaking changes

    • % is now rem, with the same behavior: (% 7 3) becomes (rem 7 3). The new mod is the floored modulo, with the sign of the divisor.
    • attrs returns an object's attributes as an object, (obj (.x 1)), instead of a list of (obj (.name x) (.value 1)). Use keyvalues for a list of (obj name value) pairs, and keys or values for the names or values alone.
    • fact-set and fact-update are removed, and so is the keyed form of fact-add ((fact-add rel key... > update...)). Write (fact-change id update...) for (fact-set id > ...) and (fact-update id > ...), and (fact rel pattern... > update...) for (fact-set rel pattern... > ...).
    • A call whose head is &name now calls what name holds: (&f 1) used to fail with unknown function: &f.
    • Many new built-in names (listed below) can no longer be defined with func. A &name reference to one of them where no variable of that name is visible, such as &last or &min, now gives the built-in's function value instead of failing with unbound variable. Variables of those names keep working where they are visible.

    Language

    • Texts: str-len, str-sub, str-find, str-starts, str-ends, str-split (at a separator, into characters or at whitespace, with .max), str-join, str-upper, str-lower, str-trim, str-ltrim, str-rtrim, str-replace, str-repeat, str<, str>, str<=, str>= and str-cmp. They take texts only and count characters, not bytes. str turns any value into a text, and num reads a number back, giving _ when the text isn't one.
    • Kinds: kind names any value's kind (int, float, str, none, list, obj, func), and is-int, is-float, is-number, is-str, is-none, is-list, is-obj and is-func test for one.
    • Numbers: floor, ceil, round and trunc return integers; abs, min, max, mod, cmp; pow, exact on integers; sqrt, exp, log (with an optional base), sin, cos, tan, asin, acos, atan (with atan2), (pi) and (e). A result that isn't a real number fails with not a real number. nears compares two numbers to 10 decimal places, or .digits.
    • Collections, on an object's items, keeping their positions: filter (without a predicate, it removes the holes), reverse, slice, concat, flatten, partition, zip, chunk and numbered. Giving new lists: sort (stable, with a comparator or a .key), unique, group-by, range (integers or floats, with .inclusive) and repeat. Giving one value: reduce, find, find-pos, any, all, count, first and last.
    • Attributes: keys, values, keyvalues, from-keyvalues and merge. items and attrs split an object in two, and (obj *i *a) rebuilds it.
    • (. obj key...) follows a path of keys, giving _ as soon as an entry is missing or a value on the way isn't an object.
    • Functions: call, map, compose, pipe and partial. Wherever a function is expected, its name works too, and (&f args...) calls the function a variable holds.
    • pprint writes a value in an indented form, one entry per line.

    Facts

    • fact-add always adds a fact. fact-change changes the fact with a given id. fact is the upsert by pattern: with > update... it updates the one match or adds the pattern and updates it; without, it adds the pattern only when nothing matches, and returns the id either way.

    Rules

    • (*after* name...) and (*before* name...), written among a rule's conditions, put it after or before other rules whenever both have activations pending.
    • *track* on a condition, or (*track*) for every condition of a rule, makes a firing own the facts it creates: once a tracked condition stops holding, the next run removes them, as CLIPS does with logical.

    Interactive shell

    • A result holding nested objects prints one entry per line, indented. Batch mode keeps every result on one line.

    JavaScript module

    • New: tklips-v0.2.0.mjs, one ES module with the engine compiled to WebAssembly, for Node 18+ and browsers. createRuntime() gives independent runtimes with eval, call, apply, run, reset, runProgram and interactive sessions. Values convert both ways, and errors throw a TklipsError.
    • define makes JavaScript functions callable from tklips as built-ins, with named arguments if asked for; undefine removes one.

    SHA-256

    4e4619692df2f7ff1fcfaffacde23a17ce8a1f18e05c96804139ce22423a305d  tklips-v0.2.0-linux-x86_64
    d184f6030d5fbcb2b480dd61f492fa75ccbbb5a73230a93cef8309b152c9fb68  tklips-v0.2.0-reference.pdf
    97140e6b455dcf98538394a72ef68c95a271ac30a8604f3e44b675ab1082fe57  tklips-v0.2.0.mjs
    
    Downloads
  • v0.1.0 53e0b04516

    tklips v0.1.0 Stable

    michael released this 2026-10-20 07:32:46 +00:00 | 16 commits to master since this release

    First release of tklips, a CLIPS-inspired rule language, as a single statically linked binary for Linux x86_64. Run a program with ./tklips < program, or start the interactive shell with ./tklips (or ./tklips -i on piped input).

    Language

    • S-expression reader with texts, numbers, lists and objects; results are echoed in a canonical form.
    • Comments: # to the end of the line, and (# ...) forms.
    • Function calls with positional and named arguments ((.name value)), including names and positions taken from variables ((.&var value)).
    • Variables with set, get and &name. Scopes are globals, function bodies and rules.
    • User functions with func and lambda: default arguments, rest parameters (*rest) and spreads (*var). Functions are values, usable with for-each.
    • Control flow: if, while, block, and, or, not, equality and numeric comparisons. Every non-empty text is true, and truth results are 1 and 0.
    • Arithmetic with + - * / % on integers and floats, with errors on division by zero and overflow.
    • Objects: obj, lookup, put, delete, push, pop, insert, remove, len, attrs.
    • Output and text: print, join.
    • Values are shared with copy-on-write; mem counts allocated and live values.

    Facts

    • A fact store: each fact is a relation and an object body, with an implicit .id.
    • fact-add (optionally with a key, to add only when nothing matches), fact-set (an upsert by id or pattern), fact-update, fact-get, fact-del, fact-del-all.
    • Queries with fact-find, fact-match and their -read variants. Patterns match literals, capture slots with &name, filter with inline predicates and join on shared captures.

    Rules

    • rule and run. A rule fires once per combination of matching facts, and again when a captured value changes or its conditions stop holding and hold again.
    • Conditions: *none*, *some*, *every* and *either*. A condition marked *persist* never makes the rule fire again when it stops holding and holds again.
    • A rule's predicates and actions only see their own captures, not the caller's or global variables.

    Interactive shell

    • A REPL with tklips> and ...> prompts, line editing and history. It keeps going after errors; Ctrl-C drops the current form and Ctrl-D ends the session.

    SHA-256

    4dccb6077b6e822f9d1d323b9e4918da3f3943ff9e65f1fbca78140ae48aaa1a  tklips-v0.1.0-linux-x86_64
    
    Downloads