{"id":18523191,"url":"https://github.com/nrkn/yuki-js","last_synced_at":"2025-04-09T11:31:29.904Z","repository":{"id":57404738,"uuid":"177880368","full_name":"nrkn/yuki-js","owner":"nrkn","description":"A tiny subset of JavaScript with configurable constraints for creating fantasy consoles","archived":false,"fork":false,"pushed_at":"2019-04-22T22:21:17.000Z","size":317,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-24T05:13:17.642Z","etag":null,"topics":["compile-to-js","fantasy-computer","fantasy-console","gamedev","retro","retrocomputing","retrogaming"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nrkn.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}},"created_at":"2019-03-26T22:51:29.000Z","updated_at":"2024-04-16T14:33:14.000Z","dependencies_parsed_at":"2022-09-26T17:01:36.168Z","dependency_job_id":null,"html_url":"https://github.com/nrkn/yuki-js","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/nrkn%2Fyuki-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrkn%2Fyuki-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrkn%2Fyuki-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrkn%2Fyuki-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nrkn","download_url":"https://codeload.github.com/nrkn/yuki-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248031414,"owners_count":21036393,"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":["compile-to-js","fantasy-computer","fantasy-console","gamedev","retro","retrocomputing","retrogaming"],"created_at":"2024-11-06T17:34:31.757Z","updated_at":"2025-04-09T11:31:28.841Z","avatar_url":"https://github.com/nrkn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yuki-js\n\nA tiny subset of javascript allowing only numbers, arrays of numbers,\nsubroutines (not functions), configurable constraints and externally provided\nfunctions.\n\nIt is intended to be used by projects that want to allow limited user scripting\nwith various constraints around memory and etc, eg for a\n[fantasy console](https://itch.io/blog/5733/your-field-guide-to-fantasy-consoles)\nproject\n\n**This is an alpha release!**\n\n## install\n\n`npm install yuki-js`\n\n## example\n\nIn the [examples folder](./examples/channel-y) you will find Pong implemented in\nyuki-js, with constraints set up to mirror the\n[Fairchild Channel F](https://en.wikipedia.org/wiki/Fairchild_Channel_F):\n\n![pong](./examples/channel-y/screenshot.png)\n\nThe fantasy console is set up to only allow for 64 bytes worth of memory for variables to be declared, the program must find into 2048 bytes, 4 colors from a fixed palette of 8 per scanline, etc.\n\nPlayer 1 uses WASD, Player 2 uses arrow keys\n\nWhen a player wins a match their color will fill the screen, left or right\narrow keys to start a new match\n\n[Play it here](http://nrkn.com/yuki/channel-y)\n\n## compiling yuki-js programs\n\n[TypeScript Example](./src/build/build-examples.ts) |\n[JavaScript Example](./dist/build/build-examples.js)\n\n```js\nconst { compile } = require( 'yuki-js' )\n/*\nrequires an esprima-style AST - you can create one from source code\nusing the esprima package\n*/\nconst yukiAst = {\n  type: 'Program',\n  body: [\n    // statements here\n  ],\n  sourceType: 'module'\n}\n\n/*\nmain is an esprima-style AST - you can turn it back into source code\nusing the escodegen package\n*/\nconst { main } = compile( yukiAst )\n```\n\n### compile options\n\nPass an object as the second argument\n\n```ts\ninterface CompileOptions {\n  memorySize: number\n  maxProgramSize: number\n  instructionSize: number\n  lib: Program\n  requiredSubroutines: string[]\n}\n```\n\n`memorySize` is the maximum size in bytes that the user-declared variables\ncan use - any remaining memory is used for the call stack. Each function call\nwhen entered uses the amount of memory in bytes that would be required to\naddress the program (see `maxProgramSize` below), and frees that memory when\nexited\n\n`maxProgramSize` is the maximum size in bytes that the program can take up -\nthe program size is determined by walking the AST and counting each non-literal\nnode as `instructionSize` bytes, and each numeric literal as the smallest number\nof bits required to hold that value\n\n`instructionSize` the size in bytes that each instruction uses - used by\n`maxProgramSize`, see above\n\n`lib` is an esprima `Program` containing any external functions that the user\ncan call from their program - only top level functions in this program will\nbe available, not any of the variables etc.\n\n`requiredSubroutines` is a list of the function names that the user program is\nrequired to implement\n\nThe default options are:\n```ts\nexport const defaultCompileOptions: CompileOptions = {\n  memorySize: 1024,\n  maxProgramSize: 1024,\n  instructionSize: 1,\n  lib: {\n    type: 'Program',\n    body: [],\n    sourceType: 'script'\n  },\n  requiredSubroutines: []\n}\n```\n\n## writing yuki-js programs\n\n[Example Program](./examples/channel-y/src/game.yuki.js)\n\nPrograms are normal JavaScript, but all `const` and `let` statements must\nappear at the beginning of the program - `var` is not supported\n\nOnly boolean literals, number literals and array literals may be assigned\nto a `const`\n\n`let` statements declare the type, numbers are initialized to `0` and arrays\nare initialized to a fixed-length array of the specified length\n\nBecause this is a memory constrained system, a wider range of int and uint types\nthan usual are provided for ease of use.\n\nYou can specify any number of bits from 2-32 for a number:\n\n```js\nlet a = Uint5\nlet b = Int23\n```\n\nNumbers are initialized to `0`\n\nAn array is declared by providing a single argument for its length:\n\n```js\nlet values = Uint17( 10 )\n```\n\nArrays are filled with `0`\n\nAll numeric and logical operators are supported\n\nControl flow consists of `break`, `continue` and `if...else` statements\n\nFunctions are implemented as subroutines - they cannot be nested, take\nparameters, contain local variables or return anything, although the `return`\nstatement with no argument is allowed anywhere in the function body.\n\nIteration consists of `do...while`, `for` and `while` statements\n\nWhen assigning to a numeric variable or array index, the value provided is\ncoerced to an acceptable value using rules similar to `C`, eg out of range\nnumbers wrap around, signed and unsigned are converted as though they had the\nsame bit pattern etc\n\n```js\nconst a = 1\nconst b = 2\nconst c = [ 1, 2, 3 ]\nconst d = false\nconst e = [ true, false, true ]\n\nlet f = Uint8\nlet g = Int16\nlet h = Int16\nlet i = Int16( 3 )\nlet j = Bool\nlet length = Int16\nlet left = Int8\nlet right = Int8\nlet sum = Int8\n\nf = 10\ng = 5\nh = f + g\n\ni[ 0 ] = f\ni[ 1 ] = g\ni[ 2 ] = h\n\nj = d \u0026\u0026 e[ 0 ]\n\n/*\n  `size` is built in - member expressions other than array indexers are\n  not allowed, so you cannot do `g.length`\n*/\nlength = size( g )\n\nfunction add(){\n  sum = left + right\n}\n\nadd()\n\n// required by options\nfunction tick(){\n  f++\n}\n```\n## writing a lib for use from yuki-js\n\n[Example Lib](./examples/channel-y/src/lib.js)\n\nA lib can be used to provide IO, graphics, sound etc to yuki-js user programs\n\nOnly top-level `function` declarations will be available\n\nBy convention, anything that could be potentially overwritten by a user program\nshould be given a name starting with `$`, as identifiers in yuki-js may not\nstart with a `$`\n\n## design and features\n\nSupported JavaScript features were heavily restricted for ease of implementation\n\nI plan to extend the capabilities in future - some possible options:\n\n- variables declared anywhere\n  - assert memory constraints at runtime instead of compile time to support this\n  - this also means you will be able to use the `delete` operator to free memory\n- strings\n  - just arrays of bytes under the hood\n  - therefore no `+` concatentation etc\n- floats\n- simple (eg JSON-style) objects\n  - will just be syntactical sugar\n- proper functions, not just subroutines\n  - take parameters\n  - return any allowed type\n  - have scope\n  - a new type allowing `let` declaration to support first class functions\n - source maps\n\n## license\n\nMIT License\n\nCopyright (c) 2019 Nik Coughlin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnrkn%2Fyuki-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnrkn%2Fyuki-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnrkn%2Fyuki-js/lists"}