{"id":16200217,"url":"https://github.com/mobarski/morty","last_synced_at":"2026-02-09T11:34:19.422Z","repository":{"id":152846865,"uuid":"369916114","full_name":"mobarski/morty","owner":"mobarski","description":"Morty programming language, Morty virtual machine and MortyVM assembler","archived":false,"fork":false,"pushed_at":"2021-07-28T19:31:24.000Z","size":624,"stargazers_count":2,"open_issues_count":4,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-13T20:52:11.254Z","etag":null,"topics":["concatenative","language","stack-machine","virtual-machine"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mobarski.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":"2021-05-22T22:19:55.000Z","updated_at":"2022-04-10T03:23:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"b1798e3d-0ce9-48a7-9745-5bfdf6778dcf","html_url":"https://github.com/mobarski/morty","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/mobarski%2Fmorty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobarski%2Fmorty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobarski%2Fmorty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobarski%2Fmorty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mobarski","download_url":"https://codeload.github.com/mobarski/morty/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247713951,"owners_count":20983797,"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":["concatenative","language","stack-machine","virtual-machine"],"created_at":"2024-10-10T09:29:34.599Z","updated_at":"2026-02-09T11:34:19.373Z","avatar_url":"https://github.com/mobarski.png","language":"C","readme":"# Morty\n\nTODO\n\n## Status\n\nThis is pre-alpha work in progress!\n\nStatus:\n- C version of the VM is fully functional.\n- The assembler is fully functional BUT error detection and error reporting are very primitive.\n- Work on the compiler has just started.\n\nThe system is now able to compile VM ASM and to execute it.\nIt's ready for running experiments \"how feature X should be compiled and how it affects the performance\". \n\nFirst [benchmarks](benchmark.md) are looking good - VM requires ~5 CPU instructions per VM instruction.\n\n## Index\n\n- [language](#morty-programming-language)\n- [compiler](#morty-compiler)\n- [vm](#morty-vitual-machine)\n- [assembler](#morty-vm-assembler)\n- [references](#references)\n- [kanban](kanban.md)\n\n## Idea\n\nWhy:\n- permacomputing\n- internet of things\n- stack VM / concatenative language experimentation\n\nTarget usage:\n- simple game/utility dev (demakes, fantasy consoles/computers)\n- education\n- robotics\n- simple backend services\n\nDesign principles:\n- easy to implement (like Forth; close to the stack machine)\n- performant\n- easy to learn (like Go)\n- easy to read (like Python or Logo; captures intent -\u003e named arguments, dot properties, array notation, less symbols)\n\nTarget VM implementations:\n- C (most performant, portable with recompilation)\n- JS (portable, GUI)\n- Python (portable)\n- MicroPython (portable - microcontrolers)\n- Go (performant backend, portable with recompilation)\n- Swift (iOS)\n\n## Morty Philosophy\n\n1. Start from scratch.\n2. Add parts one by one observing how they interact.\n3. Remove parts that can be cheaply built using other parts.\n4. Keep parts that are expensive to build but make building other parts easier.\n5. A state should be achieved where removing any single part should have drastic consequences.\n6. This is the system's core.\n7. Now add parts that will make the system more friendly / usable / performant.\n8. Try to cover 80% of requirements with 20% of features.\n\n# Morty Programming Language\n\nMorty language is similar to Morty VM instruction set.\nAlmost all VM instructions can be used directly.\n\nIn addition the language provides some high-level mechanisms:\n- named local variables\n- explicit array access\n- data structures\n\n## Language Examples\n\n```\ndef fib (n--f) :n\n    n 2 lt then 1 ret do\n    n 2 sub fib (f2)\n    n 1 sub fib (f2 f1) add (f)\nend\n```\n\n```\ndef total-energy (m v h -- e) :h :v :m\n    m v kinetic-energy   (ek)\n    m h potential-energy (ek ep) add\nend\n\ndef kinetic_energy (m v -- e)\n    dup (m v v) mul mul\nend\n\ndef potential-energy (m h -- e)\n    g (m h g) mul mul\nend\n```\n\nThe Great Win32 Computer Language Shootout:\n- [Ackermann's Function](src/test/morty/acker.morty)\n- [Fibonacci Numbers](src/test/morty/fibo.morty)\n- [Nested Loops](src/test/morty/loops.morty)\n- [Random Number Generator](src/test/morty/random.morty)\n- [Sieve of Erathostenes](src/test/morty/sieve.morty)\n\nOther:\n- [Quicksort](src/test/morty/qsort.morty)\n- [Quicksort2](src/test/morty/qsort2.morty)\n\n## Comments\n\nMorty has three kinds of comments:\n- inline comments `code (some comment) code`\n- line comments `code # some comment`\n- multi-line comments:\n```\ncode (( this is\n        multi line\n        comment )) code\n```\n\n## Named local variables\n\nMorty allows capturing values into named local variables.\nTo capture a value prefix target variable name with a colon (ie :my-var).\nUse the variable name to push its value onto the stack.\n\n```\n( y = a*x*x + b*x + c )\n\ndef poly2 (x a b c -- y) :c :b :a :x (capture params)\n    x x mul a mul (axx)\n    x b mul (axx bx) add\n    c add\nend\n```\n\nLocal variables are stored on the return stack.\nOn function end or early return they will be automatically discarded.\n\n## Conditionals\n\nMorty supports only the simplest conditional statement:\n\n```forth\ndistance 10 or-less then collision-warning do\n```\n\nCase requires defining new function:\n\n```forth\ndef age-range (n--) :age\n    age 18 or-more  then adult         ret  do\n    age 13 or-more  then teen          ret  do\n    age  7 or-more  then gradeschooler ret  do\n    age  4 or-more  then preschooler   ret  do\n    age  1 or-more  then toddler       ret  do\n                         baby\nend\n```\n\nThe support for \"else\" might be added later.\n\n## Loops\n\nThere are two counted loop types and one indefinite type.\n\nCounted loops:\n```forth\n( loop 5 times from 0 to 4 )\n5 times\n    i dot\nloop\n\n( loop from 2 to 9 with step 1 )\n2 10 1 for\n    i dot\nloop\n```\n\nIndefinite loops:\n```forth\nbegin\n    beep\n    500 ms sleep\nloop\n```\n\nLoops are counted up.  \nIn every loop \"break\" and \"continue\" can be used.  \nMinimum number of loop executions is zero.  \n\n## Structures\n\nTODO\n\n```\nstruct point   .x .y   \nstruct circle  .r .x .y\n\ndef dist-to-circle (p c -- d) :c:circle :p:point \n    p.x c.x sub dup mul\n    p.y c.y sub dup mul\n    add sqrt               (distance to the center)\n    c.r sub\nend\n```\n\nStruct definition cannot be longer than 1 line.\nThis is on purpose to keep the structures simple.\nField names are prefixed with a dot to make them easier to grep and highlight.\n\n\n## Macros\n\nThere will be no macros in Morty.\n\n## Lambda functions\n\nTODO\n\n## Global variables\n\nTODO\n\n```\n{ 42 } $LAST\ndef gen-random (max--n)\n\tLAST get 3877 mul 29573 add 139968 mod LAST set\n\t(max) LAST get mul 139968 div (n)\nend\n```\n\n## Arrays\n\nTODO\n\n```\ndef .swap ( a x y -- ) :y :x :a\n\ta[x] .get (X)\n\ta[y] .get (X Y) a[x] .set\n\t(X) a[y] .set\nend\n```\n\n## Strings\n\nTODO\n\n# Morty Compiler\n\nTODO\n\n# Morty Vitual Machine\n\n## VM Architecture\n\nVM:\n- F - frame pointer\n- I - instruction pointer\n- R - return stack pointer\n- S - (data) stack pointer\n- T - top of stack register\n- H - heap pointer\n- G - globals pointer\n- MEM - main memory\n\n## Instruction encoding\n\nCurrent:\n- each cell is 32 bit long\n- instruction always occupy 2 cells:\n  - op code\n  - argument (zero for op codes that don't take arguments)\n\nOther encoding schemes that will be tested:\n- instructions occupy 1 cell (op without arg) or 2 cells (op + arg)\n- instruction in 1 cell, opcode in 8 bits, argument in 24 bits\n- instruction in 1 cell, opcode in 6 bits, argument in 26 bits\n- bytecode, instruction in 1, 2 or 5 cells\n\n## Instruction Set\n\nMorty VM instructions are divided into core instructions and extensions.\nOnly the core instruction set must be provided by the VM.\nThe rest can be assembled by the compiler from the core instructions.\nIf the extension instruction is available in the VM the compiler should use it for better performance.\nTranslation from the extended set into the core set is done via simple expansion (ie \"neg\" -\u003e \"0 swap sub\").\nTranslation from the core set into extended set is done by peephole optimization (ie \"0 swap sub\" -\u003e \"neg\").\n\n### branching\n\n| name    | effect     | morty     | core | info | \n| ------- | ---------- | --------- | ---- | ---- |\n| jz X    | (v--)      | jz @label | yes  | set I to X (next instruction cell) if v==0                              |\n| goto X  | (--)       |           | yes  | set I to X (next instruction cell)                                      |\n| call X  | (--)(=fr)  | x         | yes  | call procedure at X (next instruction cell)                             |\n| ret     | (fr*=)     |           | yes  | return from procedure call                                              |\n| qcall   | (a--)      | call      | ???  | quick call to address from the stack without changing the frame pointer |\n| qret    | (r=)       |           | ???  | quick return without changing the frame pointer                         |\n\n### stack manipulation\n\n| asm     | effect         | morty | core | info                                        | \n| ------- | -------------- | ----- | ---- | ------------------------------------------- |\n| push X  | (--x)          | x     | yes  | push X onto the stack                       |  \n| pusha X | (--x)          | x     | yes  | push X onto the stack (X is cell address)   |  \n| stor    | (a--)(=a)      | \u003eR    | yes  | pop top of data stack onto the return stack |\n| rtos    | (--a)(a=)      | R\u003e    | yes  | pop top of return stack onto data stack     |\n| rget X  | (--a)          |       | yes  | get loop variable X                         |\n| dup     | (a--aa)        |       | yes  | duplicate top item                          |\n| drop    | (a--)          |       | yes  | drop top item                               |\n| swap    | (ab--ba)       |       | yes  | swap two top items                          |\n| over    | (ab--aba)      |       | yes  |                                             |\n| rot     | (abc--bca)     |       | yes  | rotate three items                          |\n\n### memory access\n\n| asm    | effect     | morty | core | info | \n| ------ | ---------- | ----- | ---- | ---- | \n| get    | (a--b)     |       | yes  | get value from memory cell a     |\n| set    | (va--)     |       | yes  | set memory cell a to value v     |\n| allot  | (n--a)     |       | yes  | allot n cells on the heap and return address to the first allocated cell |\n| vget X | (--n)      | x     | yes  | get local variable X             |\n| vset X | (n--)      | :x    | yes  | set local variable X             |\n| gget X | (--n)      | x     | yes  | get global variable X            |\n| gset X | (n--)      | ???   | yes  | set global variable X            |\n| rget X | (--n)      |       | yes  | get loop variable X              |\n| geti X | (a--b)     | N/A   |      | get value from memory cell a+X   | \n| seti X | (va--)     | N/A   |      | set memory cell a+X to value v   | \n\n### primitive output\n\n| asm    | effect     | morty   | core | info                                             | \n| ------ | ---------- | ------- | ---- | ------------------------------------------------ |\n| emit   | (c--)      |         | ???  | print single character                           |\n| dot    | (n--)      |         |      | print number from top of the stack and one space |\n| echo   | (w--)      |         |      | print word from top of the stack                 |\n\nWord is a short text (0-6 characters) encoded as an integer value.\nWords are intended mainly for VMs without propper string support.\nEach letter in the word is encoded on 5 bits. Only uppercase letters are available, terminator and 5 selected characters (TBD).\n\n### debugging\n\n| asm     | effect     | morty   | core | info | \n| ------- | ---------- | ------- | ---- | ---- |\n| vminfo  | (--)       |         | ???  | print information about VM registers and show time in ms since last vminfo call or start of the program |\n\n\n### I/O - virtual devices\n\nI/O is handled via vectored execution (similar to ioctl, fcntl).\n\n| asm    | effect     | morty | core | info                                              | \n| ------ | ---------- | ----- | ---- | ------------------------------------------------- |\n| ioget  | (dk--v)    |       | yes  | get value (v) for the key (k) from the device (d) |\n| ioset  | (vdk--)    |       | yes  | set key (k) to value (v) on the device (d)        |\n\nTODO: name: set vs put\nTODO: name: io vs dev\nTODO: api:  dk vs kd\n\n### ALU - arithmetic\n\n| asm    | effect     | morty | core | info                 | \n| ------ | ---------- | ----- | ---- | -------------------- |\n| add    | (ab--c)    |       | yes  | a + b                |\n| sub    | (ab--c)    |       | yes  | a - b                |\n| mul    | (ab--c)    |       | yes  | a * b                |\n| div    | (ab--c)    |       | yes  | a / b                |\n| muldiv | (abc--d)   |       | ???  | a * b / c            |\n| mulshr | (abc--d)   |       | ???  | a * b \u003e\u003e d           |\n| mod    | (ab--c)    |       | yes  | a % b                |\n| neg    | (a--b)     |       | yes  | -a                   |\n| abs    | (a--b)     |       | yes  | -a if a\u003c0 else a     |\n\n### ALU - bits\n\n| asm    | effect     | morty | core | info                   | \n| ------ | ---------- | ----- | ---- | ---------------------- | \n| and    | (ab--c)    |       | yes  | a \u0026 b                  |\n| or     | (ab--c)    |       | yes  | a \\| b                 |\n| xor    | (ab--c)    |       | yes  | a ^ b                  |\n| inv    | (a--b)     |       | yes  | ~a  (binary inversion) |\n| shl    | (ab--c)    |       | yes  | a \u003c\u003c b                 |\n| shr    | (ab--c)    |       | yes  | a \u003e\u003e b                 |\n| ushr   | (ab--c)    |       |      | unsigned shift right |\n\n### ALU - comparators\n\n| asm    | effect     | morty   | core | info               | \n| ------ | ---------- | -----   | ---- | ------------------ | \n| nz     | (a--x)     | bool    | ???  | 1 if a!=0 else 0   |\n| eqz    | (a--x)     | 0=      | ???  | 1 if a==0 else 0   |\n| gtz    | (a--x)     | 0\u003e      | ???  | 1 if a\u003e0  else 0   |\n| ltz    | (a--x)     | 0\u003c      | ???  | 1 if a\u003c0  else 0   |\n|        |            |         |      |                    |\n| eq     | (ab--x)    | ==      | yes  | 1 if a == b else 0 |\n| ne     | (ab--x)    | !=      | yes  | 1 if a != b else 0 |\n| lt     | (ab--x)    | below   | yes  | 1 if a \u003c b  else 0 |\n| gt     | (ab--x)    | above   | yes  | 1 if a \u003e b  else 0 |\n| le     | (ab--x)    | or-less | yes  | 1 if a \u003c= b else 0 |\n| ge     | (ab--x)    | or-more | yes  | 1 if a \u003e= b else 0 |\n|        |            |         |      |                    |\n| xeq    | (ab--abx)  |         |      | 1 if a == b else 0 |\n| xne    | (ab--abx)  |         |      | 1 if a != b else 0 |\n| xle    | (ab--abx)  |         |      | 1 if a \u003c= b else 0 |\n| xge    | (ab--abx)  |         |      | 1 if a \u003e= b else 0 |\n| xlt    | (ab--abx)  |         |      | 1 if a \u003c b  else 0 |\n| xgt    | (ab--abx)  |         |      | 1 if a \u003e b  else 0 |\n|        |            |         |      |                    |\n| min    | (ab--x)    |         | yes  | a if a \u003c b  else b |\n| max    | (ab--x)    |         | yes  | a if a \u003e b  else b |\n| pick   | (abc--x)   |         | yes  | a if c != 0 else b |\n\n# Morty VM Assembler\n\n## Assembler\n\nTODO\n\nInstructions consist of operation (op) and argument (arg).\nAll instruction must contain op and arg separated by the dot (.).\nLabels end with the colon (:).\nLabel's addresses are referenced with the at (@) character.\n\nStack based labels:\n- @[ -\u003e push address on the stack, \n- @] -\u003e pop address from the stack, use it here, use current address there\n- ]: -\u003e pop address from the stack, use current address there\n\n```\n    goto.@start\n    inc:\n        push.1 add.0 ret.0\n    start:\n        push.2 call.@inc\n    halt.0\n```\n\n# References\n\n|                          Title | URL                                                            |\n| -----------------------------: | -------------------------------------------------------------- |\n|      **Generic stack machine** | https://users.ece.cmu.edu/~koopman/stack_computers/sec3_2.html |\n|  **The Pancake stack machine** | https://people.ece.cornell.edu/land/courses/ece5760/DE2/Stack_cpu.html | \n|             **Permacomputing** | http://viznut.fi/texts-en/permacomputing.html                  |\n|             **Starting Forth** | https://www.forth.com/starting-forth/                          |\n|             **P-code machine** | https://en.wikipedia.org/wiki/P-code_machine                   |\n|              **Stack machine** | https://en.wikipedia.org/wiki/Stack_machine                    |\n|             **Thinking Forth** | http://thinking-forth.sourceforge.net/thinking-forth-ans.pdf   |\n|                     **Fabris** | https://github.com/mobarski/fabris                             |\n|                    **UCBLogo** | https://en.wikipedia.org/wiki/UCBLogo                          |\n|                        **Uxn** | https://100r.co/site/uxn.html                                  |\n|              **Threaded code** | https://en.wikipedia.org/wiki/Threaded_code                    |\n|            **Forth threading** | http://www.complang.tuwien.ac.at/forth/threading/              |\n|        **Forth threaded code** | http://www.complang.tuwien.ac.at/forth/threaded-code.html      |\n|               **Interpreters** | http://realityforge.org/code/virtual-machines/2011/05/19/interpreters.html |\n|         **Cozy design spaces** | https://www.lexaloffle.com/bbs/?tid=31634                      |\n|              **Another World** | https://fabiensanglard.net/another_world_polygons/             |\n|                       **Mako** | https://github.com/JohnEarnest/Mako                            |\n|                 **Blacklight** | https://github.com/acook/blacklight/wiki                       |\n|                      **Quark** | https://github.com/henrystanley/Quark                          |\n|          **Array programming** | https://en.wikipedia.org/wiki/Array_programming                |\n|        **NGA virtual machine** | https://github.com/crcx/nga/blob/master/Nga.md                 |\n|       **Parable (mem slices)** | https://github.com/crcx/parable                                |\n|         **Vaporisation (mem)** | https://slightknack.dev/blog/vaporization/                     |\n|          **Custom Allocators** | https://slembcke.github.io/2020/10/12/CustomAllocators.html    |\n|           **Global optimizer** | https://www.researchgate.net/publication/213890050_A_portable_machine-independent_global_optimizer_-_design_and_measurements |\n\n\n[//]: # (online .md editor: https://markdown-editor.github.io/ )\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobarski%2Fmorty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmobarski%2Fmorty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobarski%2Fmorty/lists"}