├── .editorconfig ├── .eslintignore ├── .flowconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── _register.js ├── base-rollup.config.js ├── create-package.sh ├── docs ├── explorer.js ├── explorer.js.map ├── index.html └── walt.png ├── generator.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── rollup-plugin-walt-grammar │ ├── index.js │ ├── package-lock.json │ └── package.json ├── walt-buildtools │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── print.js │ └── src │ │ ├── index.js │ │ ├── patches.js │ │ └── print.js ├── walt-cli │ ├── README.md │ ├── demo │ │ ├── index.walt │ │ ├── memory.walt │ │ └── string.walt │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── __tests__ │ │ ├── wrap-spec.js │ │ └── write-spec.js │ │ ├── compile-from-file.js │ │ ├── wrap.js │ │ └── write.js ├── walt-compiler │ ├── .babelrc │ ├── .eslintrc │ ├── .flowconfig │ ├── README.md │ ├── dist │ │ ├── explorer.js │ │ ├── walt.js │ │ └── walt.min.js │ ├── package-lock.json │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── __snapshots__ │ │ │ │ ├── assignment-spec.js.md │ │ │ │ ├── assignment-spec.js.snap │ │ │ │ ├── compiler-spec.js.md │ │ │ │ ├── compiler-spec.js.snap │ │ │ │ ├── function-spec.js.md │ │ │ │ ├── function-spec.js.snap │ │ │ │ ├── memory-spec.js.md │ │ │ │ ├── memory-spec.js.snap │ │ │ │ ├── object-literal-spec.js.md │ │ │ │ ├── object-literal-spec.js.snap │ │ │ │ ├── type-conversion-spec.js.md │ │ │ │ ├── type-conversion-spec.js.snap │ │ │ │ ├── type-imports-spec.js.md │ │ │ │ └── type-imports-spec.js.snap │ │ │ ├── assignment-spec.js │ │ │ ├── bitwise-operators-spec.js │ │ │ ├── compare-spec.js │ │ │ ├── compiler-spec.js │ │ │ ├── compiler-spec.walt │ │ │ ├── fibonacci-spec.js │ │ │ ├── function-spec.js │ │ │ ├── if-then-else-spec.js │ │ │ ├── logical-operators-spec.js │ │ │ ├── loop-spec.js │ │ │ ├── math-spec.js │ │ │ ├── memory-spec.js │ │ │ ├── native-opcode-spec.js │ │ │ ├── native-opcode-spec.walt │ │ │ ├── object-literal-spec.js │ │ │ ├── operator-precedence-spec.js │ │ │ ├── statics-spec.walt │ │ │ ├── string-spec.js │ │ │ ├── string-spec.walt │ │ │ ├── subscripts-spec.walt │ │ │ ├── syntax-spec.js │ │ │ ├── throw-spec.walt │ │ │ ├── type-conversion-spec.js │ │ │ └── type-imports-spec.js │ │ ├── base │ │ │ └── index.js │ │ ├── core │ │ │ ├── array.js │ │ │ ├── bool.js │ │ │ ├── function-pointer.js │ │ │ ├── function.js │ │ │ ├── imports.js │ │ │ ├── index.js │ │ │ ├── memory.js │ │ │ ├── native.js │ │ │ ├── statics.js │ │ │ ├── struct.js │ │ │ ├── types.js │ │ │ └── unary.js │ │ ├── emitter │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── value-types-spec.js.md │ │ │ │ │ └── value-types-spec.js.snap │ │ │ │ ├── opcode-spec.js │ │ │ │ └── value-types-spec.js │ │ │ ├── external_kind.js │ │ │ ├── index.js │ │ │ ├── numbers.js │ │ │ ├── opcode.js │ │ │ ├── preamble.js │ │ │ ├── section │ │ │ │ ├── code.js │ │ │ │ ├── codes.js │ │ │ │ ├── data.js │ │ │ │ ├── element.js │ │ │ │ ├── exports.js │ │ │ │ ├── functions.js │ │ │ │ ├── globals.js │ │ │ │ ├── imports.js │ │ │ │ ├── index.js │ │ │ │ ├── memory.js │ │ │ │ ├── name.js │ │ │ │ ├── start.js │ │ │ │ ├── table.js │ │ │ │ ├── types.js │ │ │ │ └── writer.js │ │ │ ├── string.js │ │ │ └── value_type.js │ │ ├── flow │ │ │ └── types.js │ │ ├── generator │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── memory-assignment-spec.js.md │ │ │ │ │ ├── memory-assignment-spec.js.snap │ │ │ │ │ ├── type-spec.js.md │ │ │ │ │ └── type-spec.js.snap │ │ │ │ └── map-syntax-spec.js │ │ │ ├── assignment-expression.js │ │ │ ├── assignment.js │ │ │ ├── binary-expression.js │ │ │ ├── block.js │ │ │ ├── break.js │ │ │ ├── constant.js │ │ │ ├── declaration.js │ │ │ ├── element.js │ │ │ ├── else.js │ │ │ ├── export.js │ │ │ ├── expression.js │ │ │ ├── flow │ │ │ │ └── types.js │ │ │ ├── function-call.js │ │ │ ├── function-pointer.js │ │ │ ├── generate-data.js │ │ │ ├── if-then-else.js │ │ │ ├── import.js │ │ │ ├── index.js │ │ │ ├── indirect-function-call.js │ │ │ ├── initializer.js │ │ │ ├── loop.js │ │ │ ├── map-syntax.js │ │ │ ├── memory.js │ │ │ ├── merge-block.js │ │ │ ├── native.js │ │ │ ├── noop.js │ │ │ ├── return-statement.js │ │ │ ├── select.js │ │ │ ├── table.js │ │ │ ├── ternary-expression.js │ │ │ ├── type.js │ │ │ ├── typecast.js │ │ │ └── utils.js │ │ ├── index.js │ │ ├── parser │ │ │ ├── README.md │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── access-spec.js.md │ │ │ │ │ ├── access-spec.js.snap │ │ │ │ │ ├── array-spec.js.md │ │ │ │ │ ├── array-spec.js.snap │ │ │ │ │ ├── context-spec.js.md │ │ │ │ │ ├── context-spec.js.snap │ │ │ │ │ ├── fragment-spec.js.md │ │ │ │ │ ├── fragment-spec.js.snap │ │ │ │ │ ├── parser-spec.js.md │ │ │ │ │ ├── parser-spec.js.snap │ │ │ │ │ ├── sizeof-spec.js.md │ │ │ │ │ ├── sizeof-spec.js.snap │ │ │ │ │ ├── type-spec.js.md │ │ │ │ │ └── type-spec.js.snap │ │ │ │ ├── access-spec.js │ │ │ │ ├── array-spec.js │ │ │ │ ├── fragment-spec.js │ │ │ │ ├── parser-spec.js │ │ │ │ ├── sizeof-spec.js │ │ │ │ ├── statement-spec.js │ │ │ │ ├── type-spec.js │ │ │ │ └── union-type-spec.walt │ │ │ ├── fragment.js │ │ │ ├── grammar │ │ │ │ ├── control-flow.ne │ │ │ │ ├── grammar.ne │ │ │ │ ├── helpers.js │ │ │ │ ├── import.ne │ │ │ │ ├── nodes.js │ │ │ │ ├── objects.ne │ │ │ │ ├── punctuators.ne │ │ │ │ └── types.ne │ │ │ └── index.js │ │ ├── plugin │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── plugin-spec.js.md │ │ │ │ │ └── plugin-spec.js.snap │ │ │ │ └── plugin-spec.js │ │ │ └── index.js │ │ ├── semantics │ │ │ ├── index.js │ │ │ └── metadata.js │ │ ├── syntax-sugar │ │ │ ├── default-arguments.js │ │ │ ├── default-arguments.ne │ │ │ └── sizeof.js │ │ ├── types.js │ │ ├── utils │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── debug-spec.js.md │ │ │ │ │ ├── debug-spec.js.snap │ │ │ │ │ ├── leb128-spec.js.md │ │ │ │ │ ├── leb128-spec.js.snap │ │ │ │ │ ├── print-node-spec.js.md │ │ │ │ │ ├── print-node-spec.js.snap │ │ │ │ │ ├── walk-node-spec.js.md │ │ │ │ │ └── walk-node-spec.js.snap │ │ │ │ ├── debug-spec.js │ │ │ │ ├── leb128-spec.js │ │ │ │ └── print-node-spec.js │ │ │ ├── compose.js │ │ │ ├── debug.js │ │ │ ├── extend-node.js │ │ │ ├── generate-error.js │ │ │ ├── has-node.js │ │ │ ├── leb128.js │ │ │ ├── output-stream.js │ │ │ ├── pick.js │ │ │ ├── pretty-print-ir.js │ │ │ ├── print-node.js │ │ │ ├── resizable-limits.js │ │ │ ├── stream.js │ │ │ ├── string.js │ │ │ ├── test-utils.js │ │ │ ├── token-stream.js │ │ │ ├── transform-with-context.js │ │ │ ├── trie.js │ │ │ └── types.js │ │ ├── validation │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ ├── validation-spec.js.md │ │ │ │ │ └── validation-spec.js.snap │ │ │ │ └── validation-spec.js │ │ │ └── index.js │ │ └── walt │ │ │ ├── malloc.walt │ │ │ ├── string.walt │ │ │ ├── tests.walt │ │ │ └── utils │ │ │ └── stream.walt │ ├── syntax │ │ ├── README.md │ │ ├── struct-test.walt │ │ ├── type-test.walt │ │ └── union-types-test.walt │ └── yarn.lock ├── walt-explorer │ ├── README.md │ ├── explorer.js │ ├── explorer.js.map │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app.js │ │ ├── ast-view │ │ │ └── index.js │ │ ├── css │ │ │ └── app.scss │ │ ├── editor │ │ │ └── index.js │ │ ├── examples │ │ │ ├── animation.js │ │ │ ├── closures.js │ │ │ ├── default.js │ │ │ ├── fibonacci.js │ │ │ ├── function-pointer.js │ │ │ ├── index.js │ │ │ ├── memory.js │ │ │ ├── object-literal.js │ │ │ ├── walt │ │ │ │ ├── animation.walt │ │ │ │ ├── closures.walt │ │ │ │ ├── default.walt │ │ │ │ ├── fibonacci.walt │ │ │ │ ├── function-pointer.walt │ │ │ │ ├── memory.walt │ │ │ │ ├── object-literal.walt │ │ │ │ └── wave.walt │ │ │ └── wave.js │ │ ├── index.js │ │ └── menu-bar │ │ │ └── index.js │ ├── walt.png │ └── webpack.config.js ├── walt-link │ ├── README.md │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── __tests__ │ │ ├── __snapshots__ │ │ │ ├── linker-spec.js.md │ │ │ └── linker-spec.js.snap │ │ └── linker-spec.js │ │ ├── index.js │ │ ├── index.walt │ │ └── walt │ │ ├── import-a.walt │ │ ├── import-b.walt │ │ └── import-c.walt ├── walt-loader │ ├── .babelrc │ ├── README.md │ ├── __tests__ │ │ └── loader-spec.js │ ├── index.js │ ├── package-lock.json │ └── package.json ├── walt-parser-tools │ ├── .eslintrc │ ├── has-node.js │ ├── map-node.js │ ├── package-lock.json │ ├── package.json │ ├── scope.js │ ├── src │ │ ├── __tests__ │ │ │ ├── map-node-spec.js │ │ │ ├── scope-spec.js │ │ │ └── walk-node-spec.js │ │ ├── has-node.js │ │ ├── index.js │ │ ├── map-node.js │ │ ├── scope.js │ │ └── walk-node.js │ └── walk-node.js ├── walt-plugin-syntax-closure │ ├── .babelrc │ ├── .eslintignore │ ├── .eslintrc │ ├── README.md │ ├── dist │ │ ├── walt-plugin-syntax-closures.js │ │ ├── walt-plugin-syntax-closures.min.js │ │ └── walt.js │ ├── package-lock.json │ ├── package.json │ ├── rollup.config.js │ └── src │ │ ├── __tests__ │ │ └── closure-plugin-spec.js │ │ ├── closures.ne │ │ ├── closures.walt │ │ └── index.js ├── walt-syntax │ ├── .babelrc │ ├── .eslintrc │ ├── README.md │ ├── dist │ │ └── walt-syntax.js │ ├── package-lock.json │ ├── package.json │ ├── rollup.config.js │ └── src │ │ ├── __tests__ │ │ ├── syntax-spec.js │ │ └── token-spec.js │ │ ├── index.js │ │ └── tokens.js └── webpack-walt-examples │ ├── README.md │ ├── example.js │ ├── example.js.map │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── App.js │ ├── CounterExample.js │ ├── Directory.js │ ├── index.js │ └── walt │ │ └── counter.walt │ └── webpack.config.js └── walt.png /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | grammar.js 2 | **/*.ne 3 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [lints] 8 | 9 | [options] 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | .DS_Store 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # docs/gatsbyjs 13 | .cache 14 | public/ 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | .nyc_output 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules 37 | jspm_packages 38 | 39 | # Optional npm cache directory 40 | .npm 41 | 42 | # Optional REPL history 43 | .node_repl_history 44 | .idea/ 45 | 46 | # AST Debug folder 47 | ast_view 48 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "10" 5 | install: 6 | - npm install 7 | script: "npm run $TEST_SUITE" 8 | after_success: 9 | - "npm run coverage" 10 | env: 11 | - TEST_SUITE=validate 12 | - TEST_SUITE=test 13 | cache: 14 | directories: 15 | - node_modules 16 | - packages/walt-loader/node_modules 17 | - packages/webpack-walt-examples/node_modules 18 | - packages/walt-compiler/node_modules 19 | - packages/walt-docs/node_modules 20 | - packages/walt-link/node_modules 21 | 22 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | We need to test that strings of length of 128+ bytes work. On a plane, so could not post lorem ipsum, this should be of correct length though. Unicode for coverage √"; 45 | test(text, stringLength(text), 191); 46 | 47 | // // Fail this spec to see the text, but this tests that multi-line strings do work 48 | test(`multi line 49 | strings`, true, true); 50 | } 51 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/__tests__/subscripts-spec.walt: -------------------------------------------------------------------------------- 1 | import { assert: Assert } from 'env'; 2 | type Assert = (i32, i32, i32) => void; 3 | 4 | type Struct = { x: i32, y: i32, list: i32[] }; 5 | 6 | const memory: Memory = { initial: 1 }; 7 | 8 | export function run() { 9 | // const x : i32[] = 0; 10 | // x[0] = 1; 11 | // x[1] = 2; 12 | const s: Struct = 0; 13 | s.list = memory.dataSize(); 14 | // // s.list[0] = 0xff; 15 | s.list[1] = 'x'; 16 | s.list[2] = 0x0f; 17 | 18 | assert('chained subscripts', 'x', s.list[1]); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/__tests__/syntax-spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The bootstrap logic for testing all of the syntax features 3 | * of the compiler. 4 | */ 5 | import test from 'ava'; 6 | import fs from 'fs'; 7 | import path from 'path'; 8 | import { harness } from '../utils/test-utils'; 9 | 10 | // Whitelist for "focusing" on specific specs, disabling specs etc. 11 | const whitelist = ['struct', 'type', 'union-types']; 12 | 13 | test('Syntax test suite', t => { 14 | let resolve; 15 | let reject; 16 | let p = new Promise((r, rj) => { 17 | resolve = r; 18 | reject = rj; 19 | }); 20 | 21 | const postfix = '-test.walt'; 22 | const isWhitelisted = f => whitelist.includes(f.slice(0, -postfix.length)); 23 | 24 | fs.readdir(path.resolve(__dirname, '../../syntax'), (err, files) => { 25 | if (err != null) { 26 | reject(err); 27 | } 28 | 29 | let testCases = files.filter(isWhitelisted); 30 | const runTest = file => { 31 | const T = { 32 | is: (e, r, text) => t.is(e, r, file + ' - ' + text), 33 | }; 34 | try { 35 | return harness(path.resolve(__dirname, '../../syntax', file))(T).catch( 36 | e => { 37 | // eslint-disable-next-line 38 | console.error( 39 | ` Runtime failure for syntax test at ${file}\n\n ${e.message}` 40 | ); 41 | throw e; 42 | } 43 | ); 44 | } catch (e) { 45 | // eslint-disable-next-line 46 | console.error( 47 | ` Failed syntax test compilation at ${file} ${e.message}` 48 | ); 49 | return Promise.reject(new Error(`Failed at ${file}`)); 50 | } 51 | }; 52 | 53 | Promise.all(testCases.map(runTest)).then(resolve); 54 | }); 55 | 56 | return p; 57 | }); 58 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/__tests__/throw-spec.walt: -------------------------------------------------------------------------------- 1 | export function run(input: i32): i32 { 2 | if (input == 0) { 3 | // Expression are allowed, but are ignored 4 | throw -1; 5 | } 6 | 7 | return input * 2; 8 | } 9 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/__tests__/type-conversion-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { compile, debug, getIR } from '..'; 3 | import compose from '../utils/compose'; 4 | 5 | const walt = `export function constant(): f32 { 6 | return 0.5; 7 | } 8 | export function variableTypecast(x: i32): f32 { 9 | return (x: f32) + 5.0; 10 | } 11 | export function _32IntTypecast(x: f32): i32 { 12 | return (x: i32) + 2; 13 | } 14 | export function _32FloatTypecast(x: i32): f32 { 15 | return 2.5 + (x: f32) + 0.5; 16 | } 17 | // We cannot call this function from the outside with a i64 number :/ 18 | export function _64IntTypecast(): i32 { 19 | const x: i64 = 2; 20 | return (2 * x): i32; 21 | } 22 | export function _64FloatTypecast(x: f64): f32 { 23 | return (2 * x): f32; 24 | } 25 | export function promotions(): f32 { 26 | return 2.5 + 2 + 0.5 * (10/ 5); 27 | } 28 | 29 | export function promoteF32toF64(): f64 { 30 | const x: f64 = 2; 31 | const y: f32 = 2; 32 | return x + y; 33 | } 34 | `; 35 | 36 | test('typecasts work', t => { 37 | const getWasm = compose(debug, getIR); 38 | const wasm = getWasm(walt); 39 | t.snapshot(wasm); 40 | return WebAssembly.instantiate(compile(walt).buffer()).then(result => { 41 | t.is(result.instance.exports.constant(), 0.5); 42 | t.is(result.instance.exports.variableTypecast(2), 7); 43 | t.is(result.instance.exports._32IntTypecast(2.0), 4); 44 | t.is(result.instance.exports._32FloatTypecast(2), 5); 45 | t.is(result.instance.exports._64IntTypecast(), 4); 46 | t.is(result.instance.exports._64FloatTypecast(2), 4); 47 | t.is(result.instance.exports.promotions(), 5.5); 48 | t.is(result.instance.exports.promoteF32toF64(), 4); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/base/index.js: -------------------------------------------------------------------------------- 1 | // Base plugin 2 | export default function base() { 3 | return { 4 | semantics() { 5 | return { 6 | '*': _ => 7 | function baseSemanticsParser([node, ...rest], t) { 8 | const result = { 9 | ...node, 10 | params: node.params.map(child => t([child, ...rest])), 11 | }; 12 | 13 | return result; 14 | }, 15 | }; 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/core/bool.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bool plugin. 3 | * Converts boolean identifiers to i32 constants, handles declarations with 4 | * type "bool". 5 | * 6 | * @flow 7 | */ 8 | import Syntax from 'walt-syntax'; 9 | import type { SemanticPlugin } from '../flow/types'; 10 | 11 | export default function booleanPlugin(): SemanticPlugin { 12 | return { 13 | semantics() { 14 | const declaration = next => ([decl, context]) => { 15 | if (decl.type === 'bool') { 16 | return next([{ ...decl, type: 'i32' }, context]); 17 | } 18 | 19 | return next([decl, context]); 20 | }; 21 | return { 22 | [Syntax.Identifier]: next => (args, transform) => { 23 | const [id, context] = args; 24 | if (!(id.value === 'true' || id.value === 'false')) { 25 | return next(args); 26 | } 27 | 28 | return transform([ 29 | { 30 | ...id, 31 | Type: Syntax.Constant, 32 | value: id.value === 'true' ? '1' : '0', 33 | type: 'i32', 34 | }, 35 | context, 36 | ]); 37 | }, 38 | [Syntax.FunctionResult]: next => ([result, context]) => { 39 | if (result.type === 'bool') { 40 | return next([{ ...result, type: 'i32' }, context]); 41 | } 42 | 43 | return next([result, context]); 44 | }, 45 | [Syntax.Declaration]: declaration, 46 | [Syntax.ImmutableDeclaration]: declaration, 47 | }; 48 | }, 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/core/native.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Native methods plugin 3 | * 4 | * @flow 5 | */ 6 | import Syntax from 'walt-syntax'; 7 | import { extendNode } from '../utils/extend-node'; 8 | import type { SemanticPlugin } from '../flow/types'; 9 | 10 | export default function nativePlugin(): SemanticPlugin { 11 | return { 12 | semantics() { 13 | return { 14 | [Syntax.FunctionCall]: next => (args, transform) => { 15 | const [node, context] = args; 16 | const [id, ...fnArgs] = node.params; 17 | if ( 18 | id.Type === Syntax.Access && 19 | id.params[0] && 20 | id.params[0].Type === Syntax.Type 21 | ) { 22 | const [type, method] = id.params; 23 | 24 | return extendNode( 25 | { 26 | value: `${type.value}.${method.value}`, 27 | type: type.value, 28 | params: fnArgs.map(p => transform([p, context])), 29 | Type: Syntax.NativeMethod, 30 | }, 31 | node 32 | ); 33 | } 34 | 35 | return next(args); 36 | }, 37 | [Syntax.Unreachable]: _ => ([node]) => { 38 | return extendNode( 39 | { 40 | value: 'unreachable', 41 | params: [], 42 | Type: Syntax.NativeMethod, 43 | }, 44 | node 45 | ); 46 | }, 47 | }; 48 | }, 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/__tests__/__snapshots__/value-types-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/emitter/__tests__/value-types-spec.js` 2 | 3 | The actual snapshot is saved in `value-types-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## getTypeString returns string version of the constant 8 | 9 | > Snapshot 1 10 | 11 | 'i32' 12 | 13 | > Snapshot 2 14 | 15 | 'f32' 16 | 17 | > Snapshot 3 18 | 19 | 'i64' 20 | 21 | > Snapshot 4 22 | 23 | 'f64' 24 | 25 | > Snapshot 5 26 | 27 | 'func' 28 | 29 | > Snapshot 6 30 | 31 | 'anyfunc' 32 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/__tests__/__snapshots__/value-types-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/emitter/__tests__/__snapshots__/value-types-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/__tests__/opcode-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import opcode, { opcodeMap, textMap } from '../opcode'; 3 | 4 | test('opcode is a list of opcodes', t => t.is(typeof opcode, 'object')); 5 | 6 | test('sanity check resulting ojects', t => { 7 | const keys = Object.keys(opcode); 8 | keys.forEach(key => { 9 | const code = opcode[key]; 10 | t.is(key, code.name, `Name is set for ${key}`); 11 | t.is(opcodeMap[code.code], code, `Opcode map is set for ${key}`); 12 | t.is(textMap[code.text], code, `Text map is set for ${key}`); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/__tests__/value-types-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { 3 | getTypeString, 4 | I32, 5 | I64, 6 | F32, 7 | F64, 8 | FUNC, 9 | ANYFUNC, 10 | } from '../value_type'; 11 | 12 | test('getTypeString returns string version of the constant', t => { 13 | t.snapshot(getTypeString(I32)); 14 | t.snapshot(getTypeString(F32)); 15 | t.snapshot(getTypeString(I64)); 16 | t.snapshot(getTypeString(F64)); 17 | t.snapshot(getTypeString(FUNC)); 18 | t.snapshot(getTypeString(ANYFUNC)); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/external_kind.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const EXTERN_FUNCTION = 0; 3 | export const EXTERN_TABLE = 1; 4 | export const EXTERN_MEMORY = 2; 5 | export const EXTERN_GLOBAL = 3; 6 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import preamble from './preamble'; 3 | import section from './section'; 4 | import OutputStream from '../utils/output-stream'; 5 | import type { ProgramType } from '../generator/flow/types'; 6 | import type { BaseOptions } from '../flow/types'; 7 | 8 | function emit(program: ProgramType, config: BaseOptions) { 9 | const stream = new OutputStream(); 10 | 11 | // Write MAGIC and VERSION. This is now a valid WASM Module 12 | const result = stream 13 | .write(preamble(program.Version)) 14 | .write(section.type(program)) 15 | .write(section.imports(program)) 16 | .write(section.function(program)) 17 | .write(section.table(program)) 18 | .write(section.memory(program)) 19 | .write(section.globals(program)) 20 | .write(section.exports(program)) 21 | .write(section.start(program)) 22 | .write(section.element(program)) 23 | .write(section.code(program)) 24 | .write(section.data(program)); 25 | 26 | if (config.encodeNames) { 27 | return result.write(section.name(program)); 28 | } 29 | 30 | return result; 31 | } 32 | 33 | export default emit; 34 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/numbers.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const u32 = 'u32'; 3 | export const varuint7 = 'varuint7'; 4 | export const varuint32 = 'varuint32'; 5 | export const varint7 = 'varint7'; 6 | export const varint1 = 'varint1'; 7 | export const varint32 = 'varint32'; 8 | export const varint64 = 'varint64'; 9 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/preamble.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u32 } from 'wasm-types'; 3 | import OutputStream from '../utils/output-stream'; 4 | 5 | export const VERSION_1 = 0x1; 6 | export const MAGIC = 0x6d736100; 7 | export const MAGIC_INDEX = 0; 8 | export const VERSION_INDEX = 4; 9 | 10 | export default function write(version: number) { 11 | return new OutputStream() 12 | .push(u32, MAGIC, '\\0asm') 13 | .push(u32, version, `version ${version}`); 14 | } 15 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/codes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const SECTION_TYPE = 1; 3 | export const SECTION_IMPORT = 2; 4 | export const SECTION_FUNCTION = 3; 5 | export const SECTION_TABLE = 4; 6 | export const SECTION_MEMORY = 5; 7 | export const SECTION_GLOBAL = 6; 8 | export const SECTION_EXPORT = 7; 9 | export const SECTION_START = 8; 10 | export const SECTION_ELEMENT = 9; 11 | export const SECTION_CODE = 10; 12 | export const SECTION_DATA = 11; 13 | // Custom sections 14 | export const SECTION_NAME = 0; 15 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/data.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8 } from 'wasm-types'; 3 | import { varint32, varuint32 } from '../numbers'; 4 | import opcode from '../opcode'; 5 | import OutputStream from '../../utils/output-stream'; 6 | import type { DataSectionType } from '../../generator/flow/types'; 7 | 8 | const emitDataSegment = (stream, segment) => { 9 | stream.push(varuint32, 0, 'memory index'); 10 | 11 | const { offset, data } = segment; 12 | 13 | stream.push(u8, opcode.i32Const.code, opcode.i32Const.text); 14 | stream.push(varint32, offset, `segment offset (${offset})`); 15 | stream.push(u8, opcode.End.code, 'end'); 16 | 17 | stream.push(varuint32, data.size, 'segment size'); 18 | // We invert the control here a bit so that any sort of data could be written 19 | // into the data section. This buys us a bit of flexibility for the cost of 20 | // doing encoding earlier in the funnel 21 | stream.write(data); 22 | }; 23 | 24 | export default function emit(dataSection: DataSectionType): OutputStream { 25 | const stream = new OutputStream(); 26 | stream.push(varuint32, dataSection.length, 'entries'); 27 | 28 | for (let i = 0, len = dataSection.length; i < len; i++) { 29 | const segment = dataSection[i]; 30 | emitDataSegment(stream, segment); 31 | } 32 | 33 | return stream; 34 | } 35 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/element.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8 } from 'wasm-types'; 3 | import { varuint32 } from '../numbers'; 4 | import opcode from '../opcode'; 5 | import OutputStream from '../../utils/output-stream'; 6 | 7 | type Element = { 8 | functionIndex: number, 9 | }; 10 | 11 | const emitElement = (stream: OutputStream) => ( 12 | { functionIndex }: Element, 13 | index: number 14 | ) => { 15 | stream.push(varuint32, 0, 'table index'); 16 | stream.push(u8, opcode.i32Const.code, 'offset'); 17 | stream.push(varuint32, index, index.toString()); 18 | stream.push(u8, opcode.End.code, 'end'); 19 | stream.push(varuint32, 1, 'number of elements'); 20 | stream.push(varuint32, functionIndex, 'function index'); 21 | }; 22 | 23 | const emit = (elements: Element[]) => { 24 | const stream = new OutputStream(); 25 | stream.push(varuint32, elements.length, 'count'); 26 | 27 | elements.forEach(emitElement(stream)); 28 | 29 | return stream; 30 | }; 31 | 32 | export default emit; 33 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/exports.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8 } from 'wasm-types'; 3 | import { varuint32 } from '../numbers'; 4 | import { emitString } from '../string'; 5 | import OutputStream from '../../utils/output-stream'; 6 | 7 | const emit = (exports: any[]) => { 8 | const payload = new OutputStream(); 9 | payload.push(varuint32, exports.length, 'count'); 10 | 11 | exports.forEach(({ field, kind, index }) => { 12 | emitString(payload, field, 'field'); 13 | 14 | payload.push(u8, kind, 'Global'); 15 | payload.push(varuint32, index, 'index'); 16 | }); 17 | 18 | return payload; 19 | }; 20 | 21 | export default emit; 22 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/functions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // Emits function section. For function code emitter look into code.js 3 | import { varuint32 } from '../numbers'; 4 | import OutputStream from '../../utils/output-stream'; 5 | 6 | const emit = (functions: any[]) => { 7 | functions = functions.filter(func => func !== null); 8 | const stream = new OutputStream(); 9 | stream.push(varuint32, functions.length, 'count'); 10 | 11 | functions.forEach(index => stream.push(varuint32, index, 'type index')); 12 | 13 | return stream; 14 | }; 15 | 16 | export default emit; 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/globals.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8, f32, f64 } from 'wasm-types'; 3 | import { I32, I64, F64, F32, getTypeString } from '../value_type'; 4 | import { varuint32, varint32, varint64 } from '../numbers'; 5 | import opcode from '../opcode'; 6 | import OutputStream from '../../utils/output-stream'; 7 | 8 | const encode = (payload, { type, init, mutable }) => { 9 | payload.push(u8, type, getTypeString(type)); 10 | payload.push(u8, mutable, 'mutable'); 11 | // Encode the constant 12 | switch (type) { 13 | case I32: 14 | payload.push(u8, opcode.i32Const.code, opcode.i32Const.text); 15 | payload.push(varint32, init, `value (${init})`); 16 | break; 17 | case F32: 18 | payload.push(u8, opcode.f32Const.code, opcode.f32Const.text); 19 | payload.push(f32, init, `value (${init})`); 20 | break; 21 | case F64: 22 | payload.push(u8, opcode.f64Const.code, opcode.f64Const.text); 23 | payload.push(f64, init, `value (${init})`); 24 | break; 25 | case I64: 26 | payload.push(u8, opcode.i64Const.code, opcode.i64Const.text); 27 | payload.push(varint64, init, `value (${init})`); 28 | } 29 | 30 | payload.push(u8, opcode.End.code, 'end'); 31 | }; 32 | 33 | const emit = (globals: any[]) => { 34 | const payload = new OutputStream(); 35 | payload.push(varuint32, globals.length, 'count'); 36 | 37 | globals.forEach(g => encode(payload, g)); 38 | 39 | return payload; 40 | }; 41 | 42 | export default emit; 43 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/imports.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import OutputStream from '../../utils/output-stream'; 3 | import { u8 } from 'wasm-types'; 4 | import { varint1, varuint32 } from '../numbers'; 5 | import { getTypeString, ANYFUNC } from '../value_type'; 6 | import { 7 | EXTERN_GLOBAL, 8 | EXTERN_FUNCTION, 9 | EXTERN_TABLE, 10 | EXTERN_MEMORY, 11 | } from '../external_kind'; 12 | import { emitString } from '../string'; 13 | 14 | const emit = (entries: any[]) => { 15 | const payload = new OutputStream().push( 16 | varuint32, 17 | entries.length, 18 | 'entry count' 19 | ); 20 | 21 | entries.forEach(entry => { 22 | emitString(payload, entry.module, 'module'); 23 | emitString(payload, entry.field, 'field'); 24 | 25 | switch (entry.kind) { 26 | case EXTERN_GLOBAL: { 27 | payload.push(u8, EXTERN_GLOBAL, 'Global'); 28 | payload.push(u8, entry.type, getTypeString(entry.type)); 29 | payload.push(u8, 0, 'immutable'); 30 | break; 31 | } 32 | case EXTERN_FUNCTION: { 33 | payload.push(u8, entry.kind, 'Function'); 34 | payload.push(varuint32, entry.typeIndex, 'type index'); 35 | break; 36 | } 37 | case EXTERN_TABLE: { 38 | payload.push(u8, entry.kind, 'Table'); 39 | payload.push(u8, ANYFUNC, 'function table types'); 40 | payload.push(varint1, 0, 'has max value'); 41 | payload.push(varuint32, 0, 'iniital table size'); 42 | break; 43 | } 44 | case EXTERN_MEMORY: { 45 | payload.push(u8, entry.kind, 'Memory'); 46 | payload.push(varint1, !!entry.max, 'has no max'); 47 | payload.push(varuint32, entry.initial, 'initial memory size(PAGES)'); 48 | if (entry.max) { 49 | payload.push(varuint32, entry.max, 'max memory size(PAGES)'); 50 | } 51 | break; 52 | } 53 | } 54 | }); 55 | 56 | return payload; 57 | }; 58 | 59 | export default emit; 60 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import imports from './imports'; 3 | import exports_ from './exports'; 4 | import globals from './globals'; 5 | import functions from './functions'; 6 | import start from './start'; 7 | import element from './element'; 8 | import types from './types'; 9 | import code from './code'; 10 | import memory from './memory'; 11 | import table from './table'; 12 | import data from './data'; 13 | import name from './name'; 14 | import { 15 | SECTION_TYPE, 16 | SECTION_IMPORT, 17 | SECTION_FUNCTION, 18 | SECTION_MEMORY, 19 | SECTION_TABLE, 20 | SECTION_GLOBAL, 21 | SECTION_EXPORT, 22 | SECTION_START, 23 | SECTION_ELEMENT, 24 | SECTION_CODE, 25 | SECTION_DATA, 26 | SECTION_NAME, 27 | } from './codes'; 28 | 29 | import writer from './writer'; 30 | 31 | export default { 32 | type: writer({ type: SECTION_TYPE, label: 'Types', emitter: types }), 33 | imports: writer({ type: SECTION_IMPORT, label: 'Imports', emitter: imports }), 34 | function: writer({ 35 | type: SECTION_FUNCTION, 36 | label: 'Functions', 37 | emitter: functions, 38 | }), 39 | table: writer({ type: SECTION_TABLE, label: 'Table', emitter: table }), 40 | memory: writer({ type: SECTION_MEMORY, label: 'Memory', emitter: memory }), 41 | exports: writer({ 42 | type: SECTION_EXPORT, 43 | label: 'Exports', 44 | emitter: exports_, 45 | }), 46 | globals: writer({ type: SECTION_GLOBAL, label: 'Globals', emitter: globals }), 47 | start: writer({ type: SECTION_START, label: 'Start', emitter: start }), 48 | element: writer({ 49 | type: SECTION_ELEMENT, 50 | label: 'Element', 51 | emitter: element, 52 | }), 53 | code: writer({ type: SECTION_CODE, label: 'Code', emitter: code }), 54 | data: writer({ type: SECTION_DATA, label: 'Data', emitter: data }), 55 | name: writer({ type: SECTION_NAME, label: 'Name', emitter: name }), 56 | }; 57 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/memory.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // Emits function section. For function code emitter look into code.js 3 | import { varuint32, varint1 } from '../numbers'; 4 | import OutputStream from '../../utils/output-stream'; 5 | 6 | const emitEntry = (payload, entry) => { 7 | payload.push(varint1, entry.max ? 1 : 0, 'has no max'); 8 | payload.push(varuint32, entry.initial, 'initial memory size(PAGES)'); 9 | if (entry.max) { 10 | payload.push(varuint32, entry.max, 'max memory size(PAGES)'); 11 | } 12 | }; 13 | 14 | const emit = (memories: any[]) => { 15 | const stream = new OutputStream(); 16 | stream.push(varuint32, memories.length, 'count'); 17 | memories.forEach(entry => emitEntry(stream, entry)); 18 | 19 | return stream; 20 | }; 21 | 22 | export default emit; 23 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/start.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { varuint32 } from '../numbers'; 3 | import OutputStream from '../../utils/output-stream'; 4 | 5 | export default function emitTables(start: number[]) { 6 | const stream = new OutputStream(); 7 | 8 | stream.push(varuint32, start[0], 'start function'); 9 | 10 | return stream; 11 | } 12 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/table.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { varuint32, varint1, varint7 } from '../numbers'; 3 | import OutputStream from '../../utils/output-stream'; 4 | 5 | const typeBytecodes = { 6 | anyfunc: 0x70, 7 | }; 8 | 9 | type TableEntryType = { 10 | initial: number, 11 | max?: number, 12 | type: string, 13 | }; 14 | 15 | const emitEntry = (payload, entry: TableEntryType) => { 16 | payload.push(varint7, typeBytecodes[entry.type], entry.type); 17 | payload.push(varint1, entry.max ? 1 : 0, 'has max'); 18 | payload.push(varuint32, entry.initial, 'initial table size'); 19 | if (entry.max) { 20 | payload.push(varuint32, entry.max, 'max table size'); 21 | } 22 | }; 23 | 24 | export default function emitTables(tables: TableEntryType[]) { 25 | const stream = new OutputStream(); 26 | stream.push(varuint32, tables.length, 'count'); 27 | tables.forEach(entry => emitEntry(stream, entry)); 28 | 29 | return stream; 30 | } 31 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { FUNC, getTypeString } from '../value_type'; 3 | import { varuint32, varint7, varint1 } from '../numbers'; 4 | import OutputStream from '../../utils/output-stream'; 5 | 6 | const emitType = (stream, { params, result }, index) => { 7 | // as of wasm 1.0 spec types are only of from === func 8 | stream.push(varint7, FUNC, `func type (${index})`); 9 | stream.push(varuint32, params.length, 'parameter count'); 10 | params.forEach(type => stream.push(varint7, type, 'param')); 11 | if (result) { 12 | stream.push(varint1, 1, 'result count'); 13 | stream.push(varint7, result, `result type ${getTypeString(result)}`); 14 | } else { 15 | stream.push(varint1, 0, 'result count'); 16 | } 17 | }; 18 | 19 | const emit = (types: any[]) => { 20 | const stream = new OutputStream(); 21 | stream.push(varuint32, types.length, 'count'); 22 | 23 | types.forEach((type, index) => emitType(stream, type, index)); 24 | 25 | return stream; 26 | }; 27 | 28 | export default emit; 29 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/section/writer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8 } from 'wasm-types'; 3 | import { varuint32 } from '../numbers'; 4 | import OutputStream from '../../utils/output-stream'; 5 | 6 | const writer = ({ 7 | type, 8 | label, 9 | emitter, 10 | }: { 11 | type: number, 12 | label: string, 13 | emitter: any => OutputStream, 14 | }) => (ast: any): ?OutputStream => { 15 | const field = ast[label]; 16 | if (!field || (Array.isArray(field) && !field.length)) { 17 | return null; 18 | } 19 | 20 | const stream = new OutputStream().push(u8, type, label + ' section'); 21 | const entries = emitter(field); 22 | 23 | stream.push(varuint32, entries.size, 'size'); 24 | stream.write(entries); 25 | 26 | return stream; 27 | }; 28 | 29 | export default writer; 30 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/string.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { u8 } from 'wasm-types'; 3 | import { varuint32 } from './numbers'; 4 | import OutputStream from '../utils/output-stream'; 5 | 6 | export function emitString( 7 | stream: OutputStream, 8 | string: string, 9 | debug: string 10 | ) { 11 | stream.push(varuint32, string.length, debug); 12 | for (let i = 0; i < string.length; i++) { 13 | stream.push(u8, string.charCodeAt(i), string[i]); 14 | } 15 | return stream; 16 | } 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/emitter/value_type.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const I32 = 0x7f; 3 | export const I64 = 0x7e; 4 | export const F32 = 0x7d; 5 | export const F64 = 0x7c; 6 | export const ANYFUNC = 0x70; 7 | export const FUNC = 0x60; 8 | export const BLOCK_TYPE = 0x40; 9 | 10 | export const stringToType = { 11 | i32: I32, 12 | i64: I64, 13 | f32: F32, 14 | f64: F64, 15 | }; 16 | 17 | export const getTypeString = (type: number) => { 18 | switch (type) { 19 | case I64: 20 | return 'i64'; 21 | case F32: 22 | return 'f32'; 23 | case F64: 24 | return 'f64'; 25 | case FUNC: 26 | return 'func'; 27 | case ANYFUNC: 28 | return 'anyfunc'; 29 | case I32: 30 | default: 31 | return 'i32'; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/__tests__/__snapshots__/memory-assignment-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/generator/__tests__/__snapshots__/memory-assignment-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/__tests__/__snapshots__/type-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/generator/__tests__/type-spec.js` 2 | 3 | The actual snapshot is saved in `type-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## type generator, empty params 8 | 9 | > Snapshot 1 10 | 11 | { 12 | id: 'EmptyParamsType', 13 | params: [], 14 | result: 127, 15 | } 16 | 17 | ## type generator, floats, 64bit types 18 | 19 | > Snapshot 1 20 | 21 | { 22 | id: 'MixedFuncType', 23 | params: [ 24 | 125, 25 | 127, 26 | 126, 27 | ], 28 | result: 125, 29 | } 30 | 31 | ## type generator, type sequence params 32 | 33 | > Snapshot 1 34 | 35 | { 36 | id: 'TestFunctionType', 37 | params: [ 38 | 127, 39 | 127, 40 | ], 41 | result: 127, 42 | } 43 | 44 | ## type generator, void return 45 | 46 | > Snapshot 1 47 | 48 | { 49 | id: 'VoidFuncType', 50 | params: [ 51 | 127, 52 | ], 53 | result: null, 54 | } 55 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/__tests__/__snapshots__/type-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/generator/__tests__/__snapshots__/type-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/__tests__/map-syntax-spec.js: -------------------------------------------------------------------------------- 1 | import mapSyntax from '../map-syntax'; 2 | import test from 'ava'; 3 | 4 | test('map syntax throws if Type is unknown', t => { 5 | t.throws(() => { 6 | mapSyntax({}, { value: 'unknown', Type: null }); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/assignment-expression.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import opcode from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateAssignment: GeneratorType = node => { 8 | const [target, value] = node.params; 9 | const block = [value].map(mapSyntax(null)).reduce(mergeBlock, []); 10 | 11 | block.push({ 12 | kind: opcode.TeeLocal, 13 | params: [Number(target.meta.LOCAL_INDEX)], 14 | debug: `${target.value}<${String(target.meta.ALIAS || target.type)}>`, 15 | }); 16 | 17 | return block; 18 | }; 19 | 20 | export default generateAssignment; 21 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/assignment.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import { setInScope } from './utils'; 4 | import mergeBlock from './merge-block'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateAssignment: GeneratorType = node => { 8 | const [target, value] = node.params; 9 | const block = [value].map(mapSyntax(null)).reduce(mergeBlock, []); 10 | 11 | block.push(setInScope(target)); 12 | 13 | return block; 14 | }; 15 | 16 | export default generateAssignment; 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/binary-expression.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import { opcodeFromOperator } from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | /** 8 | * Transform a binary expression node into a list of opcodes 9 | */ 10 | const generateBinaryExpression: GeneratorType = (node, parent) => { 11 | // Map operands first 12 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 13 | 14 | // Map the operator last 15 | block.push({ 16 | kind: opcodeFromOperator({ 17 | ...node, 18 | type: node.type, 19 | }), 20 | params: [], 21 | }); 22 | 23 | return block; 24 | }; 25 | 26 | export default generateBinaryExpression; 27 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/block.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import type { GeneratorType } from './flow/types'; 5 | 6 | const generateBlock: GeneratorType = (node, parent) => { 7 | // TODO: blocks should encode a return type and an end opcode, 8 | // but currently they are only used as part of a larger control flow instructions 9 | return node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 10 | }; 11 | 12 | export default generateBlock; 13 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/break.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import opcode from '../emitter/opcode'; 3 | import type { GeneratorType } from './flow/types'; 4 | const generateTypecast: GeneratorType = () => { 5 | return [ 6 | { 7 | kind: opcode.Br, 8 | params: [2], 9 | }, 10 | ]; 11 | }; 12 | 13 | export default generateTypecast; 14 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/constant.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import opcode from '../emitter/opcode'; 3 | import type { GeneratorType } from './flow/types'; 4 | 5 | const generateConstant: GeneratorType = node => { 6 | const kind = opcode[String(node.type) + 'Const']; 7 | const value = (node.meta.SIGN || 1) * Number(node.value); 8 | 9 | return [ 10 | { 11 | kind, 12 | params: [value], 13 | }, 14 | ]; 15 | }; 16 | 17 | export default generateConstant; 18 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/declaration.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { i32 } from 'walt-syntax'; 3 | import generateExpression from './expression'; 4 | import { isBuiltinType } from './utils'; 5 | import opcode from '../emitter/opcode'; 6 | import { LOCAL_INDEX } from '../semantics/metadata'; 7 | import type { GeneratorType } from './flow/types'; 8 | 9 | const generateDeclaration: GeneratorType = (node, parent) => { 10 | const initNode = node.params[0]; 11 | 12 | if (initNode) { 13 | const metaIndex = node.meta[LOCAL_INDEX]; 14 | 15 | const type = isBuiltinType(node.type) ? node.type : i32; 16 | 17 | return [ 18 | ...generateExpression({ ...initNode, type }, parent), 19 | { 20 | kind: opcode.SetLocal, 21 | params: [metaIndex], 22 | debug: `${node.value}<${String(node.type)}>`, 23 | }, 24 | ]; 25 | } 26 | 27 | return []; 28 | }; 29 | 30 | export default generateDeclaration; 31 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/element.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | const generateElement = (functionIndex: number) => { 3 | return { functionIndex }; 4 | }; 5 | 6 | export default generateElement; 7 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/else.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import opcode from '../emitter/opcode'; 3 | import mapSyntax from './map-syntax'; 4 | import mergeBlock from './merge-block'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateElse: GeneratorType = (node, parent) => { 8 | // TODO: blocks should encode a return type and an end opcode, 9 | // but currently they are only used as part of a larger control flow instructions 10 | return [ 11 | { kind: opcode.Else, params: [] }, 12 | ...node.params.map(mapSyntax(parent)).reduce(mergeBlock, []), 13 | ]; 14 | }; 15 | 16 | export default generateElse; 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/export.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { GLOBAL_INDEX, FUNCTION_INDEX } from '../semantics/metadata'; 3 | import { 4 | EXTERN_GLOBAL, 5 | EXTERN_MEMORY, 6 | EXTERN_TABLE, 7 | EXTERN_FUNCTION, 8 | } from '../emitter/external_kind'; 9 | import type { NodeType, IntermediateExportType } from './flow/types'; 10 | 11 | const externaKindMap = { 12 | Memory: EXTERN_MEMORY, 13 | Table: EXTERN_TABLE, 14 | }; 15 | 16 | export default function generateExport(node: NodeType): IntermediateExportType { 17 | const functionIndexMeta = node.meta[FUNCTION_INDEX]; 18 | const globalIndexMeta = node.meta[GLOBAL_INDEX]; 19 | 20 | if (globalIndexMeta != null) { 21 | const kind = externaKindMap[String(node.type)] || EXTERN_GLOBAL; 22 | const index = [EXTERN_MEMORY, EXTERN_TABLE].includes(kind) 23 | ? 0 24 | : globalIndexMeta; 25 | return { 26 | index, 27 | kind, 28 | field: node.value, 29 | }; 30 | } 31 | 32 | return { 33 | index: functionIndexMeta, 34 | kind: EXTERN_FUNCTION, 35 | field: node.value, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/expression.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import type { GeneratorType } from './flow/types'; 5 | 6 | const generateExpression: GeneratorType = (node, parent) => 7 | [node].map(mapSyntax(parent)).reduce(mergeBlock, []); 8 | 9 | export default generateExpression; 10 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/function-call.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import opcode from '../emitter/opcode'; 4 | import mergeBlock from './merge-block'; 5 | import { FUNCTION_INDEX } from '../semantics/metadata'; 6 | import type { GeneratorType } from './flow/types'; 7 | 8 | const generateFunctionCall: GeneratorType = (node, parent) => { 9 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 10 | const metaFunctionIndex = node.meta[FUNCTION_INDEX]; 11 | 12 | block.push({ 13 | kind: opcode.Call, 14 | params: [metaFunctionIndex], 15 | debug: `${node.value}<${node.type ? node.type : 'void'}>`, 16 | }); 17 | 18 | return block; 19 | }; 20 | 21 | export default generateFunctionCall; 22 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/function-pointer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import opcode from '../emitter/opcode'; 3 | import type { GeneratorType } from './flow/types'; 4 | 5 | const generateFunctionPointer: GeneratorType = node => { 6 | return [ 7 | { 8 | kind: opcode.i32Const, 9 | params: [Number(node.value)], 10 | }, 11 | ]; 12 | }; 13 | 14 | export default generateFunctionPointer; 15 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/generate-data.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // import { stringEncoder } from '../utils/string'; 3 | import { u32 } from 'wasm-types'; 4 | import OutputStream from '../utils/output-stream'; 5 | 6 | export default function generateData( 7 | statics: any, 8 | DATA_SECTION_HEADER_SIZE: number 9 | ) { 10 | // Reserve N bytes for data size header 11 | let offsetAccumulator = DATA_SECTION_HEADER_SIZE; 12 | 13 | const map: { [string]: number } = {}; 14 | 15 | const data = Object.entries(statics).reduce( 16 | (acc, [key, encoded]: [string, any]) => { 17 | acc.push({ offset: Number(offsetAccumulator), data: encoded }); 18 | map[key] = offsetAccumulator; 19 | offsetAccumulator += encoded.size; 20 | return acc; 21 | }, 22 | [] 23 | ); 24 | 25 | // reserved stream for the size header 26 | const lengthStream = new OutputStream(); 27 | lengthStream.push(u32, offsetAccumulator, String(offsetAccumulator)); 28 | 29 | return { 30 | data: [{ offset: 0, data: lengthStream }, ...data], 31 | map, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/if-then-else.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import opcode from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | // probably should be called "generateBranch" and be more generic 8 | // like handling ternary for example. A lot of shared logic here & ternary 9 | const generateIf: GeneratorType = (node, parent) => { 10 | const mapper = mapSyntax(parent); 11 | const [condition, thenBlock, ...restParams] = node.params; 12 | return [ 13 | ...[condition].map(mapper).reduce(mergeBlock, []), 14 | { 15 | kind: opcode.If, 16 | // if-then-else blocks have no return value and the Wasm spec requires us to 17 | // provide a literal byte '0x40' for "empty block" in these cases 18 | params: [0x40], 19 | }, 20 | 21 | // after the expression is on the stack and opcode is following it we can write the 22 | // implicit 'then' block 23 | ...[thenBlock].map(mapper).reduce(mergeBlock, []), 24 | 25 | // followed by the optional 'else' 26 | ...restParams.map(mapper).reduce(mergeBlock, []), 27 | { kind: opcode.End, params: [] }, 28 | ]; 29 | }; 30 | 31 | export default generateIf; 32 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/indirect-function-call.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import invariant from 'invariant'; 3 | import mapSyntax from './map-syntax'; 4 | import mergeBlock from './merge-block'; 5 | import opcode from '../emitter/opcode'; 6 | import { LOCAL_INDEX, TYPE_INDEX } from '../semantics/metadata'; 7 | import type { GeneratorType } from './flow/types'; 8 | 9 | const generateIndirectFunctionCall: GeneratorType = (node, parent) => { 10 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 11 | const localIndex = node.meta[LOCAL_INDEX]; 12 | const typeIndexMeta = node.meta[TYPE_INDEX]; 13 | invariant( 14 | localIndex != null, 15 | 'Undefined local index, not a valid function pointer' 16 | ); 17 | invariant( 18 | typeIndexMeta != null, 19 | 'Variable is not of a valid function pointer type' 20 | ); 21 | 22 | return [ 23 | ...block, 24 | { 25 | kind: opcode.CallIndirect, 26 | params: [typeIndexMeta, 0], 27 | }, 28 | ]; 29 | }; 30 | 31 | export default generateIndirectFunctionCall; 32 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/initializer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { generateValueType } from './utils'; 3 | import { I32, I64, F32, F64 } from '../emitter/value_type'; 4 | import type { NodeType, IntermediateVariableType } from './flow/types'; 5 | 6 | const generateInit = (node: NodeType): IntermediateVariableType => { 7 | const _global = generateValueType(node); 8 | const [initializer] = node.params; 9 | if (initializer != null) { 10 | const { value } = initializer; 11 | switch (_global.type) { 12 | case F32: 13 | case F64: 14 | _global.init = parseFloat(value); 15 | break; 16 | case I32: 17 | case I64: 18 | default: 19 | _global.init = parseInt(value); 20 | } 21 | } 22 | 23 | return _global; 24 | }; 25 | 26 | export default generateInit; 27 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/loop.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import opcode from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateLoop: GeneratorType = (node, parent) => { 8 | const block = []; 9 | const mapper = mapSyntax(parent); 10 | 11 | // First param in a for loop is assignment expression or Noop if it's a while loop 12 | const [initializer, condition, ...body] = node.params; 13 | 14 | block.push.apply(block, [initializer].map(mapper).reduce(mergeBlock, [])); 15 | block.push({ kind: opcode.Block, params: [0x40] }); 16 | block.push({ kind: opcode.Loop, params: [0x40] }); 17 | 18 | block.push.apply(block, [condition].map(mapper).reduce(mergeBlock, [])); 19 | block.push({ kind: opcode.i32Eqz, params: [] }); 20 | block.push({ kind: opcode.BrIf, params: [1] }); 21 | 22 | block.push.apply(block, body.map(mapper).reduce(mergeBlock, [])); 23 | 24 | block.push({ kind: opcode.Br, params: [0] }); 25 | 26 | block.push({ kind: opcode.End, params: [] }); 27 | block.push({ kind: opcode.End, params: [] }); 28 | 29 | return block; 30 | }; 31 | 32 | export default generateLoop; 33 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/memory.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Syntax from 'walt-syntax'; 3 | import walkNode from 'walt-parser-tools/walk-node'; 4 | import type { NodeType, IntermediateMemoryType } from './flow/types'; 5 | 6 | const generateMemory = (node: NodeType): IntermediateMemoryType => { 7 | const memory = { max: 0, initial: 0 }; 8 | walkNode({ 9 | [Syntax.Pair]: ({ params }) => { 10 | // This could produce garbage values but that is a fault of the source code 11 | const [{ value: key }, { value }] = params; 12 | memory[key] = parseInt(value); 13 | }, 14 | })(node); 15 | 16 | return memory; 17 | }; 18 | 19 | export default generateMemory; 20 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/merge-block.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { IntermediateOpcodeType } from './flow/types'; 3 | 4 | const mergeBlock = ( 5 | block: IntermediateOpcodeType[], 6 | v: IntermediateOpcodeType | IntermediateOpcodeType[] 7 | ): IntermediateOpcodeType[] => { 8 | // some node types are a sequence of opcodes: 9 | // nested expressions for example 10 | if (Array.isArray(v)) { 11 | block = [...block, ...v]; 12 | } else { 13 | block.push(v); 14 | } 15 | return block; 16 | }; 17 | 18 | export default mergeBlock; 19 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/native.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mergeBlock from './merge-block'; 3 | import mapSyntax from './map-syntax'; 4 | import { textMap } from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const alignCodes = { 8 | load8_s: 0, 9 | load8_u: 0, 10 | store8: 0, 11 | load16_s: 1, 12 | load16_u: 1, 13 | store16: 1, 14 | store32: 2, 15 | load32_s: 2, 16 | load32_u: 2, 17 | store: 2, 18 | load: 2, 19 | }; 20 | 21 | const immediates = { 22 | grow_memory: 0, 23 | current_memory: 0, 24 | }; 25 | 26 | const generateNative: GeneratorType = (node, parent) => { 27 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 28 | 29 | const operation = node.value.split('.').pop(); 30 | 31 | if (alignCodes[operation] == null) { 32 | block.push({ kind: textMap[node.value], params: [immediates[node.value]] }); 33 | } else { 34 | const alignment = alignCodes[operation]; 35 | 36 | const params = [alignment, 0]; 37 | 38 | block.push({ kind: textMap[node.value], params }); 39 | } 40 | 41 | return block; 42 | }; 43 | 44 | export default generateNative; 45 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/noop.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export default function generateNoop() { 3 | return []; 4 | } 5 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/return-statement.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import opcode from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateReturn: GeneratorType = node => { 8 | // Postfix in return statement should be a no-op UNLESS it's editing globals 9 | const block = node.params 10 | .filter(Boolean) 11 | .map(mapSyntax(null)) 12 | .reduce(mergeBlock, []); 13 | block.push({ kind: opcode.Return, params: [] }); 14 | 15 | return block; 16 | }; 17 | 18 | export default generateReturn; 19 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/select.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import opcode from '../emitter/opcode'; 3 | import mapSyntax from './map-syntax'; 4 | import mergeBlock from './merge-block'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateSelect: GeneratorType = (node, parent) => { 8 | const [leftHandSide, rightHandSide] = node.params; 9 | const selectOpcode = { kind: opcode.Select, params: [] }; 10 | const condition = [leftHandSide] 11 | .map(mapSyntax(parent)) 12 | .reduce(mergeBlock, []); 13 | 14 | if (node.value === '&&') { 15 | return [ 16 | ...[rightHandSide].map(mapSyntax(parent)).reduce(mergeBlock, []), 17 | { kind: opcode.i32Const, params: [0] }, 18 | ...condition, 19 | selectOpcode, 20 | ]; 21 | } 22 | 23 | return [ 24 | ...condition, 25 | ...[rightHandSide].map(mapSyntax(parent)).reduce(mergeBlock, []), 26 | ...condition, 27 | selectOpcode, 28 | ]; 29 | }; 30 | 31 | export default generateSelect; 32 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/table.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Syntax from 'walt-syntax'; 3 | import walkNode from 'walt-parser-tools/walk-node'; 4 | import type { NodeType, IntermediateTableType } from './flow/types'; 5 | 6 | export default function generateMemory(node: NodeType): IntermediateTableType { 7 | const table = { max: 0, initial: 0, type: 'element' }; 8 | 9 | walkNode({ 10 | [Syntax.Pair]: ({ params }) => { 11 | // This could produce garbage values but that is a fault of the source code 12 | const [{ value: key }, { value }] = params; 13 | switch (key) { 14 | case 'initial': 15 | table.initial = parseInt(value); 16 | break; 17 | case 'element': 18 | table.type = value; 19 | break; 20 | case 'max': 21 | table.max = parseInt(value); 22 | break; 23 | } 24 | }, 25 | })(node); 26 | 27 | return table; 28 | } 29 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/ternary-expression.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import mapSyntax from './map-syntax'; 3 | import mergeBlock from './merge-block'; 4 | import opcode from '../emitter/opcode'; 5 | import type { GeneratorType } from './flow/types'; 6 | 7 | const generateTernary: GeneratorType = (node, parent) => { 8 | // TernaryExpression has a param layout of 3(TWO) total parameters. 9 | // [truthy, falsy, condition] 10 | // The whole thing is encoded as an Select opcode 11 | // 12 | // NOTE: The use of select means both "branches" are evaluated, even if not selected 13 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 14 | block.push({ 15 | kind: opcode.Select, 16 | params: [], 17 | }); 18 | 19 | return block; 20 | }; 21 | 22 | export default generateTernary; 23 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/typecast.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // 3 | import mapSyntax from './map-syntax'; 4 | import mergeBlock from './merge-block'; 5 | import { getTypecastOpcode } from '../emitter/opcode'; 6 | import { TYPE_CAST } from '../semantics/metadata'; 7 | import invariant from 'invariant'; 8 | import type { GeneratorType } from './flow/types'; 9 | 10 | const generateTypecast: GeneratorType = (node, parent) => { 11 | const metaTypecast = node.meta[TYPE_CAST]; 12 | invariant( 13 | metaTypecast, 14 | `Cannot generate typecast for node: ${JSON.stringify(node)}` 15 | ); 16 | 17 | const { to, from } = metaTypecast; 18 | 19 | const block = node.params.map(mapSyntax(parent)).reduce(mergeBlock, []); 20 | return [ 21 | ...block, 22 | { 23 | kind: getTypecastOpcode(to, from), 24 | params: [], 25 | }, 26 | ]; 27 | }; 28 | 29 | export default generateTypecast; 30 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/generator/utils.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { builtinTypes } from 'walt-syntax'; 3 | import opcode from '../emitter/opcode'; 4 | import curry from 'curry'; 5 | import invariant from 'invariant'; 6 | import { I32, I64, F32, F64 } from '../emitter/value_type'; 7 | import { LOCAL_INDEX, GLOBAL_INDEX, TYPE_CONST } from '../semantics/metadata'; 8 | import print from '../utils/print-node'; 9 | import type { IntermediateVariableType } from './flow/types'; 10 | import type { NodeType } from '../flow/types'; 11 | 12 | export const scopeOperation = curry((op, node) => { 13 | const local = node.meta[LOCAL_INDEX]; 14 | const _global = node.meta[GLOBAL_INDEX]; 15 | const index = local != null ? local : _global; 16 | 17 | invariant( 18 | index != null, 19 | `Undefined index for scope Operation. Possibly missing metadata. op: ${JSON.stringify( 20 | op 21 | )} node: ${print(node)}` 22 | ); 23 | 24 | const kind = local != null ? op + 'Local' : op + 'Global'; 25 | const params = [Number(index)]; 26 | 27 | return { 28 | kind: opcode[kind], 29 | params, 30 | debug: `${node.value}<${node.meta.ALIAS || node.type}>`, 31 | }; 32 | }); 33 | 34 | // clean this up 35 | export const getType = (str: ?string): number => { 36 | switch (str) { 37 | case builtinTypes.f32: 38 | return F32; 39 | case builtinTypes.f64: 40 | return F64; 41 | case builtinTypes.i64: 42 | return I64; 43 | case builtinTypes.i32: 44 | default: 45 | return I32; 46 | } 47 | }; 48 | 49 | export const isBuiltinType = (type: ?string): boolean => { 50 | return typeof type === 'string' && builtinTypes[type] != null; 51 | }; 52 | 53 | export const generateValueType = ( 54 | node: NodeType 55 | ): IntermediateVariableType => ({ 56 | mutable: node.meta[TYPE_CONST] ? 0 : 1, 57 | type: getType(node.type), 58 | }); 59 | export const setInScope = scopeOperation('Set'); 60 | export const getInScope = scopeOperation('Get'); 61 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/README.md: -------------------------------------------------------------------------------- 1 | # Walt Nodes 2 | 3 | Walt AST nodes have a base type shared across all node types. 4 | 5 | _The `Marker` data structure is filled in by the tokenizer and base parser._ 6 | 7 | ```js 8 | // @flow 9 | type Marker = { 10 | sourceLine: string, 11 | line: number, 12 | col: number, 13 | }; 14 | type MetadataType = { [string]: any }; 15 | 16 | type BaseNode = { 17 | range: Marker[], 18 | type: string | null, 19 | value: string, 20 | meta: MetadataType, 21 | }; 22 | ``` 23 | 24 | With each additional node having specific `Type` and `params`. 25 | 26 | ```js 27 | // @flow 28 | type Identifier = BaseNode & { 29 | Type: 'Identifier', 30 | params: [], 31 | }; 32 | ``` 33 | 34 | All nodes in the AST must implement this structure. 35 | 36 | ## Program Structure 37 | 38 | To examine the full structure of the program please refer to the Walt 39 | [Formal EBNF Grammar](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form) 40 | you can see the source code for the grammar [here](./grammar/grammar.ne). 41 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/access-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/parser/__tests__/access-spec.js` 2 | 3 | The actual snapshot is saved in `access-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## property access 8 | 9 | > o.a = 0; 10 | 11 | `(set_local o.a␊ 12 | ;; unparsed␊ 13 | (access␊ 14 | (get_local o)␊ 15 | (get_local a)␊ 16 | )␊ 17 | (i32.const 0)␊ 18 | )␊ 19 | ` 20 | 21 | > o.a[0] = 0; 22 | 23 | `(set_local o.a␊ 24 | ;; unparsed␊ 25 | (subscript␊ 26 | ;; unparsed␊ 27 | (access␊ 28 | (get_local o)␊ 29 | (get_local a)␊ 30 | )␊ 31 | (i32.const 0)␊ 32 | )␊ 33 | (i32.const 0)␊ 34 | )␊ 35 | ` 36 | 37 | > a.b.c.d.e.f = 0; 38 | 39 | `(set_local a.b.c.d.e.f␊ 40 | ;; unparsed␊ 41 | (access␊ 42 | ;; unparsed␊ 43 | (access␊ 44 | ;; unparsed␊ 45 | (access␊ 46 | ;; unparsed␊ 47 | (access␊ 48 | ;; unparsed␊ 49 | (access␊ 50 | (get_local a)␊ 51 | (get_local b)␊ 52 | )␊ 53 | (get_local c)␊ 54 | )␊ 55 | (get_local d)␊ 56 | )␊ 57 | (get_local e)␊ 58 | )␊ 59 | (get_local f)␊ 60 | )␊ 61 | (i32.const 0)␊ 62 | )␊ 63 | ` 64 | 65 | > x = a.b + c.z + y.w.i[0]; 66 | 67 | `(set_local x␊ 68 | (??.add␊ 69 | (??.add␊ 70 | ;; unparsed␊ 71 | (access␊ 72 | (get_local a)␊ 73 | (get_local b)␊ 74 | )␊ 75 | ;; unparsed␊ 76 | (access␊ 77 | (get_local c)␊ 78 | (get_local z)␊ 79 | )␊ 80 | )␊ 81 | ;; unparsed␊ 82 | (subscript␊ 83 | ;; unparsed␊ 84 | (access␊ 85 | ;; unparsed␊ 86 | (access␊ 87 | (get_local y)␊ 88 | (get_local w)␊ 89 | )␊ 90 | (get_local i)␊ 91 | )␊ 92 | (i32.const 0)␊ 93 | )␊ 94 | )␊ 95 | )␊ 96 | ` 97 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/access-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/access-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/array-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/parser/__tests__/array-spec.js` 2 | 3 | The actual snapshot is saved in `array-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## property access 8 | 9 | > a[0] = 0; 10 | 11 | `(set_local a␊ 12 | ;; unparsed␊ 13 | (subscript␊ 14 | (get_local a)␊ 15 | (i32.const 0)␊ 16 | )␊ 17 | (i32.const 0)␊ 18 | )␊ 19 | ` 20 | 21 | > a = b[0]; 22 | 23 | `(set_local a␊ 24 | ;; unparsed␊ 25 | (subscript␊ 26 | (get_local b)␊ 27 | (i32.const 0)␊ 28 | )␊ 29 | )␊ 30 | ` 31 | 32 | > x = a[0] + a[1]; 33 | 34 | `(set_local x␊ 35 | (??.add␊ 36 | ;; unparsed␊ 37 | (subscript␊ 38 | (get_local a)␊ 39 | (i32.const 0)␊ 40 | )␊ 41 | ;; unparsed␊ 42 | (subscript␊ 43 | (get_local a)␊ 44 | (i32.const 1)␊ 45 | )␊ 46 | )␊ 47 | )␊ 48 | ` 49 | 50 | > x = a[b[c[0]]]; 51 | 52 | `(set_local x␊ 53 | ;; unparsed␊ 54 | (subscript␊ 55 | (get_local a)␊ 56 | ;; unparsed␊ 57 | (subscript␊ 58 | (get_local b)␊ 59 | ;; unparsed␊ 60 | (subscript␊ 61 | (get_local c)␊ 62 | (i32.const 0)␊ 63 | )␊ 64 | )␊ 65 | )␊ 66 | )␊ 67 | ` 68 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/array-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/array-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/context-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/parser/__tests__/context-spec.js` 2 | 3 | The actual snapshot is saved in `context-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## syntaxError generates an accurate error string 8 | 9 | > Snapshot 1 10 | 11 | `SyntaxError: ␊ 12 | let x: i32 = someUnknownToken;␊ 13 | ^^^^^^^^^^^^^^^^^^ unknown token␊ 14 | Test Error␊ 15 | at unknown (unknown:1:13)` 16 | 17 | ## unexpected generates syntax error 18 | 19 | > Snapshot 1 20 | 21 | `SyntaxError: ␊ 22 | let x: i32 = someUnknownToken;␊ 23 | ^^^^^^^^^^^^^^^^^^ Unexpected token Identifier␊ 24 | Expected: someUnknownToken␊ 25 | at unknown (unknown:1:13)` 26 | 27 | ## unknown token generates syntax error 28 | 29 | > Snapshot 1 30 | 31 | `SyntaxError: ␊ 32 | let x: i32 = someUnknownToken;␊ 33 | ^^^^^^^^^^^^^^^^^^ someUnknownToken␊ 34 | Unknown token␊ 35 | at unknown (unknown:1:13)` 36 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/context-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/context-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/fragment-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/parser/__tests__/fragment-spec.js` 2 | 3 | The actual snapshot is saved in `fragment-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## mixed replacements 8 | 9 | > Snapshot 1 10 | 11 | `(local x i32␊ 12 | (??.add␊ 13 | (??.add␊ 14 | (call __fcall␊ 15 | (get_local __fcall)␊ 16 | (i32.const 2)␊ 17 | (i32.const 4)␊ 18 | (??.add␊ 19 | (i32.const 5)␊ 20 | (i32.const 5)␊ 21 | )␊ 22 | )␊ 23 | (i32.const 42)␊ 24 | )␊ 25 | (??.add␊ 26 | (get_local x)␊ 27 | (get_local y)␊ 28 | )␊ 29 | )␊ 30 | )␊ 31 | ` 32 | 33 | ## multiple node replacements 34 | 35 | > Snapshot 1 36 | 37 | `(local x i32␊ 38 | (??.add␊ 39 | (call __fcall␊ 40 | (get_local __fcall)␊ 41 | (i32.const 2)␊ 42 | (i32.const 4)␊ 43 | (??.add␊ 44 | (i32.const 5)␊ 45 | (i32.const 5)␊ 46 | )␊ 47 | )␊ 48 | (??.add␊ 49 | (get_local x)␊ 50 | (get_local y)␊ 51 | )␊ 52 | )␊ 53 | )␊ 54 | ` 55 | 56 | ## node replacement 57 | 58 | > Snapshot 1 59 | 60 | `(local x i32␊ 61 | (call __fcall␊ 62 | (get_local __fcall)␊ 63 | (i32.const 2)␊ 64 | (i32.const 4)␊ 65 | (??.add␊ 66 | (i32.const 5)␊ 67 | (i32.const 5)␊ 68 | )␊ 69 | )␊ 70 | )␊ 71 | ` 72 | 73 | ## simple string replacement 74 | 75 | > Snapshot 1 76 | 77 | `(local x i32␊ 78 | (i32.const 0)␊ 79 | )␊ 80 | ` 81 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/fragment-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/fragment-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/parser-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/parser-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/sizeof-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/sizeof-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/type-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/parser/__tests__/type-spec.js` 2 | 3 | The actual snapshot is saved in `type-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## invalid type definition 8 | 9 | > Snapshot 1 10 | 11 | Error { 12 | offset: 8, 13 | token: { 14 | col: 17, 15 | line: 1, 16 | lineBreaks: 0, 17 | offset: 16, 18 | text: '=>', 19 | toString: Function tokenToString {}, 20 | type: 'punctuator', 21 | value: '=>', 22 | }, 23 | message: `undefined at line 1 col 17:␊ 24 | ␊ 25 | type Type = i32 =>␊ 26 | ^␊ 27 | Unexpected punctuator token: "=>"␊ 28 | `, 29 | } 30 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/__snapshots__/type-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/parser/__tests__/__snapshots__/type-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/access-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import makeParser from '..'; 3 | import { makeFragment } from '../fragment'; 4 | import print from '../../utils/print-node'; 5 | 6 | const stmt = makeFragment(makeParser([])); 7 | const variations = [ 8 | 'o.a = 0;', 9 | 'o.a[0] = 0;', 10 | 'a.b.c.d.e.f = 0;', 11 | 'x = a.b + c.z + y.w.i[0];', 12 | ]; 13 | 14 | test('property access', t => { 15 | variations.forEach(v => t.snapshot(print(stmt`${v}`), v)); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/array-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import makeParser from '..'; 3 | import { makeFragment } from '../fragment'; 4 | import print from '../../utils/print-node'; 5 | 6 | const stmt = makeFragment(makeParser([])); 7 | const variations = [ 8 | 'a[0] = 0;', 9 | 'a = b[0];', 10 | 'x = a[0] + a[1];', 11 | 'x = a[b[c[0]]];', 12 | ]; 13 | 14 | test('property access', t => { 15 | variations.forEach(v => t.snapshot(print(stmt`${v}`), v)); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/fragment-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { makeFragment } from '../fragment'; 3 | import print from '../../utils/print-node'; 4 | import makeParser from '..'; 5 | 6 | test('simple string replacement', t => { 7 | const stmt = makeFragment(makeParser([])); 8 | const type = 'i32'; 9 | const value = '0'; 10 | const node = stmt`const x : ${type} = ${value};`; 11 | t.snapshot(print(node)); 12 | }); 13 | 14 | test('node replacement', t => { 15 | const stmt = makeFragment(makeParser([])); 16 | const value = stmt`__fcall(2, 4, 5 + 5);`; 17 | const node = stmt`const x : i32 = ${value};`; 18 | t.snapshot(print(node)); 19 | }); 20 | 21 | test('multiple node replacements', t => { 22 | const stmt = makeFragment(makeParser([])); 23 | const a = stmt`__fcall(2, 4, 5 + 5);`; 24 | const b = stmt`(x + y);`; 25 | const node = stmt`const x : i32 = ${a} + ${b};`; 26 | t.snapshot(print(node)); 27 | }); 28 | 29 | test('mixed replacements', t => { 30 | const stmt = makeFragment(makeParser([])); 31 | const a = '__fcall(2, 4, 5 + 5)'; 32 | const b = 42; 33 | const c = stmt`(x + y);`; 34 | const node = stmt`const x : i32 = ${a} + ${b} + ${c};`; 35 | t.snapshot(print(node)); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/parser-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import parser from '..'; 3 | 4 | test('the most basic of modules in wasm', t => { 5 | const result = parser([], ''); 6 | // Empty ast, empty module 7 | t.snapshot(result); 8 | }); 9 | 10 | test('compiles globals', t => { 11 | const result = parser([], 'const answer: i32 = 42;'); 12 | t.snapshot(result); 13 | }); 14 | 15 | test('compiles exports', t => { 16 | const result = parser([], 'export const answer: i32 = 42;'); 17 | t.snapshot(result); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/sizeof-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { compile } from '../..'; 3 | 4 | const walt = `export function _32BitSizes(): i32 { 5 | let x: i32; 6 | let y: f32; 7 | return sizeof(x) + sizeof(y); 8 | } 9 | 10 | export function _64BitSizes(): i32 { 11 | const x: i64 = 0; 12 | const y: f64 = 0; 13 | return sizeof(x) + sizeof(y); 14 | } 15 | type Type = { a: i32, b: i32, c: i32, d: i32 }; 16 | export function userDefinedObject(): i32 { 17 | const x: Type = 0; 18 | return sizeof(x); 19 | } 20 | 21 | export function userDefinedTypeName(): i32 { 22 | return sizeof(Type); 23 | } 24 | 25 | export function userDefinedFunctions() : i32 { 26 | return sizeof(userDefinedObject); 27 | } 28 | 29 | export function nativeTypes(): i32 { 30 | return sizeof(i32) / sizeof(f32); 31 | } 32 | `; 33 | 34 | test('type sizes', t => { 35 | return WebAssembly.instantiate(compile(walt).buffer()).then(result => { 36 | t.is(result.instance.exports._32BitSizes(), 8, '32 bit sizes combined'); 37 | t.is(result.instance.exports._64BitSizes(), 16, '64 bit sizes combined'); 38 | t.is(result.instance.exports.userDefinedObject(), 16, 'object types'); 39 | t.is(result.instance.exports.userDefinedTypeName(), 16, 'type-name'); 40 | t.is(result.instance.exports.nativeTypes(), 1, 'native type sizes'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/statement-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { statementFramgent as statement } from '../../parser/fragment'; 3 | 4 | test('not yet implemented keywords throw', t => { 5 | t.throws(() => statement('table')); 6 | }); 7 | 8 | test('expressions where a statment should be, throw', t => 9 | t.throws(() => statement('='))); 10 | 11 | test('unsupported keywords throw', t => t.throws(() => statement('assert'))); 12 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/__tests__/union-type-spec.walt: -------------------------------------------------------------------------------- 1 | import { assert : Assert } from 'env'; 2 | type Assert = (i32, i32, i32) => void; 3 | 4 | export const memory : Memory = { initial: 1 }; 5 | 6 | type String = { byteLength: i32, &data: i32[] } | i32[]; 7 | 8 | let OFFSET : i32; 9 | 10 | export function run() : i32 { 11 | const string : String = OFFSET; 12 | string.byteLength = 4; 13 | 14 | // Test union types. Assign the value of "fooz" to the first index in the 15 | // i32[] array type version of string 16 | string[1] = 'f' | ('o' << 8) | ('o' << 16) | ('z' << 24); 17 | 18 | // Direct addressing test. Read back values written via direct addressing 19 | // and built-in native functions 20 | assert("char offset of string - f", i32.load8_u(string.data), 'f'); 21 | assert("char offset of string - o", i32.load8_u(string.data + 1), 'o'); 22 | assert("char offset of string - o", i32.load8_u(string.data + 2), 'o'); 23 | assert("char offset of string - z", i32.load8_u(string.data + 3), 'z'); 24 | 25 | assert("address sanity check - f", i32.load8_u(1024 + 4), 'f'); 26 | assert("address sanity check - o", i32.load8_u(1024 + 4 + 1), 'o'); 27 | assert("address sanity check - o", i32.load8_u(1024 + 4 + 2), 'o'); 28 | assert("address sanity check - z", i32.load8_u(1024 + 4 + 3), 'z'); 29 | 30 | 31 | return string; 32 | } 33 | 34 | /** 35 | * Coverage for start function/section 36 | */ 37 | function start() { 38 | OFFSET = 1024; 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/control-flow.ne: -------------------------------------------------------------------------------- 1 | # If then else .. if 2 | If -> 3 | IF _ LB _ Expression _ RB _ BranchBody {% node(Syntax.IfThenElse) %} 4 | | IF _ LB _ Expression _ RB _ BranchBody _ Else {% node(Syntax.IfThenElse) %} 5 | 6 | Else -> 7 | ELSE _ BranchBody {% node(Syntax.Else) %} 8 | BranchBody -> 9 | Statement {% id %} 10 | | Block {% id %} 11 | 12 | For -> 13 | FOR _ LB _ ForArg _ SEPARATOR _ Expression _ SEPARATOR _ ForArg _ RB _ BranchBody 14 | {% forLoop %} 15 | 16 | # Statements inside for loop are intentionally a subset of valid expressions 17 | # Missing is the ability to use an assignment-expression. If not omitted it would 18 | # result in ambigious syntax expressions vs statement assignment (which have 19 | # different semantics) 20 | ForArg -> 21 | _Assignment {% id %} 22 | | Ternary {% id %} 23 | 24 | While -> WHILE _ LB _ Expression _ RB _ BranchBody {% whileLoop %} 25 | 26 | Break -> BREAK _ SEPARATOR {% node(Syntax.Break) %} 27 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/helpers.js: -------------------------------------------------------------------------------- 1 | import compose from '../../utils/compose'; 2 | import { extendNode } from '../../utils/extend-node'; 3 | 4 | export { extendNode }; 5 | 6 | export const nth = n => d => d[n]; 7 | export const nuller = () => null; 8 | export const nonEmpty = d => { 9 | return Array.isArray(d) ? !!d.length : d != null; 10 | }; 11 | export const add = d => `${d[0]}${d[1]}`; 12 | 13 | export const flatten = d => 14 | d.reduce((acc, v) => { 15 | if (Array.isArray(v)) { 16 | return acc.concat(v); 17 | } 18 | 19 | return acc.concat(v); 20 | }, []); 21 | 22 | export const drop = d => { 23 | return d.filter(nonEmpty); 24 | }; 25 | 26 | export default { 27 | nth, 28 | nuller, 29 | nonEmpty, 30 | add, 31 | flatten, 32 | compose, 33 | drop, 34 | extendNode, 35 | }; 36 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/import.ne: -------------------------------------------------------------------------------- 1 | 2 | Import -> IMPORT _ ImportDefinition __ FROM __ StringLiteral _ SEPARATOR {% node(Syntax.Import) %} 3 | 4 | ImportDefinition -> LCB _ ImportAndTypeList _ RCB 5 | {% compose(node(Syntax.ObjectLiteral), flatten) %} 6 | 7 | ImportAndTypeList -> 8 | ImportName {% id %} 9 | | ImportAndType {% id %} 10 | | ImportName _ COMMA _ ImportAndTypeList {% flatten %} 11 | | ImportAndType _ COMMA _ ImportAndTypeList {% flatten %} 12 | 13 | ImportAndType -> 14 | ImportName _ COLON _ Type {% node(Syntax.Pair) %} 15 | | ImportName _ AS _ Identifier {% node(Syntax.BinaryExpression, { value: 'as' }) %} 16 | | ImportAndType _ AS _ Identifier {% node(Syntax.BinaryExpression, { value: 'as' }) %} 17 | 18 | ImportName -> Identifier {% id %} 19 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/objects.ne: -------------------------------------------------------------------------------- 1 | # Object Literals 2 | 3 | # Static Object literals are the only valid syntax for things like Genric Type 4 | # definitions. They must _not_ contain any references, function calls etc. 5 | StaticObjectLiteral -> 6 | LCB _ RCB 7 | {% compose(node(Syntax.ObjectLiteral)) %} 8 | | LCB _ StaticPropertyList _ RCB 9 | {% compose(node(Syntax.ObjectLiteral), flatten) %} 10 | 11 | StaticPropertyValue -> 12 | Number {% id %} 13 | | Boolean {% id %} 14 | | StringLiteral {% id %} 15 | 16 | StaticProperty -> Identifier _ COLON _ StaticPropertyValue {% node(Syntax.Pair) %} 17 | 18 | StaticPropertyList -> 19 | StaticProperty {% id %} 20 | | StaticProperty _ COMMA _ StaticPropertyList {% flatten %} 21 | 22 | ObjectLiteral -> 23 | LCB _ RCB 24 | {% node(Syntax.ObjectLiteral) %} 25 | | LCB _ PropertyList _ RCB 26 | {% compose(node(Syntax.ObjectLiteral), flatten) %} 27 | 28 | PropertyList -> 29 | Property {% id %} 30 | | Property _ COMMA _ PropertyList {% flatten %} 31 | 32 | Property -> 33 | Identifier _ COLON _ Ternary {% node(Syntax.Pair) %} 34 | | SPREAD Identifier {% spread %} 35 | | Identifier {% id %} 36 | 37 | 38 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/punctuators.ne: -------------------------------------------------------------------------------- 1 | 2 | # Punctuators 3 | SEPARATOR -> _ ";" {% nuller %} 4 | FUNCTION -> "function" {% nuller %} 5 | COMMA -> "," {% nuller %} 6 | DOT -> "." {% nuller %} 7 | LB -> "(" {% nuller %} 8 | RB -> ")" {% nuller %} 9 | LSB -> "[" {% nuller %} 10 | RSB -> "]" {% nuller %} 11 | LCB -> "{" {% nuller %} 12 | RCB -> "}" {% nuller %} 13 | COLON -> ":" {% nuller %} 14 | EQUALS -> "=" {% nuller %} 15 | LET -> "let" {% nuller %} 16 | CONST -> "const" {% nuller %} 17 | EXPORT -> "export" {% nuller %} 18 | RETURN -> "return" {% nuller %} 19 | TYPE -> "type" {% nuller %} 20 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/parser/grammar/types.ne: -------------------------------------------------------------------------------- 1 | # Type Definition Grammar 2 | 3 | # Struct types are object like definitions 4 | Struct -> 5 | TYPE __ Identifier _ EQUALS _ Union SEPARATOR {% struct %} 6 | | TYPE __ Identifier _ EQUALS _ NativeType SEPARATOR {% struct %} 7 | 8 | Union -> 9 | StructDefinition {% id %} 10 | | StructDefinition _ OR _ Union {% node(Syntax.UnionType) %} 11 | 12 | StructDefinition -> 13 | ArrayType {% id %} 14 | | Identifier {% id %} 15 | | LCB _ StructBody _ RCB 16 | {% compose(node(Syntax.ObjectLiteral), flatten) %} 17 | 18 | StructBody -> 19 | StructNameAndType {% id %} 20 | | StructNameAndType _ COMMA _ StructBody {% flatten %} 21 | 22 | StructNameAndType -> 23 | Identifier _ COLON _ Type {% node(Syntax.Pair) %} 24 | | AddressOf _ COLON _ Type {% node(Syntax.Pair) %} 25 | 26 | AddressOf -> AND Identifier {% addressOf %} 27 | 28 | # Type definitions are used for function types 29 | # type Foo = (i32, i32) => f32; 30 | TypeDef -> TYPE __ Identifier _ EQUALS _ TypeDefinition _ FATARROW _ Type _ SEPARATOR {% compose(typedef) %} 31 | 32 | TypeDefinition -> 33 | LB _ TypeList _ RB {% flatten %} 34 | | LB _ RB {% flatten %} 35 | 36 | TypeList -> 37 | Type {% id %} 38 | | Type _ COMMA _ TypeList {% flatten %} 39 | 40 | # Base cases for types 41 | _Type -> 42 | NativeType {% id %} 43 | | GenericType {% id %} 44 | | Identifier {% id %} 45 | 46 | ArrayType -> _Type _ LSB _ RSB {% arrayType %} 47 | 48 | Type -> 49 | _Type {% id %} 50 | | ArrayType {% id %} 51 | 52 | GenericType -> Identifier LT _ StaticObjectLiteral _ GT {% typeGeneric %} 53 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/plugin/__tests__/__snapshots__/plugin-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/plugin/__tests__/plugin-spec.js` 2 | 3 | The actual snapshot is saved in `plugin-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## compiler extensions use 8 | 9 | > Snapshot 1 10 | 11 | [ 12 | [ 13 | 'plugin', 14 | [ 15 | { 16 | encodeNames: false, 17 | filename: 'unknown.walt', 18 | lines: [ 19 | 'const x: i32 = 0;', 20 | ], 21 | version: 1, 22 | }, 23 | ], 24 | ], 25 | [ 26 | 'grammar', 27 | [], 28 | ], 29 | [ 30 | 'semantics', 31 | [ 32 | { 33 | parser: Function {}, 34 | stmt: Function {}, 35 | }, 36 | ], 37 | ], 38 | ] 39 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/plugin/__tests__/__snapshots__/plugin-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/plugin/__tests__/__snapshots__/plugin-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/plugin/index.js: -------------------------------------------------------------------------------- 1 | // Return a single method which will chain all of the middleware provided 2 | const combineMiddleware = transforms => { 3 | let transform; 4 | 5 | const chain = transforms.reduce((stack, go) => { 6 | return go(args => { 7 | // Each middleware get's a node and context object. The context allows for 8 | // nested node to have knowledge of the outer/parent context. All of this is 9 | // part of args array 10 | return stack(args, transform); 11 | }); 12 | // unroll last result 13 | }, ([id]) => id); 14 | 15 | return (args, topLevelTranfrom) => { 16 | transform = topLevelTranfrom; 17 | // kick off the chain of middleware, starting from right to left 18 | return chain(args, transform); 19 | }; 20 | }; 21 | 22 | export const combineParsers = sortedParsers => { 23 | const wildcards = []; 24 | 25 | // Normalize parsers by type 26 | const parsersByType = sortedParsers.reduce((acc, parser) => { 27 | Object.entries(parser).forEach(([type, cb]) => { 28 | // Wildcards may only handle types which have other callbacks attached to 29 | // them. 30 | if (type === '*') { 31 | wildcards.push(cb); 32 | return; 33 | } 34 | 35 | if (acc[type] == null) { 36 | // Prepend any previously defined wildcard to maintain precedence 37 | acc[type] = [...wildcards]; 38 | } 39 | 40 | acc[type].push(cb); 41 | }); 42 | 43 | return acc; 44 | }, {}); 45 | 46 | return Object.entries(parsersByType).reduce((acc, [key, transforms]) => { 47 | acc[key] = combineMiddleware(transforms); 48 | 49 | return acc; 50 | }, {}); 51 | }; 52 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/semantics/metadata.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const FUNCTION_INDEX = 'function/index'; 3 | export const LOCAL_INDEX_MAP = 'function/locals-index-map'; 4 | export const POSTFIX = 'operator/postfix'; 5 | export const PREFIX = 'operator/prefix'; 6 | export const LOCAL_INDEX = 'LOCAL_INDEX'; 7 | export const GLOBAL_INDEX = 'global/index'; 8 | export const TABLE_INDEX = 'table/index'; 9 | export const TYPE_CONST = 'type/const'; 10 | export const TYPE_ARRAY = 'TYPE_ARRAY'; 11 | export const TYPE_USER = 'type/user'; 12 | export const TYPE_OBJECT = 'TYPE_OBJECT'; 13 | export const TYPE_INDEX = 'TYPE_INDEX'; 14 | export const OBJECT_SIZE = 'OBJECT_SIZE'; 15 | export const TYPE_CAST = 'type/cast'; 16 | export const OBJECT_KEY_TYPES = 'OBJECT_KEY_TYPES'; 17 | export const CLOSURE_TYPE = 'closure/type'; 18 | export const AST_METADATA = 'AST_METADATA'; 19 | export const FUNCTION_METADATA = 'FUNCTION_METADATA'; 20 | export const ALIAS = 'alias'; 21 | 22 | // Statics 23 | export const STATIC_STRING = 'static/string'; 24 | export const STATIC_INDEX = 'static/index'; 25 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/syntax-sugar/default-arguments.ne: -------------------------------------------------------------------------------- 1 | # Default Arguments 2 | @{% 3 | const Syntax = this.Syntax; 4 | const { flatten } = this.helpers; 5 | const { node } = this.nodes(this.lexer); 6 | %} 7 | 8 | TypeList -> 9 | DefaultArgument {% id %} 10 | | DefaultArgument _ COMMA _ TypeList {% flatten %} 11 | 12 | DefaultArgument -> Type _ EQUALS _ Atom {% node(Syntax.Assignment) %} 13 | 14 | ParameterList -> 15 | DefaultFunctionArgument {% id %} 16 | | DefaultFunctionArgument _ COMMA _ ParameterList {% flatten %} 17 | 18 | DefaultFunctionArgument -> 19 | NameAndType _ EQUALS _ Atom {% node(Syntax.Assignment) %} 20 | 21 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/syntax-sugar/sizeof.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sizeof helper plugin. Maps size() to a static i32 constant 3 | * 4 | * @flow 5 | */ 6 | import invariant from 'invariant'; 7 | import { find } from 'walt-parser-tools/scope'; 8 | import Syntax from 'walt-syntax'; 9 | import { OBJECT_SIZE } from '../semantics/metadata'; 10 | import type { SemanticPlugin } from '../flow/types'; 11 | 12 | const sizes = { 13 | i64: 8, 14 | f64: 8, 15 | i32: 4, 16 | f32: 4, 17 | }; 18 | 19 | export default function sizeofPlugin(): SemanticPlugin { 20 | return { 21 | semantics() { 22 | return { 23 | [Syntax.FunctionCall]: next => args => { 24 | const [sizeof, context] = args; 25 | 26 | if (sizeof.value !== 'sizeof') { 27 | return next(args); 28 | } 29 | 30 | const { scopes, userTypes, functions } = context; 31 | const [, target] = sizeof.params; 32 | const ref = find(scopes, target.value); 33 | const { type = '' } = ref || {}; 34 | const userType = userTypes[target.value] || userTypes[type]; 35 | const func = functions[target.value]; 36 | 37 | if (userType != null) { 38 | const metaSize = userType.meta[OBJECT_SIZE]; 39 | invariant(metaSize, 'Object size information is missing'); 40 | return { 41 | ...sizeof, 42 | value: metaSize, 43 | params: [], 44 | type: 'i32', 45 | Type: Syntax.Constant, 46 | }; 47 | } 48 | 49 | const node = ref || func; 50 | 51 | return { 52 | ...sizeof, 53 | value: sizes[String(node ? node.type : target.value)], 54 | type: 'i32', 55 | params: [], 56 | Type: Syntax.Constant, 57 | }; 58 | }, 59 | }; 60 | }, 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const sizes = { 3 | i64: 8, 4 | f64: 8, 5 | i32: 4, 6 | f32: 4, 7 | }; 8 | 9 | export const typeWeight = (typeString: ?string): number => { 10 | switch (typeString) { 11 | case 'i32': 12 | case 'bool': 13 | return 0; 14 | case 'i64': 15 | return 1; 16 | case 'f32': 17 | return 2; 18 | case 'f64': 19 | return 3; 20 | default: 21 | return -1; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/__snapshots__/debug-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/utils/__tests__/__snapshots__/debug-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/__snapshots__/leb128-spec.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `src/utils/__tests__/leb128-spec.js` 2 | 3 | The actual snapshot is saved in `leb128-spec.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## LEB128 signed encoding 8 | 9 | > Snapshot 1 10 | 11 | [ 12 | '0x9B', 13 | '0xF1', 14 | '0x59', 15 | ] 16 | 17 | ## LEB128 unsigned encoding 18 | 19 | > Snapshot 1 20 | 21 | [ 22 | '0xE5', 23 | '0x8E', 24 | '0x26', 25 | ] 26 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/__snapshots__/leb128-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/utils/__tests__/__snapshots__/leb128-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/__snapshots__/print-node-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/utils/__tests__/__snapshots__/print-node-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/__snapshots__/walk-node-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/utils/__tests__/__snapshots__/walk-node-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/debug-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import debug from '../debug'; 3 | import { compile } from '../..'; 4 | 5 | const DEFAULT_EXAMPLE = `const x: i32 = 2; 6 | export function echo(): i32 { 7 | const x: i32 = 42; 8 | return x; 9 | }`; 10 | 11 | test('debug prints web-assembly opcodes', t => { 12 | // TODO: Change the input to debug to be a static value instead 13 | t.snapshot(debug(compile(DEFAULT_EXAMPLE).wasm)); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/leb128-spec.js: -------------------------------------------------------------------------------- 1 | // based on https://en.wikipedia.org/wiki/LEB128#Encoding_format 2 | import test from 'ava'; 3 | import { encodeSigned, encodeUnsigned } from '../leb128'; 4 | 5 | test('LEB128 signed encoding', t => { 6 | const i32Negative = encodeSigned(-624485, 32); 7 | t.snapshot(i32Negative.map(num => '0x' + num.toString(16).toUpperCase())); 8 | }); 9 | 10 | test('LEB128 unsigned encoding', t => { 11 | const i32 = encodeUnsigned(624485, 32); 12 | t.snapshot(i32.map(num => '0x' + num.toString(16).toUpperCase())); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/__tests__/print-node-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import printNode from '../print-node'; 3 | import makeParser from '../../parser'; 4 | import { makeFragment } from '../../parser/fragment'; 5 | import semantics from '../../semantics'; 6 | 7 | const parser = makeParser([]); 8 | const stmt = makeFragment(parser); 9 | const getAST = src => semantics(parser(src), [], { parser, stmt }); 10 | 11 | test('full ast printer', t => { 12 | const node = getAST(` 13 | const memory: Memory = { initial: 1 }; 14 | function simple(): i32 { 15 | const x: i32 = 1 + 1; 16 | const y: i32 = 2; 17 | return x + y; 18 | } 19 | function multiple_args(x: i32, y: f32): f32 { 20 | return x + y; 21 | } 22 | function arrays(): i32 { 23 | const x: i32[] = 0; 24 | x[0] = 2; 25 | x[1] = 2; 26 | return x[0] + x[1]; 27 | } 28 | `); 29 | t.snapshot(printNode(node)); 30 | }); 31 | 32 | test('plain ast parser', t => { 33 | const node = parser( 34 | ` 35 | type Type = (i32, f32) => i32; 36 | 37 | function simple(y: i32): i32 { 38 | const x : i32 = 2; 39 | return x + y; 40 | } 41 | ` 42 | ); 43 | 44 | t.snapshot(printNode(node)); 45 | }); 46 | 47 | test('imports/exports', t => { 48 | const node = getAST(` 49 | import { foo: FooType, bar: FooType } from 'env'; 50 | type FooType = () => i32; 51 | 52 | function two(): i32 { 53 | return 2; 54 | } 55 | 56 | export function test(): i32 { 57 | return foo(two() + 2); 58 | }`); 59 | 60 | t.snapshot(printNode(node)); 61 | }); 62 | 63 | test('assignment, ternary, if', t => { 64 | const node = getAST(` 65 | let x: i32 = 0; 66 | export function test(z: i32): i32 { 67 | let y: i32 = z > 0 ? 1 : 0; 68 | if (z == 2) { 69 | x = 2; 70 | } else { 71 | x = 1; 72 | } 73 | y = 1 + 1; 74 | return x + y; 75 | } 76 | `); 77 | t.snapshot(printNode(node)); 78 | }); 79 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/compose.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export default (...fns: any) => 3 | fns.reduce((f, g) => (...args) => f(g(...args))); 4 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/debug.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { sizeof } from 'wasm-types'; 3 | import OutputStream from './output-stream'; 4 | 5 | const _debug = (stream: OutputStream, begin: number = 0, end?: number) => { 6 | let pc = 0; 7 | return ( 8 | stream.data 9 | .slice(begin, end) 10 | .map(({ type, value, debug }) => { 11 | const pcString = `${pc.toString()} 0x${pc.toString(16)}` 12 | .padStart(6, ' ') 13 | .padEnd(stream.data.length.toString().length + 1); 14 | let valueString; 15 | if (Array.isArray(value)) { 16 | valueString = value 17 | .map(v => v.toString(16)) 18 | .join() 19 | .padStart(16); 20 | } else { 21 | valueString = value.toString(16).padStart(16); 22 | } 23 | const out = `${pcString}: ${valueString} ; ${debug}`; 24 | pc += sizeof[type] || value.length; 25 | return out; 26 | }) 27 | .join('\n') + '\n ============ fin =============' 28 | ); 29 | }; 30 | 31 | export default _debug; 32 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/extend-node.js: -------------------------------------------------------------------------------- 1 | import curry from 'curry'; 2 | 3 | export const extendNode = curry(({ meta, ...options }, node) => { 4 | return { 5 | ...node, 6 | meta: { ...node.meta, ...meta }, 7 | ...options, 8 | }; 9 | }); 10 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/generate-error.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export default function generateErrorString( 4 | msg: string, 5 | error: string, 6 | marker: { 7 | start: { sourceLine: string, line: number, col: number }, 8 | end: { sourceLine: string, line: number, col: number }, 9 | }, 10 | filename: string, 11 | func: string 12 | ): string { 13 | const line = marker.start.line; 14 | const col = marker.start.col; 15 | const end = marker.end.col; 16 | const Line = marker.end.sourceLine; 17 | 18 | const highlight = new Array(end - col + 1) 19 | .join('^') 20 | .padStart(marker.start.col - 1, ' '); 21 | return ( 22 | '\n' + 23 | Line + 24 | '\n' + 25 | highlight + 26 | ` ${error}` + 27 | '\n' + 28 | msg + 29 | '\n' + 30 | ` at ${func} (${filename}:${line}:${col})` 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/has-node.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { NodeType } from '../flow/types'; 3 | 4 | export default function hasNode(Type: string, ast: NodeType) { 5 | const test = node => node && node.Type === Type; 6 | 7 | const walker = node => { 8 | if (node == null) { 9 | return false; 10 | } 11 | 12 | return test(node) || node.params.some(walker); 13 | }; 14 | 15 | return walker(ast); 16 | } 17 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/leb128.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const encodeSigned = (value: number) => { 3 | const encoding = []; 4 | while (true) { 5 | const byte = value & 127; 6 | value = value >> 7; 7 | const signbit = byte & 0x40; 8 | 9 | if ((value === 0 && !signbit) || (value === -1 && signbit)) { 10 | encoding.push(byte); 11 | break; 12 | } else { 13 | encoding.push(byte | 0x80); 14 | } 15 | } 16 | return encoding; 17 | }; 18 | 19 | export const encodeUnsigned = (value: number) => { 20 | const encoding = []; 21 | while (true) { 22 | const i = value & 127; 23 | value = value >>> 7; 24 | if (value === 0) { 25 | encoding.push(i); 26 | break; 27 | } 28 | 29 | encoding.push(i | 0x80); 30 | } 31 | 32 | return encoding; 33 | }; 34 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/pick.js: -------------------------------------------------------------------------------- 1 | export default function pick(list, obj) { 2 | let result = {}; 3 | let i = 0; 4 | for (i; i < list.length; i++) { 5 | result[list[i]] = obj[list[i]]; 6 | } 7 | return result; 8 | } 9 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/pretty-print-ir.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { IntermediateOpcodeType } from '../generator/flow/types'; 3 | 4 | export default function prettyPrint(IRList: IntermediateOpcodeType[]): string { 5 | return [ 6 | '------ Intermediate Representation ------', 7 | `Stats: ${IRList.length} nodes`, 8 | '-----------------------------------------', 9 | '| Opcode | Parameters |', 10 | '|---------------------------------------|', 11 | ...IRList.map( 12 | ({ kind: { name }, params }) => 13 | `| ${name.padEnd(14)} | ${params.join(',').padEnd(20)} |` 14 | ), 15 | '----------------- End -------------------', 16 | ].join('\n'); 17 | } 18 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/resizable-limits.js: -------------------------------------------------------------------------------- 1 | import Syntax from 'walt-syntax'; 2 | import walkNode from 'walt-parser-tools/walk-node'; 3 | 4 | export const parseBounds = node => { 5 | const memory = {}; 6 | walkNode({ 7 | [Syntax.Pair]: ({ params }) => { 8 | const [{ value: key }, { value }] = params; 9 | memory[key] = parseInt(value); 10 | }, 11 | })(node); 12 | return memory; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/stream.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const eol = (char: string) => char === '\n'; 3 | 4 | // Base Character stream class 5 | class Stream { 6 | input: string; 7 | pos: number; 8 | line: number; 9 | col: number; 10 | lines: string[]; 11 | 12 | constructor(input: string) { 13 | this.pos = this.line = this.col = 0; 14 | this.input = input; 15 | this.lines = input.split('\n'); 16 | this.newLine(); 17 | } 18 | 19 | // Peek at a character at current position 20 | peek(): string { 21 | return this.input.charAt(this.pos); 22 | } 23 | 24 | // Advance to next character in stream 25 | next(): string { 26 | const char = this.input.charAt(this.pos++); 27 | 28 | if (this.eol(char)) { 29 | this.newLine(); 30 | } else { 31 | this.col++; 32 | } 33 | 34 | return char; 35 | } 36 | 37 | // Begin a new line 38 | newLine() { 39 | this.line++; 40 | this.col = 0; 41 | } 42 | 43 | // Is the character an end of line 44 | eol(char: string): boolean { 45 | return char === '\n'; 46 | } 47 | 48 | // Is the character an end of file 49 | eof(char: string): boolean { 50 | return char === ''; 51 | } 52 | 53 | // Is the character a whitespace 54 | static whitespace(char: string): boolean { 55 | return ( 56 | char === '\n' || 57 | char === ' ' || 58 | char === '\t' || 59 | char === '\v' || 60 | char === '\r' || 61 | char === '\f' 62 | ); 63 | } 64 | } 65 | 66 | export default Stream; 67 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/string.js: -------------------------------------------------------------------------------- 1 | import OutputStream from './output-stream'; 2 | 3 | export function* stringDecoder(view, start) { 4 | let length = 0; 5 | let index = 0; 6 | let shift = 0; 7 | let addr = start; 8 | while (true) { 9 | const byte = view.getUint8(addr, true); 10 | length |= (byte & 0x7f) << shift; 11 | addr += 1; 12 | if ((byte & 0x80) === 0) { 13 | break; 14 | } 15 | shift += 7; 16 | } 17 | 18 | let result = 0; 19 | while (index < length) { 20 | result = 0; 21 | shift = 0; 22 | while (true) { 23 | const byte = view.getUint8(addr, true); 24 | result |= (byte & 0x7f) << shift; 25 | addr += 1; 26 | if ((byte & 0x80) === 0) { 27 | break; 28 | } 29 | shift += 7; 30 | } 31 | index += 1; 32 | yield result; 33 | } 34 | } 35 | 36 | export function stringEncoder(value) { 37 | const resultStream = new OutputStream(); 38 | const characterStream = new OutputStream(); 39 | 40 | characterStream.push('varuint32', value.length, value); 41 | let i = 0; 42 | for (i = 0; i < value.length; i++) { 43 | characterStream.push('varuint32', value.codePointAt(i), value[i]); 44 | } 45 | resultStream.write(characterStream); 46 | 47 | return resultStream; 48 | } 49 | 50 | export const getText = memory => ptr => { 51 | let text = ''; 52 | const decoder = stringDecoder(new DataView(memory.buffer), ptr); 53 | let iterator = decoder.next(); 54 | while (!iterator.done) { 55 | text += String.fromCodePoint(iterator.value); 56 | iterator = decoder.next(); 57 | } 58 | 59 | return text; 60 | }; 61 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/token-stream.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { TokenType } from '../flow/types'; 3 | 4 | export type TokenStream = { 5 | next: () => TokenType, 6 | peek: () => TokenType, 7 | last: () => TokenType, 8 | tokens: TokenType[], 9 | }; 10 | 11 | export default function tokenStream(tokens: TokenType[]): TokenStream { 12 | const length = tokens.length; 13 | let pos = 0; 14 | 15 | const next = () => tokens[++pos]; 16 | const peek = () => tokens[pos + 1]; 17 | const last = () => tokens[length - 1]; 18 | 19 | return { pos, tokens, next, peek, last, length }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/transform-with-context.js: -------------------------------------------------------------------------------- 1 | export default function(transform, context) { 2 | const args = [null, context]; 3 | return function(node) { 4 | args[0] = node; 5 | return transform(args); 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/trie.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /** 3 | * A very basic trie with functional,recursive search 4 | */ 5 | const fsearch = node => { 6 | const next = (char: string) => { 7 | if (node && node.children[char]) { 8 | return fsearch(node.children[char]); 9 | } 10 | 11 | return null; 12 | }; 13 | 14 | next.leaf = node.leaf; 15 | 16 | return next; 17 | }; 18 | 19 | type Node = { 20 | char: string, 21 | children: { [string]: Node }, 22 | leaf: boolean, 23 | }; 24 | 25 | class Trie { 26 | root: Node; 27 | fsearch: any; 28 | 29 | constructor(words: Array) { 30 | this.root = { 31 | char: '', 32 | children: {}, 33 | leaf: false, 34 | }; 35 | 36 | words.map(word => this.add(word)); 37 | this.fsearch = fsearch(this.root); 38 | } 39 | 40 | add(word: string) { 41 | let current = this.root; 42 | let char = word.slice(0, 1); 43 | 44 | word = word.slice(1); 45 | 46 | while (typeof current.children[char] !== 'undefined' && char.length > 0) { 47 | current = current.children[char]; 48 | char = word.slice(0, 1); 49 | word = word.slice(1); 50 | } 51 | 52 | while (char.length > 0) { 53 | const node = { 54 | char, 55 | children: {}, 56 | leaf: false, 57 | }; 58 | 59 | current.children[char] = node; 60 | current = node; 61 | char = word.slice(0, 1); 62 | word = word.slice(1); 63 | } 64 | 65 | current.leaf = true; 66 | } 67 | } 68 | 69 | module.exports = Trie; 70 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/utils/types.js: -------------------------------------------------------------------------------- 1 | export const getTypeSize = typeString => { 2 | switch (typeString) { 3 | case 'i64': 4 | case 'f64': 5 | return 8; 6 | case 'i32': 7 | case 'f32': 8 | case 'bool': 9 | default: 10 | return 4; 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/validation/__tests__/__snapshots__/validation-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-compiler/src/validation/__tests__/__snapshots__/validation-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-compiler/src/walt/malloc.walt: -------------------------------------------------------------------------------- 1 | import { memory: Memory, log: Log } from 'env'; 2 | type Log = (i32) => void; 3 | let offset: i32 = 0; 4 | let BASE_ADDRESS: i32 = 0; 5 | 6 | // Returns nearest power of 2 7 | export function next_pow2(num: i32): i32 { 8 | if (num < 2) { 9 | return 0; 10 | } 11 | if (num == 2) { 12 | return num; 13 | } 14 | return ( 15 | (1: i64) << (32 - i32.clz(num - 1)) 16 | ) : i32; 17 | } 18 | 19 | // Returns a number aligned to a specific alignment 20 | // 21 | // Memory operations should be aligned so when setting base address we want to 22 | // be able to align arbitrary addresses 23 | export function align(num: i32, alignment: i32 = 2): i32 { 24 | const remainder: i32 = num % alignment; 25 | if (remainder) { 26 | return num + remainder; 27 | } 28 | 29 | return num; 30 | } 31 | 32 | export function malloc(size: i32) : i32 { 33 | const pointer: i32 = BASE_ADDRESS + offset; 34 | offset += size; 35 | return pointer; 36 | } 37 | 38 | export function setBaseAddress(address: i32) { 39 | BASE_ADDRESS = address; 40 | } 41 | 42 | // Initialize with the dataLength 43 | function start() { 44 | BASE_ADDRESS = align(i32.load(0)); 45 | } 46 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/walt/tests.walt: -------------------------------------------------------------------------------- 1 | // Shared test types 2 | 3 | export type Assert = (i32, i32, i32) => void; 4 | 5 | -------------------------------------------------------------------------------- /packages/walt-compiler/src/walt/utils/stream.walt: -------------------------------------------------------------------------------- 1 | import { memory: Memory, STRING_BYTE_LENGTH : i32, log : Log } from 'env'; 2 | import { setBaseAddress, align } from '../malloc'; 3 | import { getStringIterator, next, decodeLEB, done } from '../string'; 4 | import { StringIterator } from '../string'; 5 | 6 | type Log = (i32) => void; 7 | 8 | let EOL : i32; 9 | let EOF : i32; 10 | 11 | let byteOffset : i32 = 0; 12 | let pos : i32 = 0; 13 | let col : i32 = 0; 14 | let line : i32 = 0; 15 | let iterator : StringIterator = 0; 16 | let linesArray : i32; 17 | 18 | export function _newLine() { 19 | line += 1; 20 | col = 0; 21 | } 22 | 23 | // Get next character in the stream 24 | export function _next() : i32 { 25 | next(iterator); 26 | 27 | const character : i32 = iterator.value; 28 | 29 | if (character == EOL) { 30 | _newLine(); 31 | } else { 32 | col += 1; 33 | } 34 | 35 | return character; 36 | } 37 | 38 | // Get current column number 39 | export function _column() : i32 { 40 | return col; 41 | } 42 | 43 | // Get current line number 44 | export function _line() : i32 { 45 | return line; 46 | } 47 | 48 | // Peek at the next character in the stream 49 | export function _peek() : i32 { 50 | if (iterator.length == 0 || iterator.index == iterator.length) { 51 | return 0; 52 | } 53 | // decodeLEB gives a i64 so that it can return an updated address and value 54 | // we only need the value, since the address is not changed for the iterator 55 | const result : i64 = decodeLEB(iterator.addr); 56 | return (result : i32); 57 | } 58 | 59 | // Is the charater a whitespace 60 | export function whitespace(char : i32) : i32 { 61 | return ( 62 | char == '\n' || 63 | char == ' ' || 64 | char == '\t' || 65 | char == '\v' || 66 | char == '\r' || 67 | char == '\f' 68 | ); 69 | } 70 | 71 | // Initializer 72 | function start() { 73 | // Fix this once global strings work 74 | EOL = '\n'; 75 | EOF = 0; 76 | 77 | setBaseAddress(align(STRING_BYTE_LENGTH)); 78 | iterator = getStringIterator(0); 79 | 80 | _newLine(); 81 | } 82 | -------------------------------------------------------------------------------- /packages/walt-compiler/syntax/README.md: -------------------------------------------------------------------------------- 1 | # Walt Syntax Tests & Examples 2 | 3 | ## Numbers 4 | 5 | 6 | ## Types 7 | 8 | #### [_Tests_](./types-test.walt) 9 | 10 | ```js 11 | ``` 12 | 13 | ## Structs 14 | 15 | ## Union Types 16 | 17 | #### [_Tests_](./union-types-test.walt) 18 | 19 | ```js 20 | ``` 21 | -------------------------------------------------------------------------------- /packages/walt-compiler/syntax/struct-test.walt: -------------------------------------------------------------------------------- 1 | import { malloc } from '../src/walt/malloc'; 2 | import { Assert } from '../src/walt/tests'; 3 | import { assert : Assert, memory: Memory } from 'env'; 4 | 5 | export const INTROSPECT_PRETTY_PRINT : i32 = false; 6 | 7 | type Vector = { 8 | x: i32, 9 | y: i32 10 | }; 11 | 12 | function struct_type_test() : Vector { 13 | const vector: Vector = malloc(sizeof(Vector)); 14 | // NOTE: {} on a right-hand-side of assignment does not create a new object. 15 | // It only writes the fields into the source memory locations. 16 | vector = { x: 10, y: -10 }; 17 | 18 | return vector; 19 | } 20 | 21 | function struct_array_test() : Vector[] { 22 | const arr: Vector[] = malloc(sizeof(Vector) * 2); 23 | 24 | const Va : Vector = arr[0]; 25 | Va = { x: 5, y: 5 }; 26 | 27 | // This is functonally equivalent to the setting of values for "Va", however 28 | // there are few additional instructions here to look-up the value of arr[1] 29 | // for every key set. 30 | arr[1] = { x: -5, y: -5 }; 31 | 32 | return arr; 33 | } 34 | 35 | export function run() { 36 | const vec: Vector = struct_type_test(); 37 | const arr: Vector[] = struct_array_test(); 38 | 39 | assert("struct fields, vector.x", vec.x, 10); 40 | assert("struct fields, vector.y", vec.y, -10); 41 | 42 | const Va : Vector = arr[0]; 43 | assert("struct arrays, vector a -- field x", Va.x, 5); 44 | assert("struct arrays, vector a -- field y", Va.y, 5); 45 | 46 | const Vb : Vector = arr[1]; 47 | assert("struct arrays, vector b -- field x", Vb.x, -5); 48 | assert("struct arrays, vector b -- field y", Vb.y, -5); 49 | } 50 | -------------------------------------------------------------------------------- /packages/walt-compiler/syntax/type-test.walt: -------------------------------------------------------------------------------- 1 | import { Assert } from '../src/walt/tests'; 2 | import { assert : Assert, memory: Memory } from 'env'; 3 | 4 | export const INTROSPECT_PRETTY_PRINT : i32 = 0; 5 | 6 | // Type aliases 7 | type Float = f32; 8 | type Integer = i32; 9 | 10 | // Type aliases can be chained 11 | type Int = Integer; 12 | type F32 = Float; 13 | type FloatingPoint = F32; 14 | 15 | function native_type_alias(x: Int, y: Float) : FloatingPoint { 16 | return x + y; 17 | } 18 | 19 | export function run() { 20 | assert("native type aliases", native_type_alias(2, 2.0) : Integer, 4); 21 | } 22 | -------------------------------------------------------------------------------- /packages/walt-compiler/syntax/union-types-test.walt: -------------------------------------------------------------------------------- 1 | /** 2 | * Assert that structs may be joined with sugary array types to allow for 3 | * indexing into a struct. 4 | * 5 | * 6 | */ 7 | import { Assert } from '../src/walt/tests.walt'; 8 | import { assert : Assert, memory : Memory } from 'env'; 9 | 10 | export const INTROSPECT_PRETTY_PRINT : i32 = 0; 11 | 12 | let OFFSET : i32; 13 | 14 | type BaseString = { byteLength: i32 }; 15 | type DataAccess = { spacer: i32, &data: i32[] }; 16 | type String = BaseString | DataAccess | i32[]; 17 | 18 | 19 | function assert_unions(string : String) { 20 | string.spacer = 4; 21 | 22 | assert("setting values of union fields", string.spacer, string.byteLength); 23 | // Test union types. Assign the value of "fooz" to the first index in the 24 | // i32[] array type version of string 25 | string[1] = 'f' | ('o' << 8) | ('o' << 16) | ('z' << 24); 26 | 27 | // Direct addressing test. Read back values written via direct addressing 28 | // and built-in native functions 29 | assert("char offset of string - f", i32.load8_u(string.data), 'f'); 30 | assert("char offset of string - o", i32.load8_u(string.data + 1), 'o'); 31 | assert("char offset of string - o", i32.load8_u(string.data + 2), 'o'); 32 | assert("char offset of string - z", i32.load8_u(string.data + 3), 'z'); 33 | 34 | // NOTE: using the offset (1024) here to sanity check the "start" logic 35 | assert("address sanity check - f", i32.load8_u(1024 + 4), 'f'); 36 | assert("address sanity check - o", i32.load8_u(1024 + 4 + 1), 'o'); 37 | assert("address sanity check - o", i32.load8_u(1024 + 4 + 2), 'o'); 38 | assert("address sanity check - z", i32.load8_u(1024 + 4 + 3), 'z'); 39 | } 40 | 41 | function array_struct_unions() { 42 | const base : BaseString = OFFSET; 43 | assert_unions(base); 44 | const string : String = base; 45 | assert_unions(string); 46 | } 47 | 48 | export function run() { 49 | array_struct_unions(); 50 | } 51 | 52 | function start() { 53 | OFFSET = 1024; 54 | } 55 | -------------------------------------------------------------------------------- /packages/walt-explorer/README.md: -------------------------------------------------------------------------------- 1 | # Walt Explorer Site 2 | -------------------------------------------------------------------------------- /packages/walt-explorer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Walt Explorer 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/editor/index.js: -------------------------------------------------------------------------------- 1 | import CodeMirror from "react-codemirror2"; 2 | import PropTypes from "prop-types"; 3 | import React from "react"; 4 | import "codemirror/mode/javascript/javascript"; 5 | import "codemirror/lib/codemirror.css"; 6 | 7 | class Editor extends React.PureComponent { 8 | static propTypes = { 9 | code: PropTypes.string, 10 | onUpdate: PropTypes.func, 11 | extraOptions: PropTypes.object 12 | }; 13 | 14 | static defaultProps = { 15 | onUpdate() {}, 16 | extraOptions: {} 17 | }; 18 | 19 | render() { 20 | const { extraOptions, ...props } = this.props; 21 | return ( 22 | props.onUpdate(value)} 25 | options={{ 26 | lineNumbers: true, 27 | mode: "javascript", 28 | ...extraOptions 29 | }} 30 | /> 31 | ); 32 | } 33 | } 34 | 35 | export default Editor; 36 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/animation.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/animation"; 2 | 3 | const label = "Bounce (canvas)"; 4 | const output = 'Canvas'; 5 | 6 | function compile(buffer) { 7 | const canvas = document.getElementById("canvas"); 8 | const ctx = canvas.getContext("2d"); 9 | const setFillColor = (r, g, b, a) => { 10 | ctx.fillStyle = `rgba(${r},${g},${b},${a / 255.0})`; 11 | }; 12 | const fillRect = (x, y, w, h) => { 13 | ctx.fillRect(x, y, w, h); 14 | }; 15 | const getCanvasWidth = () => canvas.width; 16 | const getCanvasHeight = () => canvas.height; 17 | const env = { 18 | setFillColor, 19 | fillRect, 20 | getCanvasWidth, 21 | getCanvasHeight, 22 | log(val) { 23 | console.log(val); 24 | } 25 | }; 26 | return WebAssembly.instantiate(buffer, { env }).then(result => { 27 | const exports = result.instance.exports; 28 | exports.onInit(30); 29 | 30 | let stopped = false; 31 | function step() { 32 | if (!stopped) { 33 | exports.onAnimationFrame(Date.now()); 34 | window.requestAnimationFrame(step); 35 | } 36 | } 37 | window.requestAnimationFrame(step); 38 | 39 | return function() { 40 | stopped = true; 41 | }; 42 | }); 43 | } 44 | 45 | const example = { 46 | code, 47 | label, 48 | output, 49 | compile, 50 | js: compile.toString() 51 | }; 52 | 53 | export default example; 54 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/closures.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/closures"; 2 | import { plugin, imports } from "walt-plugin-syntax-closure"; 3 | import { compile } from "walt-compiler"; 4 | 5 | const label = "Closures (console)"; 6 | window.compile = compile; 7 | window.closurePlugin = plugin; 8 | window.closureImports = imports; 9 | 10 | function _compile(buffer) { 11 | // Because examples are eval-ed we need to use a window references 12 | // 13 | // import { compile } from 'walt-compiler'; 14 | // import { plugin, imports } from 'walt-plugin-syntax-closure'; 15 | // window.compile = compile; 16 | // window.closurePlugin = plugin; 17 | // window.closureImports = imports; 18 | return Promise.resolve(window.closureImports(null, window.compile)).then( 19 | closureImports => { 20 | return WebAssembly.instantiate( 21 | buffer, 22 | // Closure imports can also be user defined 23 | closureImports 24 | ).then(module => { 25 | const test = module.instance.exports.test; 26 | 27 | console.log(test()); 28 | }); 29 | } 30 | ); 31 | } 32 | 33 | const example = { 34 | code, 35 | label, 36 | compile: _compile, 37 | js: _compile.toString(), 38 | extensions: [plugin] 39 | }; 40 | 41 | export default example; 42 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/default.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/default"; 2 | 3 | const label = "Simple (console)"; 4 | 5 | function compile(buffer) { 6 | return WebAssembly.instantiate(buffer).then(result => { 7 | const exports = result.instance.exports; 8 | console.log(exports.echo()); 9 | }); 10 | } 11 | 12 | const example = { 13 | code, 14 | label, 15 | compile, 16 | js: compile.toString() 17 | }; 18 | 19 | export default example; 20 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/fibonacci.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/fibonacci"; 2 | 3 | const label = "Fibonacci (console)"; 4 | 5 | function compile(buffer) { 6 | return WebAssembly.instantiate(buffer).then(result => { 7 | const fib = result.instance.exports.fibonacci; 8 | [...Array(41).keys()].forEach(v => { 9 | console.log(`Fibonacci for ${v} - ${fib(v)}`); 10 | }); 11 | }); 12 | } 13 | 14 | const example = { 15 | code, 16 | label, 17 | compile, 18 | js: compile.toString() 19 | }; 20 | 21 | export default example; 22 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/function-pointer.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/function-pointer"; 2 | 3 | const label = "Function Pointer (console)"; 4 | 5 | function compile(buffer) { 6 | const table = new WebAssembly.Table({ element: "anyfunc", initial: 10 }); 7 | 8 | return WebAssembly.instantiate(buffer, { 9 | env: { 10 | table, 11 | log: function(value) { 12 | console.log("Timeout called with: " + value); 13 | }, 14 | setTimeout: (functionPointer, timeout) => { 15 | const func = table.get(functionPointer); 16 | console.log("Getting function from Table", table); 17 | console.log(`function pointer id: ${functionPointer} == ${func}`); 18 | window.setTimeout(func, timeout); 19 | } 20 | } 21 | }).then(result => result.instance.exports.test()); 22 | } 23 | 24 | const example = { 25 | code, 26 | label, 27 | compile, 28 | js: compile.toString() 29 | }; 30 | 31 | export default example; 32 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/index.js: -------------------------------------------------------------------------------- 1 | import _default from "./default"; 2 | import memory from "./memory"; 3 | import functionPointer from "./function-pointer"; 4 | import fibonacci from "./fibonacci"; 5 | import objectLiteral from "./object-literal"; 6 | import animation from "./animation"; 7 | import closures from "./closures"; 8 | import wave from './wave'; 9 | 10 | const examples = { 11 | Default: _default, 12 | Memory: memory, 13 | FunctionPointer: functionPointer, 14 | Fibonacci: fibonacci, 15 | "Object Literal": objectLiteral, 16 | Animation: animation, 17 | Closures: closures, 18 | Wave: wave, 19 | }; 20 | 21 | export default examples; 22 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/memory.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/memory"; 2 | 3 | const label = "Memory (console)"; 4 | 5 | function compile(buffer) { 6 | return WebAssembly.instantiate(buffer).then(result => { 7 | const exports = result.instance.exports; 8 | console.log(exports.test()); 9 | }); 10 | } 11 | 12 | const example = { 13 | code, 14 | label, 15 | compile, 16 | js: compile.toString() 17 | }; 18 | 19 | export default example; 20 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/object-literal.js: -------------------------------------------------------------------------------- 1 | import code from "./walt/object-literal"; 2 | 3 | const label = "Object Literal (console)"; 4 | 5 | function compile(buffer) { 6 | return WebAssembly.instantiate(buffer).then(result => { 7 | const exports = result.instance.exports; 8 | console.log(exports.test()); 9 | }); 10 | } 11 | 12 | const example = { 13 | code, 14 | label, 15 | compile, 16 | js: compile.toString() 17 | }; 18 | 19 | export default example; 20 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/closures.walt: -------------------------------------------------------------------------------- 1 | const table: Table = { element: 'anyfunc', initial: 1 }; 2 | // lambda keyword is used to indicate a function type which is used as a lambda/closure 3 | type Fun = () => i32; 4 | type Type = Lambda; 5 | 6 | function getClosure(): Type { 7 | // close over two locals 8 | let x: i32 = 1; 9 | let y: i32 = 1; 10 | // Closures/Lambdas are defined as annonymous arrow functions 11 | return (): i32 => { 12 | x += y; 13 | return x; 14 | }; 15 | } 16 | 17 | export function test(): i32 { 18 | const closure: Type = getClosure(); 19 | closure(); 20 | closure(); 21 | closure(); 22 | // should be 5 23 | const x: i32 = closure(); 24 | const closure2: Type = getClosure(); 25 | // should be 2 26 | const y: i32 = closure2(); 27 | 28 | // should be 7 29 | return x + y; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/default.walt: -------------------------------------------------------------------------------- 1 | const x: i32 = 2; 2 | export function echo(): i32 { 3 | const x: i32 = 42; 4 | return x; 5 | } 6 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/fibonacci.walt: -------------------------------------------------------------------------------- 1 | export function fibonacci(n: i32): i32 { 2 | if (n == 0) 3 | return 0; 4 | if (n == 1) 5 | return 1; 6 | return fibonacci(n - 1) + fibonacci(n - 2); 7 | } 8 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/function-pointer.walt: -------------------------------------------------------------------------------- 1 | import { table: Table } from 'env'; 2 | import { setTimeout: Later } from 'env'; 3 | import { log: Log } from 'env'; 4 | 5 | type Log = (i32) => void; 6 | type Later = (Function, i32) => void; 7 | 8 | function echo(): void { 9 | log(42); 10 | } 11 | 12 | export function test(): void { 13 | setTimeout(echo, 5); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/memory.walt: -------------------------------------------------------------------------------- 1 | // Memory type is a special global pre-defined type 2 | const memory: Memory<{ initial: 1 }>; 3 | 4 | // An object of Memory type must be defined(can be imported) 5 | // to enable memory operations 6 | 7 | export function test(): i32 { 8 | // To use arrays simple define a type with array subscript 9 | const arr: i32[] = 0; 10 | // If arr is not defined with i32[] the below line would throw a SyntaxError 11 | arr[0] = 20; 12 | arr[1] = 15; 13 | 14 | // This should return 35 15 | return arr[0] + arr[1]; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/examples/walt/object-literal.walt: -------------------------------------------------------------------------------- 1 | // Memory is required. This could also be imported 2 | const memory: Memory<{ initial: 1 }>; 3 | 4 | // Object type. This has no side-effects on the final WebAssembly output 5 | // It is only used as a compiler hint 6 | type TestObjectType = { foo: i32, bar: i32, answer: i32 }; 7 | 8 | export function test(): i32 { 9 | // An object must be defined with the appropriate type 10 | // Because objects are complex types, we need to initialize it with an 11 | // address of zero. This address can come from any malloc-like function 12 | const obj: TestObjectType = 0; 13 | 14 | // Objects are compiled to i32 pointers, every property lookup is simply 15 | // a memory operation from the i32 pointer offset matching the property 16 | obj.foo = 22; 17 | // Or a dot-operator 18 | obj.bar = 20; 19 | 20 | // Properties can be looked-up just like array keys and can be used in math 21 | // operations. 22 | obj.answer = obj.foo + obj.bar; 23 | 24 | return obj.answer; 25 | } 26 | -------------------------------------------------------------------------------- /packages/walt-explorer/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import React from 'react'; 3 | import Explorer from './app'; 4 | 5 | ReactDOM.render(, document.getElementById('app')) 6 | 7 | -------------------------------------------------------------------------------- /packages/walt-explorer/walt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-explorer/walt.png -------------------------------------------------------------------------------- /packages/walt-explorer/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack=require('webpack'); 3 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 4 | 5 | 6 | module.exports = { 7 | context: __dirname + "/src", 8 | 9 | devtool: "source-map", 10 | 11 | entry: { 12 | javascript: "./index.js" 13 | }, 14 | 15 | output: { 16 | filename: "./explorer.js" 17 | }, 18 | 19 | resolve: { 20 | extensions: [".js", ".jsx", ".json", ".scss", ".css", ".walt"] 21 | }, 22 | 23 | plugins: [ 24 | ], 25 | 26 | module: { 27 | loaders: [ 28 | { 29 | test: /\.js$/, 30 | exclude: /node_modules/, 31 | loaders: ["babel-loader"] 32 | }, 33 | { 34 | test: /\.html$/, 35 | loader: "file-loader?name=[name].[ext]" 36 | }, 37 | { 38 | test: /\.walt$/, 39 | loader: "raw-loader" 40 | }, 41 | { 42 | test: /\.scss$/, 43 | loaders: ["style-loader", "css-loader", "sass-loader"] 44 | }, 45 | { 46 | test: /\.css$/, 47 | loaders: ["style-loader", "css-loader"] 48 | }, 49 | { 50 | test: /\.(png|woff|woff2|eot|ttf|svg)$/, 51 | loader: "url-loader", 52 | query: { mimetype: "image/png" } 53 | } 54 | ] 55 | } 56 | }; 57 | 58 | if (process.env.NODE_ENV === "production") { 59 | module.exports.plugins.push( 60 | 61 | new UglifyJsPlugin({ 62 | sourceMap: true, 63 | cache: true, 64 | parallel: true, 65 | }), 66 | 67 | new webpack.DefinePlugin({ 68 | "process.env": { 69 | NODE_ENV: JSON.stringify('production'), 70 | } 71 | }), 72 | 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /packages/walt-link/README.md: -------------------------------------------------------------------------------- 1 | # walt-link 2 | 3 | Linker for `walt` WebAssembly Programs. 4 | 5 | ## About 6 | 7 | Wraps `.walt` file with a JavaScript module, with all the dependencies linked. 8 | 9 | Intented to be used in a _node environment_. Not yet implemented in a loader. 10 | 11 | **Still under development, but the API wont change.** 12 | 13 | Notes 14 | 15 | * Any import with a leading dot(`.`) will be linked into the final binary 16 | * Anything without a leading dot(`.`) will be treated as an environment import 17 | and is left up to the user to implement. 18 | * The top-level function returns a factory method which returns a function taking 19 | an import object. Every call to the method returns a brand new module 20 | * _importObj_ used in the factory method is _shared across all modules_. 21 | * Walt Dependencies are shared within a single WebAssembly module instance. Each 22 | import is a stand alone module linked by the linker. This is useful if you want 23 | shared module state across imports, similar to node modules. 24 | 25 | TODOs 26 | 27 | - 28 | 29 | ## Usage 30 | 31 | ```js 32 | const { link } = require("walt-link"); 33 | const path = require("path"); 34 | 35 | const factory = link(path.resolve(__dirname, "./index.walt")); 36 | 37 | factory({ 38 | env: { 39 | memory, 40 | }, 41 | }).then(wasmModule => { 42 | /* run your code here */ 43 | }); 44 | ``` 45 | -------------------------------------------------------------------------------- /packages/walt-link/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "walt-link", 3 | "version": "0.5.0", 4 | "description": "Links .walt WebAssembly programs", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "ava", 8 | "debug": "node --inspect-brk node_modules/ava/profile.js", 9 | "debug-container": "node --inspect-brk=\"$(hostname -I | xargs)\" node_modules/ava/profile.js", 10 | "prettier": "prettier --list-different src/**/*.js" 11 | }, 12 | "keywords": [ 13 | "walt", 14 | "javascript", 15 | "webassembly" 16 | ], 17 | "author": "Arthur Buldauskas", 18 | "license": "MIT", 19 | "dependencies": { 20 | "invariant": "^2.2.4", 21 | "walt-buildtools": "^0.1.1", 22 | "walt-compiler": "^0.21.0" 23 | }, 24 | "devDependencies": { 25 | "ava": "^0.25.0", 26 | "babel-plugin-transform-node-env-inline": "^0.4.3", 27 | "coveralls": "^3.0.0", 28 | "nyc": "^11.7.1", 29 | "prettier": "^1.12.0", 30 | "walt-compiler": "^0.21.0" 31 | }, 32 | "prettier": { 33 | "trailingComma": "es5" 34 | }, 35 | "ava": { 36 | "files": [ 37 | "src/**/*[sS]pec.js", 38 | "!**/utils.js" 39 | ], 40 | "source": [ 41 | "src/**/*.js", 42 | "src/**/*.walt" 43 | ], 44 | "failFast": true, 45 | "failWithoutAssertions": false, 46 | "tap": false, 47 | "powerAssert": false 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/walt-link/src/__tests__/__snapshots__/linker-spec.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/packages/walt-link/src/__tests__/__snapshots__/linker-spec.js.snap -------------------------------------------------------------------------------- /packages/walt-link/src/index.walt: -------------------------------------------------------------------------------- 1 | import { memory: Memory } from 'env'; 2 | import { a, hello, GetAType, getA, AType } from './walt/import-a'; 3 | import { b } from './walt/import-b'; 4 | import { c, world, hello_2 } from './walt/import-c'; 5 | 6 | const table: Table = { element: 'anyfunc', initial: 1 }; 7 | 8 | export function showImportA() : i32 { 9 | const funPtr: GetAType = getA; 10 | const _a: i32 = funPtr(); 11 | 12 | const A: AType = 0; 13 | A.foobar = _a; 14 | return A.foobar; 15 | } 16 | 17 | export function showImportB(): i32 { 18 | return b; 19 | } 20 | 21 | export function helloTest(): i32 { 22 | return hello(); 23 | } 24 | 25 | export function worldTest(): i32 { 26 | return world(); 27 | } 28 | 29 | export function run(): i32 { 30 | // Proof that statics are _shared_ in different modules 31 | return hello_2() == hello(); 32 | } 33 | -------------------------------------------------------------------------------- /packages/walt-link/src/walt/import-a.walt: -------------------------------------------------------------------------------- 1 | import { memory: Memory<{ initial: 1 }> } from 'env'; 2 | export type GetAType = () => i32; 3 | export type AType = { foobar: i32 }; 4 | 5 | export const a: i32 = 42; 6 | export function getA(): i32 { 7 | return a; 8 | } 9 | 10 | export function hello(): i32 { 11 | const hello: i32 = "hello"; 12 | return hello; 13 | } 14 | -------------------------------------------------------------------------------- /packages/walt-link/src/walt/import-b.walt: -------------------------------------------------------------------------------- 1 | export const b: i32 = 20; 2 | -------------------------------------------------------------------------------- /packages/walt-link/src/walt/import-c.walt: -------------------------------------------------------------------------------- 1 | import { memory: Memory } from 'env'; 2 | import { a } from './import-a'; 3 | import { b } from './import-b'; 4 | 5 | export function hello_2(): i32 { 6 | const hello: i32 = 'hello'; 7 | return hello; 8 | } 9 | 10 | export function world(): i32 { 11 | const world: i32 = 'world'; 12 | return world; 13 | } 14 | 15 | export function c(): i32 { 16 | return a + b; 17 | } 18 | -------------------------------------------------------------------------------- /packages/walt-loader/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", { 5 | "targets": { 6 | "node": "8.0.0" 7 | } 8 | }] 9 | ], 10 | "plugins": [ 11 | "external-helpers", 12 | "transform-runtime" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/walt-loader/__tests__/loader-spec.js: -------------------------------------------------------------------------------- 1 | import test from "ava"; 2 | import Module from "module"; 3 | import loader from ".."; 4 | 5 | const __MOCK_MODULE__ = "__MOCK_MODULE__"; 6 | 7 | const waltSimple = `export function two(): i32 { 8 | return 2; 9 | }`; 10 | 11 | const waltCounter = `let counter: i32 = 0; 12 | export function counter(): i32 { 13 | let result: i32 = counter; 14 | counter += 1; 15 | return result; 16 | }`; 17 | 18 | const getLoaderContext = callback => ({ 19 | callback, 20 | resourcePath: "./counter.walt", 21 | options: { context: __dirname + "/../" } 22 | }); 23 | 24 | test("loader works", t => 25 | new Promise(resolve => { 26 | const loaderContext = getLoaderContext((unused, result) => { 27 | t.truthy(result); 28 | resolve(); 29 | }); 30 | 31 | loader.call(loaderContext, waltSimple); 32 | })); 33 | 34 | test("create a legit module", t => 35 | new Promise(resolve => { 36 | Module._cache[__MOCK_MODULE__] = null; 37 | 38 | const loaderContext = getLoaderContext((unused, result) => { 39 | const module = new Module(__MOCK_MODULE__); 40 | module._compile(result, __MOCK_MODULE__); 41 | 42 | module.exports().then(webAssemblyModule => { 43 | const { instance: { exports: { counter } } } = webAssemblyModule; 44 | t.is(counter(), 0); 45 | t.is(counter(), 1); 46 | t.is(counter(), 2); 47 | t.is(counter(), 3); 48 | resolve(); 49 | }); 50 | }); 51 | 52 | loader.call(loaderContext, waltCounter); 53 | })); 54 | -------------------------------------------------------------------------------- /packages/walt-loader/index.js: -------------------------------------------------------------------------------- 1 | const wasmLoader = require("wasm-loader"); 2 | const { compile } = require("walt-compiler"); 3 | 4 | module.exports = function waltLoader(source) { 5 | const buffer = compile(source).buffer(); 6 | buffer.length = buffer.byteLength; 7 | // The new Buffer step can/should be skipped here, maybe 8 | wasmLoader.call(this, new Buffer(buffer)); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/walt-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "walt-loader", 3 | "version": "1.1.12", 4 | "description": "Webpack loader for Walt(WebAssembly)", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo 'tests temporarily disabled'", 8 | "debug": "node --inspect-brk node_modules/ava/profile.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+ssh://git@github.com/ballercat/walt.git" 13 | }, 14 | "keywords": [ 15 | "walt", 16 | "wasm", 17 | "webassembly", 18 | "webpack", 19 | "loader", 20 | "compiler", 21 | "js", 22 | "javascript" 23 | ], 24 | "peerDependencies": { 25 | "walt-compiler": "^0.5.3" 26 | }, 27 | "author": "Arthur Buldauskas", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/ballercat/walt/issues" 31 | }, 32 | "homepage": "https://github.com/ballercat/walt#readme", 33 | "ava": { 34 | "files": [ 35 | "__tests__/**/*[sS]pec.js" 36 | ], 37 | "source": [ 38 | "index.js" 39 | ], 40 | "failFast": true, 41 | "failWithoutAssertions": false, 42 | "tap": false, 43 | "powerAssert": false, 44 | "require": [ 45 | "babel-register" 46 | ] 47 | }, 48 | "devDependencies": { 49 | "ava": "^0.24.0", 50 | "babel-core": "^6.26.0", 51 | "babel-loader": "^7.1.2", 52 | "babel-plugin-external-helpers": "^6.22.0", 53 | "babel-plugin-transform-runtime": "^6.23.0", 54 | "babel-preset-env": "^1.6.1", 55 | "prettier": "^1.9.2", 56 | "walt-compiler": "^0.21.0" 57 | }, 58 | "dependencies": { 59 | "wasm-loader": "^1.1.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/has-node.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/has-node'); 2 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/map-node.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/map-node'); 2 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "walt-parser-tools", 3 | "version": "0.2.8", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "ava" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/ballercat/walt.git" 12 | }, 13 | "keywords": [ 14 | "wasm", 15 | "wast", 16 | "javascript", 17 | "webassembly", 18 | "compiler" 19 | ], 20 | "author": "", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/ballercat/walt/issues" 24 | }, 25 | "homepage": "https://github.com/ballercat/walt#readme", 26 | "dependencies": { 27 | "xtend": "^4.0.1" 28 | }, 29 | "devDependencies": { 30 | "ava": "0.24.0", 31 | "cross-env": "5.1.3", 32 | "eslint": "^5.0.0", 33 | "husky": "0.14.3", 34 | "lint-staged": "6.0.0", 35 | "pirates": "^3.0.2", 36 | "prettier": "1.9.2", 37 | "walt-syntax": "^0.7.0" 38 | }, 39 | "prettier": { 40 | "trailingComma": "es5", 41 | "singleQuote": true 42 | }, 43 | "ava": { 44 | "files": [ 45 | "src/**/*[sS]pec.js" 46 | ], 47 | "source": [ 48 | "src/**/*.js", 49 | "src/**/*.walt" 50 | ], 51 | "failFast": true, 52 | "failWithoutAssertions": false, 53 | "tap": false, 54 | "powerAssert": false 55 | }, 56 | "lint-staged": { 57 | "src/**/*.js": [ 58 | "prettier --write", 59 | "git add" 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/scope.js: -------------------------------------------------------------------------------- 1 | const { 2 | enter, 3 | exit, 4 | add, 5 | find, 6 | current, 7 | namespace, 8 | signature, 9 | index, 10 | } = require('./src/scope'); 11 | 12 | module.exports = { 13 | enter, 14 | exit, 15 | add, 16 | find, 17 | current, 18 | namespace, 19 | index, 20 | signature, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/__tests__/map-node-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import extend from 'xtend'; 3 | import Syntax from 'walt-syntax'; 4 | import { mapNode } from '../map-node'; 5 | 6 | const mockNodeString = 7 | '{"Type":"BinaryExpression","value":"+","range":[null,{"line":1,"col":8}],"meta":[],"params":[{"Type":"ArraySubscript","value":"[","range":[null,{"line":1,"col":4}],"meta":[],"params":[{"Type":"Identifier","value":"b","range":[{"line":1,"col":0},{"line":1,"col":1}],"meta":[{"payload":0,"type":"global/index"}],"params":[],"type":"i32"},{"Type":"Constant","value":"1","range":[{"line":1,"col":2},{"line":1,"col":3}],"meta":[],"params":[],"type":"i32"}],"type":"i32"},{"Type":"Constant","value":"5","range":[{"line":1,"col":7},{"line":1,"col":8}],"meta":[],"params":[],"type":"i32"}],"type":"i32"}'; 8 | 9 | test('mapping a node results in a new node', t => { 10 | const node = JSON.parse(mockNodeString); 11 | const newNode = mapNode({ 12 | [Syntax.BinaryExpression]: binaryNode => { 13 | if (binaryNode.value === '+') { 14 | return extend(binaryNode, { value: '-' }); 15 | } 16 | return binaryNode; 17 | }, 18 | })(node); 19 | 20 | t.not(node, newNode); 21 | }); 22 | 23 | test('wildcards', t => { 24 | const node = JSON.parse(mockNodeString); 25 | 26 | const newNode = mapNode({ 27 | '*': n => extend(n, {}), 28 | })(node); 29 | 30 | t.not(node, newNode); 31 | }); 32 | 33 | test('null nodes', t => { 34 | const newNode = mapNode({})(null); 35 | t.is(null, newNode); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/__tests__/scope-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { enter, exit, add, find, namespace, current } from '../scope'; 3 | 4 | test('scope', t => { 5 | const SCOPE_NAMESPACE = 'local'; 6 | let scopes = enter([], SCOPE_NAMESPACE); 7 | 8 | // When a scope is added it's unique namespace can be looked up 9 | t.is(current(scopes)[namespace], SCOPE_NAMESPACE); 10 | 11 | scopes = exit(scopes); 12 | 13 | t.is(current(scopes) == null, true); 14 | 15 | scopes = enter(scopes, SCOPE_NAMESPACE); 16 | 17 | const node = { 18 | value: 'x', 19 | type: 'i32', 20 | meta: { scope: current(scopes)[namespace] }, 21 | }; 22 | add(scopes, 'x', node); 23 | 24 | scopes = enter(scopes, 'nested'); 25 | add(scopes, 'x', Object.assign({}, node)); 26 | scopes = enter(scopes, 'another'); 27 | 28 | // The first in the scope chain is always returned 29 | let ref = find(scopes, 'x'); 30 | t.not(ref, node); 31 | 32 | scopes = exit(scopes); 33 | scopes = exit(scopes); 34 | 35 | ref = find(scopes, 'x'); 36 | t.is(ref, node); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/__tests__/walk-node-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Syntax from 'walt-syntax'; 3 | import walkNode from '../walk-node'; 4 | 5 | const mockNodeString = 6 | '{"Type":"BinaryExpression","value":"+","range":[null,{"line":1,"col":8}],"meta":[],"params":[{"Type":"ArraySubscript","value":"[","range":[null,{"line":1,"col":4}],"meta":[],"params":[{"Type":"Identifier","value":"b","range":[{"line":1,"col":0},{"line":1,"col":1}],"meta":[{"payload":0,"type":"global/index"}],"params":[],"type":"i32"},{"Type":"Constant","value":"1","range":[{"line":1,"col":2},{"line":1,"col":3}],"meta":[],"params":[],"type":"i32"}],"type":"i32"},{"Type":"Constant","value":"5","range":[{"line":1,"col":7},{"line":1,"col":8}],"meta":[],"params":[],"type":"i32"}],"type":"i32"}'; 7 | 8 | test('nodes are walked and callbacks are called for types', t => { 9 | const node = JSON.parse(mockNodeString); 10 | let hasBinary = false; 11 | walkNode({ 12 | [Syntax.BinaryExpression]: () => { 13 | hasBinary = true; 14 | }, 15 | })(node); 16 | t.is(hasBinary, true); 17 | }); 18 | 19 | test('wildcards are called for all nodes', t => { 20 | const node = JSON.parse(mockNodeString); 21 | const expectedTypes = [ 22 | Syntax.BinaryExpression, 23 | Syntax.ArraySubscript, 24 | Syntax.Identifier, 25 | Syntax.Constant, 26 | Syntax.Constant, 27 | ]; 28 | const walkedTypes = []; 29 | 30 | walkNode({ 31 | '*': n => walkedTypes.push(n.Type), 32 | })(node); 33 | 34 | t.deepEqual(walkedTypes, expectedTypes); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/has-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if an AST has a specific Node Type, return boolean 3 | * 4 | */ 5 | module.exports = function hasNode(Type, ast) { 6 | const test = node => node && node.Type === Type; 7 | 8 | const walker = node => { 9 | if (node == null) { 10 | return false; 11 | } 12 | 13 | return test(node) || node.params.some(walker); 14 | }; 15 | 16 | return walker(ast); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/index.js: -------------------------------------------------------------------------------- 1 | import we from 'whatever'; 2 | 3 | console.log(we); 4 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/map-node.js: -------------------------------------------------------------------------------- 1 | const extend = require('xtend'); 2 | 3 | const identity = id => id; 4 | 5 | function map(visitors) { 6 | function mapper(input) { 7 | if (!Array.isArray(input)) { 8 | throw new Error( 9 | 'Transform must be used on an Array. Received ' + JSON.stringify(input) 10 | ); 11 | } 12 | const visitor = (() => { 13 | const [node] = input; 14 | if (node.Type in visitors && typeof visitors[node.Type] === 'function') { 15 | return visitors[node.Type]; 16 | } 17 | return identity; 18 | })(); 19 | 20 | if (visitor.length === 2) { 21 | return visitor(input, mapper); 22 | } 23 | 24 | const [node, ...rest] = visitor(input); 25 | const params = node.params 26 | .filter(Boolean) 27 | .map(child => mapper([child, ...rest])); 28 | 29 | return extend(node, { params }); 30 | } 31 | 32 | return mapper; 33 | } 34 | 35 | // This should maybe be it's own module. 36 | function mapNode(visitor) { 37 | const nodeMapper = node => { 38 | if (node == null) { 39 | return node; 40 | } 41 | 42 | const mappingFunction = (() => { 43 | if ('*' in visitor && typeof visitor['*'] === 'function') { 44 | return visitor['*']; 45 | } 46 | 47 | if (node.Type in visitor && typeof visitor[node.Type] === 'function') { 48 | return visitor[node.Type]; 49 | } 50 | return identity; 51 | })(); 52 | 53 | if (mappingFunction.length === 2) { 54 | return mappingFunction(node, nodeMapper); 55 | } 56 | 57 | const mappedNode = mappingFunction(node); 58 | const params = mappedNode.params.map(nodeMapper); 59 | 60 | return extend(mappedNode, { params }); 61 | }; 62 | 63 | return nodeMapper; 64 | } 65 | 66 | module.exports = { 67 | map, 68 | mapNode, 69 | }; 70 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/scope.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Scope helpers. 3 | * 4 | * Normalizes how scope look ups are made 5 | */ 6 | const namespace = Symbol('scope namespace'); 7 | const signature = Symbol('signature'); 8 | 9 | function enter(scopes, scopeName) { 10 | return [ 11 | ...scopes, 12 | { [namespace]: scopeName, [signature]: { result: null, arguments: null } }, 13 | ]; 14 | } 15 | 16 | function exit(scopes) { 17 | return scopes.slice(0, -1); 18 | } 19 | 20 | function current(scopes) { 21 | return scopes[scopes.length - 1]; 22 | } 23 | 24 | function add(scopes, key, node) { 25 | const cur = current(scopes); 26 | if (cur) { 27 | cur[key] = node; 28 | } 29 | 30 | return cur; 31 | } 32 | 33 | function find(scopes, key) { 34 | const len = scopes.length; 35 | let i = len - 1; 36 | for (i; i >= 0; i--) { 37 | const ref = scopes[i][key]; 38 | if (ref) { 39 | return ref; 40 | } 41 | } 42 | 43 | return null; 44 | } 45 | 46 | function index(scope, key) { 47 | const pos = Object.keys(scope).indexOf(key); 48 | return pos > -1 ? pos : Object.keys(scope).length; 49 | } 50 | 51 | module.exports = { 52 | enter, 53 | exit, 54 | add, 55 | find, 56 | current, 57 | index, 58 | namespace, 59 | signature, 60 | }; 61 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/src/walk-node.js: -------------------------------------------------------------------------------- 1 | // Dead simple AST walker, takes a visitor object and calls all methods for 2 | // appropriate node Types. 3 | module.exports = function walker(visitor) { 4 | const walkNode = node => { 5 | if (node == null) { 6 | return node; 7 | } 8 | const { params } = node; 9 | 10 | const mappingFunction = (() => { 11 | if ('*' in visitor && typeof visitor['*'] === 'function') { 12 | return visitor['*']; 13 | } 14 | 15 | if (node.Type in visitor && typeof visitor[node.Type] === 'function') { 16 | return visitor[node.Type]; 17 | } 18 | 19 | return () => node; 20 | })(); 21 | 22 | if (mappingFunction.length === 2) { 23 | mappingFunction(node, walkNode); 24 | return node; 25 | } 26 | 27 | mappingFunction(node); 28 | params.forEach(walkNode); 29 | 30 | return node; 31 | }; 32 | 33 | return walkNode; 34 | }; 35 | -------------------------------------------------------------------------------- /packages/walt-parser-tools/walk-node.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/walk-node'); 2 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", { 5 | "targets": { 6 | "chrome": "60.0.0" 7 | } 8 | }] 9 | ], 10 | "sourceMaps": "inline", 11 | "plugins": [ 12 | "external-helpers", 13 | "transform-runtime", 14 | "transform-object-rest-spread" 15 | ] 16 | } 17 | 18 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/.eslintignore: -------------------------------------------------------------------------------- 1 | **/*.walt 2 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/rollup.config.js: -------------------------------------------------------------------------------- 1 | import base from '../../base-rollup.config'; 2 | 3 | const PROD = process.env.NODE_ENV === 'production'; 4 | export default { 5 | ...base, 6 | input: 'src/index.js', 7 | output: { 8 | file: PROD 9 | ? 'dist/walt-plugin-syntax-closures.min.js' 10 | : 'dist/walt-plugin-syntax-closures.js', 11 | format: 'umd', 12 | name: 'WaltClosures', 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/src/__tests__/closure-plugin-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { compile } from 'walt-compiler'; 3 | import { plugin, imports } from '..'; 4 | 5 | test('closures', t => { 6 | const source = ` 7 | const table: Table<{ element: 'anyfunc', initial: 5 }>; 8 | type Func = (i32, i32) => i32; 9 | type Simple = () => i32; 10 | type Void = () => void; 11 | type ArgsOnly = (i32, i32) => void; 12 | 13 | type Closure = Lambda; 14 | type SimpleClosure = Lambda; 15 | type VoidClosure = Lambda; 16 | type ArgsOnlyClosure = Lambda; 17 | 18 | function getSimpleLambda(): SimpleClosure { 19 | let x: i32 = 0; 20 | const z: i64 = (1 : i64); 21 | return (): i32 => { 22 | // assignment here, we need to cover regular assignment in closures 23 | let y: i32 = 0; 24 | y = z: i32; 25 | x += y; 26 | return x; 27 | }; 28 | } 29 | 30 | function getLambda(): Closure { 31 | // close over two locals 32 | let x: i32 = 0; 33 | return (xx: i32, yy: i32): i32 => { 34 | x += yy; 35 | return x + xx; 36 | }; 37 | } 38 | 39 | // Closures below are not useful, but necessary to cover all scenarios 40 | function getVoidLamba(): VoidClosure { 41 | let x: i32 = 0; 42 | return () => { 43 | x += 1; 44 | }; 45 | } 46 | 47 | function getArgsOnlyLambda(): ArgsOnlyClosure { 48 | let x: i32 = 0; 49 | return (z: i32, y: i32) => { 50 | x+= z + y; 51 | }; 52 | } 53 | 54 | export function test(): i32 { 55 | const closure: Closure = getLambda(); 56 | // // should be 5 57 | const x: i32 = closure(2, 3); 58 | 59 | const closure2: SimpleClosure = getSimpleLambda(); 60 | // should be 1 61 | closure2(); 62 | // should be 2 63 | const y: i32 = closure2(); 64 | // should be 7 65 | return x + y; 66 | } 67 | `; 68 | 69 | const options = { version: 1, extensions: [plugin] }; 70 | return Promise.resolve(imports(options, compile)) 71 | .then(closureImports => 72 | WebAssembly.instantiate(compile(source, options).buffer(), closureImports) 73 | ) 74 | .then(result => { 75 | const fn = result.instance.exports.test; 76 | t.is(fn(), 7); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/src/closures.ne: -------------------------------------------------------------------------------- 1 | @{% 2 | const { Syntax } = this; 3 | const { drop, extendNode } = this.helpers; 4 | const { node, typeGeneric } = this.nodes(this.lexer); 5 | const voidClosure = (d) => { 6 | const [args, block] = drop(d); 7 | const resultNode = extendNode( 8 | { type: null }, 9 | node(Syntax.FunctionResult)([]) 10 | ); 11 | return extendNode( 12 | { 13 | params: [ 14 | extendNode( 15 | { 16 | params: [args, resultNode, block], 17 | }, 18 | node(Syntax.FunctionDeclaration)([]) 19 | ), 20 | ], 21 | }, 22 | node(Syntax.Closure)([]) 23 | ); 24 | }; 25 | const closure = (d) => { 26 | const [args, resultNode, block] = drop(d); 27 | return extendNode( 28 | { 29 | params: [ 30 | extendNode( 31 | { 32 | params: [args, resultNode, block], 33 | }, 34 | node(Syntax.FunctionDeclaration)([]) 35 | ), 36 | ], 37 | }, 38 | node(Syntax.Closure)([]) 39 | ); 40 | }; 41 | 42 | const genericType = (d) => { 43 | const [id, gen, typeNode] = drop(d); 44 | return extendNode( 45 | { 46 | value: id.value, 47 | params: [gen, typeNode], 48 | }, 49 | node(Syntax.GenericType)([]) 50 | ); 51 | }; 52 | %} 53 | 54 | TypeDef -> TYPE __ Identifier _ EQUALS _ Lambda _ SEPARATOR {% genericType %} 55 | Lambda -> Identifier LT _ Type _ GT {% typeGeneric %} 56 | 57 | Closure -> 58 | FunctionParameters _ FATARROW _ Block {% voidClosure %} 59 | | FunctionParameters _ FunctionResult _ FATARROW _ Block {% closure %} 60 | 61 | Expression -> Closure {% id %} 62 | -------------------------------------------------------------------------------- /packages/walt-plugin-syntax-closure/src/closures.walt: -------------------------------------------------------------------------------- 1 | const memory: Memory = { initial: 1 }; 2 | let heapPointer: i32 = 0; 3 | export function __closure_malloc(size: i32): i32 { 4 | const ptr: i32 = heapPointer; 5 | heapPointer += size; 6 | return ptr; 7 | } 8 | 9 | export function __closure_free(ptr: i32) { 10 | } 11 | 12 | // Getters 13 | export function __closure_get_i32(ptr: i32): i32 { 14 | const view: i32[] = ptr; 15 | return view[0]; 16 | } 17 | 18 | export function __closure_get_f32(ptr: i32): f32 { 19 | const view: f32[] = ptr; 20 | return view[0]; 21 | } 22 | 23 | export function __closure_get_i64(ptr: i32): i64 { 24 | const view: i64[] = ptr; 25 | return view[0]; 26 | } 27 | 28 | export function __closure_get_f64(ptr: i32): f64 { 29 | const view: f64[] = ptr; 30 | return view[0]; 31 | } 32 | 33 | // Setters 34 | export function __closure_set_i32(ptr: i32, value: i32) { 35 | const view: i32[] = ptr; 36 | view[0] = value; 37 | } 38 | 39 | export function __closure_set_f32(ptr: i32, value: f32) { 40 | const view: f32[] = ptr; 41 | view[0] = value; 42 | } 43 | 44 | export function __closure_set_i64(ptr: i32, value: i64) { 45 | const view: i64[] = ptr; 46 | view[0] = value; 47 | } 48 | 49 | export function __closure_set_f64(ptr: i32, value: f64) { 50 | const view: f64[] = ptr; 51 | view[0] = value; 52 | } 53 | -------------------------------------------------------------------------------- /packages/walt-syntax/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "chrome": "60.0.0" 8 | } 9 | } 10 | ] 11 | ] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /packages/walt-syntax/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "walt-syntax", 3 | "version": "0.7.0", 4 | "description": "Walt Syntax", 5 | "main": "dist/walt-syntax.js", 6 | "scripts": { 7 | "test": "ava", 8 | "build": "cross-env node_modules/rollup/bin/rollup -c rollup.config.js", 9 | "build-prod": "cross-env NODE_ENV=production node_modules/rollup/bin/rollup -c rollup.config.js", 10 | "preversion": "npm run build && npm run build-prod", 11 | "lint": "eslint" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/ballercat/walt.git" 16 | }, 17 | "keywords": [ 18 | "wasm", 19 | "wast", 20 | "javascript", 21 | "webassembly", 22 | "compiler" 23 | ], 24 | "author": "Arthur Buldauskas", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/ballercat/walt/issues" 28 | }, 29 | "homepage": "https://github.com/ballercat/walt/tree/master/packages/walt-syntax/", 30 | "devDependencies": { 31 | "ava": "0.24.0", 32 | "babel-eslint": "^9.0.0", 33 | "babel-preset-env": "^1.7.0", 34 | "babel-register": "^6.26.0", 35 | "cross-env": "^5.2.0", 36 | "eslint": "^5.4.0", 37 | "husky": "0.14.3", 38 | "lint-staged": "6.0.0", 39 | "moo": "^0.4.3", 40 | "prettier": "1.9.2", 41 | "rollup": "^0.64.1" 42 | }, 43 | "prettier": { 44 | "trailingComma": "es5", 45 | "singleQuote": true 46 | }, 47 | "ava": { 48 | "files": [ 49 | "src/**/*[sS]pec.js" 50 | ], 51 | "source": [ 52 | "src/**/*.js", 53 | "src/**/*.walt" 54 | ], 55 | "failFast": true, 56 | "failWithoutAssertions": false, 57 | "tap": false, 58 | "powerAssert": false, 59 | "require": [ 60 | "babel-register" 61 | ], 62 | "babel": "inherit" 63 | }, 64 | "lint-staged": { 65 | "src/**/*.js": [ 66 | "prettier --write", 67 | "git add" 68 | ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/walt-syntax/rollup.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | entry: 'src/index.js', 3 | dest: 'dist/walt-syntax.js', 4 | format: 'umd', 5 | moduleName: 'walt-syntax', 6 | }; 7 | -------------------------------------------------------------------------------- /packages/walt-syntax/src/__tests__/syntax-spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import Syntax from '..'; 3 | 4 | test('Walt Syntax Definitions', t => { 5 | t.is(!!Syntax && typeof Syntax === 'object', true); 6 | }); 7 | 8 | test('Node types are all strings', t => { 9 | const typesOnly = Object.entries(Syntax).filter( 10 | ([k]) => !['statements', 'builtinTypes'].includes(k) 11 | ); 12 | t.is( 13 | // Every Definde Type is a non empty string 14 | typesOnly.every( 15 | ([, value]) => typeof value === 'string' && value.trim().length 16 | ), 17 | true 18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/walt-syntax/src/__tests__/token-spec.js: -------------------------------------------------------------------------------- 1 | import moo from 'moo'; 2 | import test from 'ava'; 3 | import { tokens } from '..'; 4 | 5 | const src = ` 6 | // comment test 7 | // const foo: i32 = 0; 8 | const a = 15; // '' 9 | lf\ncr\rcrlf\r\n 10 | `; 11 | test.only('tokens', () => { 12 | const lexer = moo.compile(tokens); 13 | lexer.reset(src); 14 | 15 | let token = lexer.next(); 16 | const result = []; 17 | while (token) { 18 | result.push(token); 19 | token = lexer.next(); 20 | } 21 | 22 | console.log('Result', result); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/walt-syntax/src/tokens.js: -------------------------------------------------------------------------------- 1 | const keyword = [ 2 | // EcmaScript 3 | 'break', 4 | 'if', 5 | 'else', 6 | 'import', 7 | 'as', 8 | 'from', 9 | 'export', 10 | 'return', 11 | 'switch', 12 | 'case', 13 | 'default', 14 | 'const', 15 | 'let', 16 | 'for', 17 | 'continue', 18 | 'do', 19 | 'while', 20 | 'throw', 21 | 'function', 22 | 23 | // s-expression 24 | 'global', 25 | 'module', 26 | 'type', 27 | 'lambda', 28 | ]; 29 | const punctuator = [ 30 | '+', 31 | '++', 32 | '-', 33 | '--', 34 | '>>', 35 | '>>>', 36 | '<<', 37 | '=', 38 | '==', 39 | '+=', 40 | '-=', 41 | '=>', 42 | '<=', 43 | '>=', 44 | '!=', 45 | '%', 46 | '*', 47 | '/', 48 | '^', 49 | '&', 50 | '~', 51 | '|', 52 | '!', 53 | '**', 54 | ':', 55 | '(', 56 | ')', 57 | '.', 58 | '{', 59 | '}', 60 | ',', 61 | '[', 62 | ']', 63 | ';', 64 | '>', 65 | '<', 66 | '?', 67 | '||', 68 | '&&', 69 | '{', 70 | '}', 71 | '...', 72 | ]; 73 | 74 | const type = ['i32', 'i64', 'f32', 'f64', 'bool']; 75 | 76 | export const tokens = { 77 | whitespace: /[ \t]+/, 78 | comment: [ 79 | { match: /\/\/.*?$/ }, 80 | { match: /\/\*[^]*?\*\//, lineBreaks: true }, 81 | ], 82 | number: [ 83 | { match: /0[xX][0-9a-fA-F]+/ }, 84 | { match: /0[oO][0-9]+/ }, 85 | { match: /0[bB][01]+/ }, 86 | { match: /(?:[0-9]+(?:\.[0-9]+)?e-?[0-9]+)/ }, 87 | { match: /[0-9]+\.[0-9]+|[0-9]+/ }, 88 | ], 89 | char: [ 90 | { match: /'(?:\\['\\bfnrtv0]|[^'\\\n])'/, value: x => x.slice(1, -1) }, 91 | ], 92 | string: [ 93 | { match: /"(?:\\["\\rn]|[^"\\\n])*?"/, value: x => x.slice(1, -1) }, 94 | { match: /'(?:\\['\\bfnrtv0]|[^'\\\n])*?'/, value: x => x.slice(1, -1) }, 95 | { match: /`(?:\\['\\bfnrtv0]|[^'\\])*?`/, value: x => x.slice(1, -1) }, 96 | ], 97 | identifier: { 98 | match: /[A-Za-z_$][A-Za-z0-9_$]*/, 99 | keywords: { keyword, type }, 100 | }, 101 | punctuator, 102 | newline: { match: /(?:\r\n|\r|\n)/, lineBreaks: true }, 103 | }; 104 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/README.md: -------------------------------------------------------------------------------- 1 | # Webpack Examples 2 | Examples of how to load Walt modules inside a larger app with Webpack. 3 | 4 | ## Usage 5 | 6 | Install: 7 | `npm install` 8 | 9 | Run: 10 | `npm start` 11 | 12 | ## Webpack config 13 | Here is the the most basic configuration necessary to seemlessly import a `.walt` 14 | module into your project: 15 | 16 | ```js 17 | module.exports = { 18 | context: __dirname + "/src", 19 | 20 | devtool: "source-map", 21 | 22 | entry: { 23 | javascript: "./index.js" 24 | }, 25 | 26 | output: { 27 | filename: "./example.js" 28 | }, 29 | 30 | resolve: { 31 | extensions: [".js", ".jsx", ".walt"] 32 | }, 33 | 34 | module: { 35 | loaders: [ 36 | { 37 | test: /\.js$/, 38 | exclude: /node_modules/, 39 | loaders: ["babel-loader"] 40 | }, 41 | { 42 | test: /\.html$/, 43 | loader: "file-loader?name=[name].[ext]" 44 | }, 45 | { 46 | test: /\.walt$/, 47 | loader: "walt-loader" 48 | } 49 | ] 50 | } 51 | }; 52 | ``` 53 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Walt Examples 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-walt-examples", 3 | "version": "1.0.45", 4 | "description": "Examples with Webpack", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server -d --hot --inline", 8 | "build": "webpack" 9 | }, 10 | "keywords": [ 11 | "walt", 12 | "wasm", 13 | "webassembly", 14 | "javascript" 15 | ], 16 | "author": "Arthur Buldauskas", 17 | "license": "MIT", 18 | "private": true, 19 | "babel": { 20 | "presets": [ 21 | "react", 22 | [ 23 | "env", 24 | { 25 | "modules": false, 26 | "targets": { 27 | "chrome": "60.0.0" 28 | } 29 | } 30 | ] 31 | ], 32 | "plugins": [ 33 | "transform-object-rest-spread", 34 | "transform-class-properties" 35 | ] 36 | }, 37 | "devDependencies": { 38 | "babel-core": "6.26.0", 39 | "babel-loader": "7.1.2", 40 | "babel-plugin-transform-class-properties": "6.24.1", 41 | "babel-plugin-transform-object-rest-spread": "6.26.0", 42 | "babel-preset-env": "1.6.0", 43 | "babel-preset-react": "6.24.1", 44 | "css-loader": "0.28.7", 45 | "file-loader": "0.11.2", 46 | "node-sass": "4.9.3", 47 | "react-hot-loader": "1.3.1", 48 | "sass-loader": "6.0.6", 49 | "style-loader": "0.18.2", 50 | "url-loader": "0.5.9", 51 | "walt-compiler": "^0.4.3", 52 | "walt-loader": "^1.1.12", 53 | "webpack": "3.6.0", 54 | "webpack-dev-server": "2.8.2" 55 | }, 56 | "dependencies": { 57 | "prop-types": "15.5.10", 58 | "react": "15.6.1", 59 | "react-dom": "15.6.1", 60 | "react-router-dom": "^4.2.2", 61 | "semantic-ui-css": "2.2.12", 62 | "semantic-ui-react": "0.73.1" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Directory from './Directory'; 3 | import CounterExample from './CounterExample'; 4 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 5 | 6 | export default function App() { 7 | return ( 8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/src/CounterExample.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import makeCounter from './walt/counter'; 3 | 4 | export default class CounterExample extends Component { 5 | state = { counter: 0, instance: null }; 6 | 7 | componentWillMount() { 8 | makeCounter().then(mod => this.setState({ instance: mod.instance })); 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 |

Counter: {this.state.counter}

15 | {this.state.instance ? ( 16 |
17 | 22 | 27 |
28 | ) : (Loading WebAssembly Module...)} 29 |
30 | ); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/src/Directory.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | export default function Directory() { 5 | return ( 6 |
    7 |
  • Counter Example
  • 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import React from 'react'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('app')) 6 | 7 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/src/walt/counter.walt: -------------------------------------------------------------------------------- 1 | let counter:i32 = 0; 2 | 3 | export function increment():i32 { 4 | counter += 1; 5 | return counter; 6 | } 7 | 8 | export function decrement():i32 { 9 | counter -= 1; 10 | return counter; 11 | } 12 | -------------------------------------------------------------------------------- /packages/webpack-walt-examples/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | context: __dirname + "/src", 5 | 6 | devtool: "source-map", 7 | 8 | entry: { 9 | javascript: "./index.js" 10 | }, 11 | 12 | output: { 13 | filename: "./example.js" 14 | }, 15 | 16 | resolve: { 17 | extensions: [".js", ".jsx", ".json", ".scss", ".css", ".walt"] 18 | }, 19 | 20 | module: { 21 | loaders: [ 22 | { 23 | test: /\.js$/, 24 | exclude: /node_modules/, 25 | loaders: ["babel-loader"] 26 | }, 27 | { 28 | test: /\.html$/, 29 | loader: "file-loader?name=[name].[ext]" 30 | }, 31 | { 32 | test: /\.walt$/, 33 | loader: "walt-loader" 34 | }, 35 | { 36 | test: /\.scss$/, 37 | loaders: ["style-loader", "css-loader", "sass-loader"] 38 | }, 39 | { 40 | test: /\.css$/, 41 | loaders: ["style-loader", "css-loader"] 42 | }, 43 | { 44 | test: /\.(png|woff|woff2|eot|ttf|svg)$/, 45 | loader: "url-loader", 46 | query: { mimetype: "image/png" } 47 | } 48 | ] 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /walt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballercat/walt/2a51deab95106d4560b8b829c4e44a09413d8db1/walt.png --------------------------------------------------------------------------------