{"id":21072201,"url":"https://github.com/xemul/cylang","last_synced_at":"2025-03-14T03:10:04.316Z","repository":{"id":70191662,"uuid":"109999578","full_name":"xemul/cylang","owner":"xemul","description":"Just for fun programming language","archived":false,"fork":false,"pushed_at":"2017-11-17T16:40:56.000Z","size":213,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-20T22:12:09.953Z","etag":null,"topics":["fun","language","programming"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xemul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-11-08T16:16:16.000Z","updated_at":"2023-02-09T00:11:22.000Z","dependencies_parsed_at":"2023-04-05T23:32:46.763Z","dependency_job_id":null,"html_url":"https://github.com/xemul/cylang","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/xemul%2Fcylang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xemul%2Fcylang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xemul%2Fcylang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xemul%2Fcylang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xemul","download_url":"https://codeload.github.com/xemul/cylang/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243515569,"owners_count":20303258,"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":["fun","language","programming"],"created_at":"2024-11-19T18:55:51.681Z","updated_at":"2025-03-14T03:10:04.291Z","avatar_url":"https://github.com/xemul.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"## CY -- a just for fun programming language\n\nThe project goal was to have some fun by implementing an interpreted\nprogramming language without a single keyWORD. All language-specific\ninstructions are symbols from the nowadays keyboard.\n\nTo simplify the syntax scanner, the program is considered to be a\nsequence of \"tokens\" separated with space, tab of a newline, when\nmet while scanning the program, each token is \"evaluated\". Some\ntokens are evaluated immediately into some value, some need one or\nmore further tokens (evaluated too). In simple words -- it's a\nprefix notation syntax.\n\nIf a token starts with a digit it's considered to be an integer.\n\nIf a token starts with a letter (any case) it's considered to be\na symbol. Symbols may include letters, digits, underbars and dots\ninside. No other characters are allowed.\n\nIf a token is `(` it's a list, if a token is `[` it's a map and if\na token is `{` it's a commands block. They start the respective set\n(or collection) and terminate at the next paired closing brace.\n\nOtherwise a token is considered to be a command.\n\nTwo exceptions are made in the space-separation rule above -- if\na token starts with a `\"` or `'` then it's considered to be a string\nconstant and the token ends with the next `\"` or `'` respectively. All\nspaces, tabs and even newlines are included in the string as is.\nNo backslashes are supported (yet), they are included in the string\nas is. The 2nd exception is token started with `#`. It's a comment\nand it terninates at the next `#` (not at the end of line).\n\nSome tokens may evaluate a boolean value or a special `NOVALUE` thing.\nThe latter is the default evaluation result for any token unless \nexplicitly documented.\n\nTokens may also result in a stream value, which represents an open\nfile, pipe, socket, etc.\n\nTo sum up -- a token can be an integer, a string, a symbol, define\nlist, map or a command block, be a stream, and NOVALUE or to be a\ncommand (or a comment, but these are ignored).\n\n### Numbers and strings\n\nThese are evaluated immediately into the respective value. Quotes for\nstrings are not included into it.\n\n### Lists\n\nList is evaluated by evaluating all the subsequent tokens untill the `)`\none, which denotes the end of the list. \"Subsequent evaluation\" literally\nmeans evaluation, e.g. the `( + 1 2 )` means a list of one element being\nthe sum of 1 and 2.\n\n### Maps\n\nMaps always use strings as keys and are evaluated by evaluating all the\nsubsequent tokens in pairs, considering the first one to be the string and\nthe second one to be any other token. The first one is thus a key and the\nsecond one is the vlaue.\n\nFor simplicity in describing and using objects the key may not be a string\ntoken (i.e. it may not start with `\"` or `'`), but can be a symbol without\ndots. In either case the key token is treated as just a string. IOW two next\ntokens mean the same\n\n    [ \"a\" 1 ]\n    [ a 1 ]\n\nMind the space before the final `]`, as the latter must be a separate token.\n\n### Command blocks\n\nLike lists, command block token grabs all the subsequent tokens until the `}`\none. Note, that it only grabs the tokens as is, without evaluating them. To\nevaluate the tokens in a command block you should pass control to it with\none of the commands described below.\n\n### Symbols\n\nSymbols are like variable names. They are always evaluated into the value they\nrefer to (except in a single case when a new symbol is declared). Symbols\ncan be considered to be pointers to other objects.\n\nCharacters `_` and `.` are special in a symbol name. If a symbol starts with a\n`_` it's one the service symbols. These are\n\n* `_` -- a cursor. This is a symbol that refers to the current element in the\nloop, map/filter and swap commands (see below)\n\n* `_-` and `_+` -- false and true constants respectively\n\n* `_?` -- a random number (unlimited, use the mod operation to trim it)\n\n* `__` -- current namespace (see below)\n\n* `_\u003c`, `_\u003e` and `_\u003e!` -- stdin, stdout and stderr streams respectively\n\nAn underbar anywhere inside symbol name is considered to be just the part of\nthe name.\n\nA dot (`.`) inside symbol is used to split a symbol name into pieces each\nof which is considered to be a key in the collection (list or map) that has\nbeen referenced by the previous part of the symbol. For example the symbol\n`a.b` means find the object named \"a\", then find an object named \"b\" in it,\nprovided `a` referred to a map.\n\nNote, that the value \"b\" is treated as the key value. If you want to treat\n\"b\" as another symbol that cotains the key value, you should use two dots as\nseparator. For example `a..b` means -- find the object \"a\", then find the\nsymbol \"b\", get what it refers to (it should be a string), then find in \"a\"\nthe value by the obtained string key.\n\nDot can follow a cursor, for example the symbol `_.a` means take the cursor\nobject, treat it as a map and find object \"a\" in it.\n\nFor lists the \"key\" is expected to be a number, for example `a.0` means \nfind list named \"a\" and get the 0th element from it. Respectively `a..b`\nmeans find list \"a\", then get what b refers to (should be a number) then\nget the b-th element.\n\nThere's also a separate `..` token that evaluates two next tokens and\neffectively results in referencing the `1st..2nd` value. IOW the\n`a..b` is equivalent to `.. a b` with the exception that `b` in the\n2nd case can be any evaluatable token.\n\nTo declare a new symbol there's a `=` command, find its description below.\n\n## Command tokens\n\nAs was said above, commands may need more subsequent tokens to be evaluated.\nHere's how.\n\n### Declaring a symbol\n\nToken `!` makes a new symbol. It takes a symbol token, and dereferences it all\nexcluding the traling component. The result should be a map. Then it evaluates \nthe next token and creates a new element in the map referenced by the 1st token\nwith the key being the trailing component of it and the value being the 2nd token.\n\nThe question is -- if all the symbols are created in some map, where would a\nsymbol without dots be created. The ansewer is -- there's an implicit root map,\nso if the symbol name doesn't have any dots in it the new entry is created in\nthis root map thus resulting in somehwat that looks like a global variable. \nFor example the `! x 1` makes a variable named \"x\" being a number 1. Respectively\n\n    ! x [ ]\n    ! x.a \"string\"\n\nmakes a new empty map named \"x\", then makes an entry with the key \"a\" in it being\na string with the value \"string\".\n\nSince all symbols start from the root map, it's possible to change this map into some\nother map. This is done with the `!!` command. It evaluates the next map token and\nsets it as the root one. All the service variables mentioned above remain accessible\nin any map, the `__` can be used to return back to the original namespace.\n\n### Arythmetics\n\nTokens: `+ - / * %`. Evaluate two more tokens. If the next tokens are numbers they \nare added, substracted, etc. The result is the number as well. Otherwise some magic\ncomes up.\n\n \\+ on two strings concatenates those and results in a new string\n \n \\+ on two lists splices them and results in a new list\n\n \\- on a list and a number removes the n-th element from the list\n \n \\- on a map and a string removes the respective key from the map\n\n### Boolean\n\nTokens: `\u0026 | ^ !`. All but `!` need two more boolean tokens, `!` needs one.\nDo what they are expected to and result in a boolean value. Note, that for\n`\u0026` and `|` both argument tokens ARE evaluated before doing the operation,\nit's not like \u0026\u0026 and || in C.\n\n### Lists\n\nTokens: `( ) (\u003c (\u003e (\u003c\u003e +( +) -( -)`. Tokens `(` and `)` mark the list\nstart and end respectively. Other tokens typically need at least one more \nlist token.\n\n`(\u003e`, `(\u003c` and `(\u003c\u003e` cut the list and result in a new one. Evaluate one list token\nand one (or two for the `\u003c\u003e` one) number(s). The resulting list is cut from head, \ntail or both respectively. Right index is included, left index is not. Rule of a\nthumb is `\u003e` results in the right (tail) part of the list and `\u003c` results in the\nleft (head) part of the list.\n\n`+(` and `+)` are push to head and push to tail respectively. Evaluate list token \nand one more one of any type, then add the latter value to the former list. The\nresult is NOVALUE, the 1st list token is modified in place.\n\nSimilarly `-(` and `-)` are pops from head or tail. Evaluate one list token and \nmodify it in place. Both result in whatever is poped from the list or in a NOVALUE \nif the list was empty.\n\n### Operations with strings\n\nTokens: `%% %~ %/ %^`. All evaluate one more token string to work on.\n\n`%%` results in a new formatted string. Formatting means scanning the argument\nstring and getting the `\\(...)` pieces from it. Each `...` piece is then\nconsidered to be a symbol which is dereferenced and instead of the whole `\\(...)` \nblock the string representation of it is inserted. E.g.\n\n    %% \"Hello, \\(name)!\"\n    \nwill dereference the \"name\" symbol and, if it's a string \"world\", will result in\na new string \"Hello, world!\"\n\n`%~` is the atio (or strtol) command. Results in a number value corresponding to\nthe argument string.\n\n`%/` splits the argument string using spaces and tabs as separator. The result is\na list of strings.\n\n`%^` and `%$` evaluates one more string and evaluate a boolean value meaning whether\nthe first argument respectively starts of ends with the second one.\n\n### Checks, if-s and loops\n\nCheck tokens: `= != \u003e \u003e= \u003c \u003c=`. Evaluate two more tokens of the same type, compare \nthem and retuls in a boolean value.\n\nIfs and loops tokens: `? ~`. All evaluate one or more command blocks and\nmay pass control to them. All typically result in NOVALUE, but if one of the\nreturn commands is met in the command block, the if/loop token is evaluated into\nits argument (see more details further).\n\nThe `?` evaluates next token. If it's a boolean value, then it's an if case,\nif it's a command block, then it's a select case.\n\nIn if case two more commabd block tokens are evaluated for then and else branches\nrespectively. One if them is then called depending on the 1st token value.\n\nIn the select case the evaluated argument is considered to consist of bool:block\npairs. The first boolean token evaluated into true value passes control to the\nrespective block token, then the whole `?` evaluation stops.\n\nLoop is `~`. It evaluates the next token. For a list or map it grabs one more token\nand calls this command block for each list element or for each map key. For command\nblock it calls one until any result (`:= :- :+`) even if novalue.\n\n### Printing\n\nTokens: `;` and `;;`. Evaluate next token and print it on the screen. The\nformer one accepts only strings and prints them as is, the latter one\naccepts any other token and prints it some string representation, e.g. strings\nare printed with quotes aound and new lines at the end.\n\n### Command blocks\n\nTokens: `{ } . : := :+ :-`. The `{` and `}` denote start and end of the command\nblock, token `.` is a shortcut for the `{ }` pair and means a no-op block (useful\nas `?` and `??` sub-blocks). Tokens `:`, `:=`, `:+` and `:-` switch between \nblocks.\n\nThe `:` one evaluates a command block token and a map token, sets the map as the \nnamespace, passes control to the command block, then restores the namespace back. \nIt's thus the way to do a function call with arguments. Using `__` namespace makes \nsmth like goto.\n\nThe `:=` is like return or break in C. It evaluates the next token, then completes\nexecution of the current command block and (!) makes the evaluated argument be the \nresult of evaluation of the token that caused the execution of this command block.\n\nE.g. the `: { := 1 }` makes the first `:` be evaluated into 1. The `? _+ { := 1 } .`\nmakes `?` be evaluated into 1, since it's `?` that caused execution of the block\nwith `:=`.\n\nThe `:+` token is used to propagate the \"return\" one more code block up. It evaluates\nthe next token, if it's a NOVALUE then the `:+` does nothing, otherwise it acts\nas `:=` stopping execution of current block and evaluating it's caller into the value.\n\nThe `:-` works the other way -- it stops execution of the current command block\nis the argument is NOVALUE, otherwise does nothing. The result of this token is\nalways NOVALUE.\n\n### Streams\n\nTokens: `\u003c~ \u003c~\u003e ~\u003e \u003c-\u003e -\u003e\u003e \u003c-\u003e\u003e` to open a stream and `\u003c\u003c \u003e\u003e` to read from and\nwrite to a stream.\n\nOpening tokens evaluate the string token and open the file by the string name.\nMode is r, r+, w, w+, a and a+ from fopen man page respectively. The result is\nstream value.\n\nReading from stream evaluates a stream token and a string token that shows what\nto read. Currently the following formats are supported:\n\n* \"ln\" results in string with a single line read from file (excluding the trailing\nnewline character).\n\n* \"b\", \"s\", \"i\" and \"l\" read 8, 16, 32 and 64-bit numbers respectively.\n\n### Miscelaneous\n\nTokens: `@ $ .| -. =. =^`.\n\nThe `@` evaluates a list token and one more token and checks whether the latter\none is present in the list. Results in a boolean value.\n\nThe `$` evaluates the next token, checks it to be list, map or string and results\nin a number value equal to the size of the argument.\n\nThe `.|` evaluates two next tokens. If the first one is NOVALUE, the it results\nin the 2nd value, otherwise results in the 1st value. It's token meaning is\nthe \"default value\".\n\nThe `-.` evaluates next token and results in NOVALUE if it's empty, i.e. a NOVALUE\nitself or false bool, zero number, empty string, list or map. Otherwise results\nin the mentioned token value. The token's meaning is \"novalue if empty\".\n\nThe `=.` token evaluates the next value and results in true if it's NOVALUE or\nfalse otherwise.\n\nThe `=^` token is re-declare one. It works like the `=` one, but unlike it, the\n`=^` results in the old value of the symbol being declared. If th symbol didn't\nexist before, the result is NOVALUE. When evaluating the velue for the new\nsymbol the cursor is available and points to the symbol's old value. E.g. the\n`= x =^ y + _ 1` is equivalent to C `x = y++`.\n\nThe \u003ccode\u003e`\u003c/code\u003e token is \"eval\" analogue. It gets the next string token\nand resolves and evaluates it's value one more time. E.g. the\n\n    ` \"+\" 1 2\n\nis the same as just `+ 1 2`.\n\n## Launching\n\nThe `cyvm` binary syntax is\n\n* `cyvm -c` prints the commands and their short meaning\n* `cyvm -r file.cy` runs the program in a file\n* `cyvm -t file.cy` prints the found tokens without evaluating them\n\nWhen running a program execution starts by evaluating the very first token. A special\nname `Args` is available in the root map and is the list of CLI arguments (including\nthe .cy file name).\n\nEach token has a location in the file in the `@line.number` format. The `-t` option\nprints tokens and their location. When an error in evaluation occurs the cyvm prints\nthe fauling token location and exits.\n\n## What else\n\nMemory management is absent. There's no explicit malloc/free commands, objects are\nallocated transparently and are not freed :) garbage collection, well, may come some\nday.\n\nError handling is not there yet. In some situations (e.g. out-of-bounds list access or\ngetting a missing key from the map) the result is NOVALUE, in all other cyvm just exits.\n\nDoing recursion looks clumsy, look at examples/qsort-rec.cy file's line\n\n    -\u003e split [ split split words b ]\n\nit does the recursive call, but to make the split function call itself it pushes its\nname into the namespace it will live in.\n\n## Command names\n\nCurrent set of commands is subject to change. The plan is to make some symbol reflect\nthe command type. E.g.\n\n* `?` for conditional ops (if, select)\n* `~` for loops of all kinds\n* `(` and `)` for lists\n* `[` and `]` for maps\n* `{` and `}` for command blocks\n* `%` for strings\n* `!` for errors (not there yet) (now used for declare)\n* `\u003c` and `\u003e` for streams\n* math and bool are very common and shouldn't change\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxemul%2Fcylang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxemul%2Fcylang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxemul%2Fcylang/lists"}