{"id":16762411,"url":"https://github.com/tlack/xs-pink","last_synced_at":"2025-09-03T10:36:25.913Z","repository":{"id":145866013,"uuid":"141928646","full_name":"tlack/xs-pink","owner":"tlack","description":"tiny programming language experiment","archived":false,"fork":false,"pushed_at":"2018-09-12T20:49:09.000Z","size":341,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-09T12:56:50.574Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/tlack.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,"zenodo":null}},"created_at":"2018-07-22T20:33:06.000Z","updated_at":"2018-09-12T20:49:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"2318f259-7728-441b-8950-3e73beb18585","html_url":"https://github.com/tlack/xs-pink","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tlack/xs-pink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlack%2Fxs-pink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlack%2Fxs-pink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlack%2Fxs-pink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlack%2Fxs-pink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tlack","download_url":"https://codeload.github.com/tlack/xs-pink/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlack%2Fxs-pink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273431176,"owners_count":25104487,"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","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-13T04:44:41.722Z","updated_at":"2025-09-03T10:36:25.847Z","avatar_url":"https://github.com/tlack.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pink\n\nThis is an experimental programming language called `pink`. It is philosophically derivative of K/Q, XXL, and Forth. \n\nThere is a Javascript interpreter at present. The goal is to use this interpreter to produce semi-smart WebAssembly binaries.\n\n## status\n\n1/5.\n\nEverything herein subject to change or being broken.\n\nStill gotta do cond() and friends\n\n## goals\n\nThese may or may not have been achieved:\n\n* Easy for non-programmers to pick up. Existing programmers should find some familiar pieces.\n\n* Extremely uniform. As little to learn as possible. No \"special forms\" of syntax. Should be learnable\nwith a one-page cheat sheet.\n\n* Flexible and adaptable. Good concept of user-defined types and constructs to make them easy to work with.\n\n* All types use the same basic verbs. Even user defined ones.\n\n* Allow for symbolic, not imperative, logic. Inspired by aspects of Mathematica\n\tand Erlang, Pink allows for the expression of complex models of information\n\tand relationships. Pink's own parser is just a few lines.\n\n* Based on vectors and verbs that penetrate deeply into their arguments so you\n\tdon't have to write so many god damn explicit loops.\n\n## syntax, semantics\n\nPink is very simple. Here are all the rules:\n\nThere is no precedence or order of operations.\n\nThe space character is all that really matters. It's 100% whitespace agnostic otherwise.\n\nCode that can be executed, or functions in general parlance, are called often called verbs in Pink. \nAll functions (verbs) have one or two parameters, refered to as `x` and `y` inside source code.\n\nMost syntax that you see actually made up of regular verbs, and you can redefine them for your own user-defined types. \n(This even includes comments via `rem`, annoyingly.) \n\nYou can name a value (or verb) anything, including punctuation.\n\nThere are only five special cased characters in the Pink parser itself: expressions with `(`..`)`, strings with\n`\"` or `'` (which can be nested to any odd-numbered depth such as `\"hello\"` or `'''hello'''`), and the semicolon.\n\nTherefore, when referring to things, you should use spaces around every name, even operators, except for these specific\ncase:\n\n__Before or after any number or any of `( ) \" ' ;`.__\n\nIn cases like 'x y z', where x is a function taking two arguments, and y is a function taking two arguments, y wins.\n\nThat's it!\n\n### examples: Messing with values\n\n**Note:** \nIn these examples I'm going to include the Pink prompt and the results as well.\nOther examples may not include the prompt, and your prompt may look different.\n\n```\npink 0\u003e\n```\n\nAlso, the prompt shows things like Javascript values right now, not Pink\nvalues. Fix on the way.\n\nFirst, we generate the first five numbers (starting from 0):\n\n```\npink 0\u003e 5 til\n[0, 1, 2, 3, 4]\n```\n\nNow, we save it to a variable that we name:\n```\npink 1\u003e 5 til is \"numbers\"\n[0, 1, 2, 3, 4]\n```\n\n(If you're an adept programmer, you might note that the assignment statement\nalso returns its value, so that you can assign named values in the middle of an\nexpression without breaking your flow. I hate that in other languages!)\n\nLet's add them all up. `over` takes some code on the right, and performs it \"in\nbetween\" each value of the thing on the left.  Some other languages call this\n`reduce`. Since we already created the name \"numbers\", we don't have to use\nquotes anymore.  Unquoted names get replaced by their values, as you'd expect.\n\n```\npink 2\u003e numbers over 'x + y'\n10\n```\n\nHere we wrote our \"code to be executed\" as just a string. One of the things I'm\nexploring in Pink is encouraging the user of strings as code. (Code can also be\nverified, `parse`'d into a parse tree, and turned into an interpreting\nJavascript function using the `compile` verb.)\n\nLet's check out some more verbs that do stuff with our code. \n\n`each` applies your code (given in `y` again) for each item, and returns it.\n```\npink 3\u003e numbers each 'x + 20'\n[20, 21, 22, 23, 24]\n```\n(Note that `+` actually automatically accepts vectors for either argument, so we\nare only using it as a means of exposition here.)\n\nWhat if we didn't want to add 20? \n\n`eachleft` takes an array in x of two parts: the \"left\" values, and the \"right\"\nvalue (i.e., `( (1,2,3) :: 6 )`), and calls your code with each item in x[0]\nas `x`, and `x[1]` as `y`. We *glue* the vector together using `::` so they\ndon't get combined into one long vector.\n\n```\npink 4\u003e numbers :: 10 eachleft 'x + y'\n[10, 11, 12, 13, 14]\npink 5\u003e numbers :: 10 eachleft (+)\n[10, 11, 12, 13, 14]\n```\nAlso notice here that we used `(+)` to refer to the `+` verb without using a code\nstring. This only works when you enclose the function in a subexpression with\nthe parentheses.\n\n`eachright` does the same, but with the `y` parameter to your code varying, and\n`x` being fixed.\n```\npink 6\u003e 7 :: numbers eachright (+)\n[7, 8, 9, 10, 11]\n```\n\nDictionaries are a list of keys linked with a list of values.\n\nCreate them with `**key** dict **value**` or `key :\u003e value`.\n\nUse `len`, `key`, `value` to manipulate.\n\n```\npink 0\u003e \"name\" :\u003e \"Arca\",(\"age\" :\u003e 5) key\n[ \"name\", \"age\" ]\n```\n\nMore coming soon.\n\n### example: Static HTML web server\n\n```\n'PORT' \u003c- 8888;\n'ROOT' \u003c- './html/';\nROOT , 'layout.html' ## '$textfile' load -\u003e 'layout'; \n'emit \"serving request: \", x; layout' -\u003e 'handler';\n'./pink_lib_web.js' importas '$web'; \nhandler :: PORT ## '$web' -\u003e 'webserver';\nwebserver load;\n\"web server launched on on \" , PORT , \" in \" , ROOT emit;\n```\n\nNoteworthy in this sample:\n\n* We're using the short forms of Pink verbs here.\n* When you assign to a value to a variable, you specify its name as a string. \n* You can assign variables either as `x -\u003e y` with `y -\u003e 'x'`. You can also use `is` or `as`. \n* In Pink, code is written as simple strings. You are encouraged to go from a\n\tstring, to its parse tree representation and back and forth, load and restore\n\tit, etc.\n* `##` (or `make`) transforms values from one kind (type) to another. It's\n\tsimilar to a combination of `cast()` and parametized `new()` in other\n\tlanguages, because user defined types override `##` to create their own\n\tbehaviors around instantiation of that type.\n* The `$textfile` type has load overriden to return the contents of a filename.\n* `importas` loads the Javascript code named in `x` and exposes its interface\n\tas a user-defined type given in `y`. We use dollar signs when naming user\n\ttypes for clarity. (This `$` thing may be dropped in the future.)\n* The `pink_lib_web.js` module here defines a `load` verb that expects an x\n\tparameter consisting of the handler callback code and the address to bind the\n\tweb server on, so we build it:\n* So we combine `handler` and `PORT` using\n\tthe glue verb `::`, and then tag it as a `$web` type.\n* `::` (also known as `glue`) takes two un-alike things and puts\n\tthem together in a vector. If we were to use `,` (or `insert`), and\n\tthe types were the same, we would create one long vector, which\n\twould be chaos for `$web :: load`.\n* Also note that we picked that name `$web` when we imported it with `importas` -\n\tuser defined types do not have to know their own typename (when referred to\n\tin user code), which should avoid global conflicts. Maybe.\n* Once we have composed our 'webserver' -- using the handler and the port --\n\twe use `load` to launch it.\n\n# All verbs thus far\n\n### `x + y` \n(missing all the others - ha)\n\n### `x amend y` or `x !! y`\nModify `x` according to `y`:\n\n```\npink 0\u003e 5,6,7,8 amend ( 0,2 :: 10 )\n[10, 6, 10, 8]\npink 1\u003e 5,6,7,8 amend ( 0,2 :: (20,21) )\n[20, 6, 21, 8]\n```\n\n### `x arity`\nTell you the number of arguments that the code in string `x` requires, either 1 or 2.\n\n### `x as y` or `x \u003c- y`\nAssign the name x to value y in the current scope. Use parentheses around y if it is a\ncomplex expression.\n\n### `x case y` \n\nTest `x` according to cases in `y` formatted as `(pred1, result1, pred2, result2, .., elseresult)`\n\n```\npink 0\u003e 2 case (1,'one',2,'two',3,'three')\n'two'\n```\n\nTo evaluate custom code as a predicate in `y`, use `compile`.\n\n### `x compile`\nParse the code in string x and return function that, when invoked, will interpret it.\nThis is optional for most of the system iterator verbs like `each`, which know\nwhat to do when given a string.\n\n### `x deep y`\n\nFor deeply glued values in `x`, perform `y` on each of the individual values, but not on the\noverall vectors containing them.\n\nThe code string in `y` can use `x` to refer to the item being considered and\n`y` for its index in the overall data structure.\n\nAn example:\n\n```\npink 0\u003e 7,8,9 glue (1,2,3 glue (4,5,6)) deep 'x + 100'\nresult :\n[ [ 107, 108, 109 ], [ [ 101, 102, 103 ], [ 104, 105, 106 ] ] ]\n```\n\nA complex example that illustrates that difference between `deep` and `wide`, outputting json (with `make`) for clarity:\n```\npink 0\u003e 1,2,3 :: (4,5,6 :: (7, 8, 9)) -\u003e \"n\"\npink 1\u003e n deep 'x , 1' make '$json'\n{ '$json': '[[[1,1],[2,1],[3,1]],[[[4,1],[5,1],[6,1]],[[7,1],[8,1],[9,1]]]]' }\npink 2\u003e n wide 'x , 1' make '$json'\n{ '$json': '[[1,2,3,1],[[4,5,6,1],[7,8,9,1],1]]' }\n```\n\n### `x dict y` or `x :\u003e y` \n\nCreate a dictionary with one value: the key `x` linked with value `y`.\n\n### `x drop y`\n\nRemove the first y items from x. If y is negative, remove the last y items from x.\n\n```\npink 0\u003e 3,4,5,6 drop 2\n[ 5, 6 ]\npink 1\u003e 3,4,5,6 take 2\n[ 3, 4 ]\n```\n\n### `x each y`\n\nPerform the code string in `y` for each value in `x` individually.\n\n### `(x1::x2) eachboth y`\n\nPerform the code string in `y` for each of the pairs of values found in `x`.\n`x` should be a glue of two vectors of the same length. These will then become\n`x` and `y` parameters in the code string.\n\n```\npink 0\u003e 4,5,6 :: (10,20,30) eachboth (+)\n[ 14, 25, 36 ]\n```\n\n### `(x1::x2) eachleft y`\n\nPerform the code string in `y` with each item in `x[0]` as `x`, and `x[1]` as `y`.\n\n```\npink 0\u003e 4,5,6 :: 10 eachleft (+)\n[ 14, 15, 16]\n```\n\n### `(x1::x2) eachright y`\n\nPerform the code in string `y` with `x[0]` as x, and each value in `x[1]` as y.\n\n```\npink 0\u003e 50 :: (4,5,6) eachright (+)\n[ 54, 55, 56]\n```\n\n### `x emit` or `x ??`\n\nOutputs x to the debugging interface. Also returns value so you can continue expression.\n\n```\npink 0\u003e 123 emit + 456 \n123 \n579\n```\n\n### `x eq y` or `x == y`\n\nReturn true if x is exactly equal to y. Takes type tagging into account.\n\n### `x find y` \n\nReturn the index of `y` in `x`, or -1 if not found.\n\n```\npink 0\u003e 1,2,3 find 3\n2\npink 1\u003e 1,2,3,3 find 3\n2 \npink 2\u003e 1,2,3,3 find 4\n-1\n```\n\nTo get call indices of matches, use `where`. \n\n### `x get y` or `x @ y`\n\nIndex x with y. For instance:\n\n```\npink 0\u003e 5,6,7,8 get 2\n7\n```\n\nFor glued structures, you can use get to index deeply into elements with a vector as `y`:\n\n```\npink 0\u003e 1,2,3 :: (4,5,6 :: (7, 8, 9)) -\u003e \"n\"\npink 1\u003e n @ (1, 1, 2)\n9\n```\n\nFor dictionaries, `get` allows you to look up by key. (See also `dict`, `key` and `value`)\n\n```\npink 0\u003e \"city\" :\u003e \"Miami\",(\"temp\" :\u003e \"Awful\") @ \"city\"\n\"Miami\"\n```\n\n### `x importas y`\n\nLoad code library from file named in x, and give it the user-defined type y.\n\nThis is a WIP. See `pink_lib_web.js` for some hints.\n\n### `x interp y`\n\n### `x ins y` or `x , y`\n\nCombine x and y into one vector. If x and y are not of the same type, you should probably use\n`glue` (also known as `::`) - see below.\n\n### `x is y` or `x -\u003e y`\nAssign the name y to value x in the current scope.\n\n### `x len`\nReturn length of vector x. If it's a single value, the length is 1.\n\n### `x key`\nReturn the indices of x. If x is a dictionary, these are its keys. Use\n`x value` to get its corresponding values.\n\n### `x make y` or `x ## y`\nTransform x into type y. \n\n### `x glue y` or `x :: y`\nStick two unlike things together into one unit, which retaining the structure of both. The result is a vector, but it's a deeply structured one.\nThis is similar to making a linked list in other languages.\n\n### `x over y` \n\nPerform y between each of the values in x in sequence, returning final value. See also `scan`.\n\n```\npink 0\u003e 20,40,60 over (+)\n120\npink 1\u003e 20,40,60 scan (+)\n60,120\n```\n\n### `x parse`\nReturn Pink parse tree for code string in x. Use `interp` to run it.\n\n### `rem x` or `x rem`\nA comment.\n\n### `x scan y`\nPerform y over each of the values in x in sequence, accumulating and returning each of the return values.\n\n```\npink 0\u003e 20,40,60 over (+)\n120\npink 1\u003e 20,40,60 scan (+)\n60,120\n```\n\n### `x take y`\nReturn the first y items of x. If y is negative, return the last y items of x (but not backward).\n\n```\npink 0\u003e 3,4,5,6 take 2\n[ 3, 4 ]\npink 1\u003e 3,4,5,6 drop 2\n[ 5, 6 ]\n```\n\n### `x til`\nReturn the numbers 0, 1.. up to x-1.\n\n### `x type`\nReturn the type of x\n\n### `x wide y`\nFor deeply glued values in x, perform y on each of the individual vectors, but not the individual values themselves.\n\n```\npink 0\u003e 7,8,9 :: (1,2,3 glue (4,5,6)) wide 'x , 777'\n[ [ 7, 8, 9, 777 ],\n  [ [ 1, 2, 3, 777 ], [ 4, 5, 6, 777 ], 777 ] ]\n```\n\nA complex example that illustrates that difference between `deep` and `wide`, outputting json for clarity:\n\n```\npink 0\u003e 1,2,3 :: (4,5,6 :: (7, 8, 9)) -\u003e \"n\"\npink 1\u003e n deep 'x , 1' make '$json'\n{ '$json': '[[[1,1],[2,1],[3,1]],[[[4,1],[5,1],[6,1]],[[7,1],[8,1],[9,1]]]]' }\npink 2\u003e n wide 'x , 1' make '$json'\n{ '$json': '[[1,2,3,1],[[4,5,6,1],[7,8,9,1],1]]' }\n```\n\n### `x where y`\n\nFind all indices of x that contain exactly y. Returns an empty list if there are no matches.\n\n```\npink 0\u003e 1,2,3,1 where 1\n[0,3]\npink 1\u003e 1,2,3,1 where 2\n[1]\npink 2\u003e 1,2,3,1 where 4\n[]\n```\n\nSee also `find` which returns just the first index (and is thus faster).\n\n# TODO\n\nConditionals verbs, more forms of looping and recursion, integers, dates/times, better match()\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlack%2Fxs-pink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftlack%2Fxs-pink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlack%2Fxs-pink/lists"}