├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── as-pect.config.js ├── docs └── tutorial.md ├── jest.config.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── as-node │ ├── README.md │ ├── assembly │ │ └── bin │ │ │ └── echo.ts │ ├── bin │ │ ├── as-node │ │ └── as-node.ts │ ├── index.ts │ ├── package-lock.json │ ├── package.json │ ├── spec │ │ └── as-node.spec.ts │ └── src │ │ ├── exec.ts │ │ ├── index.ts │ │ └── tsconfig.json ├── ash │ ├── README.md │ ├── assembly │ │ ├── __tests__ │ │ │ ├── cat.spec.ts │ │ │ ├── echo.spec.ts │ │ │ ├── fixtures.ts │ │ │ ├── jsonfs.spec.ts │ │ │ └── simple_fs.ts │ │ ├── arg-as │ │ │ └── index.ts │ │ ├── bin │ │ │ ├── cat.ts │ │ │ ├── echo.ts │ │ │ ├── grep.ts │ │ │ └── mkdir.ts │ │ └── index.ts │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── index.ts │ └── webpack.config.js ├── assemblyscript │ ├── README.md │ ├── assembly │ │ ├── __tests__ │ │ │ ├── json.spec.ts │ │ │ ├── path.spec.ts │ │ │ ├── wasa.include.ts │ │ │ └── wasa.spec.ts │ │ ├── bin │ │ │ └── echo.ts │ │ ├── flag │ │ │ └── index.ts │ │ ├── gc.d.ts │ │ ├── index.ts │ │ ├── json │ │ │ ├── decoder.ts │ │ │ ├── encoder.ts │ │ │ └── index.ts │ │ ├── preamble.ts │ │ ├── std │ │ │ ├── allocator │ │ │ │ ├── arena.ts │ │ │ │ ├── buddy.ts │ │ │ │ ├── emscripten.ts │ │ │ │ ├── system.ts │ │ │ │ └── tlsf.ts │ │ │ ├── array.ts │ │ │ ├── arraybuffer.ts │ │ │ ├── bindings │ │ │ │ ├── Date.ts │ │ │ │ ├── Math.ts │ │ │ │ ├── wasi.ts │ │ │ │ └── wasi_unstable.ts │ │ │ ├── builtins.ts │ │ │ ├── collector │ │ │ │ └── itcm.ts │ │ │ ├── dataview.ts │ │ │ ├── date.ts │ │ │ ├── diagnostics.ts │ │ │ ├── env.ts │ │ │ ├── error.ts │ │ │ ├── gc.ts │ │ │ ├── internal │ │ │ │ ├── allocator.ts │ │ │ │ ├── arraybuffer.ts │ │ │ │ ├── hash.ts │ │ │ │ ├── memory.ts │ │ │ │ ├── number.ts │ │ │ │ ├── sort.ts │ │ │ │ ├── string.ts │ │ │ │ └── typedarray.ts │ │ │ ├── iterator.ts │ │ │ ├── map.ts │ │ │ ├── math.ts │ │ │ ├── memory.ts │ │ │ ├── number.ts │ │ │ ├── polyfills.ts │ │ │ ├── regexp.ts │ │ │ ├── set.ts │ │ │ ├── string.ts │ │ │ ├── symbol.ts │ │ │ ├── table.ts │ │ │ ├── tsconfig.json │ │ │ ├── typedarray.ts │ │ │ └── vector.ts │ │ ├── testclass.ts │ │ ├── wasa │ │ │ ├── index.ts │ │ │ └── mock │ │ │ │ ├── cmdline.ts │ │ │ │ ├── console.ts │ │ │ │ ├── date.ts │ │ │ │ ├── environ.ts │ │ │ │ ├── fs │ │ │ │ ├── directory.ts │ │ │ │ ├── file.ts │ │ │ │ ├── fs.ts │ │ │ │ ├── index.ts │ │ │ │ └── inode.ts │ │ │ │ ├── index.ts │ │ │ │ ├── path.ts │ │ │ │ ├── performance.ts │ │ │ │ ├── process.ts │ │ │ │ ├── random │ │ │ │ ├── index.ts │ │ │ │ └── xor.ts │ │ │ │ └── utils │ │ │ │ └── index.ts │ │ └── wasi │ │ │ └── index.ts │ ├── bin │ │ ├── wasmos-asc │ │ └── wasmos-asc.ts │ ├── index.ts │ ├── package-lock.json │ ├── package.json │ ├── spec │ │ └── compiler.spec.ts │ └── src │ │ ├── compiler │ │ └── compiler.ts │ │ ├── index.ts │ │ ├── linker.ts │ │ └── tsconfig.json ├── fs │ ├── README.md │ ├── assembly │ │ └── index.ts │ ├── index.ts │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── fs │ │ └── index.ts │ │ ├── glob.ts │ │ ├── index.ts │ │ ├── tsconfig.json │ │ └── wasi │ │ └── index.ts ├── kernel │ ├── README.md │ ├── assembly │ │ ├── __tests__ │ │ │ └── example.spec.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── process.ts │ │ └── screen.ts │ ├── index.ts │ ├── package-lock.json │ ├── package.json │ ├── spec │ │ ├── process.spec.ts │ │ ├── worker.spec.bk.ts │ │ └── worker.ts │ └── src │ │ ├── index.ts │ │ ├── process │ │ ├── index.ts │ │ ├── process.ts │ │ ├── utf8.ts │ │ └── wasm.ts │ │ ├── threading │ │ ├── actor.ts │ │ └── worker.ts │ │ ├── tsconfig.json │ │ └── wasi │ │ ├── index.ts │ │ ├── unstable.ts │ │ └── wasi.ts └── os │ ├── README.md │ ├── assembly │ └── index.ts │ ├── docs │ └── index.md │ ├── index.ts │ ├── package.json │ └── src │ ├── index.ts │ └── tsconfig.json ├── src ├── index.ts ├── loader │ ├── features.ts │ └── index.ts └── tsconfig.json ├── tsconfig.base.json ├── tsconfig.json ├── tsconfig.ts.json ├── tslint.json ├── types ├── as-pect │ └── index.d.ts ├── assembly │ └── index.d.ts ├── index.d.ts ├── package.json ├── tsconfig.json ├── wasa │ └── index.d.ts └── wasi │ └── index.d.ts ├── utils ├── README.md ├── bin │ ├── asdb │ └── ldev ├── index.ts ├── package.json └── src │ └── index.ts ├── webpack.config.js └── webpack.test.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | coverage/ 4 | 5 | packages/**/dist/ 6 | 7 | lerna-debug\.log 8 | 9 | **/.DS_Store 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "11" 4 | 5 | script: 6 | - npm run ci 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Attach to Remote", 11 | "address": "127.0.0.1", 12 | "port": 9229, 13 | "localRoot": "${workspaceFolder}", 14 | "remoteRoot": "Absolute path to the remote directory containing the program" 15 | }, 16 | { 17 | "type": "node", 18 | "request": "launch", 19 | "name": "Launch via NPM", 20 | "runtimeExecutable": "npm", 21 | "runtimeArgs": [ 22 | "run-script", 23 | "debug" 24 | ], 25 | "port": 9229 26 | }, 27 | { 28 | "type": "node", 29 | "request": "launch", 30 | "name": "AssemblyScript", 31 | "args": [ 32 | "${workspaceFolder}/packages/assemblyscript/bin/wasm-asc.ts", 33 | "echo.ts" 34 | ], 35 | "runtimeArgs": [ 36 | "-r", 37 | "ts-node/register", 38 | "--inspect-brk" 39 | ], 40 | "cwd": "${workspaceFolder}/packages/assemblyscript" 41 | }, 42 | { 43 | "type": "node", 44 | "request": "attach", 45 | "name": "Attach", 46 | "port": 9229 47 | }, 48 | { 49 | "name": "Jest debug AssemblyScript", 50 | "type": "node", 51 | "request": "launch", 52 | "address": "localhost", 53 | "protocol": "inspector", 54 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/lerna", 55 | "runtimeArgs": [ 56 | "exec", 57 | "--scope", 58 | "assemblyscript", 59 | "--", 60 | "node" 61 | ], 62 | "args": [ 63 | "${workspaceRoot}/node_modules/jest/bin/jest.js", 64 | "--runInBand", 65 | "--no-cache", 66 | "packages/assemblyscript" 67 | ] 68 | }, 69 | { 70 | "name": "Jest", 71 | "type": "node", 72 | "request": "launch", 73 | "runtimeExecutable": "node", 74 | "args": [ 75 | "${workspaceRoot}/node_modules/jest/bin/jest.js", 76 | "--", 77 | "--runInBand", 78 | "--no-cache", 79 | "${fileDirname}" 80 | ] 81 | }, 82 | ] 83 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "typescript.tsdk": "node_modules/typescript/lib" 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "install", 9 | "path": "packages/assemblyscript/", 10 | "problemMatcher": [] 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Citizen Code of Conduct 2 | 3 | ## 1. Purpose 4 | 5 | A primary goal of Wasmos is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). 6 | 7 | This code of conduct outlines our expectations for all those who participate in our community, as well as the consequences for unacceptable behavior. 8 | 9 | We invite all those who participate in Wasmos to help us create safe and positive experiences for everyone. 10 | 11 | ## 2. Open [Source/Culture/Tech] Citizenship 12 | 13 | A supplemental goal of this Code of Conduct is to increase open [source/culture/tech] citizenship by encouraging participants to recognize and strengthen the relationships between our actions and their effects on our community. 14 | 15 | Communities mirror the societies in which they exist and positive action is essential to counteract the many forms of inequality and abuses of power that exist in society. 16 | 17 | If you see someone who is making an extra effort to ensure our community is welcoming, friendly, and encourages all participants to contribute to the fullest extent, we want to know. 18 | 19 | ## 3. Expected Behavior 20 | 21 | The following behaviors are expected and requested of all community members: 22 | 23 | * Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. 24 | * Exercise consideration and respect in your speech and actions. 25 | * Attempt collaboration before conflict. 26 | * Refrain from demeaning, discriminatory, or harassing behavior and speech. 27 | * Be mindful of your surroundings and of your fellow participants. Alert community leaders if you notice a dangerous situation, someone in distress, or violations of this Code of Conduct, even if they seem inconsequential. 28 | * Remember that community event venues may be shared with members of the public; please be respectful to all patrons of these locations. 29 | 30 | ## 4. Unacceptable Behavior 31 | 32 | The following behaviors are considered harassment and are unacceptable within our community: 33 | 34 | * Violence, threats of violence or violent language directed against another person. 35 | * Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language. 36 | * Posting or displaying sexually explicit or violent material. 37 | * Posting or threatening to post other people's personally identifying information ("doxing"). 38 | * Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. 39 | * Inappropriate photography or recording. 40 | * Inappropriate physical contact. You should have someone's consent before touching them. 41 | * Unwelcome sexual attention. This includes, sexualized comments or jokes; inappropriate touching, groping, and unwelcomed sexual advances. 42 | * Deliberate intimidation, stalking or following (online or in person). 43 | * Advocating for, or encouraging, any of the above behavior. 44 | * Sustained disruption of community events, including talks and presentations. 45 | 46 | ## 5. Weapons Policy 47 | 48 | No weapons will be allowed at Wasmos events, community spaces, or in other spaces covered by the scope of this Code of Conduct. Weapons include but are not limited to guns, explosives (including fireworks), and large knives such as those used for hunting or display, as well as any other item used for the purpose of causing injury or harm to others. Anyone seen in possession of one of these items will be asked to leave immediately, and will only be allowed to return without the weapon. Community members are further expected to comply with all state and local laws on this matter. 49 | 50 | ## 6. Consequences of Unacceptable Behavior 51 | 52 | Unacceptable behavior from any community member, including sponsors and those with decision-making authority, will not be tolerated. 53 | 54 | Anyone asked to stop unacceptable behavior is expected to comply immediately. 55 | 56 | If a community member engages in unacceptable behavior, the community organizers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning (and without refund in the case of a paid event). 57 | 58 | ## 7. Reporting Guidelines 59 | 60 | If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community organizer as soon as possible. willem at cs.umd.edu. 61 | 62 | 63 | 64 | Additionally, community organizers are available to help community members engage with local law enforcement or to otherwise help those experiencing unacceptable behavior feel safe. In the context of in-person events, organizers will also provide escorts as desired by the person experiencing distress. 65 | 66 | ## 8. Addressing Grievances 67 | 68 | If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify WebAssemblyOS with a concise description of your grievance. Your grievance will be handled in accordance with our existing governing policies. 69 | 70 | 71 | 72 | ## 9. Scope 73 | 74 | We expect all community participants (contributors, paid or otherwise; sponsors; and other guests) to abide by this Code of Conduct in all community venues--online and in-person--as well as in all one-on-one communications pertaining to community business. 75 | 76 | This code of conduct and its related procedures also applies to unacceptable behavior occurring outside the scope of community activities when such behavior has the potential to adversely affect the safety and well-being of community members. 77 | 78 | ## 10. Contact info 79 | 80 | willem at cs.umd.edu 81 | 82 | ## 11. License and attribution 83 | 84 | The Citizen Code of Conduct is distributed by [Stumptown Syndicate](http://stumptownsyndicate.org) under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/). 85 | 86 | Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy). 87 | 88 | _Revision 2.3. Posted 6 March 2017._ 89 | 90 | _Revision 2.2. Posted 4 February 2016._ 91 | 92 | _Revision 2.1. Posted 23 June 2014._ 93 | 94 | _Revision 2.0, adopted by the [Stumptown Syndicate](http://stumptownsyndicate.org) board on 10 January 2013. Posted 17 March 2013._ 95 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 WebAssemblyOS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Wasm OS 2 | 3 | This is a kernel for running AssemblyScript/WebAssembly applications. 4 | 5 | It will provide: 6 | 7 | 1. Synchronous file system 8 | 1. Implements the node `process` module. 9 | 1. Shared Memory between kernel threads to allow for atomic `wait/notify` for syscalls. 10 | 1. Networking interface for P2P applications. 11 | 12 | ## Project Setup 13 | 14 | This project is [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lernajs.io/), which allows this repo to host multiple project in one repo, making it a "mono-repo." The key idea is that each package in the repo must be a stand alone, but it makes it easy to have them depend on each other and you can use a scoping package name. For example, this project needs a wrapper around the assemblyscript compiler, which is conveniently called `@wasmos/assemblyscript.` 15 | 16 | 17 | # First step 18 | 19 | After cloning, 20 | ``` 21 | npm install 22 | npm run ci # this bootstraps all packages and runs tests. 23 | ``` 24 | 25 | This installs all of the top level dependencies, e.g. `typescript` and `jest`, and then installs each lerna package. This includes creating symlinks for local dependencies. And then runs tests. 26 | 27 | Next head to [this tutorial](docs/tutorial.md) 28 | -------------------------------------------------------------------------------- /as-pect.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * A set of globs passed to the glob package that qualify typescript files for testing. 4 | */ 5 | include: [ 6 | "packages/*/assembly/__tests__/**/*.spec.ts" 7 | ], 8 | /** 9 | * A set of globs passed to the glob package that quality files to be added to each test. 10 | */ 11 | add: ["packages/assemblyscript/assembly/__tests__/wasa.include.ts"], 12 | /** 13 | * All the compiler flags needed for this test suite. Make sure that a binary file is output. 14 | */ 15 | flags: { 16 | "--validate": [], 17 | "--debug": [], 18 | /** This is required. Do not change this. */ 19 | "--binaryFile": ["output.wasm"] 20 | }, 21 | /** 22 | * A set of regexp that will disclude source files from testing. 23 | */ 24 | disclude: [/packages\/.*node_module/i], 25 | /** 26 | * Add your required AssemblyScript imports here. 27 | */ 28 | imports: {} 29 | /** 30 | * Add a custom reporter here if you want one 31 | */ 32 | // reporter: new CustomReporter(), 33 | }; 34 | -------------------------------------------------------------------------------- /docs/tutorial.md: -------------------------------------------------------------------------------- 1 | 2 | # Getting started 3 | 4 | After cloning your fork, you need to make sure that your fork's master is caught up with the main one. 5 | 6 | ## Adding remote branch 7 | 8 | Recall that by default when you clone your fork, when you run the following: 9 | 10 | ``` 11 | git remote -v 12 | ``` 13 | 14 | You should see somethnig like: 15 | 16 | ``` 17 | origin git@github.com:willemneal/wasmos (fetch) 18 | origin git@github.com:willemneal/wasmos (push) 19 | ``` 20 | 21 | To add the main repo as an upstream run: 22 | 23 | ``` 24 | git remote add upstream git@github.com:WebAssemblyOS/wasmos.git 25 | ``` 26 | 27 | Then you need to pull from it. From your master branch run: 28 | 29 | ``` 30 | git pull upstream master 31 | ``` 32 | 33 | If you get any errors you should either do a `git stash` and after pulling `git stash pop`, or `git reset --hard HEAD` to ensure that your local branch rolls back to the HEAD deleting all changes. If you choose this path, **please** do `git status` first to make sure that there are no files that you do want to keep. This is mainly if you have configuration files that would be overwritten by the update anyway. 34 | 35 | If you have fastforwarded to the new HEAD from the main repo, you should do `git push` so that your `origin` repo catches up too. 36 | 37 | ## Making a new branch 38 | For this tutorial, I'll be implementing `echo.ts`, which will be in the `packages/ash/assembly/bin` 39 | 40 | Now that you are caught up, you need to make a new branch for what task you are working on. If you haven't already pick one from [here](https://github.com/WebAssemblyOS/wasmos/issues/19) to work on and make an issue [here](https://github.com/WebAssemblyOS/wasmos/issues) that references the first issue, e.g. "see #19" this will create a link in #19 that points to the new issue, this way you can look at #19 to see which ones have been taken. 41 | 42 | Next: 43 | 44 | ``` 45 | git checkout -b dev-echo # this creates and switches to the new branch 46 | ``` 47 | 48 | then I create a `echo.ts` file. 49 | 50 | Even if it's empty let's add it to git. 51 | 52 | ``` 53 | git add packages/ash/assembly/bin/echo.ts ## This will be different for you. 54 | git commit -m "added empty file" 55 | git push origin dev-echo ## Again this will be different for you 56 | ``` 57 | 58 | 59 | Next write tests for echo. Copy `packages/ash/assembly/__tests__/echo.spec.ts` to a new file with the name of your program. 60 | 61 | Now go ahead and also commit and push this as well. 62 | 63 | ## Making a Pull Request 64 | Once you have your initial commit to your development branch you can open a pull request, which starts the process of merging this branch with in this case `wasmos/ash`. This doesn't mean that the branch has to completely ready for merge, just that you intend of merging it. It also allows others, like me, to look at it and even colloborate with you on it. 65 | 66 | To get started make sure your pushed your branch, then head over to your fork of the repo, "https://github.com/githubusername/wasmos" and you should see above the contents a green button that asks if you want to open a pull request with the new branch you made. If this is not the case then just head over to the [main repo](https://github.com/WebAssemblyOS/wasmos) and click on Pull Requests above the contents (not the very top). 67 | 68 | Next it will ask you which branch to merge with pick `wasmos/ash`. Give it the name of your program and in the comment section include `fixes #YourIssueNumber`, a handy drop down will help you find the right one after you type `#`. If there are any conflict errors it's okay to still create the pull request as once you make it I can help correct it. 69 | 70 | 71 | ## Running tests 72 | 73 | To test your AssemblyScript run `npx asp -f "filename regex"`, e.g. `npx asp -f echo` would run just `echo.spec.ts` or any test with echo in the name. If this doesn't work try running `npm clean-install`, which will make sure you're using the latest verson of the testing framework, `as-pect`. 74 | 75 | You can use `as-pect`'s build in print function using `log("hello world")`. It's very handy and can be used in your program. If you need to print something other than a string you have to provide the type, e.g. `log(42)`. 76 | 77 | ## Other things to know 78 | 79 | To access the file system there is a global named `fs`. 80 | 81 | `fs.openFile(path: string): fd` this returns a `WasiResult` , which either failed or contains the resulting file descriptor class. 82 | 83 | ```ts 84 | let res = fs.openFile("/hello"); 85 | if (res.failed){ 86 | Console.Error(result.error.toString()) //prints the error code 87 | return; 88 | } 89 | let file = res.result; //Now have access to the FileDescriptor 90 | 91 | ``` 92 | A FileDescriptor is a reference to a file and an offset. This means if you can have two FileDescriptor's open for the same file. Then each time you read or write to the file you move the offset or "seek". 93 | ```ts 94 | file.writeString("Hello World\n"); //Writes a line to the file, which moves the file offset 95 | 96 | file.reset() // uses file.seek to move file offset to 0. 97 | let line = file.readLine(); // Returns a WasiResult as the read could have fail, e.g. at end of file. 98 | let hello = line.result; //Access the string. 99 | ``` 100 | 101 | To see the complete interface look at [types/wasa/index.d.ts](https://github.com/WebAssemblyOS/wasmos/blob/master/types/wasa/index.d.ts). 102 | 103 | Your test can import a premade file descriptor for stdout, stderr, and stdin is `packages/ash/assembly/__tests__/fixtures.ts`. This is handy because when print to stdout using `Console.write` or `Console.log`, Console has it's own file descriptor which updates it's offset after each write, whereas `stdout` will still point to the beginning of the file. 104 | 105 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after the first failure 9 | // bail: false, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "C:\\Users\\jtenner\\AppData\\Local\\Temp\\jest", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | collectCoverage: true, 22 | collectCoverageFrom: ["src/terminal/**/*.ts"], 23 | 24 | // An array of glob patterns indicating a set of files for which coverage information should be collected 25 | // collectCoverageFrom: null, 26 | 27 | // The directory where Jest should output its coverage files 28 | coverageDirectory: "coverage", 29 | 30 | // An array of regexp pattern strings used to skip coverage collection 31 | // coveragePathIgnorePatterns: [ 32 | // "\\\\node_modules\\\\" 33 | // ], 34 | 35 | // A list of reporter names that Jest uses when writing coverage reports 36 | // coverageReporters: [ 37 | // "json", 38 | // "text", 39 | // "lcov", 40 | // "clover" 41 | // ], 42 | 43 | // An object that configures minimum threshold enforcement for coverage results 44 | // coverageThreshold: null, 45 | 46 | // Make calling deprecated APIs throw helpful error messages 47 | // errorOnDeprecated: false, 48 | 49 | // Force coverage collection from ignored files usin a array of glob patterns 50 | // forceCoverageMatch: [], 51 | 52 | // A path to a module which exports an async function that is triggered once before all test suites 53 | // globalSetup: null, 54 | 55 | // A path to a module which exports an async function that is triggered once after all test suites 56 | // globalTeardown: null, 57 | 58 | // A set of global variables that need to be available in all test environments 59 | globals: { 60 | "ts-jest": { 61 | tsConfig: "tsconfig.json", 62 | isolatedModules: true, 63 | diagnostics: { 64 | ignoreCodes: [2554] 65 | } 66 | } 67 | }, 68 | 69 | // An array of directory names to be searched recursively up from the requiring module's location 70 | // moduleDirectories: [ 71 | // "node_modules" 72 | // ], 73 | 74 | // An array of file extensions your modules use 75 | moduleFileExtensions: ["ts", "tsx", "js"], 76 | 77 | // A map from regular expressions to module names that allow to stub out resources with a single module 78 | // moduleNameMapper: {}, 79 | 80 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 81 | // modulePathIgnorePatterns: [], 82 | 83 | // Activates notifications for test results 84 | // notify: false, 85 | 86 | // An enum that specifies notification mode. Requires { notify: true } 87 | // notifyMode: "always", 88 | 89 | // A preset that is used as a base for Jest's configuration 90 | // preset: null, 91 | 92 | // Run tests from one or more projects 93 | // projects: null, 94 | 95 | // Use this configuration option to add custom reporters to Jest 96 | // reporters: undefined, 97 | 98 | // Automatically reset mock state between every test 99 | // resetMocks: false, 100 | 101 | // Reset the module registry before running each individual test 102 | // resetModules: false, 103 | 104 | // A path to a custom resolver 105 | // resolver: null, 106 | 107 | // Automatically restore mock state between every test 108 | // restoreMocks: false, 109 | 110 | // The root directory that Jest should scan for tests and modules within 111 | // rootDir: null, 112 | 113 | // A list of paths to directories that Jest should use to search for files in 114 | // roots: [ 115 | // "" 116 | // ], 117 | 118 | // Allows you to use a custom runner instead of Jest's default test runner 119 | // runner: "jest-runner", 120 | 121 | // The paths to modules that run some code to configure or set up the testing environment before each test 122 | setupFiles: ["ts-jest", "jsdom-worker"], 123 | 124 | // The path to a module that runs some code to configure or set up the testing framework before each test 125 | // setupTestFrameworkScriptFile: null, 126 | 127 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 128 | // snapshotSerializers: [], 129 | 130 | // The test environment that will be used for testing 131 | testEnvironment: "jest-environment-jsdom", 132 | 133 | // Options that will be passed to the testEnvironment 134 | // testEnvironmentOptions: {}, 135 | 136 | // Adds a location field to test results 137 | // testLocationInResults: false, 138 | 139 | // The glob patterns Jest uses to detect test files 140 | // testMatch: [ 141 | // "**/__tests__/**/?(*.)+.ts" 142 | // ], 143 | 144 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 145 | testPathIgnorePatterns: ["\\\\assembly\\\\", "__setup__"], 146 | 147 | // The regexp pattern Jest uses to detect test files 148 | testRegex: "spec/(.*)spec\\.ts", 149 | 150 | // This option allows the use of a custom results processor 151 | // testResultsProcessor: null, 152 | 153 | // This option allows use of a custom test runner 154 | // testRunner: "jasmine2", 155 | 156 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 157 | // testURL: "http://localhost", 158 | 159 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 160 | // timers: "real", 161 | 162 | // A map from regular expressions to paths to transformers 163 | transform: { 164 | "^.+\\.(ts|tsx)$": "ts-jest" 165 | } 166 | 167 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 168 | // transformIgnorePatterns: [ 169 | // "\\\\node_modules\\\\" 170 | // ], 171 | 172 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 173 | // unmockedModulePathPatterns: undefined, 174 | 175 | // Indicates whether each individual test should be reported during the run 176 | // verbose: null, 177 | 178 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 179 | // watchPathIgnorePatterns: [], 180 | 181 | // Whether to use watchman for file crawling 182 | // watchman: true, 183 | }; 184 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*", "packages/**/packages/*"], 3 | "version": "independent" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wasmos", 3 | "version": "0.0.1", 4 | "description": "A set of runtime tools for WebAssembly and AssemblyScript", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test:jest": "jest", 8 | "test:as": "asp --reporter=SummaryTestReporter", 9 | "asp": "asp", 10 | "test": "npm-run-all test:jest test:as", 11 | "check": "tsc -p tsconfig.ts.json --noEmit", 12 | "bootstrap": "lerna bootstrap && npm run linkDev", 13 | "clean": "lerna clean -y", 14 | "clean:soft": "lerna exec \"rm -rf node_modules/**/node_modules\" ", 15 | "linkDev": "lerna exec \"ldev\"", 16 | "ci": "npm-run-all clean bootstrap check ci:test test:as", 17 | "ci:test": "npm run test:jest -- -i || npm run test:jest -- -i" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/WebAssemblyOS/wasmos.git" 22 | }, 23 | "keywords": [ 24 | "WebAssembly", 25 | "AssemblyScript", 26 | "loader", 27 | "runtime" 28 | ], 29 | "author": "Willem Wyndham", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/WebAssemblyOS/wasmos/issues" 33 | }, 34 | "homepage": "https://github.com/WebAssemblyOS/wasmos#readme", 35 | "devDependencies": { 36 | "@types/assembly": "file:./types", 37 | "@types/fs-extra": "^5.0.5", 38 | "@types/node": "^11.9.5", 39 | "@types/webassembly-js-api": "0.0.2", 40 | "@wasmos/utils": "file:./utils", 41 | "as-pect": "github:jtenner/as-pect", 42 | "browserfs": "git:github.com/jvilk/browserfs", 43 | "dropbox": "~4.0.9", 44 | "jest": "^24.1.0", 45 | "jsdom-worker": "^0.1.0", 46 | "node-fetch": "^2.3.0", 47 | "npm-run-all": "^4.1.5", 48 | "ts-jest": "^24.0.2", 49 | "ts-loader": "^5.3.3", 50 | "ts-node": "^8.1.0", 51 | "typescript": "^3.4.2", 52 | "webpack": "^4.29.5", 53 | "webpack-cli": "^3.2.3", 54 | "webpack-dev-server": "^3.2.0" 55 | }, 56 | "dependencies": { 57 | "@types/filesystem": "0.0.28", 58 | "@types/jest": "^24.0.11", 59 | "@types/shelljs": "^0.8.4", 60 | "lerna": "^3.13.4", 61 | "shelljs": "^0.8.3", 62 | "shx": "^0.3.2" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/as-node/README.md: -------------------------------------------------------------------------------- 1 | # as-node 2 | 3 | This package is similar to [ts-node](https://github.com/TypeStrong/ts-node) and will allow you to execute assemblyscript files as you would a node file. 4 | -------------------------------------------------------------------------------- /packages/as-node/assembly/bin/echo.ts: -------------------------------------------------------------------------------- 1 | // import {_process, Process} from "../preamble"; 2 | // import { process } from "../process"; 3 | 4 | import { File } from "@wasmos/fs"; 5 | 6 | export const enum ExitStatus { 7 | EXIT_FAILURE = -1, 8 | EXIT_SUCCESS = 0 9 | } 10 | 11 | function _main(argv: string[]): ExitStatus { 12 | Console.log(argv.slice(1).join(" ")); 13 | 14 | return ExitStatus.EXIT_SUCCESS; 15 | } 16 | 17 | let f = new File(); 18 | // log(process.uid) 19 | // log(process); 20 | // log(process.argv[0]); 21 | // process.exitCode = _main(process.argv); 22 | -------------------------------------------------------------------------------- /packages/as-node/bin/as-node: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ts-node 2 | -------------------------------------------------------------------------------- /packages/as-node/bin/as-node.ts: -------------------------------------------------------------------------------- 1 | import { exec } from "../src"; 2 | // let opts = Compiler.opts; 3 | 4 | console.log(process.argv); 5 | debugger; 6 | exec(process.argv[2], process.argv.slice(3).join(" ")); 7 | -------------------------------------------------------------------------------- /packages/as-node/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src"; 2 | -------------------------------------------------------------------------------- /packages/as-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/as-node", 3 | "version": "0.0.2", 4 | "description": "Compiles and executes AssemblyScript files", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "echo test top level" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/as-node" 12 | }, 13 | "keywords": [ 14 | "AssemblyScript", 15 | "Kernel", 16 | "OS", 17 | "WebAssembly", 18 | "WebAssemblyOS" 19 | ], 20 | "author": "Willem Wyndham", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@wasmos/assemblyscript": "git:github.com/WebAssemblyOS/assemblyscript#v0.0.2", 24 | "@wasmos/kernel": "git:github.com/WebAssemblyOS/kernel#v0.0.2", 25 | "@wasmos/fs": "git:github.com/WebAssemblyOS/fs#v0.0.2", 26 | "@wasmos/wasa": "git:github.com/WebAssemblyOS/wasa" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/as-node/spec/as-node.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | import { exec } from ".."; 3 | import { fs } from "@wasmos/fs/src"; 4 | 5 | beforeAll(() => { 6 | process.chdir(__dirname + "/.."); 7 | }) 8 | 9 | describe("echo", () => { 10 | it("should compile", async () => { 11 | await exec("./assembly/bin/echo.ts", "hello world"); 12 | expect(await fs.pathExists('./dist/bin/echo/index.wasm')).toBe(true) 13 | }, 20000); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/as-node/src/exec.ts: -------------------------------------------------------------------------------- 1 | import { Process } from "@wasmos/kernel/src"; 2 | import { Compiler } from "@wasmos/assemblyscript/src"; 3 | 4 | import { fs } from "@wasmos/fs/src"; 5 | import * as path from "path"; 6 | 7 | export async function exec(filename: string, args?: string) { 8 | let opts = Compiler.opts; 9 | let name = path.basename(filename); 10 | let wasmPath = path.join(opts.outDir!, name, "index.wasm"); 11 | 12 | if (!(await fs.pathExists(wasmPath))) { 13 | await Compiler.compileOne(path.resolve(filename), { lib: false }); 14 | } 15 | // let _process = Process.exec([filename, args].join(" ")); 16 | // console.log(_process.stdout.join("\n")); 17 | } 18 | -------------------------------------------------------------------------------- /packages/as-node/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./exec"; 2 | -------------------------------------------------------------------------------- /packages/as-node/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.ts.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/ash/README.md: -------------------------------------------------------------------------------- 1 | # AS sHell 2 | 3 | This package provides the core shell utilities for working with wasmos. It uses [xterm.js](https://github.com/willemneal/xterm.js) for emulating a terminal in a browser context. 4 | -------------------------------------------------------------------------------- /packages/ash/assembly/__tests__/cat.spec.ts: -------------------------------------------------------------------------------- 1 | import { main as cat } from "../bin/cat"; 2 | import { stdout, Hello, World, Hello_World, stderr } from './fixtures'; 3 | 4 | 5 | describe("cat", (): void => { 6 | 7 | beforeEach((): void => { 8 | stdout.reset() 9 | Console.stdout.erase() //Erases and resets 10 | stderr.reset(); 11 | Console.stderr.erase() //Erases and resets 12 | CommandLine.reset(); 13 | CommandLine.push("cat"); 14 | }); 15 | 16 | it("should print newline by default", (): void => { 17 | CommandLine.push("/test") 18 | cat(CommandLine.all()) 19 | let str = Hello_World + "\n"; 20 | expect(Console.stdout.tell()).toBe(str.lengthUTF8 - 1, "String doesn't have a terminating NUL") 21 | fs.reset(Console.stdout.fd) 22 | expect(fs.readString(Console.stdout.fd).result).toBe(Hello + " " + World + "\n") 23 | Console.stdout.reset() 24 | expect(Console.stdout.readString().result).toBe(stdout.readString().result); 25 | }); 26 | 27 | it("should write to stderr if file not found", () => { 28 | CommandLine.push("/doesnotexist"); 29 | cat(CommandLine.all()) 30 | expect(Console.stderr.tell()).toBeGreaterThan(0); 31 | expect(stderr.readString().result).toStrictEqual("cat: /doesnotexist: No such file or directory\n") 32 | }); 33 | 34 | it("should write from multiple files", () => { 35 | CommandLine.push("/test") 36 | CommandLine.push("/numbers") 37 | cat(CommandLine.all()) 38 | expect(Console.stdout.tell()).toBeGreaterThan(Hello_World.lengthUTF8 - 1); 39 | }); 40 | 41 | }) 42 | -------------------------------------------------------------------------------- /packages/ash/assembly/__tests__/echo.spec.ts: -------------------------------------------------------------------------------- 1 | 2 | import { stdout, Hello, World, readString } from './fixtures'; 3 | import { main as echo } from "../bin/echo"; 4 | 5 | describe("echo", (): void => { 6 | 7 | beforeEach((): void => { 8 | stdout.reset(); 9 | Console.stdout.erase(); 10 | CommandLine.reset(); 11 | CommandLine.push("echo"); 12 | }) 13 | 14 | it("should print newline by default", (): void => { 15 | CommandLine.push(Hello) 16 | CommandLine.push(World) 17 | echo(CommandLine.all()) 18 | let str = Hello + " " + World + "\n"; 19 | let stdoutStr = readString(stdout) 20 | expect(Console.stdout.tell()).toBe(str.lengthUTF8 - 1, "No NUL character at the end of the string") 21 | Console.stdout.reset(); 22 | expect(readString(Console.stdout)).toBe(Hello + " " + World + "\n") 23 | Console.stdout.reset(); 24 | expect(readString(Console.stdout)).toBe(stdoutStr); 25 | }); 26 | 27 | it("should print no newline with -n", () => { 28 | CommandLine.push("-n") 29 | CommandLine.push(Hello) 30 | CommandLine.push(World) 31 | echo(CommandLine.all()) 32 | let str = Hello + " " + World; 33 | expect(Console.stdout.tell()).toBe(str.lengthUTF8 - 1, "No NUL character at the end of the string") 34 | Console.stdout.reset(); 35 | expect(Console.stdout.readString().result).toBe(str) 36 | Console.stdout.reset(); 37 | expect(Console.stdout.readString().result).toBe(stdout.readString().result); 38 | }); 39 | 40 | it("should print $PATH environment variable", () => { 41 | CommandLine.push("$PATH"); 42 | let path = "/usr/bin:/bin"; 43 | Environ.add("$PATH", path); 44 | echo(CommandLine.all()) 45 | expect(readString(stdout)).toBe(path + "\n") 46 | 47 | }); 48 | }) 49 | -------------------------------------------------------------------------------- /packages/ash/assembly/__tests__/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { Wasi } from '../../../assemblyscript/assembly/wasi'; 2 | import { JSON } from '../../../assemblyscript/assembly/json'; 3 | import * as path from '../../../assemblyscript/assembly/wasa/mock/path'; 4 | import { fs_str } from "./simple_fs"; 5 | 6 | export var stdin: FileDescriptor; 7 | export var stdout: FileDescriptor; 8 | export var stderr: FileDescriptor; 9 | 10 | beforeAll(() => { 11 | init(); 12 | }) 13 | 14 | 15 | export function init(): void { 16 | fs.init(); 17 | addJSONtoFS(fs_str); 18 | log("added FS") 19 | Console.stdout; 20 | Console.stdin; 21 | Console.stderr; 22 | stdin = openStdin(); 23 | stdout = openStdout(); 24 | stderr = openStderr(); 25 | 26 | } 27 | export function openStdin(): FileDescriptor { 28 | return openFile("/dev/fd/0"); 29 | } 30 | 31 | export function openStdout(): FileDescriptor { 32 | return openFile("/dev/fd/1"); 33 | } 34 | 35 | export function openStderr(): FileDescriptor { 36 | return openFile("/dev/fd/2"); 37 | } 38 | 39 | export function openFile(path: string): FileDescriptor { 40 | let FD = fs.openFile(path) 41 | if (FD.failed) { 42 | abort(Wasi.errno.toString(FD.error)); 43 | } 44 | return FD.result; 45 | } 46 | 47 | export function createFile(path: string): FileDescriptor { 48 | let FD = fs.createFile(path) 49 | if (FD.failed) { 50 | abort(Wasi.errno.toString(FD.error)); 51 | } 52 | return FD.result; 53 | } 54 | 55 | export function createDirectory(path: string): FileDescriptor { 56 | let FD = fs.createDirectory(path) 57 | if (FD.failed) { 58 | abort(Wasi.errno.toString(FD.error)); 59 | } 60 | return FD.result; 61 | } 62 | 63 | export function testFile(): FileDescriptor { 64 | let fd = createFile("/test"); 65 | fd.writeString(Hello_World); 66 | fd.reset(); 67 | return fd; 68 | } 69 | 70 | export function readString(FD: FileDescriptor): string { 71 | let res = FD.readString(); 72 | if (res.failed) { 73 | abort(Wasi.errno.toString(res.error)) 74 | } 75 | return res.result; 76 | } 77 | 78 | export function addJSONtoFS(str: string): void { 79 | let root = JSON.parse(str); 80 | toFS(root, "/") 81 | } 82 | 83 | function toFS(obj: JSON.Object, parent: string): void { 84 | let keys = obj.keys; 85 | for (let i: i32 = 0; i < keys.length; i++) { 86 | let val = obj.obj.get(keys[i]); 87 | let _path = path.join([parent, keys[i]]); 88 | if (val.isObject) { 89 | createDirectory(_path); 90 | toFS(val as JSON.Object, _path); 91 | } else if (val.isString) { 92 | let file = createFile(_path); 93 | file.writeString(val.val); 94 | } 95 | } 96 | 97 | } 98 | 99 | 100 | export const Hello = "Hello"; 101 | export const World = "World"; 102 | export const Hello_World = "Hello World"; 103 | 104 | -------------------------------------------------------------------------------- /packages/ash/assembly/__tests__/jsonfs.spec.ts: -------------------------------------------------------------------------------- 1 | import { fs } from '../../../assemblyscript/assembly/wasa/mock'; 2 | import { FileSystem } from '../../../assemblyscript/assembly/wasa/mock/fs'; 3 | import { addJSONtoFS, createFile } from './fixtures'; 4 | import { Wasi } from "../../../assemblyscript/assembly/wasi"; 5 | import { fs_str } from "./simple_fs"; 6 | 7 | describe("fs from JSON", (): void => { 8 | 9 | beforeEach(() => { 10 | fs.fs = new FileSystem(); 11 | fs.fs.init(); 12 | }); 13 | 14 | 15 | it("Should handle just a top level file", (): void => { 16 | let s = `{"hello": "world"}`; 17 | addJSONtoFS(s); 18 | expect(createFile("/hello").readString().result).toStrictEqual("world"); 19 | }); 20 | 21 | it("Should handle just a top level directory", (): void => { 22 | let s = `{"www": { "hello": "world"}}`; 23 | addJSONtoFS(s); 24 | expect(createFile("/www/hello").readString().result).toStrictEqual("world"); 25 | }); 26 | 27 | it("Should handle just a multi-level level directory", (): void => { 28 | let s = 29 | `{ "www": \ 30 | { "test": \ 31 | { "hello": "world"}\ 32 | }\ 33 | }`; 34 | addJSONtoFS(s); 35 | expect(createFile("/www/test/hello").readString().result).toStrictEqual("world"); 36 | }); 37 | 38 | it("should reset fs each time", () => { 39 | let res = fs.openFile("/hello"); 40 | expect(res.failed).toBe(true); 41 | expect(res.error).toBe(Wasi.errno.NOENT) 42 | }); 43 | 44 | it("should handle imported string", () => { 45 | addJSONtoFS(fs_str); 46 | expect(createFile("/home/bob/documents/secret.txt").readString().result).toStrictEqual("For my eyes only.\n No one else") 47 | }) 48 | }); -------------------------------------------------------------------------------- /packages/ash/assembly/__tests__/simple_fs.ts: -------------------------------------------------------------------------------- 1 | 2 | export const fs_str = `\ 3 | {\ 4 | "test": "Hello World",\ 5 | "home": {\ 6 | "bob": {\ 7 | "documents": {\ 8 | "secret.txt": "For my eyes only.\\n No one else",\ 9 | "homework.md": "My dog ate it"\ 10 | },\ 11 | "code": {\ 12 | "src": {\ 13 | "index.ts":"console.log('Hello World!');\\n"\ 14 | },\ 15 | "README.md": "I'm a fake project"\ 16 | }\ 17 | }\ 18 | },\ 19 | "numbers": "0\\n1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12\\n13\\n14\\n15\\n16\\n17\\n18\\n19"\ 20 | }\ 21 | ` -------------------------------------------------------------------------------- /packages/ash/assembly/arg-as/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is an argument parser. Given a string it will create an arguments 3 | * object to be used by programs. 4 | */ 5 | 6 | /** 7 | * Types of option arguments 8 | */ 9 | enum ArgType { 10 | /** A boolean flag*/ 11 | Flag = 0, 12 | /** String */ 13 | String = 1, 14 | /** 32bit integer */ 15 | Int = 2, 16 | /** 32bit float */ 17 | Float = 3 18 | } 19 | 20 | type Value = i32; 21 | 22 | class Argument { 23 | constructor(public value: T) {} 24 | } 25 | 26 | class Option { 27 | private _value: string | null = null; 28 | constructor( 29 | public name: string, 30 | public type: ArgType, 31 | public desc: string, 32 | public optional: bool 33 | ) {} 34 | /** 35 | * Parsed options set the corresponding value. 36 | */ 37 | set value(val: string | null) { 38 | this._value = val; 39 | } 40 | 41 | get value(): string | null { 42 | return this._value; 43 | } 44 | 45 | parseInt(): i32 { 46 | return parseI32(this.value!); 47 | } 48 | 49 | parseFloat(): i32 { 50 | return parseFloat(this.value!); 51 | } 52 | 53 | parseBool(): bool { 54 | return this.value != null; 55 | } 56 | } 57 | 58 | export class Argas { 59 | desc: string; 60 | options: Map; 61 | optionNames: Array; 62 | input: Array; 63 | command: string; 64 | 65 | constructor(desc: string) { 66 | this.options = new Map(); 67 | this.input = new Array(); 68 | this.optionNames = new Array(); 69 | this.desc = desc; 70 | } 71 | 72 | /** 73 | * Used to add available options to print and to parse 74 | */ 75 | addOption( 76 | name: string, 77 | type: ArgType, 78 | desc: string, 79 | _shortName: string = "", 80 | optional: boolean = false 81 | ): void { 82 | this.optionNames.push(name); 83 | let shortName = _shortName ? _shortName : name.charAt(0); 84 | let option = new Option(name, type, desc, optional); 85 | this.options.set(name, option); 86 | this.options.set(shortName, option); 87 | } 88 | 89 | parse(args: string): void { 90 | let argv: string[] = args.split(" "); 91 | this.command = argv[0]; 92 | let i: i32 = 1; 93 | while (i < argv.length) { 94 | if (argv[i].startsWith("-")) { 95 | if (argv[i].startsWith("--")) { 96 | let option = this.options.get(argv[i].substr(2)); 97 | if (option.type == ArgType.Flag) { 98 | option.value = ""; 99 | } else { 100 | i++; 101 | if (i == argv.length || argv[i].startsWith("--")) { 102 | abort("Missing argument after " + option.name); 103 | } else { 104 | let val: string = argv[i]; 105 | switch (option.type) { 106 | case ArgType.Int: 107 | case ArgType.Float: 108 | case ArgType.String: { 109 | break; 110 | } 111 | default: { 112 | abort("Argument Type does not exist"); 113 | } 114 | } 115 | option.value = val; 116 | } 117 | } 118 | } else { 119 | if (argv[i].length > 2) { 120 | for (let j = 1; j < argv[1].length; j++) { 121 | let opt = this.options.get(argv[i].charAt(j)); 122 | if (opt.type != ArgType.Flag) { 123 | abort("can't combine flag options with non-flag options"); 124 | } 125 | } 126 | } 127 | } 128 | } else { 129 | this.input.push(argv[i]); 130 | } 131 | i++; 132 | } 133 | } 134 | 135 | /** 136 | * When --help or -h is passed print out the options. 137 | */ 138 | toString(): string { 139 | let descs = new Array(); 140 | descs.push(""); 141 | descs.push("SYNTAX"); 142 | descs.push("\t" + this.desc); 143 | descs.push(""); 144 | descs.push("OPTIONS"); 145 | for (let i = 0; i < this.optionNames.length; i++) { 146 | let option = this.options.get(this.optionNames[i]); 147 | descs.push("\t--" + option.name + "\t\t" + option.desc); 148 | } 149 | return descs.join("\n"); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /packages/ash/assembly/bin/cat.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export function main(args: string[]): void { 4 | if (args.length > 1) { 5 | for (let i: i32 = 1; i < args.length; i++) { 6 | let file = fs.openFile(args[i]); 7 | if (file.failed) { 8 | Console.error("cat: " + args[i] + ": No such file or directory"); 9 | continue; 10 | } 11 | Console.log(file.result.readString().result); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/ash/assembly/bin/echo.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | export function main(args: string[]): void { 5 | let newLine: bool = true; 6 | let _args: string[] = new Array(); 7 | let start: i32 = 1 8 | if (args[1] == "-n") { 9 | start = 2; 10 | newLine = false 11 | } 12 | for (let i = start; i < args.length; i++) { 13 | if (args[i] == "$PATH") { 14 | _args.push(Environ.get("$PATH")); 15 | } else { 16 | _args.push(args[i]); 17 | } 18 | } 19 | Console.write(_args.join(" "), newLine); 20 | } 21 | -------------------------------------------------------------------------------- /packages/ash/assembly/bin/grep.ts: -------------------------------------------------------------------------------- 1 | // import {RegExp} from "../regexp"; 2 | // import {Argas} from "arg-as" 3 | export function _main(args: string): i32 { 4 | // let argv: string[] = args.split(" "); 5 | // let pattern = new RegExp(argv[1]); 6 | // let rest: string = argv.slice(2).join(" "); 7 | // if (pattern.test(rest)) return 1; 8 | return -1; 9 | } 10 | -------------------------------------------------------------------------------- /packages/ash/assembly/bin/mkdir.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | export function main(args: string[]): void { 5 | // let dirname = args[1]; 6 | // if (args[1] == "-p") { 7 | // } else { 8 | // if (fs.createDirectory(args[1]).error) { 9 | // abort(); 10 | // } 11 | // } 12 | } 13 | -------------------------------------------------------------------------------- /packages/ash/assembly/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as wasi_bindings from "bindings/wasi"; 3 | -------------------------------------------------------------------------------- /packages/ash/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/ash", 3 | "version": "0.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "xterm": { 8 | "version": "3.12.0", 9 | "resolved": "https://registry.npmjs.org/xterm/-/xterm-3.12.0.tgz", 10 | "integrity": "sha512-U5w1NJdrqAtnNju4W05uOxLzNgMD1sk0AnIkZ//Wa7xRdQTi9Dl1qkPdAaxWJ1a7A8xzNM4ogrX/4oSVl15qOw==", 11 | "dev": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/ash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/ash", 3 | "version": "0.0.2", 4 | "description": "AssemblyScript Shell", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "build": "webpack --mode development", 9 | "watch": "webpack-dev-server --mode development --env=dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/ash" 14 | }, 15 | "keywords": [ 16 | "AssemblyScript", 17 | "Kernel", 18 | "OS", 19 | "WebAssembly", 20 | "WebAssemblyOS" 21 | ], 22 | "author": "Willem Wyndham", 23 | "license": "MIT", 24 | "dependencies": { 25 | "@wasmos/assemblyscript": "git:github.com/WebAssemblyOS/assemblyscript#v0.0.2", 26 | "@wasmos/fs": "git:github.com/WebAssemblyOS/fs#v0.0.2", 27 | "@wasmos/kernel": "git:github.com/WebAssemblyOS/kernel#v0.0.2" 28 | }, 29 | "devDependencies": { 30 | "xterm": "^3.12.0" 31 | }, 32 | "gitHead": "feef85b557c8395979e6d5f67db35a488eea1f6d" 33 | } 34 | -------------------------------------------------------------------------------- /packages/ash/src/index.ts: -------------------------------------------------------------------------------- 1 | var FontFaceObserver = require("fontfaceobserver"); 2 | // import { EventManager, Terminal } from "./terminal"; 3 | import { Terminal } from "xterm"; 4 | import * as fullscreen from "xterm/lib/addons/fullscreen/fullscreen"; 5 | import { Process } from "@wasmos/kernel/src"; 6 | import * as BrowserFS from "browserfs"; 7 | 8 | BrowserFS.install(window); 9 | // Configures BrowserFS to use the LocalStorage file system. 10 | 11 | import { fs, init } from "@wasmos/fs/src"; 12 | // 13 | // interface TestWindow extends Window { 14 | // terminal: Terminal; 15 | // Process: typeof Process; 16 | // fs: typeof fs; 17 | // } 18 | // 19 | // function compileStreaming( 20 | // source: Response | Promise 21 | // ): Promise { 22 | // return (WebAssembly as any).compileStreaming(source); 23 | // } 24 | // 25 | // import { Terminal as TerminalType } from "xterm"; 26 | // 27 | // export interface IWindowWithTerminal extends Window { 28 | // terminal: TerminalType; 29 | // } 30 | // declare let window: IWindowWithTerminal; 31 | // 32 | // Terminal.applyAddon(fullscreen); 33 | // 34 | // let terminal: Terminal; 35 | // 36 | // const terminalContainer = document.getElementById("terminal-container"); 37 | // 38 | // function createTerminal(): void { 39 | // // Clean terminal 40 | // while (terminalContainer.children.length) { 41 | // terminalContainer.removeChild(terminalContainer.children[0]); 42 | // } 43 | // terminal = new Terminal({}); 44 | // window.terminal = terminal; // Expose `terminal` to window for debugging purposes 45 | // 46 | // terminal.open(terminalContainer); 47 | // 48 | // // fit is called within a setTimeout, cols and rows need this. 49 | // setTimeout(() => { 50 | // initOptions(terminal); 51 | // // Set terminal size again to set the specific dimensions on the demo 52 | // runFakeTerminal(); 53 | // terminal.toggleFullScreen(); 54 | // }, 0); 55 | // } 56 | // 57 | // function runFakeTerminal(): void { 58 | // if (terminal._initialized) { 59 | // return; 60 | // } 61 | // 62 | // terminal._initialized = true; 63 | // 64 | // terminal.prompt = () => { 65 | // terminal.write("\r\n$ "); 66 | // }; 67 | // 68 | // terminal.writeln("Welcome to xterm.js"); 69 | // terminal.writeln( 70 | // "This is a local terminal emulation, without a real terminal in the back-end." 71 | // ); 72 | // terminal.writeln("Type some keys and commands to play around."); 73 | // terminal.writeln(""); 74 | // terminal.prompt(); 75 | // 76 | // terminal._core.register( 77 | // terminal.addDisposableListener("key", (key, ev) => { 78 | // const printable = 79 | // !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey; 80 | // 81 | // if (ev.keyCode === 13) { 82 | // terminal.prompt(); 83 | // } else if (ev.keyCode === 8) { 84 | // // Do not delete the prompt 85 | // if (terminal.x > 2) { 86 | // terminal.write("\b \b"); 87 | // } 88 | // } else if (printable) { 89 | // terminal.write(key); 90 | // } 91 | // }) 92 | // ); 93 | // 94 | // terminal._core.register( 95 | // terminal.addDisposableListener("paste", (data, ev) => { 96 | // terminal.write(data); 97 | // }) 98 | // ); 99 | // } 100 | // 101 | // function initOptions(term: TerminalType): void { 102 | // const blacklistedOptions = [ 103 | // // Internal only options 104 | // "cancelEvents", 105 | // "convertEol", 106 | // "debug", 107 | // "handler", 108 | // "screenKeys", 109 | // "termName", 110 | // "useFlowControl", 111 | // // Complex option 112 | // "theme" 113 | // ]; 114 | // const stringOptions = { 115 | // bellSound: null, 116 | // bellStyle: ["none", "sound"], 117 | // cursorStyle: ["block", "underline", "bar"], 118 | // experimentalCharAtlas: ["none", "static", "dynamic"], 119 | // fontFamily: null, 120 | // fontWeight: [ 121 | // "normal", 122 | // "bold", 123 | // "100", 124 | // "200", 125 | // "300", 126 | // "400", 127 | // "500", 128 | // "600", 129 | // "700", 130 | // "800", 131 | // "900" 132 | // ], 133 | // fontWeightBold: [ 134 | // "normal", 135 | // "bold", 136 | // "100", 137 | // "200", 138 | // "300", 139 | // "400", 140 | // "500", 141 | // "600", 142 | // "700", 143 | // "800", 144 | // "900" 145 | // ], 146 | // rendererType: ["dom", "canvas"] 147 | // }; 148 | // const options = Object.keys((term)._core.options); 149 | // const booleanOptions = []; 150 | // const numberOptions = []; 151 | // options 152 | // .filter(o => blacklistedOptions.indexOf(o) === -1) 153 | // .forEach(o => { 154 | // switch (typeof term.getOption(o)) { 155 | // case "boolean": 156 | // booleanOptions.push(o); 157 | // break; 158 | // case "number": 159 | // numberOptions.push(o); 160 | // break; 161 | // default: 162 | // if (Object.keys(stringOptions).indexOf(o) === -1) { 163 | // console.warn(`Unrecognized option: "${o}"`); 164 | // } 165 | // } 166 | // }); 167 | // } 168 | // 169 | // async function main() { 170 | // await init("index.zip"); 171 | // (window as TestWindow).fs = fs; 172 | // createTerminal(); 173 | // let contents = await fs.readdir("."); 174 | // for (let dir of contents) { 175 | // console.log(await fs.readdir(dir)); 176 | // } 177 | // } 178 | // main(); 179 | -------------------------------------------------------------------------------- /packages/ash/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | 4 | module.exports = { 5 | entry: { 6 | index: "./src/index.ts" 7 | // worker: "./src/threading/worker.ts" 8 | }, 9 | module: { 10 | noParse: /browserfs\.js/, 11 | rules: [ 12 | { 13 | test: /\.tsx?$/, 14 | use: "ts-loader", 15 | exclude: /node_modules/ 16 | } 17 | ] 18 | }, 19 | resolve: { 20 | // Use our versions of Node modules. 21 | alias: { 22 | fs: "browserfs/dist/shims/fs.js", 23 | buffer: "browserfs/dist/shims/buffer.js", 24 | path: "browserfs/dist/shims/path.js", 25 | processGlobal: "browserfs/dist/shims/process.js", 26 | bufferGlobal: "browserfs/dist/shims/bufferGlobal.js", 27 | bfsGlobal: require.resolve("browserfs") 28 | }, 29 | extensions: [".tsx", ".ts", ".js"] 30 | }, 31 | output: { 32 | filename: "[name].js", 33 | path: path.resolve(__dirname, "dist") 34 | }, 35 | devServer: { 36 | contentBase: path.join(__dirname, "dist"), 37 | compress: true, 38 | port: 8080 39 | }, 40 | devtool: "source-map", 41 | plugins: [ 42 | // Expose BrowserFS, process, and Buffer globals. 43 | // NOTE: If you intend to use BrowserFS in a script tag, you do not need 44 | // to expose a BrowserFS global. 45 | new webpack.ProvidePlugin({ 46 | BrowserFS: "bfsGlobal", 47 | process: "processGlobal", 48 | Buffer: "bufferGlobal" 49 | }) 50 | ], 51 | // DISABLE Webpack's built-in process and Buffer polyfills! 52 | node: { 53 | process: false, 54 | Buffer: false 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /packages/assemblyscript/README.md: -------------------------------------------------------------------------------- 1 | # AssemblyScript Compiler 2 | 3 | This provides the core set of build tools needed to compile an AssemblyScript project. 4 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/__tests__/json.spec.ts: -------------------------------------------------------------------------------- 1 | import { JSONDecoder } from "../json/decoder"; 2 | import { JSONEncoder } from "../json/encoder"; 3 | import { JSON } from '../json'; 4 | 5 | var encoder: JSONEncoder; 6 | const jsonStr = '{"hello":"world"}'; 7 | 8 | 9 | 10 | function roundripTest(jsonString: string, expectedString: string = ""): bool { 11 | expectedString = expectedString || jsonString; 12 | let buffer: Uint8Array = new Uint8Array(jsonString.lengthUTF8); 13 | let utf8ptr = jsonString.toUTF8(); 14 | // TODO: std should expose memcpy? 15 | memory.copy(buffer.buffer.data, utf8ptr, buffer.byteLength); 16 | let decoder: JSONDecoder = new JSONDecoder(encoder); 17 | decoder.deserialize(buffer); 18 | let resultBuffer = encoder.serialize(); 19 | let resultString = String.fromUTF8( 20 | resultBuffer.buffer.data, 21 | resultBuffer.length 22 | ); 23 | expect(resultString).toStrictEqual(expectedString); 24 | expect(encoder.toString()).toStrictEqual(expectedString); 25 | return true; 26 | } 27 | 28 | describe("JSON", (): void => { 29 | beforeAll( 30 | (): void => { 31 | encoder = new JSONEncoder(); 32 | }); 33 | it("round trip should produce the same string", (): void => { 34 | roundripTest(jsonStr, jsonStr); 35 | }); 36 | 37 | describe("parse should handle", (): void => { 38 | 39 | it("strings", () => { 40 | let obj = JSON.parse(jsonStr); 41 | expect(obj.getString("hello")).toStrictEqual("world"); 42 | }); 43 | 44 | it("arrays", () => { 45 | let str = '{"Hello": ["World"]}' 46 | let obj = JSON.parse(str); 47 | let arr = obj.getArray("Hello"); 48 | expect(arr.length).toBe(1) 49 | expect(arr[0].val).toStrictEqual("World"); 50 | }); 51 | 52 | it("nested objects", () => { 53 | let str = '{"top level": { "Hello": "World" } }'; 54 | let obj = JSON.parse(str); 55 | let topLevel = obj.getObject("top level"); 56 | expect(topLevel.keys.length).toBe(1); 57 | expect(topLevel.getString("Hello")).toStrictEqual("World"); 58 | }); 59 | 60 | it("numbers", () => { 61 | let str = '{"pi": 3}' 62 | let obj = JSON.parse(str); 63 | let pi: i64 = obj.getNumber("pi"); 64 | expect(pi).toBe(3); 65 | }); 66 | 67 | it("booleans", () => { 68 | let str = '{"Hello": true }' 69 | let obj = JSON.parse(str); 70 | expect(obj.getBool("Hello")).toBe(true); 71 | }); 72 | 73 | it("null", () => { 74 | let str = '{"Hello": null }' 75 | let obj = JSON.parse(str); 76 | expect(obj.getNull("Hello")).toBe(null); 77 | }) 78 | }); 79 | }); -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/__tests__/path.spec.ts: -------------------------------------------------------------------------------- 1 | import * as path from "../wasa/mock/path"; 2 | 3 | let ROOT: string; 4 | let HOME: string; 5 | let SRC: string; 6 | let SIMPLE_PATH: string; 7 | 8 | beforeAll((): void => { 9 | ROOT = "/" 10 | HOME = "/home"; 11 | SRC = "./src"; 12 | SIMPLE_PATH = "/home/foo" 13 | 14 | }) 15 | 16 | describe("path", (): void => { 17 | describe("dirname", (): void => { 18 | it("return root if passed root", (): void => { 19 | expect(path.dirname(ROOT)).toStrictEqual(ROOT); 20 | }); 21 | 22 | it("Should return root if passed a toplevel directory", (): void => { 23 | expect(path.dirname(HOME)).toStrictEqual(ROOT); 24 | }) 25 | it("Should return full path of parent directory", (): void => { 26 | expect(path.dirname(SIMPLE_PATH)).toStrictEqual(HOME); 27 | }) 28 | }); 29 | 30 | describe("basename", (): void => { 31 | it("should return basename", (): void => { 32 | expect(path.basename(HOME)).toStrictEqual("home"); 33 | }); 34 | 35 | }); 36 | 37 | describe("join", (): void => { 38 | it("should handle relative links", (): void => { 39 | let paths: string[] = new Array(); 40 | paths.push(HOME) 41 | paths.push(SRC); 42 | // expect(paths[0]).not.toBe(null); 43 | let res = path.join(paths); 44 | expect(res).not.toBe(null); 45 | expect(res).toStrictEqual(HOME + path.PATH_SEP + SRC.substr(2)); 46 | }); 47 | }); 48 | }); 49 | 50 | 51 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/__tests__/wasa.include.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Console, fs, Process, CommandLine, fd, FileDescriptor } from '../wasa/mock/index'; 3 | import { Wasi } from "../wasi"; 4 | import { WasiResult } from '../wasa/index'; 5 | 6 | /** This file is included with tests so that the default globals are set up properly. */ 7 | beforeAll(() => { 8 | fs.fs.init(); 9 | }) 10 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/__tests__/wasa.spec.ts: -------------------------------------------------------------------------------- 1 | import { Console, StringUtils, fs } from "../wasa/mock"; 2 | import { FileDescriptor } from '../wasa/mock/fs'; 3 | import * as path from "../wasa/mock/path"; 4 | import { FileSystem } from '../wasa/mock/fs/fs'; 5 | import { Wasi } from '../wasi'; 6 | import { WasiResult } from '../wasa/index'; 7 | 8 | const STDOUT: string = "/dev/fd/1"; 9 | var stdout: WasiResult; 10 | let jsonStr = '{"hello":"world"}'; 11 | let _fs: FileSystem; 12 | 13 | beforeAll(() => { 14 | _fs = fs.fs; 15 | _fs.init(); 16 | }) 17 | 18 | describe("Console", (): void => { 19 | it("should be print hello World", (): void => { 20 | Console.log(jsonStr); 21 | let std1 = fs.get(Console.stdout.fd).result; 22 | let std2 = fs.get(Console.stdout.fd).result; 23 | expect(std1).toStrictEqual( 24 | std2, 25 | "Two non-unique file descriptors points to the same object" 26 | ); 27 | 28 | stdout = fs.openFile("/dev/fd/1"); 29 | expect(stdout.result.offset).toBe( 30 | 0, 31 | "A fresh file descriptor has a seek (offset) of 0" 32 | ); 33 | 34 | expect(Console.stdout.offset).toBe( 35 | jsonStr.lengthUTF8, //No NUL character at the end of the string 36 | "length of string + \\n" 37 | ); 38 | // expect(stdout.offset).toBe(0); //"new line addded" 39 | // let stdoutStr = fs.readString(stdout.id); 40 | let newLineStr = jsonStr + "\n"; 41 | stdout.result.reset() 42 | expect(stdout.result.readString().result).toStrictEqual(newLineStr); 43 | }); 44 | }); 45 | 46 | 47 | 48 | describe("readLine", (): void => { 49 | it("should read until newline", (): void => { 50 | let str = "Hello\nWorld"; 51 | let utfStr = str.toUTF8(); 52 | expect(StringUtils.fromCStringTilNewLine(utfStr, str.lengthUTF8)).toStrictEqual("Hello\n") 53 | }); 54 | 55 | it("should read null when reading from a terminating char", (): void => { 56 | let str = "Hello World"; 57 | let utfStr = str.toUTF8(); 58 | expect(StringUtils.fromCStringTilNewLine(utfStr + str.lengthUTF8, str.lengthUTF8)).toBeNull(); 59 | }); 60 | 61 | it("should read chunk", () => { 62 | let hello = "Hello "; 63 | let world = hello + "World"; 64 | expect(StringUtils.fromCString(world.toUTF8(), hello.lengthUTF8)).toStrictEqual(hello); 65 | }); 66 | }); 67 | 68 | describe("Open", (): void => { 69 | it("full path should work", (): void => { 70 | let _path = "/Hello/World"; 71 | expect(fs.fs.paths.has("/")).toBeTruthy(); 72 | let res = _fs.fullPath(_path); 73 | expect(path.dirname("/test")).toBe("/"); 74 | expect(res).toStrictEqual(_path); 75 | }); 76 | 77 | it("create a top level file", (): void => { 78 | let file = _fs.createFileAt(fs.fs.cwd, "./test"); 79 | expect(file.failed).toBeFalsy(); 80 | expect(file.result.file!.path).toStrictEqual("/test"); 81 | }); 82 | 83 | it("should create a top level directory", (): void => { 84 | let dir = _fs.createDirectory("/dev"); 85 | expect(dir.failed).toBeFalsy(Wasi.errno.toString(dir.error)); 86 | }); 87 | 88 | it("should fail if parent doesn't exist", (): void => { 89 | let dir = _fs.createDirectory("/foo/test"); 90 | log(Wasi.errno.toString(dir.error)); 91 | expect(dir.failed).toBeTruthy(); 92 | }); 93 | 94 | }); 95 | 96 | describe("read", (): void => { 97 | it("read string should return error if offset is at the eof", () => { 98 | let file = _fs.createFile("./tmp"); 99 | file.result.erase(); 100 | expect(file.result.readString().error).toBe(Wasi.errno.NOMEM); 101 | }); 102 | }) 103 | 104 | let file: FileDescriptor; 105 | describe("write", (): void => { 106 | 107 | beforeEach(() => { 108 | file = _fs.createFile("./tmp").result; 109 | file.erase(); 110 | }); 111 | 112 | it("should update size after a write", () => { 113 | expect(file.size).toBe(0); 114 | let str = "hello world"; 115 | expect(file.writeString("hello world")).toBe(Wasi.errno.SUCCESS) 116 | expect(file.size).toBe(str.lengthUTF8 - 1, "No NUL character at the end of the string") 117 | }); 118 | 119 | it("should not update size if offset is less than size", (): void => { 120 | let str = "hello world"; 121 | expect(file.writeString("hello world")).toBe(Wasi.errno.SUCCESS) 122 | file.reset(); 123 | expect(file.writeString("HELLO")).toBe(Wasi.errno.SUCCESS) 124 | expect(file.size).toBe(str.lengthUTF8 - 1, "No NUL character at the end of the string") 125 | }) 126 | }) 127 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/bin/echo.ts: -------------------------------------------------------------------------------- 1 | // import { IO, Console } from "@wasmos/wasa"; 2 | 3 | // import {_process, Process} from "../preamble"; 4 | // import { Console } from "@wasmos/wasa"; 5 | // import "allocator/arena"; 6 | 7 | // import { Console } from "../wasa/mock"; 8 | 9 | export const enum ExitStatus { 10 | EXIT_FAILURE = -1, 11 | EXIT_SUCCESS = 0 12 | } 13 | 14 | export function _main(argv: string[]): ExitStatus { 15 | Console.log(argv.slice(1).join(" ")); 16 | return ExitStatus.EXIT_SUCCESS; 17 | } 18 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/flag/index.ts: -------------------------------------------------------------------------------- 1 | export function hasFlag(val: u32, flag: u32): boolean { 2 | return popcnt(val & flag) > 0; 3 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/gc.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare function __gc_allocate( 3 | size: usize, 4 | markFn: (ref: usize) => void 5 | ): usize; 6 | 7 | declare function __gc_link(parentRef: usize, childRef: usize): void; 8 | 9 | declare function __gc_mark(ref: usize): void; 10 | 11 | declare function __gc_collect(): void; -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./wasa"; 2 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/json/encoder.ts: -------------------------------------------------------------------------------- 1 | declare function logStr(str: string): void; 2 | declare function logF64(val: f64): void; 3 | 4 | export class JSONEncoder { 5 | private isFirstKey: bool[] = new Array(1); 6 | private result: string[] = new Array(); 7 | 8 | constructor() { 9 | this.isFirstKey[0] = true; 10 | } 11 | 12 | serialize(): Uint8Array { 13 | // TODO: Write directly to UTF8 bytes 14 | let result = this.toString(); 15 | let utf8ptr = result.toUTF8(); 16 | let buffer = new Uint8Array(result.lengthUTF8 - 1); 17 | memory.copy(buffer.buffer.data, utf8ptr, buffer.byteLength); 18 | return buffer; 19 | } 20 | 21 | toString(): String { 22 | return this.result.join(""); 23 | } 24 | 25 | setString(name: string, value: string): void { 26 | this.writeKey(name); 27 | this.writeString(value); 28 | } 29 | 30 | setBoolean(name: string, value: bool): void { 31 | this.writeKey(name); 32 | this.writeBoolean(value); 33 | } 34 | 35 | setNull(name: string): void { 36 | this.writeKey(name); 37 | this.write("null"); 38 | } 39 | 40 | setInteger(name: string, value: i64): void { 41 | this.writeKey(name); 42 | this.writeInteger(value); 43 | } 44 | 45 | pushArray(name: string): bool { 46 | this.writeKey(name); 47 | this.write("["); 48 | this.isFirstKey.push(true); 49 | return true; 50 | } 51 | 52 | popArray(): void { 53 | this.write("]"); 54 | this.isFirstKey.pop(); 55 | } 56 | 57 | pushObject(name: string): bool { 58 | this.writeKey(name); 59 | this.write("{"); 60 | this.isFirstKey.push(true); 61 | return true; 62 | } 63 | 64 | popObject(): void { 65 | this.write("}"); 66 | this.isFirstKey.pop(); 67 | } 68 | 69 | private writeKey(str: string): void { 70 | if (!this.isFirstKey[this.isFirstKey.length - 1]) { 71 | this.write(","); 72 | } else { 73 | this.isFirstKey[this.isFirstKey.length - 1] = false; 74 | } 75 | if (str != null) { 76 | this.writeString(str); 77 | this.write(":"); 78 | } 79 | } 80 | 81 | private writeString(str: string): void { 82 | this.write('"'); 83 | let savedIndex = 0; 84 | for (let i = 0; i < str.length; i++) { 85 | let char = str.charCodeAt(i); 86 | let needsEscaping = char < 0x20 || char == '"'.charCodeAt(0) || char == '\\'.charCodeAt(0); 87 | if (needsEscaping) { 88 | this.write(str.substring(savedIndex, i)); 89 | savedIndex = i + 1; 90 | if (char == '"'.charCodeAt(0)) { 91 | this.write('\\"'); 92 | } else if (char == "\\".charCodeAt(0)) { 93 | this.write("\\\\"); 94 | } else if (char == "\b".charCodeAt(0)) { 95 | this.write("\\b"); 96 | } else if (char == "\n".charCodeAt(0)) { 97 | this.write("\\n"); 98 | } else if (char == "\r".charCodeAt(0)) { 99 | this.write("\\r"); 100 | } else if (char == "\t".charCodeAt(0)) { 101 | this.write("\\t"); 102 | } else { 103 | // TODO: Implement encoding for other contol characters 104 | //@ts-ignore 105 | assert(false, "Unsupported control character code: " + char.toString()); 106 | } 107 | } 108 | } 109 | this.write(str.substring(savedIndex, str.length)); 110 | this.write('"'); 111 | } 112 | 113 | private writeBoolean(value: bool): void { 114 | this.write(value ? "true" : "false"); 115 | } 116 | 117 | private writeInteger(value: i64): void { 118 | //@ts-ignore 119 | this.write(value.toString()); 120 | } 121 | 122 | private write(str: string): void { 123 | this.result.push(str); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/json/index.ts: -------------------------------------------------------------------------------- 1 | import { JSONDecoder, JSONHandler} from "./decoder"; 2 | 3 | 4 | export namespace JSON { 5 | export enum Val_Type { 6 | STRING = 0, 7 | NUMBER = 1, 8 | BOOL = 2, 9 | NULL = 3, 10 | ARRAY = 4, 11 | OBJECT = 5 12 | } 13 | export abstract class Value { 14 | constructor(public val: string, public type: Val_Type) { } 15 | 16 | static String(str: string): Value { 17 | return new Str(str) 18 | } 19 | static Number(num: i64): Value { 20 | return new Number(num) 21 | } 22 | static Bool(b: bool): Value { 23 | return new Bool(b) 24 | } 25 | static Null(): Value { 26 | return new Null(); 27 | } 28 | static Array(): Value { 29 | return new Arr(); 30 | } 31 | static Object(): Value { 32 | return new Object(); 33 | } 34 | 35 | get isString(): bool { 36 | return this.type == Val_Type.STRING; 37 | } 38 | 39 | get isObject(): bool { 40 | return this.type == Val_Type.OBJECT; 41 | } 42 | 43 | get isArray(): bool { 44 | return this.type == Val_Type.ARRAY; 45 | } 46 | 47 | get isNumber(): bool { 48 | return this.type == Val_Type.NUMBER; 49 | } 50 | 51 | get isBool(): bool { 52 | return this.type == Val_Type.BOOL; 53 | } 54 | 55 | get isNull(): bool { 56 | return this.type == Val_Type.NULL; 57 | } 58 | 59 | } 60 | 61 | export class Str extends Value { 62 | constructor(val: string) { 63 | super(val, Val_Type.STRING); 64 | } 65 | } 66 | export class Number extends Value { 67 | constructor(public num: i64) { 68 | //@ts-ignore 69 | super(num.toString(), Val_Type.NUMBER); 70 | } 71 | } 72 | 73 | export class Null extends Value { 74 | constructor() { 75 | super("null", Val_Type.NULL); 76 | } 77 | } 78 | 79 | export class Bool extends Value { 80 | constructor(public bool: bool) { 81 | super(bool ? "true" : "false", Val_Type.BOOL); 82 | } 83 | } 84 | 85 | export class Arr extends Value { 86 | array: Array = new Array(); 87 | constructor() { 88 | super("", Val_Type.ARRAY); 89 | } 90 | } 91 | 92 | export class Object extends Value { 93 | obj: Map = new Map(); 94 | keys: Array = new Array(); 95 | 96 | constructor() { 97 | super("", Val_Type.OBJECT); 98 | } 99 | 100 | set(key: string, value: Value): void { 101 | if (!this.obj.has(key)) { 102 | this.keys.push(key); 103 | } 104 | this.obj.set(key, value); 105 | } 106 | 107 | getString(key: string): string { 108 | let str = this.obj.get(key).val 109 | return str; 110 | } 111 | 112 | getObject(key: string): Object { 113 | return (this.obj.get(key) as Object); 114 | } 115 | 116 | getArray(key: string): Array { 117 | return (this.obj.get(key) as Arr).array; 118 | } 119 | 120 | getBool(key: string): bool { 121 | return (this.obj.get(key) as Bool).bool; 122 | } 123 | 124 | getNumber(key: string): i64 { 125 | return (this.obj.get(key) as Number).num; 126 | } 127 | 128 | getNull(key: string): Value | null { 129 | let val = this.obj.get(key); 130 | return val.val == "null" ? null : val; 131 | } 132 | 133 | } 134 | 135 | export class Handler extends JSONHandler { 136 | map: Map = new Map(); 137 | stack: Value[]; 138 | constructor() { 139 | super(); 140 | this.stack = new Array(); 141 | } 142 | 143 | get peek(): Value { 144 | return this.stack[this.stack.length - 1]; 145 | } 146 | 147 | setString(name: string, value: string): void { 148 | let obj: Value = Value.String(value); 149 | this.addValue(name, obj); 150 | } 151 | 152 | setBoolean(name: string, value: bool): void { 153 | let obj = Value.Bool(value); 154 | this.addValue(name, obj); 155 | } 156 | 157 | setNull(name: string): void { 158 | let obj = Value.Null(); 159 | this.addValue(name, obj); 160 | } 161 | 162 | setInteger(name: string, value: i64): void { 163 | let obj = Value.Number(value); 164 | this.addValue(name, obj); 165 | } 166 | 167 | pushArray(name: string): bool { 168 | let obj: Value = Value.Array(); 169 | this.addValue(name, obj); 170 | this.stack.push(obj); 171 | return true; 172 | } 173 | 174 | popArray(): void { 175 | if (this.stack.length > 1) { 176 | this.stack.pop(); 177 | } 178 | } 179 | 180 | pushObject(name: string): bool { 181 | let obj: Value = Value.Object(); 182 | this.addValue(name, obj); 183 | this.stack.push(obj) 184 | return true; 185 | } 186 | 187 | popObject(): void { 188 | if (this.stack.length > 1) 189 | this.stack.pop(); 190 | } 191 | 192 | addValue(name: string, obj: Value): void { 193 | if (name == null && obj.type == Val_Type.OBJECT) { 194 | this.stack.push(obj); 195 | return; 196 | } 197 | if (this.peek.type == Val_Type.OBJECT) { 198 | (this.peek as Object).set(name, obj) 199 | } 200 | else if (this.peek.type == Val_Type.ARRAY) { 201 | (this.peek as Arr).array.push(obj); 202 | } 203 | } 204 | } 205 | 206 | export function parse(str: string): Object { 207 | let buffer: Uint8Array = new Uint8Array(str.lengthUTF8); 208 | let utf8ptr = str.toUTF8(); 209 | // TODO: std should expose memcpy? 210 | memory.copy(buffer.buffer.data, utf8ptr, buffer.byteLength); 211 | let handler = new Handler(); 212 | let decoder: JSONDecoder = new JSONDecoder(handler); 213 | decoder.deserialize(buffer); 214 | return handler.peek as Object; 215 | 216 | } 217 | } 218 | 219 | 220 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/preamble.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is concatenated to the assemblyscript to execute. 3 | */ 4 | /** 5 | * Must choose which memory allocator we want 6 | */ 7 | import "allocator/arena"; 8 | 9 | /** 10 | * Always needto export memory 11 | */ 12 | // @ts-ignore Can export memory 13 | export { memory }; 14 | 15 | 16 | /** 17 | * The entry function to start the Instance after it's been initialized. 18 | */ 19 | export function main(): void { } 20 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/allocator/arena.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Arena Memory Allocator 3 | * 4 | * Provides a `memory.reset` function to reset the heap to its initial state. A user has to make 5 | * sure that there are no more references to cleared memory afterwards. Always aligns to 8 bytes. 6 | * 7 | * @module std/assembly/allocator/arena 8 | *//***/ 9 | 10 | import { AL_MASK, MAX_SIZE_32 } from "../internal/allocator"; 11 | 12 | var startOffset: usize = (HEAP_BASE + AL_MASK) & ~AL_MASK; 13 | var offset: usize = startOffset; 14 | 15 | // Memory allocator interface 16 | 17 | @global export function __memory_allocate(size: usize): usize { 18 | if (size > MAX_SIZE_32) unreachable(); 19 | var ptr = offset; 20 | var newPtr = (ptr + max(size, 1) + AL_MASK) & ~AL_MASK; 21 | var pagesBefore = memory.size(); 22 | if (newPtr > pagesBefore << 16) { 23 | let pagesNeeded = ((newPtr - ptr + 0xffff) & ~0xffff) >>> 16; 24 | let pagesWanted = max(pagesBefore, pagesNeeded); // double memory 25 | if (memory.grow(pagesWanted) < 0) { 26 | if (memory.grow(pagesNeeded) < 0) { 27 | unreachable(); // out of memory 28 | } 29 | } 30 | } 31 | offset = newPtr; 32 | return ptr; 33 | } 34 | 35 | @global export function __memory_free(ptr: usize): void { /* nop */ } 36 | 37 | @global export function __memory_reset(): void { 38 | offset = startOffset; 39 | } 40 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/allocator/emscripten.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Emscripten Memory Allocator. 3 | * 4 | * Uses Emscripten's exported _malloc and _free implementations, i.e., when linking with 5 | * Emscripten-compiled programs that already provide these. Differs from 'system' in that their 6 | * names are prefixed with an underscore. 7 | * 8 | * @module std/assembly/allocator/emscripten 9 | *//***/ 10 | 11 | declare function _malloc(size: usize): usize; 12 | declare function _free(ptr: usize): void; 13 | 14 | // Memory allocator interface 15 | // @ts-ignore decorators is correct 16 | @global export function __memory_allocate(size: usize): usize { 17 | return _malloc(size); 18 | } 19 | // @ts-ignore decorators is correct 20 | @global export function __memory_free(ptr: usize): void { 21 | _free(ptr); 22 | } 23 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/allocator/system.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * System Memory Allocator. 3 | * 4 | * Uses the environment's malloc and free implementations, i.e., when linking with other C-like 5 | * programs that already provide these. 6 | * 7 | * @module std/assembly/allocator/system 8 | *//***/ 9 | 10 | declare function malloc(size: usize): usize; 11 | declare function free(ptr: usize): void; 12 | 13 | // Memory allocator interface 14 | // @ts-ignore decorators is correct 15 | @global export function __memory_allocate(size: usize): usize { 16 | return malloc(size); 17 | } 18 | // @ts-ignore decorators is correct 19 | @global export function __memory_free(ptr: usize): void { 20 | free(ptr); 21 | } 22 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/arraybuffer.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HEADER_SIZE, 3 | MAX_BLENGTH, 4 | allocateUnsafe 5 | } from "./internal/arraybuffer"; 6 | 7 | import { 8 | Uint8ClampedArray, 9 | Uint8Array, 10 | Int8Array, 11 | Uint16Array, 12 | Int16Array, 13 | Uint32Array, 14 | Int32Array, 15 | Uint64Array, 16 | Int64Array 17 | } from "./typedarray"; 18 | 19 | import { 20 | DataView 21 | } from "./dataview"; 22 | 23 | @sealed 24 | export class ArrayBuffer { 25 | 26 | readonly byteLength: i32; // capped to [0, MAX_LENGTH] 27 | 28 | @inline static isView(value: T): bool { 29 | if (value === null) return false; 30 | if (value instanceof Uint8ClampedArray) return true; 31 | if (value instanceof Uint8Array) return true; 32 | if (value instanceof Int8Array) return true; 33 | if (value instanceof Uint16Array) return true; 34 | if (value instanceof Int16Array) return true; 35 | if (value instanceof Uint32Array) return true; 36 | if (value instanceof Int32Array) return true; 37 | if (value instanceof Uint64Array) return true; 38 | if (value instanceof Int64Array) return true; 39 | if (value instanceof DataView) return true; 40 | return false; 41 | } 42 | 43 | // @unsafe 44 | @inline get data(): usize { return changetype(this) + HEADER_SIZE; } 45 | 46 | constructor(length: i32, unsafe: bool = false) { 47 | if (length > MAX_BLENGTH) throw new RangeError("Invalid array buffer length"); 48 | var buffer = allocateUnsafe(length); 49 | if (!unsafe) memory.fill(changetype(buffer) + HEADER_SIZE, 0, length); 50 | return buffer; 51 | } 52 | 53 | slice(begin: i32 = 0, end: i32 = MAX_BLENGTH): ArrayBuffer { 54 | var len = this.byteLength; 55 | begin = begin < 0 ? max(len + begin, 0) : min(begin, len); 56 | end = end < 0 ? max(len + end, 0) : min(end, len); 57 | len = max(end - begin, 0); 58 | var buffer = allocateUnsafe(len); 59 | memory.copy( 60 | changetype(buffer) + HEADER_SIZE, 61 | changetype(this) + HEADER_SIZE + begin, 62 | len 63 | ); 64 | return buffer; 65 | } 66 | 67 | toString(): string { 68 | return "[object ArrayBuffer]"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/bindings/Date.ts: -------------------------------------------------------------------------------- 1 | export declare function UTC( 2 | // NOTE: Using i32 below saves us a f64.convert_s instruction and moves the responsibility for 3 | // converting the value to the WASM/JS boundary. 4 | year: i32, 5 | month: i32, 6 | day: i32, 7 | hour: i32, 8 | minute: i32, 9 | second: i32, 10 | millisecond: f64 11 | ): f64; 12 | export declare function now(): f64; 13 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/bindings/Math.ts: -------------------------------------------------------------------------------- 1 | export declare const E: f64; 2 | export declare const LN2: f64; 3 | export declare const LN10: f64; 4 | export declare const LOG2E: f64; 5 | export declare const LOG10E: f64; 6 | export declare const PI: f64; 7 | export declare const SQRT1_2: f64; 8 | export declare const SQRT2: f64; 9 | 10 | export declare function abs(x: f64): f64; 11 | export declare function acos(x: f64): f64; 12 | export declare function acosh(x: f64): f64; 13 | export declare function asin(x: f64): f64; 14 | export declare function asinh(x: f64): f64; 15 | export declare function atan(x: f64): f64; 16 | export declare function atan2(y: f64, x: f64): f64; 17 | export declare function atanh(x: f64): f64; 18 | export declare function cbrt(x: f64): f64; 19 | export declare function ceil(x: f64): f64; 20 | export declare function clz32(x: f64): f64; 21 | export declare function cos(x: f64): f64; 22 | export declare function cosh(x: f64): f64; 23 | export declare function exp(x: f64): f64; 24 | export declare function expm1(x: f64): f64; 25 | export declare function floor(x: f64): f64; 26 | export declare function fround(x: f64): f32; 27 | export declare function hypot(value1: f64, value2: f64): f64; // TODO: rest 28 | export declare function imul(a: f64, b: f64): f64; 29 | export declare function log(x: f64): f64; 30 | export declare function log10(x: f64): f64; 31 | export declare function log1p(x: f64): f64; 32 | export declare function log2(x: f64): f64; 33 | export declare function max(value1: f64, value2: f64): f64; // TODO: rest 34 | export declare function min(value1: f64, value2: f64): f64; // TODO: rest 35 | export declare function pow(base: f64, exponent: f64): f64; 36 | export declare function random(): f64; 37 | export declare function round(x: f64): f64; 38 | export declare function sign(x: f64): f64; 39 | export declare function sin(x: f64): f64; 40 | export declare function sinh(x: f64): f64; 41 | export declare function sqrt(x: f64): f64; 42 | export declare function tan(x: f64): f64; 43 | export declare function tanh(x: f64): f64; 44 | export declare function trunc(x: f64): f64; 45 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/bindings/wasi.ts: -------------------------------------------------------------------------------- 1 | export * from "./wasi_unstable"; 2 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/date.ts: -------------------------------------------------------------------------------- 1 | import { 2 | UTC as Date_UTC, 3 | now as Date_now 4 | } from "./bindings/Date"; 5 | 6 | export class Date { 7 | 8 | @inline static UTC( 9 | year: i32, 10 | month: i32 = 0, 11 | day: i32 = 1, 12 | hour: i32 = 0, 13 | minute: i32 = 0, 14 | second: i32 = 0, 15 | millisecond: i64 = 0 16 | ): i64 { 17 | return Date_UTC(year, month, day, hour, minute, second, millisecond); 18 | } 19 | 20 | @inline static now(): i64 { 21 | return Date_now(); 22 | } 23 | 24 | private value: i64; 25 | 26 | constructor(value: i64) { 27 | this.value = value; 28 | } 29 | 30 | getTime(): i64 { 31 | return this.value; 32 | } 33 | 34 | setTime(value: i64): i64 { 35 | this.value = value; 36 | return value; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/diagnostics.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | 3 | // @ts-ignore decorators is correct 4 | @builtin export declare function ERROR(message?: void): void; 5 | // @ts-ignore decorators is correct 6 | @builtin export declare function WARNING(message?: void): void; 7 | // @ts-ignore decorators is correct 8 | @builtin export declare function INFO(message?: void): void; 9 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/env.ts: -------------------------------------------------------------------------------- 1 | declare function abort( 2 | message?: string | null, 3 | fileName?: string | null, 4 | lineNumber?: u32, 5 | columnNumber?: u32 6 | ): void; 7 | 8 | declare function trace( 9 | message: string, 10 | n?: i32, 11 | a0?: f64, 12 | a1?: f64, 13 | a2?: f64, 14 | a3?: f64, 15 | a4?: f64 16 | ): void; 17 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/error.ts: -------------------------------------------------------------------------------- 1 | export class Error { 2 | 3 | name: string = "Error"; 4 | stack: string = ""; // TODO 5 | 6 | constructor( 7 | public message: string = "" 8 | ) {} 9 | 10 | toString(): string { 11 | var message = this.message; 12 | return message.length 13 | ? this.name + ": " + message 14 | : this.name; 15 | } 16 | } 17 | 18 | export class RangeError extends Error { 19 | constructor(message: string = "") { 20 | super(message); 21 | this.name = "RangeError"; 22 | } 23 | } 24 | 25 | export class TypeError extends Error { 26 | constructor(message: string = "") { 27 | super(message); 28 | this.name = "TypeError"; 29 | } 30 | } 31 | 32 | export class SyntaxError extends Error { 33 | constructor(message: string = "") { 34 | super(message); 35 | this.name = "SyntaxError"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/gc.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | 3 | // @ts-ignore decorators is correct 4 | @builtin export declare function iterateRoots(fn: (ref: usize) => void): void; 5 | 6 | export namespace gc { 7 | 8 | export function collect(): void { 9 | if (isDefined(__gc_collect)) { __gc_collect(); return; } 10 | WARNING("Calling 'gc.collect' requires a garbage collector to be present."); 11 | unreachable(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/internal/allocator.ts: -------------------------------------------------------------------------------- 1 | /** Number of alignment bits. */ 2 | // @ts-ignore decorators is correct 3 | @inline export const AL_BITS: u32 = 3; 4 | /** Number of possible alignment values. */ 5 | // @ts-ignore decorators is correct 6 | @inline export const AL_SIZE: usize = 1 << AL_BITS; 7 | /** Mask to obtain just the alignment bits. */ 8 | // @ts-ignore decorators is correct 9 | @inline export const AL_MASK: usize = AL_SIZE - 1; 10 | /** Maximum 32-bit allocation size. */ 11 | // @ts-ignore decorators is correct 12 | @inline export const MAX_SIZE_32: usize = 1 << 30; // 1GB 13 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/internal/arraybuffer.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AL_MASK, 3 | MAX_SIZE_32 4 | } from "./allocator"; 5 | 6 | /** Size of an ArrayBuffer header. */ 7 | @inline export const HEADER_SIZE: usize = (offsetof() + AL_MASK) & ~AL_MASK; 8 | /** Maximum byte length of an ArrayBuffer. */ 9 | @inline export const MAX_BLENGTH: i32 = MAX_SIZE_32 - HEADER_SIZE; 10 | 11 | function computeSize(byteLength: i32): usize { 12 | // round up to power of 2, with HEADER_SIZE=8: 13 | // 0 -> 2^3 = 8 14 | // 1..8 -> 2^4 = 16 15 | // 9..24 -> 2^5 = 32 16 | // ... 17 | // MAX_LENGTH -> 2^30 = 0x40000000 (MAX_SIZE_32) 18 | return 1 << (32 - clz(byteLength + HEADER_SIZE - 1)); 19 | } 20 | 21 | // Low-level utility 22 | 23 | function __gc(ref: usize): void {} 24 | 25 | export function allocateUnsafe(byteLength: i32): ArrayBuffer { 26 | assert(byteLength <= MAX_BLENGTH); 27 | var buffer: usize; 28 | if (isManaged()) { 29 | buffer = __gc_allocate(computeSize(byteLength), __gc); // tslint:disable-line 30 | } else { 31 | buffer = memory.allocate(computeSize(byteLength)); 32 | } 33 | store(buffer, byteLength, offsetof("byteLength")); 34 | return changetype(buffer); 35 | } 36 | 37 | export function reallocateUnsafe(buffer: ArrayBuffer, newByteLength: i32): ArrayBuffer { 38 | var oldByteLength = buffer.byteLength; 39 | if (newByteLength > oldByteLength) { 40 | assert(newByteLength <= MAX_BLENGTH); 41 | if (newByteLength <= (computeSize(oldByteLength) - HEADER_SIZE)) { // fast path: zero out additional space 42 | store(changetype(buffer), newByteLength, offsetof("byteLength")); 43 | } else { // slow path: copy to new buffer 44 | let newBuffer = allocateUnsafe(newByteLength); 45 | memory.copy( 46 | changetype(newBuffer) + HEADER_SIZE, 47 | changetype(buffer) + HEADER_SIZE, 48 | oldByteLength 49 | ); 50 | if (!isManaged()) { 51 | memory.free(changetype(buffer)); 52 | } 53 | buffer = newBuffer; 54 | } 55 | memory.fill( 56 | changetype(buffer) + HEADER_SIZE + oldByteLength, 57 | 0, 58 | (newByteLength - oldByteLength) 59 | ); 60 | } else if (newByteLength < oldByteLength) { // fast path: override size 61 | // TBD: worth to copy and release if size is significantly less than before? 62 | assert(newByteLength >= 0); 63 | store(changetype(buffer), newByteLength, offsetof("byteLength")); 64 | } 65 | return buffer; 66 | } 67 | 68 | // The helpers below use two different types in order to emit loads and stores that load respectively 69 | // store one type to/from memory while returning/taking the desired output/input type. This allows to 70 | // emit instructions like 71 | // 72 | // * `i32.load8` ^= `load(...)` that reads an i8 but returns an i32, or 73 | // * `i64.load32_s` ^= `load(...)`) that reads a 32-bit as a 64-bit integer 74 | // 75 | // without having to emit an additional instruction for conversion purposes. The second parameter 76 | // can be omitted for references and other loads and stores that simply return the exact type. 77 | 78 | @inline export function LOAD(buffer: ArrayBuffer, index: i32, byteOffset: i32 = 0): TOut { 79 | return load(changetype(buffer) + (index << alignof()) + byteOffset, HEADER_SIZE); 80 | } 81 | 82 | @inline export function STORE(buffer: ArrayBuffer, index: i32, value: TIn, byteOffset: i32 = 0): void { 83 | store(changetype(buffer) + (index << alignof()) + byteOffset, value, HEADER_SIZE); 84 | } 85 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/internal/hash.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HEADER_SIZE 3 | } from "./string"; 4 | 5 | /** Computes the 32-bit hash of a value of any type. */ 6 | @inline 7 | export function HASH(key: T): u32 { 8 | // branch-level tree-shaking makes this a `(return (call ...))` 9 | if (isString(key)) { 10 | return hashStr(key); 11 | } else if (isReference()) { 12 | if (sizeof() == 4) return hash32(changetype(key)); 13 | if (sizeof() == 8) return hash64(changetype(key)); 14 | } else if (isFloat()) { 15 | if (sizeof() == 4) return hash32(reinterpret(key)); 16 | if (sizeof() == 8) return hash64(reinterpret(key)); 17 | } else { 18 | if (sizeof() == 1) return hash8 (key); 19 | if (sizeof() == 2) return hash16(key); 20 | if (sizeof() == 4) return hash32(key); 21 | if (sizeof() == 8) return hash64(key); 22 | } 23 | unreachable(); 24 | } 25 | 26 | // FNV-1a 32-bit as a starting point, see: http://isthe.com/chongo/tech/comp/fnv/ 27 | 28 | @inline const FNV_OFFSET: u32 = 2166136261; 29 | @inline const FNV_PRIME: u32 = 16777619; 30 | 31 | function hash8(key: u32): u32 { 32 | return (FNV_OFFSET ^ key) * FNV_PRIME; 33 | } 34 | 35 | function hash16(key: u32): u32 { 36 | var v = FNV_OFFSET; 37 | v = (v ^ ( key & 0xff)) * FNV_PRIME; 38 | v = (v ^ ( key >> 8 )) * FNV_PRIME; 39 | return v; 40 | } 41 | 42 | function hash32(key: u32): u32 { 43 | var v = FNV_OFFSET; 44 | v = (v ^ ( key & 0xff)) * FNV_PRIME; 45 | v = (v ^ ((key >> 8) & 0xff)) * FNV_PRIME; 46 | v = (v ^ ((key >> 16) & 0xff)) * FNV_PRIME; 47 | v = (v ^ ( key >> 24 )) * FNV_PRIME; 48 | return v; 49 | } 50 | 51 | function hash64(key: u64): u32 { 52 | var l = key; 53 | var h = (key >>> 32); 54 | var v = FNV_OFFSET; 55 | v = (v ^ ( l & 0xff)) * FNV_PRIME; 56 | v = (v ^ ((l >> 8) & 0xff)) * FNV_PRIME; 57 | v = (v ^ ((l >> 16) & 0xff)) * FNV_PRIME; 58 | v = (v ^ ( l >> 24 )) * FNV_PRIME; 59 | v = (v ^ ( h & 0xff)) * FNV_PRIME; 60 | v = (v ^ ((h >> 8) & 0xff)) * FNV_PRIME; 61 | v = (v ^ ((h >> 16) & 0xff)) * FNV_PRIME; 62 | v = (v ^ ( h >> 24 )) * FNV_PRIME; 63 | return v; 64 | } 65 | 66 | function hashStr(key: string): u32 { 67 | var v = FNV_OFFSET; 68 | for (let i: usize = 0, k: usize = key.length << 1; i < k; ++i) { 69 | v = (v ^ load(changetype(key) + i, HEADER_SIZE)) * FNV_PRIME; 70 | } 71 | return v; 72 | } 73 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/internal/sort.ts: -------------------------------------------------------------------------------- 1 | import { 2 | LOAD, 3 | STORE 4 | } from "./arraybuffer"; 5 | 6 | import { 7 | compareUnsafe 8 | } from "./string"; 9 | 10 | /** Obtains the default comparator for the specified value type. */ 11 | @inline 12 | export function COMPARATOR(): (a: T, b: T) => i32 { 13 | if (isInteger()) { 14 | if (isSigned() && sizeof() <= 4) { 15 | return (a: T, b: T): i32 => ((a - b)); 16 | } else { 17 | return (a: T, b: T): i32 => ((a > b) - (a < b)); 18 | } 19 | } else if (isFloat()) { 20 | if (sizeof() == 4) { 21 | return (a: T, b: T): i32 => { 22 | var ia = reinterpret(a); 23 | var ib = reinterpret(b); 24 | ia ^= (ia >> 31) >>> 1; 25 | ib ^= (ib >> 31) >>> 1; 26 | return (ia > ib) - (ia < ib); 27 | }; 28 | } else { 29 | return (a: T, b: T): i32 => { 30 | var ia = reinterpret(a); 31 | var ib = reinterpret(b); 32 | ia ^= (ia >> 63) >>> 1; 33 | ib ^= (ib >> 63) >>> 1; 34 | return (ia > ib) - (ia < ib); 35 | }; 36 | } 37 | } else if (isString()) { 38 | return (a: T, b: T): i32 => { 39 | if (a === b || a === null || b === null) return 0; 40 | var alen = (a).length; 41 | var blen = (b).length; 42 | if (!alen && !blen) return 0; 43 | if (!alen) return -1; 44 | if (!blen) return 1; 45 | return compareUnsafe(a, 0, b, 0, min(alen, blen)); 46 | }; 47 | } else { 48 | return (a: T, b: T): i32 => ((a > b) - (a < b)); 49 | } 50 | } 51 | 52 | @inline 53 | export function SORT( 54 | buffer: ArrayBuffer, 55 | byteOffset: i32, 56 | length: i32, 57 | comparator: (a: T, b: T) => i32 58 | ): void { 59 | if (isReference()) { 60 | // TODO replace this to faster stable sort (TimSort) when it implemented 61 | insertionSort(buffer, byteOffset, length, comparator); 62 | } else { 63 | if (length < 256) { 64 | insertionSort(buffer, byteOffset, length, comparator); 65 | } else { 66 | weakHeapSort(buffer, byteOffset, length, comparator); 67 | } 68 | } 69 | } 70 | 71 | /** Sorts an Array with the 'Insertion Sort' algorithm. */ 72 | function insertionSort( 73 | buffer: ArrayBuffer, 74 | byteOffset: i32, 75 | length: i32, 76 | comparator: (a: T, b: T) => i32 77 | ): void { 78 | for (let i = 0; i < length; i++) { 79 | let a = LOAD(buffer, i, byteOffset); // a = arr[i] 80 | let j = i - 1; 81 | while (j >= 0) { 82 | let b = LOAD(buffer, j, byteOffset); // b = arr[j] 83 | if (comparator(a, b) < 0) { 84 | STORE(buffer, j-- + 1, b, byteOffset); // arr[j + 1] = b 85 | } else break; 86 | } 87 | STORE(buffer, j + 1, a, byteOffset); // arr[j + 1] = a 88 | } 89 | } 90 | 91 | /** Sorts an Array with the 'Weak Heap Sort' algorithm. */ 92 | function weakHeapSort( 93 | buffer: ArrayBuffer, 94 | byteOffset: i32, 95 | length: i32, 96 | comparator: (a: T, b: T) => i32 97 | ): void { 98 | const shift32 = alignof(); 99 | 100 | var bitsetSize = (length + 31) >> 5 << shift32; 101 | var bitset = memory.allocate(bitsetSize); // indexed in 32-bit chunks below 102 | memory.fill(bitset, 0, bitsetSize); 103 | 104 | // see: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.21.1863&rep=rep1&type=pdf 105 | 106 | for (let i = length - 1; i > 0; i--) { 107 | let j = i; 108 | while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; 109 | 110 | let p = j >> 1; 111 | let a = LOAD(buffer, p, byteOffset); // a = arr[p] 112 | let b = LOAD(buffer, i, byteOffset); // b = arr[i] 113 | if (comparator(a, b) < 0) { 114 | store( 115 | bitset + (i >> 5 << shift32), 116 | load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) 117 | ); 118 | STORE(buffer, i, a, byteOffset); // arr[i] = a 119 | STORE(buffer, p, b, byteOffset); // arr[p] = b 120 | } 121 | } 122 | 123 | for (let i = length - 1; i >= 2; i--) { 124 | let a = LOAD(buffer, 0, byteOffset); 125 | STORE(buffer, 0, LOAD(buffer, i, byteOffset), byteOffset); 126 | STORE(buffer, i, a, byteOffset); 127 | 128 | let x = 1, y: i32; 129 | while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; 130 | 131 | while (x > 0) { 132 | a = LOAD(buffer, 0, byteOffset); // a = arr[0] 133 | let b = LOAD(buffer, x, byteOffset); // b = arr[x] 134 | 135 | if (comparator(a, b) < 0) { 136 | store( 137 | bitset + (x >> 5 << shift32), 138 | load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) 139 | ); 140 | STORE(buffer, x, a, byteOffset); // arr[x] = a 141 | STORE(buffer, 0, b, byteOffset); // arr[0] = b 142 | } 143 | x >>= 1; 144 | } 145 | } 146 | 147 | memory.free(bitset); 148 | 149 | var t = LOAD(buffer, 1, byteOffset); // t = arr[1] 150 | STORE(buffer, 1, LOAD(buffer, 0, byteOffset), byteOffset); 151 | STORE(buffer, 0, t, byteOffset); // arr[0] = t 152 | } 153 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/internal/string.ts: -------------------------------------------------------------------------------- 1 | import { MAX_SIZE_32 } from "./allocator"; 2 | import { String } from "../string"; 3 | 4 | /** Size of a String header. */ 5 | @inline export const HEADER_SIZE = (offsetof() + 1) & ~1; // 2 byte aligned 6 | /** Maximum length of a String. */ 7 | @inline export const MAX_LENGTH = (MAX_SIZE_32 - HEADER_SIZE) >>> 1; 8 | 9 | // Low-level utility 10 | 11 | function __gc(ref: usize): void {} 12 | 13 | export function allocateUnsafe(length: i32): String { 14 | assert(length > 0 && length <= MAX_LENGTH); 15 | var buffer: usize; 16 | if (isManaged()) { 17 | buffer = __gc_allocate(HEADER_SIZE + (length << 1), __gc); // tslint:disable-line 18 | } else { 19 | buffer = memory.allocate(HEADER_SIZE + (length << 1)); 20 | } 21 | store(buffer, length); 22 | return changetype(buffer); 23 | } 24 | 25 | @inline 26 | export function freeUnsafe(buffer: String): void { 27 | if (!isManaged()) { 28 | assert(buffer); 29 | memory.free(changetype(buffer)); 30 | } 31 | } 32 | 33 | export function copyUnsafe(dest: String, destOffset: usize, src: String, srcOffset: usize, len: usize): void { 34 | memory.copy( 35 | changetype(dest) + (destOffset << 1) + HEADER_SIZE, 36 | changetype(src) + (srcOffset << 1) + HEADER_SIZE, 37 | len << 1 38 | ); 39 | } 40 | 41 | export function compareUnsafe(str1: String, offset1: usize, str2: String, offset2: usize, len: usize): i32 { 42 | var cmp: i32 = 0; 43 | var ptr1 = changetype(str1) + (offset1 << 1); 44 | var ptr2 = changetype(str2) + (offset2 << 1); 45 | while (len && !(cmp = load(ptr1, HEADER_SIZE) - load(ptr2, HEADER_SIZE))) { 46 | --len, ptr1 += 2, ptr2 += 2; 47 | } 48 | return cmp; 49 | } 50 | 51 | export function repeatUnsafe(dest: String, destOffset: usize, src: String, count: i32): void { 52 | var length = src.length; 53 | if (ASC_SHRINK_LEVEL > 1) { 54 | let strLen = length << 1; 55 | let to = changetype(dest) + HEADER_SIZE + (destOffset << 1); 56 | let from = changetype(src) + HEADER_SIZE; 57 | for (let i = 0, len = strLen * count; i < len; i += strLen) { 58 | memory.copy(to + i, from, strLen); 59 | } 60 | } else { 61 | switch (length) { 62 | case 0: break; 63 | case 1: { 64 | let cc = load(changetype(src), HEADER_SIZE); 65 | let out = changetype(dest) + (destOffset << 1); 66 | for (let i = 0; i < count; ++i) { 67 | store(out + (i << 1), cc, HEADER_SIZE); 68 | } 69 | break; 70 | } 71 | case 2: { 72 | let cc = load(changetype(src), HEADER_SIZE); 73 | let out = changetype(dest) + (destOffset << 1); 74 | for (let i = 0; i < count; ++i) { 75 | store(out + (i << 2), cc, HEADER_SIZE); 76 | } 77 | break; 78 | } 79 | case 3: { 80 | let cc1 = load(changetype(src), HEADER_SIZE + 0); 81 | let cc2 = load(changetype(src), HEADER_SIZE + 4); 82 | let out = changetype(dest) + (destOffset << 1); 83 | for (let i = 0; i < count; ++i) { 84 | store(out + (i << 2), cc1, HEADER_SIZE + 0); 85 | store(out + (i << 1), cc2, HEADER_SIZE + 4); 86 | } 87 | break; 88 | } 89 | case 4: { 90 | let cc = load(changetype(src), HEADER_SIZE); 91 | let out = changetype(dest) + (destOffset << 1); 92 | for (let i = 0; i < count; ++i) { 93 | store(out + (i << 3), cc, HEADER_SIZE); 94 | } 95 | break; 96 | } 97 | default: { 98 | let strLen = length << 1; 99 | let to = changetype(dest) + HEADER_SIZE + (destOffset << 1); 100 | let from = changetype(src) + HEADER_SIZE; 101 | for (let i = 0, len = strLen * count; i < len; i += strLen) { 102 | memory.copy(to + i, from, strLen); 103 | } 104 | break; 105 | } 106 | } 107 | } 108 | } 109 | 110 | // Helpers 111 | 112 | @inline export const enum CharCode { 113 | PLUS = 0x2B, 114 | MINUS = 0x2D, 115 | DOT = 0x2E, 116 | _0 = 0x30, 117 | _1 = 0x31, 118 | _2 = 0x32, 119 | _3 = 0x33, 120 | _4 = 0x34, 121 | _5 = 0x35, 122 | _6 = 0x36, 123 | _7 = 0x37, 124 | _8 = 0x38, 125 | _9 = 0x39, 126 | A = 0x41, 127 | B = 0x42, 128 | E = 0x45, 129 | N = 0x4E, 130 | O = 0x4F, 131 | X = 0x58, 132 | Z = 0x5a, 133 | a = 0x61, 134 | b = 0x62, 135 | e = 0x65, 136 | n = 0x6E, 137 | o = 0x6F, 138 | x = 0x78, 139 | z = 0x7A 140 | } 141 | 142 | export function isWhiteSpaceOrLineTerminator(c: u16): bool { 143 | switch (c) { 144 | case 9: // 145 | case 10: // 146 | case 13: // 147 | case 11: // 148 | case 12: // 149 | case 32: // 150 | case 160: // 151 | case 8232: // 152 | case 8233: // 153 | case 65279: return true; // 154 | default: return false; 155 | } 156 | } 157 | 158 | /** Parses a string to an integer (usually), using the specified radix. */ 159 | export function parse(str: String, radix: i32 = 0): T { 160 | var len: i32 = str.length; 161 | if (!len) return NaN; 162 | 163 | var ptr = changetype(str) /* + HEAD -> offset */; 164 | var code = load(ptr, HEADER_SIZE); 165 | 166 | // determine sign 167 | var sign: T; 168 | if (code == CharCode.MINUS) { 169 | if (!--len) return NaN; 170 | code = load(ptr += 2, HEADER_SIZE); 171 | sign = -1; 172 | } else if (code == CharCode.PLUS) { 173 | if (!--len) return NaN; 174 | code = load(ptr += 2, HEADER_SIZE); 175 | sign = 1; 176 | } else { 177 | sign = 1; 178 | } 179 | 180 | // determine radix 181 | if (!radix) { 182 | if (code == CharCode._0 && len > 2) { 183 | switch (load(ptr + 2, HEADER_SIZE)) { 184 | case CharCode.B: 185 | case CharCode.b: { 186 | ptr += 4; len -= 2; 187 | radix = 2; 188 | break; 189 | } 190 | case CharCode.O: 191 | case CharCode.o: { 192 | ptr += 4; len -= 2; 193 | radix = 8; 194 | break; 195 | } 196 | case CharCode.X: 197 | case CharCode.x: { 198 | ptr += 4; len -= 2; 199 | radix = 16; 200 | break; 201 | } 202 | default: radix = 10; 203 | } 204 | } else radix = 10; 205 | } else if (radix < 2 || radix > 36) { 206 | return NaN; 207 | } 208 | 209 | // calculate value 210 | var num: T = 0; 211 | while (len--) { 212 | code = load(ptr, HEADER_SIZE); 213 | if (code >= CharCode._0 && code <= CharCode._9) { 214 | code -= CharCode._0; 215 | } else if (code >= CharCode.A && code <= CharCode.Z) { 216 | code -= CharCode.A - 10; 217 | } else if (code >= CharCode.a && code <= CharCode.z) { 218 | code -= CharCode.a - 10; 219 | } else break; 220 | if (code >= radix) break; 221 | num = (num * radix) + code; 222 | ptr += 2; 223 | } 224 | return sign * num; 225 | } 226 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/iterator.ts: -------------------------------------------------------------------------------- 1 | export abstract class Iterable { 2 | // ? 3 | } 4 | 5 | @sealed 6 | export abstract class Iterator { 7 | 8 | // private constructor(iterable: Iterable) { 9 | // } 10 | 11 | // TODO: these need to evaluate the classId at the respective reference in order to obtain the 12 | // next value, i.e. arrays work differently than maps. we'd then have: 13 | // 14 | // ╒═══════════════════ Iterator layout (32-bit) ══════════════════╕ 15 | // 3 2 1 16 | // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits 17 | // ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤ 18 | // │ index │ 19 | // ├─────────────────────────────────────────────────────────┬───┬─┤ 20 | // │ reference │ 0 │D│ 21 | // └─────────────────────────────────────────────────────────┴───┴─┘ 22 | // D: Done flag 23 | 24 | // get value(this: u64): T { 25 | // ? 26 | // } 27 | 28 | // next(this: u64): Iterator { 29 | // ? 30 | // } 31 | 32 | done(this: u64): bool { 33 | return (this & 1); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/memory.ts: -------------------------------------------------------------------------------- 1 | import { memcmp, memmove, memset } from "./internal/memory"; 2 | // @ts-ignore valid asc 3 | @builtin export declare const HEAP_BASE: usize; // tslint:disable-line 4 | 5 | /* tslint:disable */ 6 | 7 | export namespace memory { 8 | // @ts-ignore decorators is correct 9 | @builtin export declare function size(): i32; 10 | // @ts-ignore decorators is correct 11 | @builtin export declare function grow(pages: i32): i32; 12 | 13 | // @ts-ignore decorators is correct 14 | @builtin @inline 15 | export function fill(dest: usize, c: u8, n: usize): void { // see: musl/src/string/memset 16 | memset(dest, c, n); // fallback if "bulk-memory" isn't enabled 17 | } 18 | 19 | // @ts-ignore decorators is correct 20 | @builtin @inline 21 | export function copy(dest: usize, src: usize, n: usize): void { // see: musl/src/string/memmove.c 22 | memmove(dest, src, n); // fallback if "bulk-memory" isn't enabled 23 | } 24 | 25 | // @ts-ignore decorators is correct 26 | @inline export function compare(vl: usize, vr: usize, n: usize): i32 { // see: musl/src/string/memcmp.c 27 | return memcmp(vl, vr, n); 28 | } 29 | 30 | // Passive segments 31 | 32 | // export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void { 33 | // __memory_init(segmentIndex, srcOffset, dstOffset); 34 | // } 35 | 36 | // export function drop(segmentIndex: u32): void { 37 | // __memory_drop(segmentIndex); 38 | // } 39 | 40 | // Allocator 41 | 42 | // @ts-ignore decorators is correct 43 | @inline export function allocate(size: usize): usize { 44 | // @ts-ignore valid asc 45 | if (isDefined(__memory_allocate)) return __memory_allocate(size); 46 | WARNING("Calling 'memory.allocate' requires a memory manager to be present."); 47 | return unreachable(); 48 | } 49 | 50 | // @ts-ignore decorators is correct 51 | @inline export function free(ptr: usize): void { 52 | // @ts-ignore valid asc 53 | if (isDefined(__memory_free)) { __memory_free(ptr); return; } 54 | WARNING("Calling 'memory.free' requires a memory manager to be present."); 55 | unreachable(); 56 | } 57 | 58 | // @ts-ignore decorators is correct 59 | @inline export function reset(): void { 60 | // @ts-ignore valid asc 61 | if (isDefined(__memory_reset)) { __memory_reset(); return; } 62 | unreachable(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/polyfills.ts: -------------------------------------------------------------------------------- 1 | export function bswap(value: T): T { 2 | if (isInteger()) { 3 | if (sizeof() == 2) { 4 | // @ts-ignore valid asc 5 | return ((value << 8) | ((value >> 8) & 0x00FF)); 6 | } 7 | if (sizeof() == 4) { 8 | // @ts-ignore valid asc 9 | return ( 10 | // @ts-ignore valid asc 11 | rotl(value & 0xFF00FF00, 8) | 12 | // @ts-ignore valid asc 13 | rotr(value & 0x00FF00FF, 8) 14 | ); 15 | } 16 | if (sizeof() == 8) { 17 | // @ts-ignore valid asc 18 | let a = (value >> 8) & 0x00FF00FF00FF00FF; 19 | // @ts-ignore valid asc 20 | let b = (value & 0x00FF00FF00FF00FF) << 8; 21 | let v = a | b; 22 | 23 | a = (v >> 16) & 0x0000FFFF0000FFFF; 24 | b = (v & 0x0000FFFF0000FFFF) << 16; 25 | // @ts-ignore valid asc 26 | return rotr(a | b, 32); 27 | } 28 | return value; 29 | } 30 | assert(false); 31 | return value; 32 | } 33 | // @ts-ignore decorators is correct 34 | @inline 35 | export function bswap16(value: T): T { 36 | if (isInteger() && sizeof() <= 4) { 37 | if (sizeof() == 2) { 38 | // @ts-ignore valid asc 39 | return ((value << 8) | ((value >> 8) & 0x00FF)); 40 | } else if (sizeof() == 4) { 41 | // @ts-ignore valid asc 42 | return (((value << 8) & 0xFF00) | ((value >> 8) & 0x00FF) | (value & 0xFFFF0000)); 43 | } 44 | return value; 45 | } 46 | assert(false); 47 | return value; 48 | } 49 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/regexp.ts: -------------------------------------------------------------------------------- 1 | export class RegExp { 2 | 3 | // @binding(CALL_NEW, [ STRING, STRING], OBJECT_HANDLE) 4 | constructor(pattern: string, flags: string = "") { throw new Error("unreachable"); } 5 | 6 | // @binding(CALL_THIS, [ STRING ], PASS_THRU) 7 | test(search: string): bool { throw new Error("unreachable"); } 8 | 9 | // @binding(CALL_THIS, [], STRING) 10 | toString(): string { throw new Error("unreachable"); } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/set.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HEADER_SIZE as HEADER_SIZE_AB 3 | } from "./internal/arraybuffer"; 4 | 5 | import { 6 | HASH 7 | } from "./internal/hash"; 8 | 9 | // A deterministic hash set based on CloseTable from https://github.com/jorendorff/dht 10 | 11 | // @ts-ignore decorators is correct 12 | @inline const INITIAL_CAPACITY = 4; 13 | // @ts-ignore decorators is correct 14 | @inline const FILL_FACTOR: f64 = 8 / 3; 15 | // @ts-ignore decorators is correct 16 | @inline const FREE_FACTOR: f64 = 3 / 4; 17 | 18 | /** Structure of a set entry. */ 19 | @unmanaged class SetEntry { 20 | key: K; 21 | taggedNext: usize; // LSB=1 indicates EMPTY 22 | } 23 | 24 | /** Empty bit. */ 25 | // @ts-ignore decorators is correct 26 | @inline const EMPTY: usize = 1 << 0; 27 | 28 | /** Size of a bucket. */ 29 | // @ts-ignore decorators is correct 30 | @inline const BUCKET_SIZE = sizeof(); 31 | 32 | /** Computes the alignment of an entry. */ 33 | // @ts-ignore decorators is correct 34 | @inline function ENTRY_ALIGN(): usize { 35 | // can align to 4 instead of 8 if 32-bit and K is <= 32-bits 36 | const align = (sizeof() > sizeof() ? sizeof() : sizeof()) - 1; 37 | return align; 38 | } 39 | 40 | /** Computes the aligned size of an entry. */ 41 | // @ts-ignore decorators is correct 42 | @inline function ENTRY_SIZE(): usize { 43 | const align = ENTRY_ALIGN(); 44 | const size = (offsetof>() + align) & ~align; 45 | return size; 46 | } 47 | 48 | export class Set { 49 | 50 | // buckets holding references to the respective first entry within 51 | private buckets: ArrayBuffer; // usize[bucketsMask + 1] 52 | private bucketsMask: u32; 53 | 54 | // entries in insertion order 55 | private entries: ArrayBuffer; // SetEntry[entriesCapacity] 56 | private entriesCapacity: i32; 57 | private entriesOffset: i32; 58 | private entriesCount: i32; 59 | 60 | get size(): i32 { return this.entriesCount; } 61 | 62 | constructor() { this.clear(); } 63 | 64 | clear(): void { 65 | const bucketsSize = INITIAL_CAPACITY * BUCKET_SIZE; 66 | this.buckets = new ArrayBuffer(bucketsSize); 67 | this.bucketsMask = INITIAL_CAPACITY - 1; 68 | const entriesSize = INITIAL_CAPACITY * ENTRY_SIZE(); 69 | this.entries = new ArrayBuffer(entriesSize, true); 70 | this.entriesCapacity = INITIAL_CAPACITY; 71 | this.entriesOffset = 0; 72 | this.entriesCount = 0; 73 | } 74 | 75 | private find(key: K, hashCode: u32): SetEntry | null { 76 | var entry = load>( 77 | changetype(this.buckets) + (hashCode & this.bucketsMask) * BUCKET_SIZE, 78 | HEADER_SIZE_AB 79 | ); 80 | while (entry) { 81 | if (!(entry.taggedNext & EMPTY) && entry.key == key) return entry; 82 | entry = changetype>(entry.taggedNext & ~EMPTY); 83 | } 84 | return null; 85 | } 86 | 87 | has(key: K): bool { 88 | return this.find(key, HASH(key)) !== null; 89 | } 90 | 91 | add(key: K): void { 92 | var hashCode = HASH(key); 93 | var entry = this.find(key, hashCode); 94 | if (!entry) { 95 | // check if rehashing is necessary 96 | if (this.entriesOffset == this.entriesCapacity) { 97 | this.rehash( 98 | this.entriesCount <(this.entriesCapacity * FREE_FACTOR) 99 | ? this.bucketsMask // just rehash if 1/4+ entries are empty 100 | : (this.bucketsMask << 1) | 1 // grow capacity to next 2^N 101 | ); 102 | } 103 | // append new entry 104 | let entries = this.entries; 105 | entry = changetype>( 106 | changetype(entries) + HEADER_SIZE_AB + this.entriesOffset++ * ENTRY_SIZE() 107 | ); 108 | entry.key = key; 109 | ++this.entriesCount; 110 | // link with previous entry in bucket 111 | let bucketPtrBase = changetype(this.buckets) + (hashCode & this.bucketsMask) * BUCKET_SIZE; 112 | entry.taggedNext = load(bucketPtrBase, HEADER_SIZE_AB); 113 | store(bucketPtrBase, changetype(entry), HEADER_SIZE_AB); 114 | if (isManaged()) __gc_link(changetype(this), changetype(key)); // tslint:disable-line 115 | } 116 | } 117 | 118 | delete(key: K): bool { 119 | var entry = this.find(key, HASH(key)); 120 | if (!entry) return false; 121 | entry.taggedNext |= EMPTY; 122 | --this.entriesCount; 123 | // check if rehashing is appropriate 124 | var halfBucketsMask = this.bucketsMask >> 1; 125 | if ( 126 | halfBucketsMask + 1 >= max(INITIAL_CAPACITY, this.entriesCount) && 127 | this.entriesCount <(this.entriesCapacity * FREE_FACTOR) 128 | ) this.rehash(halfBucketsMask); 129 | return true; 130 | } 131 | 132 | private rehash(newBucketsMask: u32): void { 133 | var newBucketsCapacity = (newBucketsMask + 1); 134 | var newBuckets = new ArrayBuffer(newBucketsCapacity * BUCKET_SIZE); 135 | var newEntriesCapacity = (newBucketsCapacity * FILL_FACTOR); 136 | var newEntries = new ArrayBuffer(newEntriesCapacity * ENTRY_SIZE(), true); 137 | 138 | // copy old entries to new entries 139 | var oldPtr = changetype(this.entries) + HEADER_SIZE_AB; 140 | var oldEnd = oldPtr + this.entriesOffset * ENTRY_SIZE(); 141 | var newPtr = changetype(newEntries) + HEADER_SIZE_AB; 142 | while (oldPtr != oldEnd) { 143 | let oldEntry = changetype>(oldPtr); 144 | if (!(oldEntry.taggedNext & EMPTY)) { 145 | let newEntry = changetype>(newPtr); 146 | newEntry.key = oldEntry.key; 147 | let newBucketIndex = HASH(oldEntry.key) & newBucketsMask; 148 | let newBucketPtrBase = changetype(newBuckets) + newBucketIndex * BUCKET_SIZE; 149 | newEntry.taggedNext = load(newBucketPtrBase, HEADER_SIZE_AB); 150 | store(newBucketPtrBase, newPtr, HEADER_SIZE_AB); 151 | newPtr += ENTRY_SIZE(); 152 | } 153 | oldPtr += ENTRY_SIZE(); 154 | } 155 | 156 | this.buckets = newBuckets; 157 | this.bucketsMask = newBucketsMask; 158 | this.entries = newEntries; 159 | this.entriesCapacity = newEntriesCapacity; 160 | this.entriesOffset = this.entriesCount; 161 | } 162 | 163 | toString(): string { 164 | return "[object Set]"; 165 | } 166 | 167 | private __gc(): void { 168 | __gc_mark(changetype(this.buckets)); // tslint:disable-line 169 | var entries = this.entries; 170 | __gc_mark(changetype(entries)); // tslint:disable-line 171 | if (isManaged()) { 172 | let offset: usize = 0; 173 | let end: usize = this.entriesOffset * ENTRY_SIZE(); 174 | while (offset < end) { 175 | let entry = changetype>( 176 | changetype(entries) + HEADER_SIZE_AB + offset * ENTRY_SIZE() 177 | ); 178 | if (!(entry.taggedNext & EMPTY)) __gc_mark(changetype(entry.key)); // tslint:disable-line 179 | offset += ENTRY_SIZE(); 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/symbol.ts: -------------------------------------------------------------------------------- 1 | import { Map } from "./map"; 2 | // @ts-ignore decorators is correct 3 | @lazy var stringToId: Map; 4 | // @ts-ignore decorators is correct 5 | @lazy var idToString: Map; 6 | // @ts-ignore decorators is correct 7 | @lazy var nextId: usize = 12; // Symbol.unscopables + 1 8 | // @ts-ignore can use symbol 9 | @unmanaged export class symbol { 10 | toString(): string { 11 | var id = changetype(this); 12 | var str = ""; 13 | switch (id) { 14 | case 1: { str = "hasInstance"; break; } 15 | case 2: { str = "isConcatSpreadable"; break; } 16 | case 3: { str = "isRegExp"; break; } 17 | case 4: { str = "match"; break; } 18 | case 5: { str = "replace"; break; } 19 | case 6: { str = "search"; break; } 20 | case 7: { str = "species"; break; } 21 | case 8: { str = "split"; break; } 22 | case 9: { str = "toPrimitive"; break; } 23 | case 10: { str = "toStringTag"; break; } 24 | case 11: { str = "unscopables"; break; } 25 | default: { 26 | if (idToString !== null && idToString.has(id)) str = idToString.get(id); 27 | break; 28 | } 29 | } 30 | return "Symbol(" + str + ")"; 31 | } 32 | } 33 | 34 | export function Symbol(description: string | null = null): symbol { 35 | var id = nextId++; 36 | if (!id) unreachable(); // out of ids 37 | return changetype(id); 38 | } 39 | 40 | export namespace Symbol { 41 | // @ts-ignore decorators is correct 42 | @lazy export const hasInstance = changetype(1); 43 | // @ts-ignore decorators is correct 44 | @lazy export const isConcatSpreadable = changetype(2); 45 | // @ts-ignore decorators is correct 46 | @lazy export const isRegExp = changetype(3); 47 | // @ts-ignore decorators is correct 48 | @lazy export const iterator = changetype(3); 49 | // @ts-ignore decorators is correct 50 | @lazy export const match = changetype(4); 51 | // @ts-ignore decorators is correct 52 | @lazy export const replace = changetype(5); 53 | // @ts-ignore decorators is correct 54 | @lazy export const search = changetype(6); 55 | // @ts-ignore decorators is correct 56 | @lazy export const species = changetype(7); 57 | // @ts-ignore decorators is correct 58 | @lazy export const split = changetype(8); 59 | // @ts-ignore decorators is correct 60 | @lazy export const toPrimitive = changetype(9); 61 | // @ts-ignore decorators is correct 62 | @lazy export const toStringTag = changetype(10); 63 | // @ts-ignore decorators is correct 64 | @lazy export const unscopables = changetype(11); 65 | 66 | /* tslint:disable */// not valid TS 67 | export function _for(key: string): symbol { 68 | if (!stringToId) { stringToId = new Map(); idToString = new Map(); } 69 | else if (stringToId.has(key)) return changetype(stringToId.get(key)); 70 | var id = nextId++; 71 | if (!id) unreachable(); // out of ids 72 | stringToId.set(key, id); 73 | idToString.set(id, key); 74 | return changetype(id); 75 | } 76 | /* tslint:enable */ 77 | 78 | export function keyFor(sym: symbol): string | null { 79 | return idToString !== null && idToString.has(changetype(sym)) 80 | ? idToString.get(changetype(sym)) 81 | : null; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/table.ts: -------------------------------------------------------------------------------- 1 | export namespace table { 2 | 3 | // export function copy(dst: u32, src: u32, n: u32): void { 4 | // __table_copy(dst, src, n); 5 | // } 6 | 7 | // Passive elements 8 | 9 | // export function init(elementIndex: u32, srcOffset: u32, dstOffset: u32, n: u32): void { 10 | // __table_init(elementIndex, srcOffset, dstOffset, n); 11 | // } 12 | 13 | // export function drop(elementIndex: u32): void { 14 | // __table_drop(elementIndex); 15 | // } 16 | } 17 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/std/vector.ts: -------------------------------------------------------------------------------- 1 | @sealed 2 | export abstract class V128 { 3 | } 4 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/testclass.ts: -------------------------------------------------------------------------------- 1 | export class TestClass {} 2 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as mock from "./mock"; 3 | import { Wasi } from '../wasi'; 4 | 5 | class Tuple { 6 | constructor(public first: T1, public second: T2) { } 7 | } 8 | 9 | /** Simple generic reference for wrapping non reference types*/ 10 | export class Ref{ 11 | constructor(public val: T) { } 12 | } 13 | 14 | //@ts-ignore 15 | @global 16 | /** 17 | * Helper class for dealing with errors. 18 | */ 19 | export class WasiResult extends Tuple | null, Wasi.errno> { 20 | /** 21 | * 22 | * @param first 23 | * @param second 24 | * @param isReference: bool - Whether the value passed to first is T or Ref 25 | */ 26 | private constructor(first: Ref | null, 27 | second: Wasi.errno = Wasi.errno.SUCCESS, 28 | private isReference: bool = true) { 29 | super(first, second); 30 | } 31 | 32 | /** 33 | * Tests if the error is not a success. 34 | */ 35 | get failed(): boolean { 36 | return this.error != Wasi.errno.SUCCESS; 37 | } 38 | 39 | get error(): Wasi.errno { 40 | return this.second 41 | } 42 | 43 | get result(): T { 44 | if (this.isReference) { 45 | return changetype(this.first!); 46 | } 47 | return (this.first!).val; 48 | } 49 | 50 | static resolve(result: T): WasiResult { 51 | let res: Ref = isInteger(result) ? new Ref(result) : changetype>(result); 52 | return new WasiResult(res, Wasi.errno.SUCCESS, isReference(result)); 53 | } 54 | 55 | static fail(err: Wasi.errno): WasiResult { 56 | return new WasiResult(null, err); 57 | } 58 | 59 | /** 60 | * Special case where there is no result type just the error. 61 | * @param res error 62 | */ 63 | static void(res: Wasi.errno): WasiResult { 64 | return this.fail(res); 65 | } 66 | } 67 | 68 | export { mock }; 69 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/cmdline.ts: -------------------------------------------------------------------------------- 1 | 2 | //@ts-ignore 3 | @global 4 | export class CommandLine { 5 | static _args: Array = new Array(); 6 | 7 | static push(item: string): void { 8 | this._args.push(item); 9 | } 10 | 11 | /** 12 | * Return all the command-line arguments 13 | */ 14 | static all(): Array { 15 | return this._args; 16 | } 17 | 18 | /** 19 | * Return the i-th command-ine argument 20 | * @param i index 21 | */ 22 | static get(i: usize): string | null { 23 | let args_len: usize = this._args[0].length; 24 | if (i < args_len) { 25 | return this._args[i]; 26 | } 27 | return null; 28 | } 29 | 30 | get args(): Array { 31 | return CommandLine._args; 32 | } 33 | /** 34 | * Deletes arguments 35 | */ 36 | static reset(): void { 37 | while (this._args.length > 0) { 38 | this._args.pop(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/console.ts: -------------------------------------------------------------------------------- 1 | import { FileDescriptor } from './fs'; 2 | 3 | // @ts-ignore: Decorators *are* valid here! 4 | @global 5 | export class Console { 6 | /** TODO: Add error checking */ 7 | private static _stdin: FileDescriptor | null = null; 8 | private static _stdout: FileDescriptor | null = null; 9 | private static _stderr: FileDescriptor | null = null; 10 | 11 | static get stdin(): FileDescriptor { 12 | if (Console._stdin == null) { 13 | // @ts-ignore: Private methods and fields shouldn't matter 14 | Console._stdin = fs.createFile("/dev/fd/0").result; 15 | } 16 | return Console._stdin!; 17 | } 18 | 19 | static get stdout(): FileDescriptor { 20 | if (Console._stdout == null) { 21 | // @ts-ignore: Private methods and fields shouldn't matter 22 | Console._stdout = fs.createFile("/dev/fd/1").result; 23 | } 24 | return Console._stdout!; 25 | } 26 | 27 | static get stderr(): FileDescriptor { 28 | if (Console._stderr == null) { 29 | // @ts-ignore: Private methods and fields shouldn't matter 30 | Console._stderr = fs.createFile("/dev/fd/2").result; 31 | } 32 | return Console._stderr!; 33 | } 34 | 35 | /** 36 | * Write a string to the console 37 | * @param s string 38 | * @param newline `false` to avoid inserting a newline after the string 39 | */ 40 | static write(s: string, newline: boolean = false): void { 41 | this.stdout.writeString(s, newline); 42 | } 43 | 44 | /** 45 | * Read an UTF8 string from the console, convert it to a native string 46 | */ 47 | static readAll(): string | null { 48 | let res = this.stdin.readString(); 49 | if (res.failed) { 50 | return null; 51 | } 52 | return res.result; 53 | } 54 | 55 | /** 56 | * Alias for `Console.write()` 57 | */ 58 | static log(s: string): void { 59 | this.write(s, true); 60 | } 61 | 62 | /** 63 | * Write an error to the console 64 | * @param s string 65 | * @param newline `false` to avoid inserting a newline after the string 66 | */ 67 | static error(s: string, newline: boolean = true): void { 68 | this.stderr.writeString(s, newline); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/date.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Date { 3 | /** 4 | * Return the current timestamp, as a number of milliseconds since the epoch 5 | */ 6 | static now(): f64 { 7 | let time_ptr = memory.allocate(8); 8 | let unix_ts = load(time_ptr); 9 | memory.free(time_ptr); 10 | return (unix_ts as f64) / 1000.0; 11 | } 12 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/environ.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | class EnvironEntry { 4 | constructor(readonly key: string, readonly value: string) { } 5 | } 6 | 7 | //@ts-ignore 8 | @global 9 | export class Environ { 10 | static env: Array = new Array(); 11 | 12 | static add(key: string, value: string): void { 13 | this.env.push(new EnvironEntry(key, value)); 14 | } 15 | 16 | /** 17 | * Return all environment variables 18 | */ 19 | static all(): Array { 20 | return this.env; 21 | } 22 | 23 | /** 24 | * Return the value for an environment variable 25 | * @param key environment variable name 26 | */ 27 | static get(key: string): string { 28 | for (let i = 0, j = this.env.length; i < j; i++) { 29 | if (this.env[i].key == key) { 30 | return this.env[i].value; 31 | } 32 | } 33 | return ""; 34 | } 35 | 36 | static reset(): void { 37 | while (this.env.length > 0) { 38 | this.env.pop(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/fs/directory.ts: -------------------------------------------------------------------------------- 1 | import { Inode } from "./inode" 2 | 3 | export class Directory extends Inode { 4 | 5 | 6 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/fs/file.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { Inode } from "./inode"; 4 | 5 | export class File extends Inode { 6 | constructor(public path: string) { 7 | super(path); 8 | this._stat.filetype = Wasi.filetype.REGULAR_FILE; 9 | } 10 | 11 | 12 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/fs/index.ts: -------------------------------------------------------------------------------- 1 | import { FileSystem, FileDescriptor, fd, DirectoryDescriptor } from "./fs"; 2 | import { WasiResult } from '../..'; 3 | import { Wasi } from "../../../wasi"; 4 | export * from "./fs"; 5 | 6 | let DefaultFS = FileSystem.Default(); 7 | 8 | const BASE_RIGHTS: Wasi.rights = Wasi.rights.FD_READ | Wasi.rights.FD_WRITE | Wasi.rights.FD_READDIR 9 | 10 | // @ts-ignore decorator is valid 11 | @global 12 | export class fs { 13 | public static _fs: FileSystem = DefaultFS; 14 | private static initialized: bool = false; 15 | 16 | static set fs(_fs: FileSystem) { 17 | fs._fs = _fs; 18 | } 19 | 20 | static get fs(): FileSystem { 21 | if (!fs.initialized) { 22 | fs._fs.init(); 23 | fs.initialized = true; 24 | } 25 | return fs._fs; 26 | } 27 | 28 | static init(): void { 29 | fs.fs; 30 | } 31 | 32 | /** 33 | * A simplified interface to open a file for read operations 34 | * @param path Path 35 | * @param dirfd Base directory descriptor (will be automatically set soon) 36 | */ 37 | static openForRead(path: string, dirfd: fd = fs.fs.cwd): WasiResult { 38 | return this.fs.openFileAt(dirfd, path); 39 | } 40 | 41 | static createFile(path: string): WasiResult { 42 | return this.fs.createFile(path); 43 | } 44 | 45 | static createFileAt(dirfd: fd, path: string): WasiResult { 46 | return this.fs.createFileAt(dirfd, path) 47 | } 48 | 49 | /** 50 | * A simplified interface to open a file for write operations 51 | * @param path Path 52 | * @param dirfd Base directory descriptor (will be automatically set soon) 53 | */ 54 | static openForWrite(path: string, dirfd: fd = fs.fs.cwd): WasiResult { 55 | return this.fs.openFileAt(dirfd, path); 56 | } 57 | 58 | 59 | static openFile(path: string, options: Wasi.oflags = 0): WasiResult { 60 | return this.fs.openFile(path, options); 61 | } 62 | 63 | static openFileAt(dirfd: fd, path: string, options?: Wasi.oflags): WasiResult { 64 | return this.fs.openFileAt(dirfd, path, options) 65 | } 66 | 67 | 68 | static open(path: string, type: Wasi.filetype, options: Wasi.oflags): WasiResult { 69 | return this.fs.open(path, type, options); 70 | } 71 | 72 | /** 73 | * 74 | * @param path path of new directory 75 | */ 76 | static createDirectory(path: string): WasiResult { 77 | return this.fs.createDirectory(path); 78 | } 79 | 80 | static createDirectoryAt(dirfd: fd, path: string): WasiResult { 81 | return this.fs.createDirectoryAt(dirfd, path); 82 | } 83 | 84 | static openDirectory(path: string): WasiResult { 85 | return this.fs.openDirectory(path); 86 | } 87 | 88 | static openDirectoryAt(path: string, dirfd: fd): WasiResult { 89 | return this.fs.openDirectoryAt(dirfd, path) 90 | } 91 | /** 92 | * Close a file descriptor 93 | * @param fd file descriptor 94 | */ 95 | static close(fd: fd): void { 96 | this.fs.close(fd); 97 | } 98 | 99 | /** 100 | * Write data to a file descriptor 101 | * @param fd file descriptor 102 | * @param data data 103 | */ 104 | static write(fd: fd, data: Array): Wasi.errno { 105 | return this.fs.write(fd, data); 106 | } 107 | 108 | /** 109 | * Write a string to a file descriptor, after encoding it to UTF8 110 | * @param fd file descriptor 111 | * @param s string 112 | * @param newline `true` to add a newline after the string 113 | */ 114 | static writeString(fd: fd, s: string, newline: boolean = false): Wasi.errno { 115 | return this.fs.writeString(fd, s, newline); 116 | } 117 | 118 | /** 119 | * Write a string to a file descriptor, after encoding it to UTF8, with a newline 120 | * @param fd file descriptor 121 | * @param s string 122 | */ 123 | static writeStringLn(fd: fd, s: string): Wasi.errno { 124 | return this.writeString(fd, s, true); 125 | } 126 | 127 | /** 128 | * Read data from a file descriptor 129 | * @param fd file descriptor 130 | * @param data existing array to push data to 131 | * @param chunk_size chunk size (default: 4096) 132 | */ 133 | static read(fd: fd, data: Array = [], chunk_size: usize = 4096): Wasi.errno { 134 | return this.fs.read(fd, data); 135 | } 136 | 137 | /** 138 | * Read from a file descriptor until the end of the stream 139 | * @param fd file descriptor 140 | * @param data existing array to push data to 141 | * @param chunk_size chunk size (default: 4096) 142 | */ 143 | static readAll(fd: fd, data: Array = [], chunk_size: usize = 4096): Wasi.errno { 144 | return this.fs.read(fd, data); 145 | } 146 | 147 | /** 148 | * Read an UTF8 string from a file descriptor, convert it to a native string 149 | * @param fd file descriptor 150 | * @param chunk_size chunk size (default: 4096) 151 | */ 152 | static readString(fd: fd, chunk_size: usize = 4096): WasiResult { 153 | return this.fs.readString(fd, chunk_size) 154 | } 155 | 156 | /** 157 | * Reach an UTF8 String from a file descriptor until a new line is reached. 158 | */ 159 | static readLine(fd: fd, chunk_size: usize = 4096): WasiResult { 160 | return this.fs.readline(fd, chunk_size) 161 | } 162 | 163 | static reset(fd: fd): void { 164 | this.seek(fd, 0, Wasi.whence.SET); 165 | } 166 | 167 | /** 168 | * 169 | * @param fd File fd 170 | * returns the current offset of the file descriptor 171 | */ 172 | static tell(fd: fd): WasiResult { 173 | return this.fs.tell(fd); 174 | } 175 | 176 | /** 177 | * 178 | * @param fd File fd 179 | * @param offset The number of bytes to move 180 | * @param whence The base from which the offset is relative 181 | */ 182 | static seek(fd: fd, offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): WasiResult { 183 | return this.fs.seek(fd, offset, whence); 184 | } 185 | 186 | static get(fd: fd): WasiResult { 187 | return this.fs.get(fd); 188 | } 189 | 190 | static getDir(fd: fd): WasiResult { 191 | return this.fs.getDir(fd); 192 | } 193 | 194 | static erase(fd: fd): WasiResult { 195 | return this.fs.erase(fd); 196 | } 197 | 198 | static listdir(fd: fd): WasiResult { 199 | return this.fs.listdir(fd); 200 | } 201 | 202 | static delete(path: string): WasiResult { 203 | return this.fs.delete(path); 204 | } 205 | 206 | static deleteDirectory(path: string): WasiResult { 207 | return this.fs.deleteDirectory(path); 208 | } 209 | 210 | static grow(fd: fd, amount?: usize): WasiResult { 211 | return this.fs.grow(fd, amount); 212 | } 213 | 214 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/fs/inode.ts: -------------------------------------------------------------------------------- 1 | import * as Wasi from "../../../std/bindings/wasi"; 2 | 3 | 4 | 5 | export class Inode { 6 | static inode: Wasi.inode; 7 | constructor(public path: string) { 8 | this._data = new ArrayBuffer(Inode.DefaultSize); 9 | this._stat = new Wasi.filestat(); 10 | 11 | } 12 | _data: ArrayBuffer 13 | _stat: Wasi.filestat 14 | static DefaultSize: u32 = 1024; 15 | 16 | get data(): usize { 17 | return this._data.data; 18 | } 19 | 20 | grow(): File { 21 | let newData = new ArrayBuffer(this._data.byteLength * 2); 22 | memory.copy(newData.data, this.data, this._data.byteLength); 23 | return this; 24 | } 25 | 26 | erase(): void { 27 | this._data = new ArrayBuffer(File.DefaultSize); 28 | } 29 | 30 | /** Device ID of device containing the file. */ 31 | get dev(): Wasi.device { 32 | return this._stat.dev; 33 | } 34 | /** File serial number. */ 35 | get ino(): Wasi.inode { 36 | return this._stat.ino 37 | } 38 | /** File type. */ 39 | get filetype(): Wasi.filetype { 40 | return Wasi.filetype.UNKNOWN 41 | } 42 | /** Number of hard links to the file. */ 43 | get nlink(): Wasi.linkcount { 44 | return this._stat.nlink 45 | } 46 | /** For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. */ 47 | get size(): Wasi.filesize { 48 | return this._data.byteLength; 49 | } 50 | /** Last data access timestamp. */ 51 | get atim(): Wasi.timestamp { 52 | return this._stat.atim 53 | } 54 | /** Last data modification timestamp. */ 55 | get mtim(): Wasi.timestamp { 56 | return this._stat.mtim 57 | } 58 | /** Last file status change timestamp. */ 59 | get ctim(): Wasi.timestamp { 60 | return this._stat.ctim 61 | } 62 | 63 | 64 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./fs"; 2 | export * from "./random"; 3 | export * from "./process"; 4 | export * from "./console"; 5 | export * from "./environ"; 6 | export * from "./cmdline"; 7 | export * from "./date"; 8 | export * from "./performance"; 9 | export * from "./utils"; 10 | 11 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/path.ts: -------------------------------------------------------------------------------- 1 | export const PATH_SEP: string = "/" 2 | 3 | export function basename(path: string): string { 4 | return path.substr(path.lastIndexOf("/") + 1); 5 | } 6 | 7 | 8 | export function dirname(path: string): string { 9 | if (path == PATH_SEP) { 10 | return path; 11 | } 12 | let res: string = path; 13 | if (path.endsWith(PATH_SEP)) { 14 | res = path.substr(0, path.length - 1); 15 | } 16 | res = res.substr(0, res.lastIndexOf(PATH_SEP)); 17 | return res == "" ? PATH_SEP : res; 18 | } 19 | 20 | export function getPath(path: string, from: usize, to: usize): string { 21 | let paths: string[] = path.split(PATH_SEP); 22 | let start: usize = Math.max((from + paths.length) % paths.length, 0); 23 | let end: usize = Math.max((to + paths.length) % paths.length, 1); 24 | let res: string[] = paths.slice(start, end); 25 | let output = res.join(PATH_SEP); 26 | log(output); 27 | return output.startsWith("/") ? output : "/" + output; 28 | } 29 | 30 | 31 | export function join(paths: string[]): string { 32 | let paths_cleaned: string[] = new Array(); 33 | for (let i: usize = 0; i < (paths.length as usize); i++) { 34 | let path: string = paths[i]; 35 | if (path.endsWith(PATH_SEP) && !isAbsolute(path)) { 36 | path = path.substr(0, paths.length - 1); 37 | } else if (path == PATH_SEP) { 38 | path = ""; 39 | } 40 | if (path.startsWith("./")) { 41 | path = path.substr(2) 42 | } 43 | paths_cleaned.push(path) 44 | } 45 | return paths_cleaned.join(PATH_SEP); 46 | } 47 | 48 | export function isAbsolute(path: string): bool { 49 | return path.startsWith(PATH_SEP); 50 | } 51 | 52 | export function relative(pathFrom: string, pathTo: string): string { 53 | //TODO 54 | return "" 55 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/performance.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Performance { 3 | static now(): f64 { 4 | let time_ptr = memory.allocate(8); 5 | let res_ts = load(time_ptr); 6 | memory.free(time_ptr); 7 | return res_ts as f64; 8 | } 9 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/process.ts: -------------------------------------------------------------------------------- 1 | import { fd } from "./fs"; 2 | import { Wasi } from "../../wasi"; 3 | 4 | //@ts-ignore 5 | @global 6 | export class Process { 7 | static _singleton: Process; 8 | 9 | constructor(cwd: fd) { 10 | this._cwd = cwd; 11 | Process._singleton = this; 12 | } 13 | _cwd: fd; 14 | /** 15 | * Cleanly terminate the current process 16 | * @param status exit code 17 | */ 18 | static exit(status: Wasi.errno): void { 19 | if (status != Wasi.errno.SUCCESS) { 20 | abort("Error "); 21 | } 22 | abort(); 23 | } 24 | 25 | static get cwd(): fd { 26 | return Process._singleton._cwd; 27 | } 28 | 29 | static set cwd(fd: fd) { 30 | Process._singleton._cwd = fd; 31 | } 32 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/random/index.ts: -------------------------------------------------------------------------------- 1 | import { RNG } from "./xor"; 2 | 3 | export class Random { 4 | static RNG: RNG = RNG.fromSeed(84); 5 | 6 | /** 7 | * Fill a buffer with random data 8 | * @param buffer An array buffer 9 | */ 10 | static randomFill(buffer: ArrayBuffer): void { 11 | for (let i = 0; i < buffer.byteLength; i++) { 12 | store(buffer.data + i, this.RNG.next()); 13 | } 14 | } 15 | 16 | /** 17 | * Return an array of random bytes 18 | * @param len length 19 | */ 20 | static randomBytes(len: usize): Uint8Array { 21 | let array = new Uint8Array(len); 22 | this.randomFill(array.buffer); 23 | return array; 24 | } 25 | 26 | static randomU32(): u32 { 27 | let len = sizeof(); 28 | let array = this.randomBytes(len) as Uint32Array; 29 | return array[1]; 30 | 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/random/xor.ts: -------------------------------------------------------------------------------- 1 | class RandomNumberGenerator { 2 | next(): u32 { 3 | return 0; 4 | } 5 | } 6 | 7 | //inspired by https://github.com/dubzzz/pure-rand/blob/master/src/generator/XorShift.ts 8 | 9 | class XorShift128Plus extends RandomNumberGenerator { 10 | constructor( 11 | private s01: u32, 12 | private s00: u32, 13 | private s11: u32, 14 | private s10: u32 15 | ) { 16 | super(); 17 | } 18 | min(): u32 { 19 | return -0x80000000; 20 | } 21 | max(): u32 { 22 | return 0x7fffffff; 23 | } 24 | next(): u32 { 25 | // let a0 = this.s00 ^ (this.s00 << 23); 26 | // let a1 = this.s01 ^ ((this.s01 << 23) | (this.s00 >>> 9)); 27 | // let b0 = 28 | // a0 ^ 29 | // this.s10 ^ 30 | // ((a0 >>> 17) | (a1 << 15)) ^ 31 | // ((this.s10 >>> 26) | (this.s11 << 6)); 32 | // let b1 = a1 ^ this.s11 ^ (a1 >>> 17) ^ (this.s11 >>> 26); 33 | // this.s01 = this.s11; 34 | // this.s00 = this.s10; 35 | // this.s11 = b1; 36 | // this.s10 = b0; 37 | return (this.s10++); 38 | } 39 | 40 | static fromSeed(seed: u32): XorShift128Plus { 41 | return new XorShift128Plus(-1, ~seed, 0, seed | 0); 42 | }; 43 | } 44 | export { XorShift128Plus as RNG } 45 | -------------------------------------------------------------------------------- /packages/assemblyscript/assembly/wasa/mock/utils/index.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export class StringUtils { 4 | static readonly NUL: u8 = 0; 5 | static readonly EOT: u8 = 4; 6 | static readonly LF: u8 = 10; 7 | 8 | static isNewLine(ptr: usize): boolean { 9 | return load(ptr) == this.LF; 10 | } 11 | 12 | private static terminates(ptr: usize): bool { 13 | let char: u8 = load(ptr); 14 | return char == this.NUL || char == this.EOT 15 | } 16 | 17 | static fromCString(cstring: usize, max: usize = 4096): string | null { 18 | let size: usize = 0; 19 | while (!this.terminates(cstring + size) && size < max - 1) { 20 | size++; 21 | } 22 | if (size == 0) { 23 | return null 24 | } 25 | return String.fromUTF8(cstring, size); 26 | } 27 | 28 | static fromCStringTilNewLine(cstring: usize, max: usize): string | null { 29 | let size: usize = 0; 30 | while (!this.terminates(cstring + size) && size < max - 1) { 31 | if (this.isNewLine(cstring + size)) { 32 | break; 33 | } 34 | size++; 35 | } 36 | if (size == 0) { 37 | return null 38 | } 39 | return String.fromUTF8(cstring, size + 1); 40 | } 41 | } -------------------------------------------------------------------------------- /packages/assemblyscript/bin/wasmos-asc: -------------------------------------------------------------------------------- 1 | wasmos-asc.ts -------------------------------------------------------------------------------- /packages/assemblyscript/bin/wasmos-asc.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ts-node 2 | import { Compiler } from "../src"; 3 | if (process.argv.length < 3) { 4 | console.log("missing input file") 5 | process.exit(0); 6 | } 7 | Compiler.compileOne(process.argv[2]); 8 | -------------------------------------------------------------------------------- /packages/assemblyscript/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src"; 2 | -------------------------------------------------------------------------------- /packages/assemblyscript/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/assemblyscript", 3 | "version": "0.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@protobufjs/utf8": { 8 | "version": "1.1.0", 9 | "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", 10 | "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" 11 | }, 12 | "assemblyscript": { 13 | "version": "github:willemneal/assemblyscript#fa7c0fa7ec4d0e623731efbbb01547921e2f8b1f", 14 | "from": "github:willemneal/assemblyscript#fa7c0fa7ec4d0e623731efbbb01547921e2f8b1f", 15 | "requires": { 16 | "@protobufjs/utf8": "^1.1.0", 17 | "binaryen": "73.0.0-nightly.20190327", 18 | "glob": "^7.1.3", 19 | "long": "^4.0.0", 20 | "opencollective-postinstall": "^2.0.0", 21 | "source-map-support": "^0.5.11" 22 | } 23 | }, 24 | "balanced-match": { 25 | "version": "1.0.0", 26 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 27 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 28 | }, 29 | "binaryen": { 30 | "version": "73.0.0-nightly.20190327", 31 | "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-73.0.0-nightly.20190327.tgz", 32 | "integrity": "sha512-FMHRsdX5pkPX3qO3Ez6CFMk1gCigk5tBkyGXDYlWATslR8l5rPB4UGGq/DYfB3yE1riEHzV9VFUlz/WXG0W3vA==" 33 | }, 34 | "brace-expansion": { 35 | "version": "1.1.11", 36 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 37 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 38 | "requires": { 39 | "balanced-match": "^1.0.0", 40 | "concat-map": "0.0.1" 41 | } 42 | }, 43 | "buffer-from": { 44 | "version": "1.1.1", 45 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 46 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 47 | }, 48 | "concat-map": { 49 | "version": "0.0.1", 50 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 51 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 52 | }, 53 | "fs.realpath": { 54 | "version": "1.0.0", 55 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 56 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 57 | }, 58 | "glob": { 59 | "version": "7.1.3", 60 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 61 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 62 | "requires": { 63 | "fs.realpath": "^1.0.0", 64 | "inflight": "^1.0.4", 65 | "inherits": "2", 66 | "minimatch": "^3.0.4", 67 | "once": "^1.3.0", 68 | "path-is-absolute": "^1.0.0" 69 | } 70 | }, 71 | "inflight": { 72 | "version": "1.0.6", 73 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 74 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 75 | "requires": { 76 | "once": "^1.3.0", 77 | "wrappy": "1" 78 | } 79 | }, 80 | "inherits": { 81 | "version": "2.0.3", 82 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 83 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 84 | }, 85 | "long": { 86 | "version": "4.0.0", 87 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 88 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 89 | }, 90 | "minimatch": { 91 | "version": "3.0.4", 92 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 93 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 94 | "requires": { 95 | "brace-expansion": "^1.1.7" 96 | } 97 | }, 98 | "once": { 99 | "version": "1.4.0", 100 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 101 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 102 | "requires": { 103 | "wrappy": "1" 104 | } 105 | }, 106 | "opencollective-postinstall": { 107 | "version": "2.0.2", 108 | "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", 109 | "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==" 110 | }, 111 | "path-is-absolute": { 112 | "version": "1.0.1", 113 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 114 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 115 | }, 116 | "source-map": { 117 | "version": "0.6.1", 118 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 119 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 120 | }, 121 | "source-map-support": { 122 | "version": "0.5.12", 123 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", 124 | "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", 125 | "requires": { 126 | "buffer-from": "^1.0.0", 127 | "source-map": "^0.6.0" 128 | } 129 | }, 130 | "wrappy": { 131 | "version": "1.0.2", 132 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 133 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /packages/assemblyscript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/assemblyscript", 3 | "version": "0.0.2", 4 | "description": "Fork of AssemblyScript", 5 | "main": "dist/index.js", 6 | "typings": "assembly/index", 7 | "scripts": { 8 | "test": "jest" 9 | }, 10 | "files": [ 11 | "lib/", 12 | "tsconfig.json", 13 | "tsconfig-base.json", 14 | "bin/" 15 | ], 16 | "bin": { 17 | "wasmos-asc": "./bin/wasmos-asc.ts" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/assemblyscript" 22 | }, 23 | "keywords": [ 24 | "AssemblyScript", 25 | "WebAssembly", 26 | "WebAssemblyOS" 27 | ], 28 | "author": "Willem Wyndham", 29 | "license": "MIT", 30 | "dependencies": { 31 | "@wasmos/fs": "git:github.com/WebAssemblyOS/fs#v0.0.2", 32 | "assemblyscript": "github:willemneal/assemblyscript#fa7c0fa7ec4d0e623731efbbb01547921e2f8b1f" 33 | } 34 | } -------------------------------------------------------------------------------- /packages/assemblyscript/spec/compiler.spec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as shell from "shelljs"; 3 | import * as path from "path"; 4 | 5 | import { Compiler, linkLibrary } from "../src"; 6 | 7 | const ROOT = path.join(__dirname, ".."); 8 | 9 | describe("Link Library", () => { 10 | (test)( 11 | "should find all the assembly files", 12 | async () => { 13 | await linkLibrary(ROOT); 14 | expect(shell.test("-e", ROOT + "/node_modules/.assembly")).toBe(true); 15 | }, 16 | 4000 17 | ); 18 | }); 19 | 20 | describe("echo", () => { 21 | it("should compile", async () => { 22 | let x = 1; 23 | let y = x + x; 24 | // process.chdir(__dirname + "/.."); 25 | // await Compiler.compileOne(path.join("./assembly", "bin", "echo.ts")); 26 | }, 20000); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/assemblyscript/src/compiler/compiler.ts: -------------------------------------------------------------------------------- 1 | import { glob, fs, mkdirp } from "@wasmos/fs/src/index"; 2 | import * as asc from "assemblyscript/cli/asc"; 3 | import { linkLibrary } from "../linker"; 4 | import * as path from "path"; 5 | import assert = require("assert"); 6 | 7 | let join = path.join; 8 | 9 | interface CompilerOptions { 10 | /** Standard output stream to use. */ 11 | stdout?: asc.OutputStream; 12 | /** Standard error stream to use. */ 13 | stderr?: asc.OutputStream; 14 | /** Reads a file from disk (or memory). */ 15 | readFile?: (filename: string, baseDir: string) => Promise; 16 | /** Writes a file to disk (or memory). */ 17 | writeFile?: ( 18 | filename: string, 19 | contents: Uint8Array, 20 | baseDir: string 21 | ) => Promise; 22 | /** Lists all files within a directory. */ 23 | listFiles?: (dirname: string, baseDir: string) => Promise; 24 | /** Output Directory */ 25 | outDir?: string; 26 | /** Base directory for assembly source */ 27 | baseDir?: string; 28 | /** Command line args passed to asc */ 29 | cmdline?: string[]; 30 | /** Whether to print mesaurements */ 31 | mesaure?: boolean; 32 | /** Whether to include all assembly library folders */ 33 | lib?: boolean; 34 | } 35 | 36 | function isRoot(dir: string): boolean { 37 | return path.basename(dir) !== ""; 38 | } 39 | 40 | export class Compiler { 41 | static get opts(): CompilerOptions { 42 | return Compiler._opts; 43 | } 44 | static mergeOpts(newOpts?: CompilerOptions): CompilerOptions { 45 | if (newOpts) this._opts = { ...newOpts, ...this._opts }; 46 | return this._opts; 47 | } 48 | 49 | private static _opts = { 50 | readFile: async (basename: string, baseDir: string) => { 51 | let base = baseDir ? baseDir : "."; 52 | try { 53 | let file = path.join(base, basename); 54 | // let libPath = path.join("../node_modules/.assembly", basename); 55 | if (await fs.pathExists(basename)) { 56 | file = basename; 57 | } 58 | let source = await fs.readFile(file); 59 | let sourceStr = source.toString(); 60 | if (basename.startsWith("node_modules")) { 61 | let libname = basename.replace(/.*\.assembly\/(.*)\.ts/, "$1"); 62 | libname = libname.replace(/(.*)\/index/, "$1"); 63 | if (!asc.libraryFiles[libname]) asc.libraryFiles[libname] = sourceStr; 64 | } 65 | return sourceStr; 66 | } catch (e) { 67 | return null; 68 | } 69 | }, 70 | writeFile: async ( 71 | basename: string, 72 | content: Uint8Array, 73 | baseDir: string 74 | ) => { 75 | let base = baseDir ? baseDir : ""; 76 | let file = path.join(base, basename); 77 | let folder = path.dirname(file); 78 | await mkdirp(folder); //Create parent folders 79 | await fs.writeFile(file, content, { flag: "w" }); 80 | }, 81 | listFiles: async (basename: string, baseDir: string): Promise => { 82 | let base = baseDir ? baseDir : ""; 83 | let dir = path.join(base, basename); 84 | try { 85 | var files: string[] = []; 86 | files = await fs.readdir(dir); 87 | } catch (error) { 88 | try { 89 | files = await fs.readdir(await fs.realpath(dir)); 90 | } catch (error) { 91 | throw error; 92 | } 93 | } 94 | return files; 95 | }, 96 | stdout: asc.createMemoryStream(), 97 | stderr: asc.createMemoryStream(), 98 | outDir: "../dist/bin", 99 | baseDir: "./assembly", 100 | cmdline: [], 101 | mesaure: false, 102 | lib: true 103 | }; 104 | 105 | static async compileOne(bin: string, _opts?: CompilerOptions): Promise { 106 | let binPath = path.isAbsolute(bin) ? bin : path.join(process.cwd(), bin); 107 | 108 | let opts = this.mergeOpts(_opts); 109 | let folder = path.basename(bin).split(".")[0]; 110 | 111 | let outDir = join(opts.outDir!, folder); 112 | let baseDir = this.findRoot(binPath); 113 | let relativeBin = path.relative(baseDir, binPath); 114 | let relativeDir = path.relative(process.cwd(), baseDir); 115 | let libraryPath = path.relative( 116 | process.cwd(), 117 | await linkLibrary(path.join(baseDir, "..")) 118 | ); 119 | let allPaths = await glob(libraryPath + "/**/*.ts"); 120 | // await Promise.all( 121 | // allPaths.map(async file => { 122 | // let libname = file.replace(/.*\.assembly\/(.*)\.ts/, "$1"); 123 | // // libname = libname.replace(/(.*)\/index/, "$1"); 124 | // console.log("------------------- " + libname); 125 | // asc.libraryFiles[libname] = (await opts.readFile!(file, "")) || ""; 126 | // }) 127 | // ); 128 | 129 | let libFolders: string[] = opts.lib ? ["--lib", libraryPath] : []; 130 | 131 | var preamble: string[] = []; 132 | let preamblePath = path.join(baseDir, "preamble.ts"); 133 | if (await fs.pathExists(preamblePath)) { 134 | preamble.push("preamble.ts"); 135 | } 136 | preamble = preamble.concat( 137 | allPaths.filter((x: string) => x.endsWith("preamble.ts")) 138 | ); 139 | // console.log(`Preamble: ${preamble}`); 140 | // console.log(`libfolders: ${libFolders}`); 141 | // console.log(`all Paths: ${allPaths}`); 142 | 143 | let asc_opts = [ 144 | relativeBin, 145 | "--baseDir", 146 | relativeDir, 147 | "--binaryFile", 148 | `${outDir}/index.wasm`, 149 | "--textFile", 150 | `${outDir}/index.wat`, 151 | "--tsdFile", 152 | `${outDir}/index.d.ts`, 153 | "--importMemory", 154 | "--measure", 155 | "--validate", 156 | "--debug" 157 | ].concat(libFolders); 158 | 159 | return new Promise((resolve, reject) => { 160 | (asc).main( 161 | preamble.concat(asc_opts).concat(opts.cmdline!), 162 | { ...opts }, 163 | (x: Error) => { 164 | if (x == null) { 165 | if (opts.mesaure) { 166 | let err = opts.stderr!.toString(); 167 | console.log(err); 168 | } 169 | resolve(); 170 | } else { 171 | console.error(opts.stderr!.toString()); 172 | console.error(x); 173 | reject(); 174 | } 175 | } 176 | ); 177 | }); 178 | } 179 | 180 | static findRoot(baseDir: string): string { 181 | while (isRoot(baseDir)) { 182 | baseDir = path.dirname(baseDir); 183 | if (path.basename(baseDir) === "assembly") { 184 | return baseDir; 185 | } 186 | } 187 | return this._opts.baseDir; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /packages/assemblyscript/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./compiler/compiler"; 2 | import * as loader from "assemblyscript/lib/loader/lib"; 3 | export { loader }; 4 | export * from "assemblyscript/lib/host/lib"; 5 | export * from "./linker"; 6 | 7 | export async function main() {} 8 | -------------------------------------------------------------------------------- /packages/assemblyscript/src/linker.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { fs, assemblyFolders } from "@wasmos/fs/src/index"; 3 | 4 | export async function linkLibrary(rootPath: string): Promise { 5 | let folders = await assemblyFolders(rootPath); 6 | let assemblyFolder = path.join(rootPath, "node_modules", ".assembly"); 7 | await fs.mkdirp(assemblyFolder); 8 | let pwd = process.cwd(); 9 | process.chdir(assemblyFolder); 10 | await Promise.all( 11 | folders.map(async (v: string) => { 12 | let folder = path.dirname(v); 13 | let grandFolder = path.dirname(folder); 14 | folder = path.basename(folder); 15 | while (path.basename(grandFolder) != "node_modules") { 16 | folder = path.join(path.basename(grandFolder), folder); 17 | grandFolder = path.dirname(grandFolder); 18 | } 19 | if (path.basename(path.dirname(folder)) != "node_modules") { 20 | await fs.mkdirp(path.dirname(folder)); 21 | } 22 | let folderExists = await fs.pathExists(folder); 23 | if (!folderExists) { 24 | let realPath = await fs.realpath(v); 25 | await fs.symlink(realPath, folder, "dir"); 26 | } 27 | }) 28 | ); 29 | process.chdir(pwd); 30 | 31 | return assemblyFolder; 32 | } 33 | -------------------------------------------------------------------------------- /packages/assemblyscript/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.ts.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/fs/README.md: -------------------------------------------------------------------------------- 1 | # fs 2 | 3 | Provides the file system interface for the kernel. 4 | -------------------------------------------------------------------------------- /packages/fs/assembly/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the interface assemblyscript programs will use to access the filesystem. 3 | */ 4 | 5 | export class File {} 6 | 7 | // declare function open(path: string): File; 8 | 9 | // declare function close(f: File): void; 10 | 11 | // declare function write(f: File, c: Uint8Array | string): void; 12 | 13 | // declare function read(f: File, bytes: number): Uint8Array; 14 | -------------------------------------------------------------------------------- /packages/fs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; -------------------------------------------------------------------------------- /packages/fs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/fs", 3 | "version": "0.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/events": { 8 | "version": "3.0.0", 9 | "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", 10 | "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", 11 | "dev": true 12 | }, 13 | "@types/glob": { 14 | "version": "7.1.1", 15 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 16 | "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", 17 | "dev": true, 18 | "requires": { 19 | "@types/events": "*", 20 | "@types/minimatch": "*", 21 | "@types/node": "*" 22 | } 23 | }, 24 | "@types/minimatch": { 25 | "version": "3.0.3", 26 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 27 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 28 | "dev": true 29 | }, 30 | "@types/node": { 31 | "version": "11.13.4", 32 | "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", 33 | "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==", 34 | "dev": true 35 | }, 36 | "balanced-match": { 37 | "version": "1.0.0", 38 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 39 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 40 | }, 41 | "brace-expansion": { 42 | "version": "1.1.11", 43 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 44 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 45 | "requires": { 46 | "balanced-match": "^1.0.0", 47 | "concat-map": "0.0.1" 48 | } 49 | }, 50 | "concat-map": { 51 | "version": "0.0.1", 52 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 53 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 54 | }, 55 | "fs.realpath": { 56 | "version": "1.0.0", 57 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 58 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 59 | }, 60 | "glob": { 61 | "version": "7.1.3", 62 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 63 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 64 | "requires": { 65 | "fs.realpath": "^1.0.0", 66 | "inflight": "^1.0.4", 67 | "inherits": "2", 68 | "minimatch": "^3.0.4", 69 | "once": "^1.3.0", 70 | "path-is-absolute": "^1.0.0" 71 | } 72 | }, 73 | "inflight": { 74 | "version": "1.0.6", 75 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 76 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 77 | "requires": { 78 | "once": "^1.3.0", 79 | "wrappy": "1" 80 | } 81 | }, 82 | "inherits": { 83 | "version": "2.0.3", 84 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 85 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 86 | }, 87 | "minimatch": { 88 | "version": "3.0.4", 89 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 90 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 91 | "requires": { 92 | "brace-expansion": "^1.1.7" 93 | } 94 | }, 95 | "once": { 96 | "version": "1.4.0", 97 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 98 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 99 | "requires": { 100 | "wrappy": "1" 101 | } 102 | }, 103 | "path-is-absolute": { 104 | "version": "1.0.1", 105 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 106 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 107 | }, 108 | "wrappy": { 109 | "version": "1.0.2", 110 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 111 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /packages/fs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/fs", 3 | "version": "0.0.2", 4 | "description": "Core OS kernel for assemblyscript and WebAssembly", 5 | "types": "assembly/index.ts", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/fs" 12 | }, 13 | "keywords": [ 14 | "AssemblyScript", 15 | "Kernel", 16 | "OS", 17 | "WebAssembly", 18 | "WebAssemblyOS" 19 | ], 20 | "author": "Willem Wyndham", 21 | "license": "MIT", 22 | "dependencies": { 23 | "glob": "^7.1.3" 24 | }, 25 | "devDependencies": { 26 | "@types/glob": "^7.1.1" 27 | } 28 | } -------------------------------------------------------------------------------- /packages/fs/src/fs/index.ts: -------------------------------------------------------------------------------- 1 | import * as BrowserFS from "browserfs/dist/browserfs"; 2 | import { glob, promisfy } from "../glob"; 3 | 4 | export async function assemblyFolders(startingDir: string): Promise { 5 | let dir = startingDir + "/node_modules/**/**/assembly"; 6 | let res = new Set(); 7 | return (await glob(dir)) 8 | .filter( 9 | v => !(v.endsWith("std/types/assembly") || v.endsWith("std/assembly")) 10 | ) 11 | .reduce((acc: string[], v: string) => { 12 | let endName = v.substring(v.lastIndexOf("node_modules")); 13 | if (!res.has(endName)) { 14 | acc.push(v); 15 | res.add(endName); 16 | } 17 | return acc; 18 | }, []); 19 | } 20 | export async function init( 21 | root: string | ArrayBuffer = "assembly.zip" 22 | ): Promise { 23 | BrowserFS.install(global || window); 24 | return new Promise(async (resolve, reject) => { 25 | let zipData; 26 | if (typeof root === "string") { 27 | let response = await fetch(root); 28 | zipData = await response.arrayBuffer(); 29 | } else { 30 | zipData = root; 31 | } 32 | BrowserFS.configure( 33 | { 34 | fs: "MountableFileSystem", 35 | options: { 36 | "/": { 37 | fs: "OverlayFS", 38 | options: { 39 | readable: { 40 | fs: "ZipFS", 41 | options: { 42 | // Wrap as Buffer object. 43 | zipData: Buffer.from(zipData) 44 | } 45 | }, 46 | writable: { 47 | fs: "LocalStorage", 48 | options: {} 49 | } 50 | } 51 | } 52 | } 53 | }, 54 | function (e) { 55 | if (e) { 56 | // An error occurred. 57 | reject(e); 58 | } 59 | resolve(); 60 | } 61 | ); 62 | }); 63 | } 64 | 65 | export async function initWorker(): Promise { 66 | await promisfy(BrowserFS.configure)({ 67 | fs: "WorkerFS", 68 | options: { worker: self } 69 | }); 70 | } 71 | export function attachWorker(worker: Worker) { 72 | BrowserFS.FileSystem.WorkerFS.attachRemoteListener(worker); 73 | } 74 | 75 | import { promises as _fs, constants } from "fs"; 76 | 77 | 78 | interface fs { 79 | pathExists(path: string): Promise; 80 | mkdirp( 81 | p: string, 82 | opts?: any, 83 | made?: string 84 | ): Promise 85 | } 86 | let fs: fs & typeof _fs = { ..._fs, pathExists, mkdirp }; 87 | 88 | async function pathExists(path: string): Promise { 89 | try { 90 | await _fs.access(path, constants.R_OK | constants.W_OK) 91 | return true; 92 | } catch (error) { 93 | return false 94 | } 95 | } 96 | /* 97 | Copyright 2010 James Halliday (mail@substack.net) 98 | 99 | This project is free software released under the MIT/X11 license: 100 | 101 | Permission is hereby granted, free of charge, to any person obtaining a copy 102 | of this software and associated documentation files (the "Software"), to deal 103 | in the Software without restriction, including without limitation the rights 104 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105 | copies of the Software, and to permit persons to whom the Software is 106 | furnished to do so, subject to the following conditions: 107 | 108 | The above copyright notice and this permission notice shall be included in 109 | all copies or substantial portions of the Software. 110 | 111 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 112 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 113 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 114 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 115 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 116 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 117 | THE SOFTWARE. 118 | */ 119 | 120 | import * as path from "path"; 121 | 122 | var _0777 = parseInt("0777", 8); 123 | /** 124 | * Creates a directory including the parents if they don't exist. 125 | */ 126 | export async function mkdirp( 127 | p: string, 128 | opts: any | null = null, 129 | made: string | null = null 130 | ): Promise { 131 | if (!opts || typeof opts !== "object") { 132 | opts = { mode: opts }; 133 | } 134 | var mode = opts.mode; 135 | if (mode === undefined) { 136 | mode = _0777 & ~process.umask(); 137 | } 138 | if (!made) made = null; 139 | p = path.resolve(p); 140 | try { 141 | await _fs.mkdir(p, mode); 142 | made = made || p; 143 | } catch (err0) { 144 | switch (err0.code) { 145 | case "ENOENT": 146 | made = await mkdirp(path.dirname(p), opts, made); 147 | await mkdirp(p, opts, made); 148 | break; 149 | default: 150 | var stat; 151 | try { 152 | stat = await _fs.stat(p); 153 | } catch (err1) { 154 | throw err0; 155 | } 156 | if (!stat.isDirectory()) throw err0; 157 | break; 158 | } 159 | } 160 | return made; 161 | } 162 | 163 | export { fs }; 164 | 165 | -------------------------------------------------------------------------------- /packages/fs/src/glob.ts: -------------------------------------------------------------------------------- 1 | import __glob from "glob"; 2 | 3 | export function promisfy(fn: any) { 4 | return (...args: any[]) => 5 | new Promise((resolve: any, reject: any) => { 6 | fn(...args, (error: any, content: any) => { 7 | if (error) reject(error); 8 | resolve(content); 9 | }); 10 | }); 11 | } 12 | function _glob( 13 | pattern: string, 14 | options: any, 15 | cb: (err: Error, matches: string[]) => void 16 | ) { 17 | if (typeof options === "function") (cb = options), (options = {}); 18 | if (!options) options = {}; 19 | return new __glob.Glob(pattern, options, cb); 20 | } 21 | 22 | let glob: (glob: string)=> Promise = promisfy(_glob); 23 | export {glob} 24 | -------------------------------------------------------------------------------- /packages/fs/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./fs"; 2 | export * from "./glob"; 3 | -------------------------------------------------------------------------------- /packages/fs/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.ts.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/fs/src/wasi/index.ts: -------------------------------------------------------------------------------- 1 | type u32 = number; 2 | 3 | export class FileDescriptor { 4 | constructor(public id: u32, public offset: u32 = 0) {} 5 | } 6 | -------------------------------------------------------------------------------- /packages/kernel/README.md: -------------------------------------------------------------------------------- 1 | # Kernel 2 | 3 | This is the core of the OS. It contains a set of core packages. As of right now a kernel binary is statically compiled. 4 | 5 | [Wasa](https://github.com/WebAssemblyOS/wasa) provides the AssemblyScript API for the kernel and a typescript interface for creating the corresponding assemblyscript imports. 6 | -------------------------------------------------------------------------------- /packages/kernel/assembly/__tests__/example.spec.ts: -------------------------------------------------------------------------------- 1 | describe("args", (): void => { 2 | it("should be truthy", (): void => { 3 | expect(true).toBe(true); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/kernel/assembly/index.d.ts: -------------------------------------------------------------------------------- 1 | import {Process} from "./process"; 2 | 3 | 4 | // declare global { 5 | // /** 6 | // * Each binary has a global called process 7 | // */ 8 | // var process: Process; 9 | // } 10 | 11 | declare var process: Process; 12 | -------------------------------------------------------------------------------- /packages/kernel/assembly/index.ts: -------------------------------------------------------------------------------- 1 | 2 | // import * as fs from "./fs"; 3 | import {Process} from "./process"; 4 | import {ViewBuffer, CharBuffer} from "./screen"; 5 | 6 | @external("kernel", "initProcess") 7 | declare function initProcess(p: Process): void; 8 | 9 | class Queue extends Array{ 10 | 11 | } 12 | 13 | /** 14 | * This is singleton class is the core of the OS. 15 | * It's purpose is to be the link between WebAssembly programs and the browser. 16 | * 17 | */ 18 | class Kernel { 19 | /** 20 | * The state of the kernel is: 21 | * - filesystems mounted 22 | * - open files 23 | * - running processes 24 | * - waiting processes 25 | * - idle processes 26 | */ 27 | // public fs: FileSystem; 28 | public running: Queue; 29 | public waiting: Queue; 30 | public idle: Queue; 31 | 32 | /** Process initial running that can forked and execed. 33 | * For our purpose it will be the shell. 34 | */ 35 | private init: Process; 36 | 37 | constructor() { 38 | // this.fs = new FileSystem(); 39 | this.running = new Queue(); 40 | this.waiting = new Queue(); 41 | this.idle = new Queue(); 42 | // this.init = new Process("/boot/init", process.cwd); 43 | } 44 | 45 | 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /packages/kernel/assembly/process.ts: -------------------------------------------------------------------------------- 1 | type EnvVar = Map; 2 | 3 | export class InputStream { 4 | constructor() {} 5 | } 6 | 7 | export class OutputStream { 8 | constructor() {} 9 | } 10 | 11 | export class Process { 12 | private _uid: i32; 13 | private _cwd: string; 14 | public argv: string[]; 15 | public cmd: string; 16 | public argv0: string; 17 | public stdout: OutputStream; 18 | public stdin: InputStream; 19 | public exitCode: i32; 20 | 21 | constructor(cmdline: string, currentDir: string) { 22 | this.cmd = cmdline; 23 | this.argv = cmdline.split(" "); 24 | this.argv0 = this.argv[0]; 25 | this._cwd = currentDir; 26 | this.stdin = new InputStream(); 27 | this.stdout = new OutputStream(); 28 | } 29 | 30 | chdir(dir: string): void { 31 | this._cwd = dir; 32 | } 33 | 34 | get cwd(): string { 35 | return this._cwd; 36 | } 37 | 38 | get uid(): i32 { 39 | return this._uid; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/kernel/assembly/screen.ts: -------------------------------------------------------------------------------- 1 | 2 | @external("host", "initScreen") 3 | declare function initScreen(view: ViewBuffer): void; 4 | 5 | export class Position { 6 | constructor(public col: i32, public row: i32){} 7 | } 8 | 9 | export class ViewBuffer { 10 | data: Array; 11 | width: i32; 12 | start: i32; 13 | 14 | /** 15 | * Given a buffer of characters 16 | */ 17 | constructor(data: Array, width: i32, start: i32){ 18 | this.data = data; 19 | this.width = width; 20 | this.start = start; 21 | initScreen(this); 22 | } 23 | 24 | 25 | } 26 | 27 | export type CharBuffer = ViewBuffer; 28 | -------------------------------------------------------------------------------- /packages/kernel/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src"; -------------------------------------------------------------------------------- /packages/kernel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/kernel", 3 | "version": "0.0.2", 4 | "description": "Core OS kernel for assemblyscript and WebAssembly", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/kernel" 12 | }, 13 | "keywords": [ 14 | "AssemblyScript", 15 | "Kernel", 16 | "OS", 17 | "WebAssembly", 18 | "WebAssemblyOS" 19 | ], 20 | "author": "Willem Wyndham", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@wasmos/assemblyscript": "git:github.com/WebAssemblyOS/assemblyscript#v0.0.2", 24 | "@wasmos/fs": "git:github.com/WebAssemblyOS/fs#v0.0.2", 25 | "@wasmos/wasa": "git:github.com/WebAssemblyOS/wasa" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/kernel/spec/process.spec.ts: -------------------------------------------------------------------------------- 1 | import { UTF8, Env } from "../src/process"; 2 | import { ASProcess } from "../src/process/wasm"; 3 | import { stringToUTF8Array, fromUTF8Array, toUint8Array } from "@wasmos/utils"; 4 | import { loader } from "@wasmos/assemblyscript/src/index"; 5 | 6 | var args: UTF8.Array; 7 | var env: UTF8.Map; 8 | const Hello = "Hello"; 9 | const world = "world"; 10 | beforeEach(() => { 11 | args = new UTF8.Array([]); 12 | env = UTF8.Map.fromMap(new Map([[Hello, world]])); 13 | }); 14 | 15 | function bytesEqual(expected: Uint8Array, received: Uint8Array) { 16 | expect(expected.subarray(0, expected.length - 1)).toEqual(received); 17 | } 18 | 19 | describe("Args", () => { 20 | it("has size and bytes", () => { 21 | args.push(Hello); 22 | let data = new Uint8Array(Hello.length * 4 + 1); 23 | let size = stringToUTF8Array(Hello, data, 0, Hello.length + 2); 24 | expect(args.bytes.slice(0, args.size - 1)).toEqual(data.slice(0, size)); 25 | args.push(world); 26 | expect(args.length).toBe(2); 27 | }); 28 | }); 29 | 30 | describe("Env", () => { 31 | it("has should add an equal sign", async () => { 32 | //One for `=` and null at the end. 33 | expect(env.size).toBe(Hello.length + world.length + 2); 34 | bytesEqual(env.bytes, toUint8Array([Hello, world].join("="))); 35 | }); 36 | }); 37 | 38 | describe("Process", () => { 39 | describe("Storing data", () => { 40 | it("should store args", async () => { 41 | args.push(Hello); 42 | args.push(world); 43 | let _args = [Hello, world]; 44 | let asp = new ASProcess(_args); 45 | expect(asp.args.length).toBe(2); 46 | expect(fromUTF8Array(asp.utf8Args.args[0].data)).toEqual(Hello); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /packages/kernel/spec/worker.spec.bk.ts: -------------------------------------------------------------------------------- 1 | // 2 | // import 'jsdom-worker'; 3 | 4 | import * as fs_ from "fs"; 5 | import { init, attachWorker } from "../packages/fs/src"; 6 | import * as path from "path"; 7 | const sleep = t => 8 | new Promise(r => { 9 | setTimeout(r, t); 10 | }); 11 | 12 | // import { Worker, isMainThread, parentPort, workerData } from 'worker_threads'; 13 | 14 | let worker: Worker; 15 | 16 | // beforeAll(async () => { 17 | // 18 | 19 | // 20 | // }, 10000); 21 | 22 | afterAll(async () => { 23 | // worker.terminate(); 24 | }); 25 | 26 | describe("worker thread", () => { 27 | it("should ping back", async () => { 28 | // let res = await new Promise(async (resolve, reject) => { 29 | // try { 30 | // let zipData = fs_.readFileSync(path.join(__dirname, "build.zip")); 31 | // console.log(zipData.length); 32 | // await init(zipData); 33 | // let source = fs_ 34 | // .readFileSync(path.join(__dirname, "build", "worker.js")) 35 | // .toString(); 36 | // let url = URL.createObjectURL(new Blob([source])); 37 | // console.log(url); 38 | // worker = new Worker(url); 39 | // attachWorker(worker as any); 40 | // worker.onmessage = (ev: MessageEvent) => { 41 | // if (!ev.data.browserfsMessage) { 42 | // resolve(ev.data); 43 | // } 44 | // }; 45 | // worker.postMessage("Hi earth"); 46 | // } catch (error) { 47 | // console.log(error.stack); 48 | // console.log(error.message); 49 | // } 50 | // }); 51 | // console.log(res); 52 | }, 4000); 53 | }); 54 | // describe('jsdom-worker', () => { 55 | // it('should work', async () => { 56 | // let code = `onmessage = e => { postMessage(e.data*2) }`; 57 | // let worker = new Worker(URL.createObjectURL(new Blob([code]))); 58 | // worker.onmessage = jest.fn(); 59 | // worker.postMessage(5); 60 | // await sleep(10); 61 | // expect(worker.onmessage).toHaveBeenCalledWith({ data: 10 }); 62 | // }); 63 | // 64 | // it('should work with importScripts', async () => { 65 | // // const mod = await fs.readFile(path.join(__dirname, './module.js')); 66 | // const code = await fs.readFile(path.join(__dirname, './worker.js')); 67 | // // let combined = new Buffer(code.toString()); 68 | // const worker = new Worker(URL.createObjectURL(new Blob([code]))); 69 | // worker.onmessage = jest.fn(); 70 | // worker.postMessage({}); 71 | // await sleep(10); 72 | // expect(worker.onmessage).toHaveBeenCalledWith({ data: 'test' }); 73 | // }); 74 | // 75 | // it('should work with IIFE', async () => { 76 | // const n = Math.random(); 77 | // const code = `(function(n){ onmessage = e => { postMessage(n) } })(${n})`; 78 | // const worker = new Worker(URL.createObjectURL(new Blob([code]))); 79 | // worker.onmessage = jest.fn(); 80 | // worker.postMessage({}); 81 | // await sleep(10); 82 | // expect(worker.onmessage).toHaveBeenCalledWith({ data: n }); 83 | // }); 84 | // }); 85 | -------------------------------------------------------------------------------- /packages/kernel/spec/worker.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | 3 | import * as BrowserFS from "browserfs"; 4 | // import { isMainThread, parentPort, workerData } from "worker_threads"; 5 | // import {promisfy} from "../src/util"; 6 | import * as fs from "fs"; 7 | 8 | function promisfy(fn: any): any { 9 | return (...args) => 10 | new Promise((resolve, reject) => { 11 | fn(...args, (err, contents) => { 12 | if (err) reject(err); 13 | resolve(contents); 14 | }); 15 | }); 16 | } 17 | 18 | type Address = string; 19 | console.log("hello"); 20 | // 21 | // class Worker { 22 | // addEventListener = parentPort.on 23 | // 24 | // postMessage( mesg: any ): void { 25 | // console.log(mesg) 26 | // parentPort.postMessage(mesg); 27 | // } 28 | // } 29 | 30 | async function start() { 31 | // try { 32 | // debugger; 33 | await promisfy(BrowserFS.configure)({ 34 | fs: "WorkerFS", 35 | options: { worker: self } 36 | }); 37 | let fs = BrowserFS.BFSRequire("fs"); 38 | // onmessage = (mesg: any) => { 39 | // postMessage({type:"String"},""); 40 | // }; 41 | console.log(await promisfy(fs.readdir)(".")); 42 | // fs.watch(".", (event, filename) => { 43 | // console.log(event, filename); 44 | // }) 45 | // postMessage("hi"); 46 | // } catch (err) { 47 | // console.log(err); 48 | // } 49 | } 50 | // 51 | start(); 52 | // parentPort.postMessage(mesg)); 53 | -------------------------------------------------------------------------------- /packages/kernel/src/index.ts: -------------------------------------------------------------------------------- 1 | export class Kernel { 2 | worker: Worker; 3 | constructor(path: string = "worker.js") { 4 | this.worker = new Worker(path); 5 | // attachWorker(this.worker); 6 | this.worker.postMessage({ init: path }); 7 | this.worker.onmessage = this.onmessage.bind(this); 8 | } 9 | 10 | onmessage(event: MessageEvent) { 11 | console.log(event.data); 12 | } 13 | 14 | static async create(path?: string): Promise { 15 | let kernel = new Kernel(path); 16 | 17 | return kernel; 18 | } 19 | } 20 | export * from "./process"; 21 | -------------------------------------------------------------------------------- /packages/kernel/src/process/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./process"; 2 | export * from "./utf8"; 3 | -------------------------------------------------------------------------------- /packages/kernel/src/process/process.ts: -------------------------------------------------------------------------------- 1 | import { 2 | loader, 3 | ASImport, 4 | Host, 5 | Env as _Env 6 | } from "@wasmos/assemblyscript/src/index"; 7 | 8 | import { fs } from "@wasmos/fs/src"; 9 | import * as path from "path"; 10 | 11 | enum ExitStatus { 12 | Finished = 0, 13 | Crashed = -1 14 | } 15 | 16 | export class Env extends _Env { 17 | PATH: string[] = ["/bin"]; 18 | map: Map = new Map(); 19 | static default: Env = Env.fromMap([["PATH", "/usr/bin"]]); 20 | 21 | set(name: string, value: string): Env { 22 | this.map.set(name, value); 23 | return this; 24 | } 25 | 26 | async search(arg: string): Promise { 27 | for (let p of this.PATH) { 28 | let bin = path.join(p, arg); 29 | if (await fs.pathExists(bin)) { 30 | return bin; 31 | } 32 | } 33 | return null; 34 | } 35 | 36 | static fromMap(map: Map | Iterable): Env { 37 | let env = new Env(); 38 | env.map = (map instanceof Map) ? map : new Map(map); 39 | return env; 40 | } 41 | } 42 | 43 | export class Process { 44 | stdout = Array(); 45 | status: ExitStatus; 46 | host: Host; 47 | binName: string; 48 | binpath: string; 49 | 50 | constructor(public args: string[], public env: Env = new Env()) { 51 | this.binName = args[0]; 52 | } 53 | 54 | async searchPath(name: string): Promise { 55 | let binary = path.join(name, "index.wasm"); 56 | let asc = path.join(name, "index.ts"); 57 | if (await this.env.search(binary)) { 58 | return binary; 59 | } else if (await fs.pathExists(asc)) { 60 | return asc; 61 | } 62 | return null; 63 | } 64 | 65 | static async spawn(args: string[], env: Env) {} 66 | } 67 | -------------------------------------------------------------------------------- /packages/kernel/src/process/utf8.ts: -------------------------------------------------------------------------------- 1 | import { toUint8Array, fromUTF8Array } from "@wasmos/utils/src"; 2 | type _Map = Map; 3 | 4 | export namespace UTF8 { 5 | toUint8Array; 6 | 7 | export class String { 8 | data: Uint8Array; 9 | 10 | constructor(str: string | Uint8Array) { 11 | if (typeof str === "string") { 12 | this.data = toUint8Array(str); 13 | } else { 14 | this.data = str; 15 | } 16 | } 17 | 18 | get size(): number { 19 | return this.data.length + 1; 20 | } 21 | 22 | get str(): string { 23 | return fromUTF8Array(this.data); 24 | } 25 | } 26 | 27 | export class Array { 28 | args: UTF8.String[] = []; 29 | 30 | constructor(strs: string[] = []) { 31 | strs.map(str => { 32 | this.push(str); 33 | }); 34 | } 35 | 36 | push(arg: string): void { 37 | this.args.push(new UTF8.String(arg)); 38 | } 39 | /** 40 | * number of bytes 41 | */ 42 | get size(): number { 43 | return this.args.reduce((acc, curr) => { 44 | return acc + curr.size; 45 | }, 0); 46 | } 47 | /** 48 | * number of elements 49 | */ 50 | get length(): number { 51 | return this.args.length; 52 | } 53 | 54 | get bytes(): Uint8Array { 55 | // TODO: Find the right type 56 | let array = new Uint8Array(this.size); 57 | this.ptrs.forEach((ptr, idx, ptrs) => { 58 | array.set(this.args[idx].data, ptr); 59 | }); 60 | return array; 61 | } 62 | 63 | get ptrs(): Uint32Array { 64 | let ptrs = new Uint32Array(this.length); 65 | this.args.reduce((acc, cur, idx) => { 66 | ptrs[idx] = acc; 67 | return acc + cur.size; 68 | }, 0); 69 | return ptrs; 70 | } 71 | } 72 | 73 | /* 74 | * Creates a map by making an array of key value pairs joi 75 | */ 76 | export class Map extends UTF8.Array { 77 | static fromMap(map: _Map): UTF8.Array { 78 | let res = new Map(); 79 | map.forEach((value, key) => { 80 | let str = `${key}=${value}`; 81 | res.push(str); 82 | }); 83 | return res; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /packages/kernel/src/threading/actor.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | const ctx: Worker = self as any; 4 | 5 | type method = (...a: any[]) => any; 6 | 7 | /** 8 | * An actor is a remote object. 9 | */ 10 | export abstract class Actor { 11 | /** 12 | * Since constructors can't be asynchrous 13 | */ 14 | abstract async init(...args: any[]): Promise; 15 | 16 | methods: Map = new Map(); 17 | 18 | /** 19 | * An actor has a unique address that other actors can use to send it messages. 20 | */ 21 | constructor(public address: string | Uint8Array) { } 22 | 23 | onmessage(message: { fn: string, args: any[] }) { 24 | // postMessage({ result: this[message.fn](...message.args) }); 25 | } 26 | 27 | 28 | bindWorker(worker: Worker) { 29 | let constructor = (this).constructor; 30 | let className: string = constructor.name.toLowerCase(); 31 | for (let member of Object.getOwnPropertyNames(constructor.prototype)) { 32 | if (typeof (this)[member] == "function") { 33 | this[member] = (...args) => { 34 | // postMessage({ fn: member, args: args }) 35 | } 36 | } 37 | } 38 | } 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /packages/kernel/src/threading/worker.ts: -------------------------------------------------------------------------------- 1 | /// reference 2 | 3 | // import * as asc from "assemblyscript/dist/asc"; 4 | import { loader } from "@wasmos/assemblyscript/src/index"; 5 | // import * as vue from 'vue-compiler'; 6 | import * as BrowserFS from "browserfs"; 7 | // import { promisfy } from "../util"; 8 | import { Actor } from "./actor"; 9 | 10 | // import tsc from "typescript"; 11 | // import {initWorker} from "../fs"; 12 | 13 | export class worker { 14 | static get isMainThread(): boolean { 15 | try { 16 | // return (this instanceof DedicatedWorkerGlobalScope); 17 | } catch (error) { 18 | return false; 19 | } 20 | } 21 | } 22 | 23 | let ctx: Worker = self; 24 | import * as fs from "fs"; 25 | 26 | async function start() { 27 | // await initWorker(); 28 | (ctx).fs = BrowserFS.BFSRequire("fs"); 29 | let fs = (ctx).fs; 30 | // console.log(await promisfy(fs.readdir)(".")); 31 | // postMessage({event:await promisfy(fs.readdir)(".")}); 32 | } 33 | start(); 34 | 35 | async function readFile(path: string, basename?: string) { 36 | // return promisfy(fs.readFile)(path).toString(); 37 | } 38 | 39 | async function writeFile(path: string, data: any) { 40 | // promisfy(fs.writeFile)(path, data) 41 | } 42 | 43 | // async function compile(path: string) { 44 | // let source = {}; 45 | // source[path] = ""; 46 | 47 | // return await (asc.compileString)(source, {readFile, writeFile}); 48 | // } 49 | 50 | onmessage = async (mesg: MessageEvent) => { 51 | if (mesg.data.path) { 52 | // postMessage({result: await readFile(mesg.data.path)}) 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /packages/kernel/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.ts.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/kernel/src/wasi/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./wasi"; 2 | export * from "./unstable"; 3 | -------------------------------------------------------------------------------- /packages/os/README.md: -------------------------------------------------------------------------------- 1 | ## Title 2 | 3 | # Big Ideas 4 | -------------------------------------------------------------------------------- /packages/os/assembly/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssemblyOS/wasmos/ab45736c245ed7eb9f75e4b2f604ab08d7c017f4/packages/os/assembly/index.ts -------------------------------------------------------------------------------- /packages/os/index.ts: -------------------------------------------------------------------------------- 1 | export * from './src'; -------------------------------------------------------------------------------- /packages/os/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/os", 3 | "version": "0.0.2", 4 | "description": "AssemeblyScript version of node's 'os' module", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "test": "echo test at top level" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/packages/os" 12 | }, 13 | "keywords": [ 14 | "AssemblyScript", 15 | "Kernel", 16 | "OS", 17 | "WebAssembly", 18 | "WebAssemblyOS" 19 | ], 20 | "author": "Willem Wyndham", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /packages/os/src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const EOL: string= '\n'; 4 | 5 | export function platform(): string { 6 | return "wasmos"; 7 | } -------------------------------------------------------------------------------- /packages/os/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.ts.json" 3 | } 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Kernel } from "../packages/kernel/src"; 4 | import { fs } from "../packages/fs/src"; 5 | import { bootup } from "./loader"; 6 | 7 | export async function main() { 8 | await bootup(); 9 | (window as any).kernel = await Kernel.create(); 10 | (window).fs = fs; 11 | } 12 | main(); 13 | -------------------------------------------------------------------------------- /src/loader/features.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Determine what features the host has. E.g. SharedMemory, POST MVP WebAssembly. 3 | */ 4 | -------------------------------------------------------------------------------- /src/loader/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This package handles all configurations with setting up the kernel. 3 | */ 4 | 5 | // import { init, fs } from "../fs"; 6 | // import * as ts from "ntypescript"; 7 | // import * as os from "../os"; 8 | 9 | export async function bootup() { 10 | // await init(); 11 | setupReslover(window); 12 | setupTypescript(window); 13 | 14 | } 15 | 16 | function setupReslover(window: any) { 17 | const systemJSPrototype = window.System.constructor.prototype; 18 | const resolve = systemJSPrototype.resolve 19 | systemJSPrototype.resolve 20 | 21 | } 22 | 23 | function setupTypescript(window: any) { 24 | const systemJSPrototype = window.System.constructor.prototype; 25 | const instantiate = systemJSPrototype.instantiate; 26 | systemJSPrototype.instantiate = async function(url, parent) { 27 | if (!['.js', '.ts'].indexOf(url.slice(-3))) 28 | return instantiate.call(this, url, parent); 29 | const loader = this; 30 | return fetch(url) 31 | .then(function(res) { 32 | if (!res.ok) 33 | throw new Error('Fetch error: ' + res.status + ' ' + res.statusText + (parent ? ' loading from ' + parent : '')); 34 | return res.text(); 35 | }) 36 | .then(function(source) { 37 | return loader.transform.call(this, url, JSON.parse(source)); 38 | }) 39 | .then(function(source) { 40 | return [[], function(_export) { 41 | return { 42 | setters: [], 43 | execute: function() { 44 | _export(source); 45 | } 46 | } 47 | }] 48 | }); 49 | }; 50 | 51 | 52 | } 53 | 54 | /* 55 | * SystemJS format Babel transformer 56 | */ 57 | 58 | // import * as babel from '@babel/core'; 59 | // import babelPluginSyntaxDynamicImport from '@babel/plugin-syntax-dynamic-import'; 60 | // import babelPluginSyntaxImportMeta from '@babel/plugin-syntax-import-meta'; 61 | // import babelPluginTransformModulesSystemJS from '@babel/plugin-transform-modules-systemjs'; 62 | // import babelPluginTransformTypescript from "@babel/plugin-transform-typescript"; 63 | 64 | // const plugins = [ 65 | // babelPluginSyntaxDynamicImport, 66 | // babelPluginSyntaxImportMeta, 67 | // babelPluginTransformModulesSystemJS, 68 | // babelPluginTransformTypescript 69 | // ]; 70 | 71 | function setupBabel(window: any) { 72 | // const systemJSPrototype = window.System.constructor.prototype; 73 | // const transform = systemJSPrototype.transform; 74 | // systemJSPrototype.transform = function(url, source) { 75 | // // composition of transform is done based on assuming every format 76 | // // returns its own System.register. So we don't "compose" transforms 77 | // // but rather treat transforms "fallbacks" where they can select themselves 78 | // return Promise.resolve(transform.call(this, url, source)) 79 | // .then(function(_source) { 80 | // console.log("setting up " + url); 81 | // // if there was translation done, then stop 82 | // if (source !== _source) 83 | // return _source; 84 | 85 | // return new Promise((resolve, reject) => { 86 | // babel.transform(source, { 87 | // plugins: plugins, 88 | // sourceMaps: 'inline', 89 | // sourceFileName: url.split('/').pop() 90 | // }, function(err, result) { 91 | // if (err) 92 | // reject(err); 93 | // else 94 | // resolve(result); 95 | // }); 96 | // }) 97 | // .then(function(result: any) { 98 | // return result.code; 99 | // }); 100 | // }) 101 | // }; 102 | } 103 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.ts.json", 3 | "compilerOptions": { 4 | // "lib": ["webworker", "es6", "scripthost", "es2015", "es2017"], 5 | "typeRoots": [ 6 | "node_modules/@types", 7 | "**/node_modules/@types", 8 | "node_modules/dropbox/src" 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "moduleResolution": "node", 5 | "esModuleInterop": true, 6 | "module": "commonjs", 7 | "allowJs": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "typeRoots": [ 5 | "./types" 6 | ], 7 | "types": [ 8 | "assembly", 9 | "wasa", 10 | "as-pect", 11 | "wasi" 12 | ], 13 | "noLib": true, 14 | "alwaysStrict": true, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitThis": true, 18 | "noEmitOnError": true, 19 | "strictNullChecks": true, 20 | "experimentalDecorators": true, 21 | "baseUrl": ".", 22 | "paths": { 23 | "*": [ 24 | "packages/assemblyscript/assembly/std/*", 25 | "packages/*/assembly", 26 | ] 27 | } 28 | }, 29 | "include": [ 30 | "packages/*/assembly/**/*" 31 | ], 32 | "exclude": [ 33 | "**/assemblyscript/src", 34 | "packages/**/node_modules/**/*" 35 | ] 36 | } -------------------------------------------------------------------------------- /tsconfig.ts.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "include": ["./src/**/*.ts", "packages/*/src/**/*.ts"], 4 | "exclude": ["packages/**/node_modules/**/*"], 5 | "compilerOptions": { 6 | "lib": ["es2017", "es2015"], 7 | "outDir": "./dist", 8 | "typeRoots": [ 9 | "node_modules/@types", 10 | "**/node_modules/@types", 11 | "node_modules/dropbox/src" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/assemblyscript/lib/lint/index.json" 3 | } 4 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssemblyOS/wasmos/ab45736c245ed7eb9f75e4b2f604ab08d7c017f4/types/index.d.ts -------------------------------------------------------------------------------- /types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@types/assembly", 3 | "version": "0.0.2", 4 | "files": [ 5 | "*" 6 | ], 7 | "keywords": [ 8 | "AssemblyScript", 9 | "Kernel", 10 | "OS", 11 | "WebAssembly", 12 | "WebAssemblyOS" 13 | ], 14 | "author": "Willem Wyndham", 15 | "license": "MIT" 16 | } 17 | -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "alwaysStrict": true, 4 | "noImplicitAny": true, 5 | "noImplicitReturns": true, 6 | "noImplicitThis": true, 7 | "noEmitOnError": true, 8 | "strictNullChecks": true, 9 | "experimentalDecorators": true, 10 | "target": "es6", 11 | "moduleResolution": "node", 12 | "esModuleInterop": true, 13 | "module": "commonjs", 14 | "noLib": true, 15 | "allowJs": false, 16 | "typeRoots": ["./as-pect", "./wasa", "./assembly"] 17 | }, 18 | "include": ["**/*.d.ts"], 19 | "exclude": ["node_modules/"] 20 | } 21 | -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | # Utils 2 | 3 | Collection of utilities. 4 | -------------------------------------------------------------------------------- /utils/bin/asdb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | node -r ts-node/register --inspect-brk $@ -------------------------------------------------------------------------------- /utils/bin/ldev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | let shell = require("shelljs"); 4 | let path = require("path") 5 | 6 | function exists(name) { 7 | return shell.test("-e", name) 8 | } 9 | //Get the root Binaries 10 | let rootBin = path.resolve(path.dirname( __dirname)+"/../node_modules/.bin/"); 11 | if (!exists("./node_modules/.bin")){ 12 | console.log(path.basename(shell.pwd().stdout) + " has no installed dependencies. Try running `npm run bootstrap` if it should.") 13 | process.exit(0) 14 | } 15 | 16 | shell.cd("./node_modules/.bin") 17 | shell.ls(rootBin).forEach(bin => { 18 | let binName = path.basename(bin) 19 | let dirName = path.join(rootBin, bin); 20 | let relativeBinary = path.join(path.relative(shell.pwd().stdout, rootBin), binName) 21 | if (!exists(binName)){ 22 | shell.ln("-s", relativeBinary, path.resolve(binName)) 23 | } 24 | }) 25 | shell.cd("../..") 26 | console.log(path.basename(shell.pwd().stdout) +"'s '.bin/' linked"); 27 | -------------------------------------------------------------------------------- /utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src"; 2 | -------------------------------------------------------------------------------- /utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasmos/utils", 3 | "version": "0.0.2", 4 | "description": "Core OS kernel for assemblyscript and WebAssembly", 5 | "types": "src/index.ts", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "bin": { 10 | "ldev": "./bin/ldev", 11 | "asdb": "./bin/asdb" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/WebAssemblyOS/wasmos/tree/master/utils" 16 | }, 17 | "keywords": [ 18 | "AssemblyScript", 19 | "Kernel", 20 | "OS", 21 | "WebAssembly", 22 | "WebAssemblyOS" 23 | ], 24 | "author": "Willem Wyndham", 25 | "license": "MIT" 26 | } 27 | -------------------------------------------------------------------------------- /utils/src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | /// see https://github.com/emscripten-core/emscripten/blob/e9c44b413781c0cdf3293bcc50894d9984930b5b/src/runtime_strings.js#L149 3 | /* 4 | * Copies the given Javascript String object 'str' to the given byte array at address 'outIdx', 5 | * encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP. 6 | * Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. 7 | * Parameters: 8 | * str: the Javascript string to copy. 9 | * outU8Array: the array to copy to. Each index in this array is assumed to be one 8-byte element. 10 | * outIdx: The starting offset in the array to begin the copying. 11 | * maxBytesToWrite: The maximum number of bytes this function can write to the array. 12 | * This count should include the null terminator, 13 | * i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else. 14 | * maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator. 15 | * Returns the number of bytes written, EXCLUDING the null terminator. 16 | */ 17 | export function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) { 18 | if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. 19 | return 0; 20 | 21 | var startIdx = outIdx; 22 | var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. 23 | for (var i = 0; i < str.length; ++i) { 24 | // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8. 25 | // See http://unicode.org/faq/utf_bom.html#utf16-3 26 | // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629 27 | var u = str.charCodeAt(i); // possibly a lead surrogate 28 | if (u >= 0xD800 && u <= 0xDFFF) { 29 | var u1 = str.charCodeAt(++i); 30 | u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); 31 | } 32 | if (u <= 0x7F) { 33 | if (outIdx >= endIdx) break; 34 | outU8Array[outIdx++] = u; 35 | } else if (u <= 0x7FF) { 36 | if (outIdx + 1 >= endIdx) break; 37 | outU8Array[outIdx++] = 0xC0 | (u >> 6); 38 | outU8Array[outIdx++] = 0x80 | (u & 63); 39 | } else if (u <= 0xFFFF) { 40 | if (outIdx + 2 >= endIdx) break; 41 | outU8Array[outIdx++] = 0xE0 | (u >> 12); 42 | outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); 43 | outU8Array[outIdx++] = 0x80 | (u & 63); 44 | } else { 45 | if (outIdx + 3 >= endIdx) break; 46 | if (u >= 0x200000) throw new Error('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).'); 47 | 48 | outU8Array[outIdx++] = 0xF0 | (u >> 18); 49 | outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63); 50 | outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); 51 | outU8Array[outIdx++] = 0x80 | (u & 63); 52 | } 53 | } 54 | // Null-terminate the pointer to the buffer. 55 | outU8Array[outIdx] = 0; 56 | return outIdx - startIdx; 57 | } 58 | 59 | export function toUint8Array(str: string): Uint8Array { 60 | let maxSize = str.length * 4 + 1; 61 | let tmp = new Uint8Array(maxSize); 62 | let size = stringToUTF8Array(str, tmp, 0, maxSize) 63 | return tmp.slice(0, size); 64 | } 65 | 66 | export function fromUTF8Array(data: Uint8Array): string { // array of bytes 67 | var str = '', 68 | i; 69 | 70 | for (i = 0; i < data.length; i++) { 71 | var value = data[i]; 72 | if (value < 0x80) { 73 | str += String.fromCharCode(value); 74 | } else if (value > 0xBF && value < 0xE0) { 75 | str += String.fromCharCode((value & 0x1F) << 6 | data[i + 1] & 0x3F); 76 | i += 1; 77 | } else if (value > 0xDF && value < 0xF0) { 78 | str += String.fromCharCode((value & 0x0F) << 12 | (data[i + 1] & 0x3F) << 6 | data[i + 2] & 0x3F); 79 | i += 2; 80 | } else { 81 | // surrogate pair 82 | var charCode = ((value & 0x07) << 18 | (data[i + 1] & 0x3F) << 12 | (data[i + 2] & 0x3F) << 6 | data[i + 3] & 0x3F) - 0x010000; 83 | 84 | str += String.fromCharCode(charCode >> 10 | 0xD800, charCode & 0x03FF | 0xDC00); 85 | i += 3; 86 | } 87 | } 88 | 89 | return str; 90 | } 91 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: { 6 | index: './src/index.ts', 7 | worker: "./src/threading/worker.ts"}, 8 | module: { 9 | noParse: /browserfs\.js/, 10 | rules: [ 11 | { 12 | test: /\.tsx?$/, 13 | use: 'ts-loader', 14 | exclude: /node_modules/ 15 | } 16 | ] 17 | }, 18 | resolve: { 19 | // Use our versions of Node modules. 20 | alias: { 21 | 'fs': 'browserfs/dist/shims/fs.js', 22 | 'buffer': 'browserfs/dist/shims/buffer.js', 23 | 'path': 'browserfs/dist/shims/path.js', 24 | 'processGlobal': 'browserfs/dist/shims/process.js', 25 | 'bufferGlobal': 'browserfs/dist/shims/bufferGlobal.js', 26 | 'bfsGlobal': require.resolve('browserfs') 27 | }, 28 | extensions: [ '.tsx', '.ts', '.js' ] 29 | }, 30 | output: { 31 | filename: '[name].js', 32 | path: path.resolve(__dirname, 'dist') 33 | }, 34 | devServer: { 35 | contentBase: path.join(__dirname, 'dist'), 36 | compress: true, 37 | port: 8080 38 | }, 39 | devtool: "source-map", 40 | plugins: [ 41 | // Expose BrowserFS, process, and Buffer globals. 42 | // NOTE: If you intend to use BrowserFS in a script tag, you do not need 43 | // to expose a BrowserFS global. 44 | new webpack.ProvidePlugin({ BrowserFS: 'bfsGlobal', process: 'processGlobal', Buffer: 'bufferGlobal' }) 45 | ], 46 | // DISABLE Webpack's built-in process and Buffer polyfills! 47 | node: { 48 | process: false, 49 | Buffer: false 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /webpack.test.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: { 6 | worker: './spec/worker.ts' 7 | }, 8 | module: { 9 | noParse: /browserfs\.js/, 10 | rules: [ 11 | { 12 | test: /\.tsx?$/, 13 | use: 'ts-loader', 14 | exclude: /node_modules/ 15 | } 16 | ] 17 | }, 18 | resolve: { 19 | // Use our versions of Node modules. 20 | alias: { 21 | 'fs': 'browserfs/dist/shims/fs.js', 22 | 'buffer': 'browserfs/dist/shims/buffer.js', 23 | 'path': 'browserfs/dist/shims/path.js', 24 | 'processGlobal': 'browserfs/dist/shims/process.js', 25 | 'bufferGlobal': 'browserfs/dist/shims/bufferGlobal.js', 26 | 'bfsGlobal': require.resolve('browserfs') 27 | }, 28 | extensions: [ '.tsx', '.ts', '.js' ] 29 | }, 30 | output: { 31 | filename: '[name].js', 32 | path: path.resolve(__dirname, 'spec', 'build') 33 | }, 34 | devServer: { 35 | contentBase: path.join(__dirname, 'spec','build'), 36 | compress: true, 37 | port: 8080 38 | }, 39 | devtool: "source-map", 40 | plugins: [ 41 | // Expose BrowserFS, process, and Buffer globals. 42 | // NOTE: If you intend to use BrowserFS in a script tag, you do not need 43 | // to expose a BrowserFS global. 44 | new webpack.ProvidePlugin({ BrowserFS: 'bfsGlobal', process: 'processGlobal', Buffer: 'bufferGlobal' }) 45 | ], 46 | // DISABLE Webpack's built-in process and Buffer polyfills! 47 | node: { 48 | process: false, 49 | Buffer: false 50 | } 51 | }; 52 | --------------------------------------------------------------------------------