{"id":17482857,"url":"https://github.com/creationix/ujkl","last_synced_at":"2025-07-16T03:49:26.750Z","repository":{"id":66014282,"uuid":"56950680","full_name":"creationix/ujkl","owner":"creationix","description":"Micro Jack Lisp - For ESP8266 and Raspberry PI","archived":false,"fork":false,"pushed_at":"2016-06-01T04:19:04.000Z","size":74,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T04:14:36.765Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/creationix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-24T02:39:33.000Z","updated_at":"2024-02-03T19:48:24.000Z","dependencies_parsed_at":"2023-03-27T23:20:28.222Z","dependency_job_id":null,"html_url":"https://github.com/creationix/ujkl","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fujkl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fujkl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fujkl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fujkl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creationix","download_url":"https://codeload.github.com/creationix/ujkl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248145589,"owners_count":21055162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-18T23:46:16.053Z","updated_at":"2025-04-10T02:44:04.475Z","avatar_url":"https://github.com/creationix.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UJKL\n\nUJKL (will probably be renamed) is a small lisp interpreter aimed at IoT devices.\nMy main target will be raspberry PI computers and esp8266 chips.  The purpose is\nto enable children to design and program machines in the real world.\n\nWhile this is a lisp in syntax and semantics, it is not common lisp or scheme,\nmany conventions here are my own.\n\nCode is data and data is code.  This means that a function is nothing more than\na data list with special structure.\n\n**NOTICE** The code is not yet complete.  It currently has a working repl and\nsome of the documented APIs here, but I'm doing readme-driven-development and\ndesigning the language/apis before implementing them.  Feel free to comment on\nthe design or peruse the code patterns in general, but don't be surprised if\nthe code doesn't match the docs (or doesn't compile at all).\n\n## Value Types\n\nThere are very few primitives types in the runtime.  They are:\n\n- Integers - signed integers with 29 bits of capacity (-268435456 to 268435455)\n- True, False - useful for boolean operations\n- Nil - Represents the empty list usually\n- Symbol - An interned, immutable string.  Used for variable names and property\n  names mostly.\n- Native - Also a symbol, but instead of resolving to something in the local\n  environment, this points to a native C function.\n- Pair - This is the only data structure in the VM.  It is a container that can\n  reference exactly two values.\n- TypeError, RangeError, Undefined, etc... - result of a bad operation.\n\n## Value Conventions\n\n- List - A list is a chain of pairs with value on left and pointer to next node\n  on right.\n- Table - A table is a list where every value is a cons pair containing key and\n  value.  This is how local variables in the environments are implemented.\n- Function - A function is a list where the first value is a list of symbols\n  for the parameters, everything after that is the body.\n\n## Keywords:\n\nThese take the environment table as well as unevaluated arguments.  This means\nthey can alter the environment or choose to not evaluate certain arguments.\n\n### Local Variables / Environment\n\nHere `key` can be a list of keys or a single key. If it's a list, each value\nwill resolve using the result of the previous as the new table.\n\n- (get key) -\u003e value\n- (has key ...) -\u003e bool\n- (del key ...)\n- (set key value ...)\n- (def key (params...) body...) - define a function\n\n### Control Flow\n\n- (if condition block...)\n- (else-if condition block...)\n- (else block...)\n- (while condition block...)\n- (do block...)\n\n## Functions\n\nFunctions simply take a list of arguments (pre-evaluated) and return a value.\n\nA function can be a builtin or user-defined structure.  A user-defined function\nis an parameters list followed by the body.\n\n- (fn args...) - Call a function with args\n- (apply fn args...) - same thing, but exposing apply.\n\n### Cons Pair Operations\n\n- (car pair) -\u003e value - return left side of pair\n- (cdr pair) -\u003e value - return right side of pair\n- (set-car! pair value) -\u003e bool - modify pair in place\n- (set-cdr! pair value) -\u003e bool - modify pair in place\n\nThe following equivalents are in the C interface.\n\n```c\nvalue_t car(value_t pair);\nvalue_t cdr(value_t pair);\nbool set_car(value_t pair, value_t val);\nbool set_cdr(value_t pair, value_t val);\n```\n\n### List Operations\n\nA list is a singly-linked list of cons pairs where the data is on the left side\nand a reference to the next node is on the right.\n\n- (list? list) -\u003e boolean - each node is either a nil or a pair pointing to a node\n- (length? list) -\u003e number - length of list\n- (reverse list) -\u003e list\n- (sort list) -\u003e list - sort with default sorting\n- (sort list ((l r)...)-\u003erank) -\u003e list - sort a list with optional sort function\n\n- (concat list list...) -\u003e combined-list\n- (append! list value...) -\u003e list - add some values to end of list.\n\n- (iget list index) -\u003e value\n- (iset! list index value) -\u003e list\n\n- (has? set value) -\u003e boolean\n- (add! set value) -\u003e list\n- (remove! set value) -\u003e list\n\nIn the C interface for functions these are the equivalents\n\n```c\nbool is_list(value_t val);\nint list_length(value_t list);\nvalue_t list_reverse(value_t list);\nvalue_t list_sort(value_t list);\nvalue_t list_custom_sort(value_t list, value_t context, api_fn, sorter);\nvalue_t list_append(value_t list, value_t tail);\nvalue_t list_get(value_t set, int index);\nvalue_t list_set(value_t set, int index, value_t value);\nbool list_has(value_t list, value_t val);\nvalue_t list_add(value_t list, value_t val);\nvalue_t list_remove(value_t list, value_t val);\n```\n\n### Table Operations\n\n- in all these `key` can be a list of keys or a key\n\n- (table? tab) -\u003e boolean - a list of pairs\n- (t-get tab key) -\u003e value\n- (t-has tab key ...) -\u003e bool\n- (t-del! tab key ...) -\u003e tab\n- (t-set! tab key value ...) -\u003e tab\n\nThe following C functions are also available.\n\n```c\nbool is_table(value_t val);\nvalue_t table_get(value_t tab, value_t key);\nvalue_t table_aget(value_t tab, value_t keys);\nbool table_has(value_t tab, value_t key);\nbool table_ahas(value_t tab, value_t keys);\nvalue_t table_del(value_t tab, value_t key);\nvalue_t table_adel(value_t tab, value_t keys);\nvalue_t table_set(value_t tab, value_t key, value);\n```\n\n### Iterators\n\n- If iter is list, loop through each item\n- If iter is positive number, loop from 0 to number -1\n- if iter is negative number, loop from -number - 1 to 0\n\n- (each iter ((item)...)-\u003evalue) -\u003e last-value\n- (map iter ((item)...)-\u003evalue) -\u003e list\n- (filter iter ((item)...)-\u003eboolean) -\u003e list\n- (filter-map iter ((item)...)-\u003eboolean) -\u003e list\n\n```c\nvalue_t list_each(value_t list, value_t context, api_fn block);\nvalue_t list_map(value_t list, value_t context, api_fn block);\nvalue_t list_filter(value_t list, value_t context, api_fn block);\nvalue_t list_filter_map(value_t list, value_t context, api_fn block);\n```\n\n\n### Integer Math\n\n- (+ number...) -\u003e number - Add numbers\n- (* number...) -\u003e number - multiply numbers\n- (- a b) -\u003e number - subtract\n- (- a) -\u003e number - negate\n- (/ num dem) -\u003e number - divide\n- (% num mod) -\u003e number - modulus\n- (rand) -\u003e random integer using full precision\n- (rand mod) -\u003e random integer from 0 to mod - 1\n- (rand start stop) -\u003e random integer from start to stop inclusive\n\n```c\nvoid deadbeef_seed(int seed);\nint deadbeef_rand();\n```\n\n### Comparison\n\nValues must be of same type, numbers can compare with numbers, symbols compare\nalphabetically, pairs compare by contents recursively, left first, then right.\n\nIf types don't match, != will false, = will true, others type-error.\n\n- (\u003c a b ...) -\u003e bool - check if values on left are less than values on right\n- (\u003e a b ...) -\u003e bool - greater than\n- (\u003c= a b ...) -\u003e bool - greater than or equal\n- (\u003e= a b ...) -\u003e bool - greater than or equal\n- (!= a b) -\u003e bool - check if values are different\n- (= a b) -\u003e bool check if values are equal\n\n### Logic\n\nTruthyness is defined as:\n\n- true, numbers, symbols, pairs - all truthy\n- false, nil, undefined, etc - all falsy\n\n```c\nbool to_bool(value_t val);\n```\n\n- (and a b ...) -\u003e value - short circuit evaluation, return last value processed\n- (or a b ...) -\u003e value - same props as and\n- (xor a b) -\u003e value - returns false if values are both truthy, truthy value otherwise\n- (not a) -\u003e bool - negates\n\n### Console/Serial I/O\n\n- (print value...) dump values separated by spaces\n\n### PubSub Mesh Communication\n\nNodes can live within a network and communicate via pubsub system.\n\n- (net-put name data) - send data to all nodes with name\n- (net-get name) -\u003e data - Read data from queue, nil if empty\n- (net-when name ((data)...)) -\u003e handle - Setup listener callback\n- (net-stop handle) - remove listener\n\n### GPIO\n\nLow level access to digital GPOIs.  This is great for controlling LEDs and\nreading buttons.\n\n- (gpio-enable pin mode) - mode can be 'output, 'input, or 'input-pullup.\n- (gpio-write pin value) - value is boolean\n- (gpio-read pin) -\u003e value - value is boolean\n- (gpio-when pin ((value)...)) -\u003e handle - Register a callback for when a pin\n  changes value.\n- (gpio-stop handle) - remove listener\n\n### I2C\n\nThis allows writing drivers for I2C devices in the scripting language!\n\n- (i2c-init scl-pin sda-pin) - initialize pins for i2c\n- (i2c-write byte) -\u003e ack - low level write command\n- (i2c-read ack) -\u003e byte - low level read command\n- (i2c-start) - low level start command\n- (i2d-stop) - low level stop command\n- (i2c-slave-write addr bytes) -\u003e bool - high level write command\n- (i2c-slave-read addr data len) -\u003e bytes - high level read command\n\n### WS2812\n\nIf we can get away with it, this allows streaming of neopixel values.\n\nIf we are too slow then start and stop will need to be baked into just the list\ncommands.\n\n- (ws2812-seq-start)\n- (ws2812-seq-stop)\n- (ws2812-byte pin byte)\n- (ws2812-rgb pin color)\n- (ws2812-rgbw pin color)\n- (ws2812-rgb-list pin colors)\n- (ws2812-rgbw-list pin colors)\n\n### Tone\n\nGenerate a square wave by flipping a digital pin at a frequency.\n\n- (tone pin freq duration) - Play tone at frequency on pin for duration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fujkl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreationix%2Fujkl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fujkl/lists"}