{"id":16521961,"url":"https://github.com/meshula/landru","last_synced_at":"2025-10-27T12:16:54.913Z","repository":{"id":9115666,"uuid":"10899814","full_name":"meshula/Landru","owner":"meshula","description":"Landru compiler and VM","archived":false,"fork":false,"pushed_at":"2021-01-26T08:22:39.000Z","size":1636,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-13T13:30:30.191Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/meshula.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}},"created_at":"2013-06-24T05:50:27.000Z","updated_at":"2020-05-03T00:28:49.000Z","dependencies_parsed_at":"2022-08-29T02:01:20.579Z","dependency_job_id":null,"html_url":"https://github.com/meshula/Landru","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/meshula%2FLandru","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meshula%2FLandru/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meshula%2FLandru/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meshula%2FLandru/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meshula","download_url":"https://codeload.github.com/meshula/Landru/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241596856,"owners_count":19988145,"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-11T16:58:53.509Z","updated_at":"2025-10-27T12:16:54.820Z","avatar_url":"https://github.com/meshula.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n**Landru** is a reactive state machine oriented **Forth** dialect.\n\n**Forth** is executed line by line as source is interpreted. **Landru** is compiled.\n\nComments are **C++** style.\n\n```\n// This is a comment.\n```\n\n**Landru** allows the import of modules using the *require* keyword.\n\n```\naudio = require(\"audio\")\ntime  = require(\"time\")\nio    = require(\"io\")\n```\n\n**Landru** has a number of standard libraries, including\n - io -- input and output\n - time -- time related utilities\n - int -- integer math\n - real -- real number math\n\nThere are some optional libraries as well, such as\n - audio\n\nThe fundamental execution unit is a *machine*. When machines are\nencountered in a Landru file, they are compiled. There is one special\nmachine, named *main*. It's special because it is executed automatically as\nsoon as the whole file is compiled.\n\n```\nmachine main:\n    // this machine is trivial\n;\n```\n\nAs in **Forth**, **Landru** language structures are declared, then surrounded\nwith a colon and semicolon. Here, *machine main* is pretty trivial.\n\nMachines are made up of declared persistent state, and states. There is one\nspecial state, named *main*. When a machine is started, the machine's state\nvariables are instantiated, and then *main* automatically runs.\n\n```\nmachine main:\n  declare: audio.Context audioContext;\n\n  state main:\n  ;\n;\n```\n\nWhitespace is not significant.\n\n```\n// The same program.\n\nmachine main:\n declare: audio.Context audioContext;\n state main: ;;\n```\n\n**Forth** uses a prefix notation where parameters are loaded up on a stack, then\na function is invoked. **Landru** also has a data stack, loaded up between\nparenthesis. Commas between arguments are optional. Functions are always\nexecuted on an object. There are no free functions.\n\n```\n  int.add(3 5)\n  int.add(3, 5)\n```\n\nA *machine* can launch another *machine*.\n\n```\nmachine pong:\n  state main: io.print(\"pong\") ;;\n\nmachine ping:\n  state main: io.print(\"ping\")\n              launch(\"pong\")   ;;\n```\n\nA *machine* can launch another instance of its own kind.\n\n```\nmachine recurse:\n   state main: launch(\"recurse\") ;;\n```\n\nThe *recurse* machine does not lock up the execution environment,\nbecause *lauch* instructions do not execute immediately. Instead, they are\nqueued, and run when a state yields.\n\nA *machine* retires when it has no pending state transitions. **Landru**\nexecution continues until all launched machines retire, or are otherwise\nterminated.\n\nA real *machine* will have more than one state. State transitions are invoked\nby the *goto* statement.\n\n```\nmachine pingpong:\n  state ping: io.print(\"ping\") goto pong ;\n  state pong: io.print(\"pong\") goto ping ;\n  state main: goto ping ;;\n```\n\nNotice that the statements executed by the state are bracketed by **Forth*'s\ncolon-semicolon scoping syntax.\n\nThe *pingpong machine* will print out ping and pong like crazy. (Not completely\ncrazy, gotos yield before they take affect.) Actor based\nlanguages are event driven, and **Landru** is no exception. **Landru** uses\nthe *on* keyword to indicate events that will be responded to.\n\nThe *time* standard library has an after event. The *pingpong machine* can be\nbrought under control by involving a timer.\n\n```\nmachine pingpong:\n  state ping: io.print(\"ping\")\n              on time.after(0.5): goto pong ;;\n  state pong: io.print(\"pong\")\n              on time.after(0.5): goto ping ;;\n  state main: goto ping ;;\n```\n\nThis *pingpong machine* will change state every half a second. Notice that\nthe *on* statement takes the form of *on condition* followed by the things to do\nenclosed in **Forth**'s typical colon semicolon scoping syntax.\n\nvariables\n---------\n\nVariables have a hierarchy of scopes.\n\nLocal variables are declared within a scope, and don't persist beyond it.\n\n```\nmachine localVar:\n  state main:\n    float a = 3\n    io.print(\"a is \", a);;\n```\n\nThe variable *a* won't be avalable outside of the state, and will be initialized\nto 3 every time the state is initialized.\n\n```\nmachine instanceVar:\n  declare: float b = 3;\n  state main:\n    io.print(\"b is \", b);;\n```\n\nWhen a machine of type *instanceVar* is launched, it will have its own copy of *b*,\ninitialized to 3. If a state modifies b, the new value is seen by any other states\nwithin that instatiated machine, but not by other machines of the same time.\n\n```\nmachine sharedInstanceVar:\n  declare: shared float c = 3;\n  state main:\n    io.print(\"c is \", c) ;;\n```\n\nWhen the first machine of type *sharedInstanceVar* is instantiated, *c* will be\nhave the value of 3. If *c* is modified, all other instances of *sharedInstanceVar*\nwill see that new value. When new instances are created, they will share the\nalready existing *c*. If all copies of *sharedInstanceVar* exit, *c* will also\ndisappear, meaning the next *sharedINstanceVar* object will reinitialize *c* with\nthe value 3.\n\n```\nrequire(\"test\")\nmachine requireVar:\n  state main:\n    io.print(\"test.d is \", d) ;;\n```\n\nIf the module test is known to have a value *d* in it, a machine can access it\nusing dotted scope syntax.\n\n```\ndeclare:\n  float e = 3 ;\n\nmachine globalVar:\n  state main:\n    io.print(\"global e is \", e) ;;\n```\n\nVariables declared in the global scope persist until all launched machines have\nexited and the script stops running.\n\nStates can have local variables.\n\n```\nmachine stateVar:\n    state main:\n      declare: int j = 5; ;\n    ;\n;\n```\n\nScoping rules are that the most local scope has precedence. So a local variable\nis preferred to machine variable (shared or instance), is preferred to a required\nmodule's variable or a global variable. If for some reason namespacing caused a\nglobal variable to have the same name as a module's variable, the module\nvariable hides the global variable.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeshula%2Flandru","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeshula%2Flandru","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeshula%2Flandru/lists"}