├── test ├── fixtures │ ├── ir │ │ ├── 001.ambient │ │ ├── 002.ambient │ │ ├── 003.ambient │ │ ├── 004.ambient │ │ ├── 005.ambient │ │ ├── 001.json │ │ ├── 007.ambient │ │ ├── 006.ambient │ │ ├── 008.ambient │ │ ├── 012.ambients │ │ ├── 009.ambient │ │ ├── 013.ambient │ │ ├── 011.ambient │ │ ├── 010.ambient │ │ ├── 002.json │ │ ├── 003.json │ │ ├── 014.ambient │ │ ├── 004.json │ │ ├── 005.json │ │ ├── 012.json │ │ ├── 007.json │ │ ├── 006.json │ │ ├── 011.json │ │ ├── 014.json │ │ ├── 008.json │ │ ├── 013.json │ │ ├── 010.json │ │ └── 009.json │ └── parser │ │ ├── 001.ambient │ │ ├── 002.ambient │ │ ├── 003.ambient │ │ ├── 004.ambient │ │ ├── 005.ambient │ │ ├── 007.ambient │ │ ├── 006.ambient │ │ ├── 008.ambient │ │ ├── 012.ambients │ │ ├── 009.ambient │ │ ├── 013.ambient │ │ ├── 011.ambient │ │ ├── 010.ambient │ │ ├── 001.json │ │ ├── 002.json │ │ ├── 004.json │ │ ├── 005.json │ │ ├── 014.ambient │ │ ├── 007.json │ │ ├── 008.json │ │ ├── 003.json │ │ ├── 006.json │ │ ├── 012.json │ │ ├── 011.json │ │ ├── 013.json │ │ ├── 010.json │ │ ├── 009.json │ │ └── 014.json ├── parser.spec.js └── dag.test.js ├── .gitignore ├── Makefile ├── package.json ├── LICENSE ├── src ├── index.js ├── ir │ ├── ambients.pegjs │ ├── tiny.js │ └── index.js ├── cli.js └── parser │ └── index.js └── README.md /test/fixtures/ir/001.ambient: -------------------------------------------------------------------------------- 1 | a[] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/001.ambient: -------------------------------------------------------------------------------- 1 | a[] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/002.ambient: -------------------------------------------------------------------------------- 1 | a[ b[] ] | c[] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /test/fixtures/ir/003.ambient: -------------------------------------------------------------------------------- 1 | a[in b] | b[in_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/004.ambient: -------------------------------------------------------------------------------- 1 | b[a[out b]|out_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/002.ambient: -------------------------------------------------------------------------------- 1 | a[ b[] ] | c[] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/005.ambient: -------------------------------------------------------------------------------- 1 | a[b[open_|c[]]|open b] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/003.ambient: -------------------------------------------------------------------------------- 1 | a[in b] | b[in_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/004.ambient: -------------------------------------------------------------------------------- 1 | b[a[out b]|out_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/001.json: -------------------------------------------------------------------------------- 1 | { "id": "a", "type": "Ambient" } 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/005.ambient: -------------------------------------------------------------------------------- 1 | a[b[open_|c[]]|open b] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/007.ambient: -------------------------------------------------------------------------------- 1 | a[in b|c[]] | a[in b|d[]] | b[in_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/007.ambient: -------------------------------------------------------------------------------- 1 | a[in b|c[]] | a[in b|d[]] | b[in_ a] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/006.ambient: -------------------------------------------------------------------------------- 1 | a[in c] | b[in c] | c[in_ a.in_ b.in d] | d[in_ c] 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/006.ambient: -------------------------------------------------------------------------------- 1 | a[in c] | b[in c] | c[in_ a.in_ b.in d] | d[in_ c] 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/008.ambient: -------------------------------------------------------------------------------- 1 | func[in_ x.open x.open_] | x[in func.open_|result[]] | 2 | open func 3 | -------------------------------------------------------------------------------- /test/fixtures/parser/008.ambient: -------------------------------------------------------------------------------- 1 | func[in_ x.open x.open_] | x[in func.open_|result[]] | 2 | open func 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | npm run build:parser 3 | npm run build:parser:tiny 4 | 5 | test: build 6 | npx mocha 7 | -------------------------------------------------------------------------------- /test/fixtures/ir/012.ambients: -------------------------------------------------------------------------------- 1 | x[call[out x.in y.open_|payload[]] | out_ call] | 2 | y[in_ call.open call] 3 | -------------------------------------------------------------------------------- /test/fixtures/parser/012.ambients: -------------------------------------------------------------------------------- 1 | x[call[out x.in y.open_|payload[]] | out_ call] | 2 | y[in_ call.open call] 3 | -------------------------------------------------------------------------------- /test/fixtures/ir/009.ambient: -------------------------------------------------------------------------------- 1 | arg[in_ x.open x.in y.open_] | x[in arg.open_|input[]] | 2 | y[in_ arg.open arg.in func.open_] | 3 | func[in_ y.open y.open_] 4 | -------------------------------------------------------------------------------- /test/fixtures/ir/013.ambient: -------------------------------------------------------------------------------- 1 | x[ 2 | call[out x.in y.open_|return[open_.in x]]| 3 | out_ call.in_ y 4 | ] | 5 | y[in_ call.open call.open return] 6 | -------------------------------------------------------------------------------- /test/fixtures/parser/009.ambient: -------------------------------------------------------------------------------- 1 | arg[in_ x.open x.in y.open_] | x[in arg.open_|input[]] | 2 | y[in_ arg.open arg.in func.open_] | 3 | func[in_ y.open y.open_] 4 | -------------------------------------------------------------------------------- /test/fixtures/parser/013.ambient: -------------------------------------------------------------------------------- 1 | x[ 2 | call[out x.in y.open_|return[open_.in x]]| 3 | out_ call.in_ y 4 | ] | 5 | y[in_ call.open call.open return] 6 | -------------------------------------------------------------------------------- /test/fixtures/ir/011.ambient: -------------------------------------------------------------------------------- 1 | func[ 2 | in_ message.open message.open func.open_| 3 | arg[ 4 | in func.in x.open_| 5 | string[hello[]] 6 | ] 7 | ]| 8 | open func 9 | -------------------------------------------------------------------------------- /test/fixtures/parser/011.ambient: -------------------------------------------------------------------------------- 1 | func[ 2 | in_ message.open message.open func.open_| 3 | arg[ 4 | in func.in x.open_| 5 | string[hello[]] 6 | ] 7 | ]| 8 | open func 9 | -------------------------------------------------------------------------------- /test/fixtures/ir/010.ambient: -------------------------------------------------------------------------------- 1 | message[ 2 | in func.open_| 3 | func[ 4 | x[in_ arg.open arg.in message.open_]| 5 | message[in_ x.open x]| 6 | in_ arg.open_ 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /test/fixtures/parser/010.ambient: -------------------------------------------------------------------------------- 1 | message[ 2 | in func.open_| 3 | func[ 4 | x[in_ arg.open arg.in message.open_]| 5 | message[in_ x.open x]| 6 | in_ arg.open_ 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /test/fixtures/parser/001.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"", 3 | "children":[ 4 | {"name":"a","children":[],"capabilities":[],"create":[]} 5 | ], 6 | "capabilities":[], 7 | "create":[] 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/parser/002.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"a","children":[{"name":"b","children":[],"capabilities":[],"create":[]}],"capabilities":[],"create":[]},{"name":"c","children":[],"capabilities":[],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/004.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"b","children":[{"name":"a","children":[],"capabilities":[{"op":"out","target":"b","next":null}],"create":[]}],"capabilities":[{"op":"out_","target":"a","next":null}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/005.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"a","children":[{"name":"b","children":[{"name":"c","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"open_","target":"","next":null}],"create":[]}],"capabilities":[{"op":"open","target":"b","next":null}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/002.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "id": "b", 6 | "type": "Ambient" 7 | }], 8 | "id": "a", 9 | "type": "Ambient" 10 | }, 11 | { 12 | "id": "c", 13 | "type": "Ambient" 14 | } 15 | ], 16 | "type": "Parallel" 17 | } 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/ir/003.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "id": "b", 6 | "type": "In" 7 | }], 8 | "id": "a", 9 | "type": "Ambient" 10 | }, 11 | { 12 | "children": [{ 13 | "id": "a", 14 | "type": "In_" 15 | }], 16 | "id": "b", 17 | "type": "Ambient" 18 | } 19 | ], 20 | "type": "Parallel" 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/ir/014.ambient: -------------------------------------------------------------------------------- 1 | string_concat[ 2 | in_ call.open call.( 3 | func[ 4 | left[ 5 | in_ arg.open arg.in string.in concat 6 | ]| 7 | right[ 8 | in_ arg.open arg.in string.in concat 9 | ]| 10 | string[ 11 | concat[in_ left|in_ right]| 12 | in_ left|in_ right 13 | ]| 14 | open_ 15 | ]| 16 | open return.open_ 17 | ) 18 | ] 19 | -------------------------------------------------------------------------------- /test/fixtures/parser/014.ambient: -------------------------------------------------------------------------------- 1 | string_concat[ 2 | in_ call.open call.( 3 | func[ 4 | left[ 5 | in_ arg.open arg.in string.in concat 6 | ]| 7 | right[ 8 | in_ arg.open arg.in string.in concat 9 | ]| 10 | string[ 11 | concat[in_ left|in_ right]| 12 | in_ left|in_ right 13 | ]| 14 | open_ 15 | ]| 16 | open return.open_ 17 | ) 18 | ] 19 | -------------------------------------------------------------------------------- /test/fixtures/ir/004.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [{ 3 | "children": [ 4 | { 5 | "children": [{ 6 | "id": "b", 7 | "type": "Out" 8 | }], 9 | "id": "a", 10 | "type": "Ambient" 11 | }, 12 | { 13 | "id": "a", 14 | "type": "Out_" 15 | } 16 | ], 17 | "type": "Parallel" 18 | }], 19 | "id": "b", 20 | "type": "Ambient" 21 | } 22 | 23 | -------------------------------------------------------------------------------- /test/fixtures/parser/007.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"a","children":[{"name":"c","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"in","target":"b","next":null}],"create":[]},{"name":"a","children":[{"name":"d","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"in","target":"b","next":null}],"create":[]},{"name":"b","children":[],"capabilities":[{"op":"in_","target":"a","next":null}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/008.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"func","children":[],"capabilities":[{"op":"in_","target":"x","next":{"op":"open","target":"x","next":{"op":"open_","target":"","next":null}}}],"create":[]},{"name":"x","children":[{"name":"result","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"in","target":"func","next":{"op":"open_","target":"","next":null}}],"create":[]}],"capabilities":[{"op":"open","target":"func","next":null}],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/003.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"", 3 | "children":[ 4 | { 5 | "name":"a", 6 | "children":[], 7 | "capabilities":[ 8 | {"op": "in", "target": "b", "next": null } 9 | ], 10 | "create":[] 11 | }, 12 | { 13 | "name":"b", 14 | "children":[], 15 | "capabilities":[ 16 | { "op": "in_", "target": "a", "next": null } 17 | ], 18 | "create":[] 19 | } 20 | ], 21 | "capabilities":[], 22 | "create":[] 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/parser/006.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"a","children":[],"capabilities":[{"op":"in","target":"c","next":null}],"create":[]},{"name":"b","children":[],"capabilities":[{"op":"in","target":"c","next":null}],"create":[]},{"name":"c","children":[],"capabilities":[{"op":"in_","target":"a","next":{"op":"in_","target":"b","next":{"op":"in","target":"d","next":null}}}],"create":[]},{"name":"d","children":[],"capabilities":[{"op":"in_","target":"c","next":null}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/012.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"x","children":[{"name":"call","children":[{"name":"payload","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"out","target":"x","next":{"op":"in","target":"y","next":{"op":"open_","target":"","next":null}}}],"create":[]}],"capabilities":[{"op":"out_","target":"call","next":null}],"create":[]},{"name":"y","children":[],"capabilities":[{"op":"in_","target":"call","next":{"op":"open","target":"call","next":null}}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/011.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"func","children":[{"name":"arg","children":[{"name":"string","children":[{"name":"hello","children":[],"capabilities":[],"create":[]}],"capabilities":[],"create":[]}],"capabilities":[{"op":"in","target":"func","next":{"op":"in","target":"x","next":{"op":"open_","target":"","next":null}}}],"create":[]}],"capabilities":[{"op":"in_","target":"message","next":{"op":"open","target":"message","next":{"op":"open","target":"func","next":{"op":"open_","target":"","next":null}}}}],"create":[]}],"capabilities":[{"op":"open","target":"func","next":null}],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/005.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [{ 3 | "children": [ 4 | { 5 | "children": [{ 6 | "children": [ 7 | { 8 | "id": "*", 9 | "type": "Open_" 10 | }, 11 | { 12 | "id": "c", 13 | "type": "Ambient" 14 | } 15 | ], 16 | "type": "Parallel" 17 | }], 18 | "id": "b", 19 | "type": "Ambient" 20 | }, 21 | { 22 | "id": "b", 23 | "type": "Open" 24 | } 25 | ], 26 | "type": "Parallel" 27 | }], 28 | "id": "a", 29 | "type": "Ambient" 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/fixtures/parser/013.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"x","children":[{"name":"call","children":[{"name":"return","children":[],"capabilities":[{"op":"open_","target":"","next":{"op":"in","target":"x","next":null}}],"create":[]}],"capabilities":[{"op":"out","target":"x","next":{"op":"in","target":"y","next":{"op":"open_","target":"","next":null}}}],"create":[]}],"capabilities":[{"op":"out_","target":"call","next":{"op":"in_","target":"y","next":null}}],"create":[]},{"name":"y","children":[],"capabilities":[{"op":"in_","target":"call","next":{"op":"open","target":"call","next":{"op":"open","target":"return","next":null}}}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/010.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"message","children":[{"name":"func","children":[{"name":"x","children":[],"capabilities":[{"op":"in_","target":"arg","next":{"op":"open","target":"arg","next":{"op":"in","target":"message","next":{"op":"open_","target":"","next":null}}}}],"create":[]},{"name":"message","children":[],"capabilities":[{"op":"in_","target":"x","next":{"op":"open","target":"x","next":null}}],"create":[]}],"capabilities":[{"op":"in_","target":"arg","next":{"op":"open_","target":"","next":null}}],"create":[]}],"capabilities":[{"op":"in","target":"func","next":{"op":"open_","target":"","next":null}}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/parser/009.json: -------------------------------------------------------------------------------- 1 | {"name":"","children":[{"name":"arg","children":[],"capabilities":[{"op":"in_","target":"x","next":{"op":"open","target":"x","next":{"op":"in","target":"y","next":{"op":"open_","target":"","next":null}}}}],"create":[]},{"name":"x","children":[{"name":"input","children":[],"capabilities":[],"create":[]}],"capabilities":[{"op":"in","target":"arg","next":{"op":"open_","target":"","next":null}}],"create":[]},{"name":"y","children":[],"capabilities":[{"op":"in_","target":"arg","next":{"op":"open","target":"arg","next":{"op":"in","target":"func","next":{"op":"open_","target":"","next":null}}}}],"create":[]},{"name":"func","children":[],"capabilities":[{"op":"in_","target":"y","next":{"op":"open","target":"y","next":{"op":"open_","target":"","next":null}}}],"create":[]}],"capabilities":[],"create":[]} 2 | -------------------------------------------------------------------------------- /test/fixtures/ir/012.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"Parallel","children":[ 3 | {"type":"Ambient","id":"x","children":[ 4 | {"type":"Parallel","children":[ 5 | {"type":"Ambient","id":"call","children":[ 6 | {"type":"Parallel","children":[ 7 | {"type":"Serial","children":[ 8 | {"type":"Out","id":"x", "children": [ 9 | {"type":"In","id":"y", "children": [ 10 | {"type":"Open_","id":"*"} 11 | ]} 12 | ]} 13 | ]}, 14 | {"type":"Ambient","id":"payload"} 15 | ]} 16 | ]}, 17 | {"type":"Out_","id":"call"} 18 | ]} 19 | ]}, 20 | {"type":"Ambient","id":"y","children":[ 21 | {"type":"Serial","children":[ 22 | {"type":"In_","id":"call", "children": [ 23 | {"type":"Open","id":"call"} 24 | ]} 25 | ]} 26 | ]} 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ambc", 3 | "version": "0.1.0", 4 | "description": "Compiles source code to Ambients protocol syntax", 5 | "main": "src/index.js", 6 | "bin": { 7 | "ambc": "src/cli.js" 8 | }, 9 | "scripts": { 10 | "test": "make test", 11 | "build:parser": "pegjs -o src/ir/index.js src/ir/ambients.pegjs", 12 | "build:parser:tiny": "pegjs --optimize size -o src/ir/tiny.js src/ir/ambients.pegjs" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "flex-js": "^1.0.5", 18 | "js2amb": "aphelionz/js2amb#master", 19 | "mime-types": "^2.1.25", 20 | "multiaddr": "^7.2.1", 21 | "orbit-db-io": "^0.1.1", 22 | "pegjs": "^0.10.0", 23 | "yargs": "^14.2.0" 24 | }, 25 | "devDependencies": { 26 | "cids": "^0.7.1", 27 | "ipfs": "^0.39.0", 28 | "ipfs-http-client": "^39.0.2", 29 | "mocha": "^6.2.2", 30 | "multihashes": "^0.4.15" 31 | }, 32 | "standard": { 33 | "env": "mocha" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/fixtures/ir/007.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "children": [ 6 | { 7 | "id": "b", 8 | "type": "In" 9 | }, 10 | { 11 | "id": "c", 12 | "type": "Ambient" 13 | } 14 | ], 15 | "type": "Parallel" 16 | }], 17 | "id": "a", 18 | "type": "Ambient" 19 | }, 20 | { 21 | "children": [{ 22 | "children": [ 23 | { 24 | "id": "b", 25 | "type": "In" 26 | }, 27 | { 28 | "id": "d", 29 | "type": "Ambient" 30 | } 31 | ], 32 | "type": "Parallel" 33 | }], 34 | "id": "a", 35 | "type": "Ambient" 36 | }, 37 | { 38 | "children": [{ 39 | "id": "a", 40 | "type": "In_" 41 | }], 42 | "id": "b", 43 | "type": "Ambient" 44 | } 45 | ], 46 | "type": "Parallel" 47 | } 48 | 49 | -------------------------------------------------------------------------------- /test/fixtures/ir/006.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "id": "c", 6 | "type": "In" 7 | }], 8 | "id": "a", 9 | "type": "Ambient" 10 | }, 11 | { 12 | "children": [{ 13 | "id": "c", 14 | "type": "In" 15 | }], 16 | "id": "b", 17 | "type": "Ambient" 18 | }, 19 | { 20 | "children": [{ 21 | "children": [ 22 | { 23 | "id": "a", 24 | "type": "In_", 25 | "children": [{ 26 | "id": "b", 27 | "type": "In_", 28 | "children": [{ 29 | "id": "d", 30 | "type": "In" 31 | }] 32 | }] 33 | }], 34 | "type": "Serial" 35 | }], 36 | "id": "c", 37 | "type": "Ambient" 38 | }, 39 | { 40 | "children": [{ 41 | "id": "c", 42 | "type": "In_" 43 | }], 44 | "id": "d", 45 | "type": "Ambient" 46 | } 47 | ], 48 | "type": "Parallel" 49 | } 50 | -------------------------------------------------------------------------------- /test/fixtures/ir/011.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"Parallel","children":[ 3 | {"type":"Ambient","id":"func","children":[ 4 | {"type":"Parallel","children":[ 5 | {"type":"Serial","children":[ 6 | {"type":"In_","id":"message", "children": [ 7 | {"type":"Open","id":"message", "children": [ 8 | {"type":"Open","id":"func", "children": [ 9 | {"type":"Open_","id":"*"} 10 | ]} 11 | ]} 12 | ]} 13 | ]}, 14 | {"type":"Ambient","id":"arg","children":[ 15 | {"type":"Parallel","children":[ 16 | {"type":"Serial","children":[ 17 | {"type":"In","id":"func", "children": [ 18 | {"type":"In","id":"x", "children": [ 19 | {"type":"Open_","id":"*"} 20 | ]} 21 | ]} 22 | ]}, 23 | {"type":"Ambient","id":"string","children":[ 24 | {"type":"Ambient","id":"hello"} 25 | ]} 26 | ]} 27 | ]} 28 | ]} 29 | ]}, 30 | {"type":"Open","id":"func"} 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/fixtures/ir/014.json: -------------------------------------------------------------------------------- 1 | 2 | {"type":"Ambient","id":"string_concat","children":[{"type":"Serial","children":[{"type":"In_","id":"call","children":[{"type":"Open","id":"call","children":[{"type":"Group","children":[{"type":"Parallel","children":[{"type":"Ambient","id":"func","children":[{"type":"Parallel","children":[{"type":"Ambient","id":"left","children":[{"type":"Serial","children":[{"type":"In_","id":"arg","children":[{"type":"Open","id":"arg","children":[{"type":"In","id":"string","children":[{"type":"In","id":"concat"}]}]}]}]}]},{"type":"Ambient","id":"right","children":[{"type":"Serial","children":[{"type":"In_","id":"arg","children":[{"type":"Open","id":"arg","children":[{"type":"In","id":"string","children":[{"type":"In","id":"concat"}]}]}]}]}]},{"type":"Ambient","id":"string","children":[{"type":"Parallel","children":[{"type":"Ambient","id":"concat","children":[{"type":"Parallel","children":[{"type":"In_","id":"left"},{"type":"In_","id":"right"}]}]},{"type":"In_","id":"left"},{"type":"In_","id":"right"}]}]},{"type":"Open_","id":"*"}]}]},{"type":"Serial","children":[{"type":"Open","id":"return","children":[{"type":"Open_","id":"*"}]}]}]}]}]}]}]}]} 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Haja Networks OY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const irParser = require('./ir') 2 | const parse = require('./parser') 3 | const js2amb = require('js2amb') 4 | const io = require('orbit-db-io') 5 | const fs = require('fs') 6 | 7 | const ambients = { irParser, parse } 8 | 9 | const js = { 10 | irParser: (js) => { 11 | const ambientSyntax = js2amb(js) 12 | return ambients.irParser.parse(ambientSyntax) 13 | }, 14 | parse: (js) => { 15 | const ambientSyntax = js2amb(js) 16 | return ambients.parse(ambientSyntax) 17 | } 18 | } 19 | 20 | const output = async (ipfs, ambient, argv) => { 21 | // console.log(argv) 22 | // --format option 23 | let result 24 | switch (argv.format) { 25 | case 'ambient': 26 | result = ambient 27 | break 28 | case 'ir': 29 | result = js.irParser.parse(ambient) 30 | break 31 | default: 32 | result = js.parse(ambient) 33 | break 34 | } 35 | 36 | // --display flag 37 | // -o option 38 | if (argv.display) return process.stdout.write(result) 39 | if (argv.o) return fs.writeFileSync(argv.o, result) 40 | 41 | const hash = await io.write(ipfs, 'dag-cbor', result) 42 | return hash 43 | } 44 | 45 | module.exports = { ambients, js, output } 46 | -------------------------------------------------------------------------------- /test/fixtures/ir/008.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "children": [ 6 | { 7 | "id": "x", 8 | "type": "In_", 9 | "children": [{ 10 | "id": "x", 11 | "type": "Open", 12 | "children": [{ 13 | "id": "*", 14 | "type": "Open_" 15 | }] 16 | }] 17 | } 18 | ], 19 | "type": "Serial" 20 | }], 21 | "id": "func", 22 | "type": "Ambient" 23 | }, 24 | { 25 | "children": [{ 26 | "children": [ 27 | { 28 | "children": [ 29 | { 30 | "id": "func", 31 | "type": "In", 32 | "children": [{ 33 | "id": "*", 34 | "type": "Open_" 35 | }] 36 | }], 37 | "type": "Serial" 38 | }, 39 | { 40 | "id": "result", 41 | "type": "Ambient" 42 | } 43 | ], 44 | "type": "Parallel" 45 | }], 46 | "id": "x", 47 | "type": "Ambient" 48 | }, 49 | { 50 | "id": "func", 51 | "type": "Open" 52 | } 53 | ], 54 | "type": "Parallel" 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/fixtures/ir/013.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"Parallel","children":[ 3 | {"type":"Ambient","id":"x","children":[ 4 | {"type":"Parallel","children":[ 5 | {"type":"Ambient","id":"call","children":[ 6 | {"type":"Parallel","children":[ 7 | {"type":"Serial","children":[ 8 | {"type":"Out","id":"x", "children": [ 9 | {"type":"In","id":"y", "children": [ 10 | {"type":"Open_","id":"*"} 11 | ]} 12 | ]} 13 | ]}, 14 | {"type":"Ambient","id":"return","children":[ 15 | {"type":"Serial","children":[ 16 | {"type":"Open_","id":"*", "children": [ 17 | {"type":"In","id":"x"} 18 | ]} 19 | ]} 20 | ]} 21 | ]} 22 | ]}, 23 | {"type":"Serial","children":[ 24 | {"type":"Out_","id":"call", "children": [ 25 | {"type":"In_","id":"y"} 26 | ]} 27 | ]} 28 | ]} 29 | ]}, 30 | {"type":"Ambient","id":"y","children":[ 31 | {"type":"Serial","children":[ 32 | {"type":"In_","id":"call", "children": [ 33 | {"type":"Open","id":"call", "children": [ 34 | {"type":"Open","id":"return"} 35 | ]} 36 | ]} 37 | ]} 38 | ]} 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /test/parser.spec.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | 3 | const { ambients, js } = require('../src') 4 | const fs = require('fs') 5 | 6 | const IR_FIXTURES_PATH = 'test/fixtures/ir/' 7 | const PARSER_FIXTURES_PATH = 'test/fixtures/parser/' 8 | 9 | describe('Parser', function () { 10 | it('Parses ambient syntax into intermediate representation', () => { 11 | const fixtures = fs.readdirSync(IR_FIXTURES_PATH) 12 | while (fixtures.length > 0) { 13 | console.log(`Parsing: ${fixtures[0].split('.')[0]}`) 14 | const syntax = fs.readFileSync(IR_FIXTURES_PATH + fixtures[0]) 15 | // console.log(JSON.stringify(parser.parse(syntax.toString().trim()))) 16 | const result = fs.readFileSync(IR_FIXTURES_PATH + fixtures[1]) 17 | assert.deepStrictEqual(ambients.irParser.parse(syntax.toString().trim()), JSON.parse(result.toString())) 18 | fixtures.splice(0, 2) 19 | } 20 | }) 21 | 22 | it('Parses ambient syntax into machine-readable primitive representation', () => { 23 | const fixtures = fs.readdirSync(PARSER_FIXTURES_PATH) 24 | while (fixtures.length > 0) { 25 | console.log(`Parsing: ${fixtures[0].split('.')[0]}`) 26 | const syntax = fs.readFileSync(PARSER_FIXTURES_PATH + fixtures[0]).toString().trim() 27 | // console.log(JSON.stringify(parse(syntax.toString().trim()))) 28 | const result = fs.readFileSync(PARSER_FIXTURES_PATH + fixtures[1]).toString().trim() 29 | assert.deepStrictEqual(ambients.parse(syntax), JSON.parse(result), `Failed at "${fixtures[0]}`) 30 | fixtures.splice(0, 2) 31 | } 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /src/ir/ambients.pegjs: -------------------------------------------------------------------------------- 1 | Execution 2 | = head:SubExecution tail:(_ ("|") _ SubExecution)+ { 3 | return { 4 | type: "Parallel", 5 | children: tail.reduce((acc, step) => { 6 | step.map((s) => { 7 | if(!s.type) return; 8 | acc.push(s) 9 | }) 10 | return acc 11 | }, [head]) 12 | } 13 | } 14 | / SubExecution 15 | 16 | SubExecution 17 | = head:ThirdTier tail:((".") ThirdTier)+ { 18 | tail = tail.map(t => t[1]) 19 | tail = (function tree (t) { 20 | return t.length > 1 21 | ? [{ ...t[0], children: tree(t.slice(1)) }] 22 | : t 23 | })(tail) 24 | head.children = tail 25 | 26 | return { 27 | type: "Serial", 28 | children: [head] 29 | } 30 | } 31 | / ThirdTier 32 | 33 | ThirdTier 34 | = "(" _ ex:Execution _ ")" { return { type: "Group", children: [ex] }; } 35 | / AMBIENT 36 | / PATH 37 | 38 | AMBIENT 39 | = path:PATH "[]" { return { "type": "Ambient", id: path.trim() }; } 40 | / path:PATH "[" _ ex:Execution _ "]" { 41 | return { type: "Ambient", id: path.trim(), children: [ex] }; 42 | } 43 | 44 | CAPABILITY 45 | = "in_" id:ID* { return { "type": "In_", id: id[0] ? id[0].trim() : '*' }; } 46 | / "in " id:ID { return { "type": "In", id: id.trim() }; } 47 | / "open_" id:ID* { return { "type": "Open_", id: id[0] ? id[0].trim() : '*' }; } 48 | / "open " id:ID { return { "type": "Open", id: id.trim() }; } 49 | / "out_ " id:ID* { return { "type": "Out_", id: id[0] ? id[0].trim() : '*' }; } 50 | / "out " id:ID { return { "type": "Out", id: id.trim() }; } 51 | 52 | PATH 53 | = "nu" _ id:ID { return id; } 54 | / "rec" _ pv:PROCVAR { return pv; } 55 | / pv:PROCVAR { return pv; } 56 | / cap:CAPABILITY { return cap; } 57 | / id:ID { return id; } 58 | 59 | ID "string" = _ [a-zA-Z0-0_\-]+ { return text() } 60 | PROCVAR "string" = [A-Z] { return test() } 61 | 62 | _ "whitespace" = [ \t\n\r]* 63 | -------------------------------------------------------------------------------- /test/fixtures/ir/010.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"Ambient", 3 | "id":"message", 4 | "children":[{ 5 | "type":"Parallel", 6 | "children":[ 7 | {"type":"Serial","children":[ 8 | {"type":"In","id":"func", "children": [ 9 | {"type":"Open_","id":"*"} 10 | ]} 11 | ]}, 12 | {"type":"Ambient","id":"func","children":[{ 13 | "type":"Parallel","children":[ 14 | {"type":"Ambient","id":"x","children":[ 15 | {"type":"Serial","children":[ 16 | {"type":"In_","id":"arg", "children": [ 17 | {"type":"Open","id":"arg", "children": [ 18 | {"type":"In","id":"message", "children": [ 19 | {"type":"Open_","id":"*"} 20 | ]} 21 | ]} 22 | ]} 23 | ]} 24 | ]}, 25 | {"type":"Ambient","id":"message","children":[ 26 | {"type":"Serial","children":[ 27 | {"type":"In_","id":"x", "children": [ 28 | {"type":"Open","id":"x"} 29 | ]} 30 | ]} 31 | ]}, 32 | {"type":"Serial","children":[ 33 | {"type":"In_","id":"arg", "children": [ 34 | {"type":"Open_","id":"*"} 35 | ]} 36 | ]} 37 | ]} 38 | ]} 39 | ]}] 40 | } 41 | -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs') 4 | const mime = require('mime-types') 5 | const { output } = require('./index') 6 | const multiaddr = require('multiaddr') 7 | 8 | const argv = require('yargs') 9 | .usage('$0 [options]', 'Compile source code to ambient syntax or JSON AST', (yargs) => { 10 | yargs 11 | .positional('input', { 12 | describe: 'Path to the source code file you want to compile' 13 | }) 14 | .option('display', { 15 | describe: 'Write output to stdout instead of the output file', 16 | type: 'boolean', 17 | default: false 18 | }) 19 | .option('ipfs-api', { 20 | describe: 'Use an IPFS HTTP API by specifying a multiaddress i.e. "/ip4/127.0.0.1/tcp/5001"' 21 | }) 22 | .option('format', { 23 | describe: 'Output format of the compiler', 24 | choices: ['ambient', 'ir', 'final'], 25 | default: 'final' 26 | }) 27 | .option('o', { 28 | describe: 'Use to specify a custom path to the output file i.e. "./out/function.js"' 29 | }) 30 | }) 31 | .showHelpOnFail(true, 'Specify --help for available options') 32 | .argv 33 | 34 | ;(async (argv) => { 35 | let ipfs 36 | 37 | try { 38 | if (argv['ipfs-api']) { 39 | // --ipfs-api option 40 | const IPFS = require('ipfs-http-client') 41 | const addr = multiaddr(argv['ipfs-api']) 42 | const nodeAddress = addr.nodeAddress() 43 | ipfs = new IPFS(nodeAddress.address, nodeAddress.port) 44 | } else { 45 | const IPFS = require('ipfs') 46 | ipfs = await IPFS.create({ start: false }) 47 | } 48 | } catch (e) { 49 | console.error(e) 50 | throw new Error('Please use npm to install either `ipfs` or `ipfs-http-client`.') 51 | } 52 | 53 | // Register new MIME type for .ambient files 54 | mime.extensions['text/ambients'] = ['ambient'] 55 | mime.types.ambient = 'text/ambients' 56 | 57 | const file = fs.readFileSync(argv.input).toString().trim() 58 | 59 | let result 60 | switch (mime.lookup(argv.input)) { 61 | case 'application/javascript': 62 | result = await output(ipfs, file, argv); break 63 | case 'text/ambients': 64 | result = await output(ipfs, file, argv); break 65 | default: 66 | throw new Error('File type not recognized') 67 | } 68 | 69 | process.stdout.write(result + '\n') 70 | process.exit(0) 71 | })(argv) 72 | -------------------------------------------------------------------------------- /test/fixtures/ir/009.json: -------------------------------------------------------------------------------- 1 | { 2 | "children": [ 3 | { 4 | "children": [{ 5 | "children": [ 6 | { 7 | "id": "x", 8 | "type": "In_", 9 | "children": [{ 10 | "id": "x", 11 | "type": "Open", 12 | "children": [{ 13 | "id": "y", 14 | "type": "In", 15 | "children": [{ 16 | "id": "*", 17 | "type": "Open_" 18 | }] 19 | }] 20 | }] 21 | } 22 | ], 23 | "type": "Serial" 24 | }], 25 | "id": "arg", 26 | "type": "Ambient" 27 | }, 28 | { 29 | "children": [{ 30 | "children": [ 31 | { 32 | "children": [ 33 | { 34 | "id": "arg", 35 | "type": "In", 36 | "children": [{ 37 | "id": "*", 38 | "type": "Open_" 39 | }] 40 | } 41 | ], 42 | "type": "Serial" 43 | }, 44 | { 45 | "id": "input", 46 | "type": "Ambient" 47 | } 48 | ], 49 | "type": "Parallel" 50 | }], 51 | "id": "x", 52 | "type": "Ambient" 53 | }, 54 | { 55 | "children": [{ 56 | "children": [ 57 | { 58 | "id": "arg", 59 | "type": "In_", 60 | "children": [{ 61 | "id": "arg", 62 | "type": "Open", 63 | "children": [{ 64 | "id": "func", 65 | "type": "In", 66 | "children": [{ 67 | "id": "*", 68 | "type": "Open_" 69 | }] 70 | }] 71 | }] 72 | } 73 | ], 74 | "type": "Serial" 75 | }], 76 | "id": "y", 77 | "type": "Ambient" 78 | }, 79 | { 80 | "children": [{ 81 | "children": [ 82 | { 83 | "id": "y", 84 | "type": "In_", 85 | "children": [{ 86 | "id": "y", 87 | "type": "Open", 88 | "children": [{ 89 | "id": "*", 90 | "type": "Open_" 91 | }] 92 | }] 93 | } 94 | ], 95 | "type": "Serial" 96 | }], 97 | "id": "func", 98 | "type": "Ambient" 99 | } 100 | ], 101 | "type": "Parallel" 102 | } 103 | 104 | 105 | -------------------------------------------------------------------------------- /test/dag.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | const IPFS = require('ipfs') 3 | const io = require('orbit-db-io') 4 | const CID = require('cids') 5 | const multihash = require('multihashes') 6 | 7 | const { ambients } = require('../src') 8 | const fs = require('fs') 9 | 10 | const PARSER_FIXTURES_PATH = 'test/fixtures/parser/' 11 | const fixtures = fs.readdirSync(PARSER_FIXTURES_PATH) 12 | 13 | describe('DAG', function () { 14 | let ipfs, cid 15 | 16 | before(async () => { 17 | ipfs = await IPFS.create() 18 | const syntax = fs.readFileSync(PARSER_FIXTURES_PATH + fixtures[6]) 19 | const result = ambients.parse(syntax.toString()) 20 | const hash = await io.write(ipfs, 'dag-cbor', result) 21 | assert.strictEqual(hash, 'zdpuAzo5YJPXi4ToJfY9Nfdx51JnYQ8R8PSQaiLrQ8tW3j211') 22 | cid = new CID(hash) 23 | }) 24 | 25 | it('outputs an IPLD CBOR CID', async () => { 26 | multihash.validate(cid.multihash) 27 | assert.strictEqual(cid.version, 1) 28 | assert.strictEqual(cid.codec, 'dag-cbor') 29 | assert.strictEqual(cid.multibaseName, 'base58btc') 30 | }) 31 | 32 | const dagStruct = (value) => { return { remainderPath: '', value: value } } 33 | 34 | it('can traverse the AST via DAG', async () => { 35 | assert.deepStrictEqual((await ipfs.dag.get(cid, 'name')), dagStruct('')) 36 | assert.deepStrictEqual((await ipfs.dag.get(cid, 'capabilities')), dagStruct([])) 37 | assert.deepStrictEqual((await ipfs.dag.get(cid, 'create')), dagStruct([])) 38 | assert.deepStrictEqual((await ipfs.dag.get(cid, 'children/0/children/0/capabilities')), 39 | dagStruct([{ 40 | next: null, 41 | op: 'out', 42 | target: 'b' 43 | }])) 44 | }) 45 | 46 | it('can traverse the DAG tree', async () => { 47 | const tree = [ 48 | 'name', 49 | 'create', 50 | 'children', 51 | 'children/0', 52 | 'children/0/name', 53 | 'children/0/create', 54 | 'children/0/children', 55 | 'children/0/children/0', 56 | 'children/0/children/0/name', 57 | 'children/0/children/0/create', 58 | 'children/0/children/0/children', 59 | 'children/0/children/0/capabilities', 60 | 'children/0/children/0/capabilities/0', 61 | 'children/0/children/0/capabilities/0/op', 62 | 'children/0/children/0/capabilities/0/next', 63 | 'children/0/children/0/capabilities/0/target', 64 | 'children/0/capabilities', 65 | 'children/0/capabilities/0', 66 | 'children/0/capabilities/0/op', 67 | 'children/0/capabilities/0/next', 68 | 'children/0/capabilities/0/target', 69 | 'capabilities' 70 | ] 71 | assert.deepStrictEqual((await ipfs.dag.tree(cid)), tree) 72 | }) 73 | 74 | after(async () => { 75 | await ipfs.stop() 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /test/fixtures/parser/014.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "children": [ 4 | { 5 | "name": "string_concat", 6 | "children": [], 7 | "capabilities": [ 8 | { 9 | "op": "in_", 10 | "target": "call", 11 | "next": { 12 | "op": "open", 13 | "target": "call", 14 | "next": { 15 | "op": "create", 16 | "target": "", 17 | "next": null 18 | } 19 | } 20 | } 21 | ], 22 | "create": [ 23 | { 24 | "name": "", 25 | "children": [ 26 | { 27 | "name": "func", 28 | "children": [ 29 | { 30 | "name": "left", 31 | "children": [], 32 | "capabilities": [ 33 | { 34 | "op": "in_", 35 | "target": "arg", 36 | "next": { 37 | "op": "open", 38 | "target": "arg", 39 | "next": { 40 | "op": "in", 41 | "target": "string", 42 | "next": { 43 | "op": "in", 44 | "target": "concat", 45 | "next": null 46 | } 47 | } 48 | } 49 | } 50 | ], 51 | "create": [] 52 | }, 53 | { 54 | "name": "right", 55 | "children": [], 56 | "capabilities": [ 57 | { 58 | "op": "in_", 59 | "target": "arg", 60 | "next": { 61 | "op": "open", 62 | "target": "arg", 63 | "next": { 64 | "op": "in", 65 | "target": "string", 66 | "next": { 67 | "op": "in", 68 | "target": "concat", 69 | "next": null 70 | } 71 | } 72 | } 73 | } 74 | ], 75 | "create": [] 76 | }, 77 | { 78 | "name": "string", 79 | "children": [ 80 | { 81 | "name": "concat", 82 | "children": [], 83 | "capabilities": [ 84 | { 85 | "op": "in_", 86 | "target": "left", 87 | "next": null 88 | }, 89 | { 90 | "op": "in_", 91 | "target": "right", 92 | "next": null 93 | } 94 | ], 95 | "create": [] 96 | } 97 | ], 98 | "capabilities": [ 99 | { 100 | "op": "in_", 101 | "target": "left", 102 | "next": null 103 | }, 104 | { 105 | "op": "in_", 106 | "target": "right", 107 | "next": null 108 | } 109 | ], 110 | "create": [] 111 | } 112 | ], 113 | "capabilities": [ 114 | { 115 | "op": "open_", 116 | "target": "", 117 | "next": null 118 | } 119 | ], 120 | "create": [] 121 | } 122 | ], 123 | "capabilities": [ 124 | { 125 | "op": "open", 126 | "target": "return", 127 | "next": { 128 | "op": "open_", 129 | "target": "", 130 | "next": null 131 | } 132 | } 133 | ], 134 | "create": [] 135 | } 136 | ] 137 | } 138 | ], 139 | "capabilities": [], 140 | "create": [] 141 | } -------------------------------------------------------------------------------- /src/parser/index.js: -------------------------------------------------------------------------------- 1 | const Lexer = require('flex-js') 2 | const assert = require("assert") 3 | 4 | // const input = "func[in_ x.open x.open_] | x[in func.open_ | result[y[open_]]] | open func" 5 | 6 | const parse = (input) => { 7 | let depth = 0 8 | let curOp = null 9 | 10 | let ambient = {name: "", children: [], capabilities: [], create: [], prev: null} 11 | let blockParent = null 12 | let parentOp = null 13 | let createMode = false 14 | let createMode2 = false 15 | 16 | const ambientToString = (a) => { 17 | return a.next.map((e, i) => { 18 | let res = "" 19 | if (e.op === "create") { 20 | res += e.target + "[" 21 | } else { 22 | res += e.op + (e.target ? " " + e.target : "") 23 | if (e.next.length > 0) 24 | res += "." 25 | } 26 | 27 | if (i === a.next.length) 28 | res += "" 29 | else 30 | res += ambientToString(e) 31 | 32 | if (e.op === "create") 33 | res += "]" 34 | 35 | if (a.next.length > 1 && i < a.next.length - 1) 36 | res += " | " 37 | 38 | return res 39 | }).join("") 40 | } 41 | 42 | const createNext = (lexer) => { 43 | const [op, target] = lexer.text.split(" ") 44 | // console.log("", " ".repeat(depth), "op!", "op:", op, ", target:", target || "") 45 | if (curOp) { 46 | // curOp.next.push({op, target: target || "", next: []}) 47 | curOp.next = {op, target: target || "", next: null} 48 | curOp = curOp.next 49 | } else { 50 | curOp = {op, target: target || "", next: null} 51 | ambient.capabilities.push(curOp) 52 | } 53 | } 54 | const endOfSequence = () => { 55 | curOp = null 56 | } 57 | 58 | const lexer = new Lexer() 59 | lexer.addState('ambient', true) 60 | lexer.addState('comment', false) 61 | 62 | lexer.addRule(/(in+\s+\w+\b)/, createNext) 63 | lexer.addRule(/(in_+\s+\w+\b)/, createNext) 64 | lexer.addRule(/(out+\s+\w+\b)/, createNext) 65 | lexer.addRule(/(out_+\s+\w+\b)/, createNext) 66 | lexer.addRule(/(open+\s+\w+\b)/, createNext) 67 | lexer.addRule(/(open_+)/, createNext) 68 | lexer.addRule('|', endOfSequence) 69 | lexer.addRule('.', lexer => {}) 70 | lexer.addRule('[', lexer => {}) 71 | lexer.addRule(']', lexer => { 72 | endOfSequence() 73 | // console.log(">>", JSON.stringify(ambient, null, 2)) 74 | const prev = ambient.prev 75 | delete ambient.prev 76 | if (createMode2) 77 | prev.create.push(ambient) 78 | else 79 | prev.children.push(ambient) 80 | ambient = prev 81 | createMode = false 82 | createMode2 = false 83 | }) 84 | 85 | lexer.addRule('(', lexer => { 86 | // console.log() 87 | // console.log("1", ambient) 88 | blockParent = Object.assign({}, ambient) 89 | parentOp = curOp 90 | 91 | let op = {op: "create", target: "", next: null} 92 | curOp.next = op 93 | curOp = null 94 | createMode = true 95 | // ambient.capabilities.push(op) 96 | // ambient.capabilities.push("create") 97 | ambient = {name: "", children: [], capabilities: [], create: [], prev: Object.assign({}, ambient)} 98 | }) 99 | lexer.addRule(')', lexer => { 100 | endOfSequence() 101 | // console.log() 102 | // console.log("2", ambient) 103 | // console.log("------------\n", JSON.stringify(ambient, null, 2)) 104 | // console.log("------------") 105 | const prev = ambient.prev 106 | delete ambient.prev 107 | prev.create.push(ambient) 108 | ambient = prev 109 | curOp = parentOp 110 | createMode = false 111 | // console.log("3", JSON.stringify(ambient, null, 2)) 112 | }) 113 | 114 | lexer.addRule(/\.\w+\b\[/, lexer => { 115 | // console.log("FOUND!", lexer.text) 116 | let op = {op: "create", target: "", next: null} 117 | curOp.next = op 118 | curOp = null 119 | createMode2 = true 120 | // ambient.capabilities.push(op) 121 | let nested = {name: lexer.text.replace('.', '').replace('[', ''), children: [], capabilities: [], create: []} 122 | // ambient.children.push(nested) 123 | nested = {...nested, prev: Object.assign({}, ambient)} 124 | // ambient = {name: "", children: [], capabilities: [], create: [], prev: Object.assign({}, ambient)} 125 | ambient = nested 126 | // lexer.echo() 127 | }) 128 | 129 | // Match words as ambient names 130 | lexer.addRule(/\w+\b/, lexer => { 131 | ambient = {name: lexer.text, children: [], capabilities: [], create: [], prev: ambient} 132 | }) 133 | // Discard everything else 134 | lexer.addRule(/\w/, lexer.discard()) 135 | 136 | // Run 137 | lexer.setSource(input) 138 | lexer.lex() 139 | 140 | delete ambient.prev 141 | // console.log(JSON.stringify(ambient, null, 2)) 142 | return ambient 143 | } 144 | 145 | module.exports = parse -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ambients Protocol Compiler _(ambc)_ 2 | 3 | > Ambient Syntax `a[]` to AST `{ "id": "a", "children": [], "capabilities": [], "create": [] }` 4 | 5 | ## Table of contents 6 | 7 | - [Background](#background) 8 | - [Install](#install) 9 | - [Usage](#usage) 10 | - [Via the command line](#via-the-command-line) 11 | - [In code](#in-code) 12 | - [Description](#description) 13 | - [Supported source languages](#supported-source-languages) 14 | - [Compiler steps](#compiler-steps) 15 | - [Intermediate abstract syntax tree format](#intermediate-abstract-syntax-tree-format) 16 | - [Final abstract syntax tree format](#final-abstract-syntax-tree-format) 17 | - [Compiler Output](#compiler-output) 18 | - [Contributing](#contributing) 19 | - [License](#license) 20 | 21 | ## Background 22 | 23 | [Ambients](https://ambients.org) is a protocol for distributed computation. It allows you to request and execute computation as easily as you can data inside OrbitDB. Think of it like AWS Lambda or Azure Cloud functions, but on a decentralized peer-to-peer network. 24 | 25 | The protocol also includes guarantees as to the verfiability and safety of the code, all without a blockchain. 26 | 27 | ## Install 28 | 29 | ```bash 30 | $ npm install ambc -g 31 | ``` 32 | 33 | First, [install node.js](https://www.nodejs.org) Then: 34 | 35 | ```bash 36 | $ git clone https://github.com/ambientsprotocol/ambc 37 | $ cd ambc 38 | $ npm install 39 | ``` 40 | 41 | ## Usage 42 | 43 | ### Supported source languages 44 | 45 | - Ambients Syntax 46 | - [JavaScript](https://github.com/aphelionz/js2amb) (WIP) 47 | 48 | ### Via the command line 49 | 50 | 51 | Usage for the CLI tool can be viewed by simply running `ambc`: 52 | 53 | ```bash 54 | Compile source code to ambient syntax or JSON AST 55 | 56 | Positionals: 57 | input Path to the source code file you want to compile 58 | 59 | Options: 60 | --help Show help [boolean] 61 | --version Show version number [boolean] 62 | --display Write output to stdout instead of the output file 63 | [boolean] [default: false] 64 | --ipfs-api Use an IPFS HTTP API by specifying a multiaddress i.e. 65 | "/ip4/127.0.0.1/tcp/5001" 66 | --format Output format of the compiler 67 | [choices: "ambient", "ir", "final"] [default: "final"] 68 | -o Use to specify a custom path to the output file i.e. 69 | "./out/function.js" 70 | ``` 71 | 72 | ### In code 73 | 74 | You can also use `ambc` within your JavaScript code. 75 | 76 | ```JavaScript 77 | const js2amb = require('js2amb') 78 | const { irParser, parse } = require('ambc') 79 | 80 | const js = '() => "hello"' 81 | 82 | const ambientSyntax = js2amb(js) // Outputs ambient syntax from JS 83 | const irAst = irParser.parse(js) // Outputs intermediate representation AST 84 | const finalAst = parse(js) // Outputs final AST 85 | ``` 86 | 87 | Note that to get ambient syntax from JavaScript, you will also need `js2amb`. 88 | 89 | ## Description 90 | 91 | From the [Ambients whitepaper](https://github.com/ambientsprotocol/whitepaper/blob/master/06-compilation-model.md#translating-ambients-programs): 92 | 93 | > The Ambients protocol overall is programming language-agnostic. That means almost any programming language can be used to write distributed programs, as long as there's a compiler that can process the source language and turn it into the Ambients bytecode. While most common programming languages can be used, due to the protocol primitives, functions and types, functional languages are especially well-suited to write distributed programs. 94 | 95 | > Compilation model requires all compilers to: 96 | 97 | > 1. compile original source code to an intermediate abstract syntax structure (usually as in Abstract Syntax Tree) 98 | > 2. translate the intermediate structure to the computation primitives, distribution primitives and computation abstractions of the Ambients protocol 99 | > 3. generate the bytecode executable from the primitives 100 | 101 | `ambc` satisfies requirements #1 and #2 by compiling ambients syntax, and JavaScript into either an intermeidate representation or final [Abstract Syntax Tree](#intermediate-abstract-syntax-tree-format). 102 | 103 | Both ASTs are lossless encodings, meaning that no data is lost from the ambient syntax and by-proxy the original JS code. Downstream components in the overall system can satisfy requirement #3 as required. 104 | 105 | ### Compiler steps 106 | 107 | The compiler is very simple, and has only two primary steps, the second of which has two different types of output (IR vs final) 108 | 109 | #### Step 1: Source code -> Ambients syntax 110 | 111 | Compile source code from JavaScript (other languages TBD) to Ambient ASCII syntax. Users can choose to output ambient syntax by passing the `--format ambient` option to `ambc` 112 | 113 | 114 | For example: 115 | 116 | ```JavaScript 117 | () => "hello" 118 | ``` 119 | ⬇ 120 | ```text 121 | func[ 122 | open_| 123 | string[hello[]] 124 | ]| 125 | open func 126 | ``` 127 | 128 | #### Step 2a: Ambients Syntax to intermediate representation (IR) AST 129 | 130 | Users can choose to display an IR AST by passing the `--format ir` option to `ambc`. 131 | 132 | ```text 133 | func[ 134 | open_| 135 | string[hello[]] 136 | ]| 137 | open func 138 | ``` 139 | ⬇ 140 | ```json 141 | { "type": "Parallel", "children": [ 142 | { "type": "Ambient", "id": "func", "children": [ 143 | { "type": "Parallel", "children": [ 144 | { "type": "Open_", "id": "*" }, 145 | { "type": "Ambient", "id": "string", "children": [ 146 | { "type": "Noop", "id": "hello" } 147 | ]} 148 | ]}, 149 | { "type": "Open", "id": "func" } 150 | ]} 151 | ]} 152 | ``` 153 | 154 | #### Step 2b: Ambients Syntax to final AST 155 | 156 | This is the default output of the compiler, which encodes protocol primitives into the JSON. 157 | 158 | ```text 159 | func[ 160 | open_| 161 | string[hello[]] 162 | ]| 163 | open func 164 | ``` 165 | ⬇ 166 | ```json 167 | { 168 | "name": "", 169 | "children": [], 170 | "capabilities": [ 171 | "in_ call", 172 | "open call", 173 | "create" 174 | ], 175 | "create": [ 176 | { 177 | "name": "", 178 | "children": [], 179 | "capabilities": [ 180 | "open return", 181 | "open_" 182 | ], 183 | "create": [] 184 | } 185 | ] 186 | } 187 | ``` 188 | 189 | ### Intermediate abstract syntax tree format 190 | 191 | The IR AST exceedingly and intentionally naive. It simply encodes the ambient syntax directly using a recursive structure of nodes. 192 | 193 | Each node has three fields: 194 | 195 | 1. `type`: **Required** - the type of the ambient, a string enum which can be one of: 196 | - Parallel 197 | - Serial 198 | - Group 199 | - Ambient 200 | - In_ 201 | - In 202 | - Out_ 203 | - Open 204 | - Open_ 205 | 2. `id`: _Optional_ - a string identifier 206 | 3. `children` _Optional_ - array of more child nodes 207 | 208 | The idea here is that it is the simplest possible encoding that does not lose any of the data presented in the original ASCII syntax. Once the tree is generated it can be stored as a DAG on any compatible store. In development we simply use the in-memory structures to work with, but in practice we will likely use IPFS or IPLD. 209 | 210 | ### Final abstract syntax tree format 211 | 212 | The final AST format encodes protocol primitives into the JSON and is more meant for machine consumption. It has the following format. Note that all fields are **required** but initialized with default blank values. 213 | 214 | Each node in the structure has three fields: 215 | 216 | 1. `name`: The name of the ambient 217 | 2. `capabilities`: The capabilities and co-capabilitie of the ambient. Each capability has three fields: 218 | 1. `op`: The operation to take, one of: 219 | - in 220 | - in_ 221 | - out 222 | - out_ 223 | - open 224 | - open_ 225 | 2. `target`: The name of the ambient the capability refers to 226 | 3. `next`: The action to take after the capability has completed 227 | 3. `children`: array of one or more child ambients. 228 | 4. `create`: used to encode group execution, `( )` in the ambient syntax. 229 | 230 | Parallel computation is simply encoded using arrays, and serial computation is encoded using a tree structure, using the `children` field. 231 | 232 | ### Compiler Output 233 | 234 | If no output `-o` is specified, and the `--display` flag is not used, `ambc` will return 235 | a [multihash](https://github.com/multiformats/multihash) from an `ipfs dag put` operation. 236 | 237 | This hash will be used by the execution engine to run the code on a distributed, peer to peer 238 | network. 239 | 240 | ## Contributing 241 | 242 | Please do! Issues and PRs are very welcome. 243 | 244 | If you're _at all_ interested in this topic you should definitely 245 | [seek us out on Gitter](https://gitter.im/ambientsprotocol/community), open issues, and submit PRs. 246 | 247 | To run the tests: 248 | 249 | ```bash 250 | $ npm install 251 | $ npm test 252 | ``` 253 | 254 | ### Contribution Notes: 255 | - `npm test` is mapped to `make test` and either command should produce identical output. 256 | - To edit the IR parser syntax, edit the grammar at `src/ir/ambients.pegjs` and then run `make build` to build the `parser.js` file (optimized for speed) and its little buddy the `parser-tiny.js` file, optimized for size. 257 | - To edit the final parser syntax, edit the js file at `src/parser/index.js` directly. 258 | 259 | ## License 260 | 261 | [MIT](LICENSE) © Haja Networks Oy 262 | -------------------------------------------------------------------------------- /src/ir/tiny.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated by PEG.js 0.10.0. 3 | * 4 | * http://pegjs.org/ 5 | */ 6 | 7 | "use strict"; 8 | 9 | function peg$subclass(child, parent) { 10 | function ctor() { this.constructor = child; } 11 | ctor.prototype = parent.prototype; 12 | child.prototype = new ctor(); 13 | } 14 | 15 | function peg$SyntaxError(message, expected, found, location) { 16 | this.message = message; 17 | this.expected = expected; 18 | this.found = found; 19 | this.location = location; 20 | this.name = "SyntaxError"; 21 | 22 | if (typeof Error.captureStackTrace === "function") { 23 | Error.captureStackTrace(this, peg$SyntaxError); 24 | } 25 | } 26 | 27 | peg$subclass(peg$SyntaxError, Error); 28 | 29 | peg$SyntaxError.buildMessage = function(expected, found) { 30 | var DESCRIBE_EXPECTATION_FNS = { 31 | literal: function(expectation) { 32 | return "\"" + literalEscape(expectation.text) + "\""; 33 | }, 34 | 35 | "class": function(expectation) { 36 | var escapedParts = "", 37 | i; 38 | 39 | for (i = 0; i < expectation.parts.length; i++) { 40 | escapedParts += expectation.parts[i] instanceof Array 41 | ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) 42 | : classEscape(expectation.parts[i]); 43 | } 44 | 45 | return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; 46 | }, 47 | 48 | any: function(expectation) { 49 | return "any character"; 50 | }, 51 | 52 | end: function(expectation) { 53 | return "end of input"; 54 | }, 55 | 56 | other: function(expectation) { 57 | return expectation.description; 58 | } 59 | }; 60 | 61 | function hex(ch) { 62 | return ch.charCodeAt(0).toString(16).toUpperCase(); 63 | } 64 | 65 | function literalEscape(s) { 66 | return s 67 | .replace(/\\/g, '\\\\') 68 | .replace(/"/g, '\\"') 69 | .replace(/\0/g, '\\0') 70 | .replace(/\t/g, '\\t') 71 | .replace(/\n/g, '\\n') 72 | .replace(/\r/g, '\\r') 73 | .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) 74 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); 75 | } 76 | 77 | function classEscape(s) { 78 | return s 79 | .replace(/\\/g, '\\\\') 80 | .replace(/\]/g, '\\]') 81 | .replace(/\^/g, '\\^') 82 | .replace(/-/g, '\\-') 83 | .replace(/\0/g, '\\0') 84 | .replace(/\t/g, '\\t') 85 | .replace(/\n/g, '\\n') 86 | .replace(/\r/g, '\\r') 87 | .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) 88 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); 89 | } 90 | 91 | function describeExpectation(expectation) { 92 | return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); 93 | } 94 | 95 | function describeExpected(expected) { 96 | var descriptions = new Array(expected.length), 97 | i, j; 98 | 99 | for (i = 0; i < expected.length; i++) { 100 | descriptions[i] = describeExpectation(expected[i]); 101 | } 102 | 103 | descriptions.sort(); 104 | 105 | if (descriptions.length > 0) { 106 | for (i = 1, j = 1; i < descriptions.length; i++) { 107 | if (descriptions[i - 1] !== descriptions[i]) { 108 | descriptions[j] = descriptions[i]; 109 | j++; 110 | } 111 | } 112 | descriptions.length = j; 113 | } 114 | 115 | switch (descriptions.length) { 116 | case 1: 117 | return descriptions[0]; 118 | 119 | case 2: 120 | return descriptions[0] + " or " + descriptions[1]; 121 | 122 | default: 123 | return descriptions.slice(0, -1).join(", ") 124 | + ", or " 125 | + descriptions[descriptions.length - 1]; 126 | } 127 | } 128 | 129 | function describeFound(found) { 130 | return found ? "\"" + literalEscape(found) + "\"" : "end of input"; 131 | } 132 | 133 | return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; 134 | }; 135 | 136 | function peg$parse(input, options) { 137 | options = options !== void 0 ? options : {}; 138 | 139 | var peg$FAILED = {}, 140 | 141 | peg$startRuleIndices = { Execution: 0 }, 142 | peg$startRuleIndex = 0, 143 | 144 | peg$consts = [ 145 | "|", 146 | peg$literalExpectation("|", false), 147 | function(head, tail) { 148 | return { 149 | type: "Parallel", 150 | children: tail.reduce((acc, step) => { 151 | step.map((s) => { 152 | if(!s.type) return; 153 | acc.push(s) 154 | }) 155 | return acc 156 | }, [head]) 157 | } 158 | }, 159 | ".", 160 | peg$literalExpectation(".", false), 161 | function(head, tail) { 162 | tail = tail.map(t => t[1]) 163 | tail = (function tree (t) { 164 | return t.length > 1 165 | ? [{ ...t[0], children: tree(t.slice(1)) }] 166 | : t 167 | })(tail) 168 | head.children = tail 169 | 170 | return { 171 | type: "Serial", 172 | children: [head] 173 | } 174 | }, 175 | "(", 176 | peg$literalExpectation("(", false), 177 | ")", 178 | peg$literalExpectation(")", false), 179 | function(ex) { return { type: "Group", children: [ex] }; }, 180 | "[]", 181 | peg$literalExpectation("[]", false), 182 | function(path) { return { "type": "Ambient", id: path.trim() }; }, 183 | "[", 184 | peg$literalExpectation("[", false), 185 | "]", 186 | peg$literalExpectation("]", false), 187 | function(path, ex) { 188 | return { type: "Ambient", id: path.trim(), children: [ex] }; 189 | }, 190 | "in_", 191 | peg$literalExpectation("in_", false), 192 | function(id) { return { "type": "In_", id: id[0] ? id[0].trim() : '*' }; }, 193 | "in ", 194 | peg$literalExpectation("in ", false), 195 | function(id) { return { "type": "In", id: id.trim() }; }, 196 | "open_", 197 | peg$literalExpectation("open_", false), 198 | function(id) { return { "type": "Open_", id: id[0] ? id[0].trim() : '*' }; }, 199 | "open ", 200 | peg$literalExpectation("open ", false), 201 | function(id) { return { "type": "Open", id: id.trim() }; }, 202 | "out_ ", 203 | peg$literalExpectation("out_ ", false), 204 | function(id) { return { "type": "Out_", id: id[0] ? id[0].trim() : '*' }; }, 205 | "out ", 206 | peg$literalExpectation("out ", false), 207 | function(id) { return { "type": "Out", id: id.trim() }; }, 208 | "nu", 209 | peg$literalExpectation("nu", false), 210 | function(id) { return id; }, 211 | "rec", 212 | peg$literalExpectation("rec", false), 213 | function(pv) { return pv; }, 214 | function(cap) { return cap; }, 215 | peg$otherExpectation("string"), 216 | /^[a-zA-Z0-0_\-]/, 217 | peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "0"], "_", "-"], false, false), 218 | function() { return text() }, 219 | /^[A-Z]/, 220 | peg$classExpectation([["A", "Z"]], false, false), 221 | function() { return test() }, 222 | peg$otherExpectation("whitespace"), 223 | /^[ \t\n\r]/, 224 | peg$classExpectation([" ", "\t", "\n", "\r"], false, false) 225 | ], 226 | 227 | peg$bytecode = [ 228 | peg$decode("%;!/\x95#$%;(/D#2 \"\"6 7!/5$;(/,$;!/#$+$)($'#(#'#(\"'#&'#/Q#0N*%;(/D#2 \"\"6 7!/5$;(/,$;!/#$+$)($'#(#'#(\"'#&'#&&&#/)$8\":\"\"\"! )(\"'#&'#.# &;!"), 229 | peg$decode("%;\"/q#$%2#\"\"6#7$/,#;\"/#$+\")(\"'#&'#/?#0<*%2#\"\"6#7$/,#;\"/#$+\")(\"'#&'#&&&#/)$8\":%\"\"! )(\"'#&'#.# &;\""), 230 | peg$decode("%2&\"\"6&7'/R#;(/I$; /@$;(/7$2(\"\"6(7)/($8%:*%!\")(%'#($'#(#'#(\"'#&'#.) &;#.# &;%"), 231 | peg$decode("%;%/7#2+\"\"6+7,/($8\":-\"!!)(\"'#&'#.l &%;%/b#2.\"\"6.7//S$;(/J$; /A$;(/8$20\"\"6071/)$8&:2&\"%\")(&'#(%'#($'#(#'#(\"'#&'#"), 232 | peg$decode("%23\"\"6374/8#$;&0#*;&&/($8\":5\"! )(\"'#&'#.\xDF &%26\"\"6677/1#;&/($8\":8\"! )(\"'#&'#.\xBB &%29\"\"697:/8#$;&0#*;&&/($8\":;\"! )(\"'#&'#.\x90 &%2<\"\"6<7=/1#;&/($8\":>\"! )(\"'#&'#.l &%2?\"\"6?7@/8#$;&0#*;&&/($8\":A\"! )(\"'#&'#.A &%2B\"\"6B7C/1#;&/($8\":D\"! )(\"'#&'#"), 233 | peg$decode("%2E\"\"6E7F/:#;(/1$;&/($8#:G#! )(#'#(\"'#&'#.\x80 &%2H\"\"6H7I/:#;(/1$;'/($8#:J#! )(#'#(\"'#&'#.S &%;'/' 8!:J!! ).A &%;$/' 8!:K!! )./ &%;&/' 8!:G!! )"), 234 | peg$decode("<%;(/I#$4M\"\"5!7N/,#0)*4M\"\"5!7N&&&#/'$8\":O\" )(\"'#&'#=.\" 7L"), 235 | peg$decode("<%4P\"\"5!7Q/& 8!:R! )=.\" 7L"), 236 | peg$decode("<$4T\"\"5!7U0)*4T\"\"5!7U&=.\" 7S") 237 | ], 238 | 239 | peg$currPos = 0, 240 | peg$savedPos = 0, 241 | peg$posDetailsCache = [{ line: 1, column: 1 }], 242 | peg$maxFailPos = 0, 243 | peg$maxFailExpected = [], 244 | peg$silentFails = 0, 245 | 246 | peg$result; 247 | 248 | if ("startRule" in options) { 249 | if (!(options.startRule in peg$startRuleIndices)) { 250 | throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); 251 | } 252 | 253 | peg$startRuleIndex = peg$startRuleIndices[options.startRule]; 254 | } 255 | 256 | function text() { 257 | return input.substring(peg$savedPos, peg$currPos); 258 | } 259 | 260 | function location() { 261 | return peg$computeLocation(peg$savedPos, peg$currPos); 262 | } 263 | 264 | function expected(description, location) { 265 | location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) 266 | 267 | throw peg$buildStructuredError( 268 | [peg$otherExpectation(description)], 269 | input.substring(peg$savedPos, peg$currPos), 270 | location 271 | ); 272 | } 273 | 274 | function error(message, location) { 275 | location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) 276 | 277 | throw peg$buildSimpleError(message, location); 278 | } 279 | 280 | function peg$literalExpectation(text, ignoreCase) { 281 | return { type: "literal", text: text, ignoreCase: ignoreCase }; 282 | } 283 | 284 | function peg$classExpectation(parts, inverted, ignoreCase) { 285 | return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; 286 | } 287 | 288 | function peg$anyExpectation() { 289 | return { type: "any" }; 290 | } 291 | 292 | function peg$endExpectation() { 293 | return { type: "end" }; 294 | } 295 | 296 | function peg$otherExpectation(description) { 297 | return { type: "other", description: description }; 298 | } 299 | 300 | function peg$computePosDetails(pos) { 301 | var details = peg$posDetailsCache[pos], p; 302 | 303 | if (details) { 304 | return details; 305 | } else { 306 | p = pos - 1; 307 | while (!peg$posDetailsCache[p]) { 308 | p--; 309 | } 310 | 311 | details = peg$posDetailsCache[p]; 312 | details = { 313 | line: details.line, 314 | column: details.column 315 | }; 316 | 317 | while (p < pos) { 318 | if (input.charCodeAt(p) === 10) { 319 | details.line++; 320 | details.column = 1; 321 | } else { 322 | details.column++; 323 | } 324 | 325 | p++; 326 | } 327 | 328 | peg$posDetailsCache[pos] = details; 329 | return details; 330 | } 331 | } 332 | 333 | function peg$computeLocation(startPos, endPos) { 334 | var startPosDetails = peg$computePosDetails(startPos), 335 | endPosDetails = peg$computePosDetails(endPos); 336 | 337 | return { 338 | start: { 339 | offset: startPos, 340 | line: startPosDetails.line, 341 | column: startPosDetails.column 342 | }, 343 | end: { 344 | offset: endPos, 345 | line: endPosDetails.line, 346 | column: endPosDetails.column 347 | } 348 | }; 349 | } 350 | 351 | function peg$fail(expected) { 352 | if (peg$currPos < peg$maxFailPos) { return; } 353 | 354 | if (peg$currPos > peg$maxFailPos) { 355 | peg$maxFailPos = peg$currPos; 356 | peg$maxFailExpected = []; 357 | } 358 | 359 | peg$maxFailExpected.push(expected); 360 | } 361 | 362 | function peg$buildSimpleError(message, location) { 363 | return new peg$SyntaxError(message, null, null, location); 364 | } 365 | 366 | function peg$buildStructuredError(expected, found, location) { 367 | return new peg$SyntaxError( 368 | peg$SyntaxError.buildMessage(expected, found), 369 | expected, 370 | found, 371 | location 372 | ); 373 | } 374 | 375 | function peg$decode(s) { 376 | var bc = new Array(s.length), i; 377 | 378 | for (i = 0; i < s.length; i++) { 379 | bc[i] = s.charCodeAt(i) - 32; 380 | } 381 | 382 | return bc; 383 | } 384 | 385 | function peg$parseRule(index) { 386 | var bc = peg$bytecode[index], 387 | ip = 0, 388 | ips = [], 389 | end = bc.length, 390 | ends = [], 391 | stack = [], 392 | params, i; 393 | 394 | while (true) { 395 | while (ip < end) { 396 | switch (bc[ip]) { 397 | case 0: 398 | stack.push(peg$consts[bc[ip + 1]]); 399 | ip += 2; 400 | break; 401 | 402 | case 1: 403 | stack.push(void 0); 404 | ip++; 405 | break; 406 | 407 | case 2: 408 | stack.push(null); 409 | ip++; 410 | break; 411 | 412 | case 3: 413 | stack.push(peg$FAILED); 414 | ip++; 415 | break; 416 | 417 | case 4: 418 | stack.push([]); 419 | ip++; 420 | break; 421 | 422 | case 5: 423 | stack.push(peg$currPos); 424 | ip++; 425 | break; 426 | 427 | case 6: 428 | stack.pop(); 429 | ip++; 430 | break; 431 | 432 | case 7: 433 | peg$currPos = stack.pop(); 434 | ip++; 435 | break; 436 | 437 | case 8: 438 | stack.length -= bc[ip + 1]; 439 | ip += 2; 440 | break; 441 | 442 | case 9: 443 | stack.splice(-2, 1); 444 | ip++; 445 | break; 446 | 447 | case 10: 448 | stack[stack.length - 2].push(stack.pop()); 449 | ip++; 450 | break; 451 | 452 | case 11: 453 | stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1])); 454 | ip += 2; 455 | break; 456 | 457 | case 12: 458 | stack.push(input.substring(stack.pop(), peg$currPos)); 459 | ip++; 460 | break; 461 | 462 | case 13: 463 | ends.push(end); 464 | ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); 465 | 466 | if (stack[stack.length - 1]) { 467 | end = ip + 3 + bc[ip + 1]; 468 | ip += 3; 469 | } else { 470 | end = ip + 3 + bc[ip + 1] + bc[ip + 2]; 471 | ip += 3 + bc[ip + 1]; 472 | } 473 | 474 | break; 475 | 476 | case 14: 477 | ends.push(end); 478 | ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); 479 | 480 | if (stack[stack.length - 1] === peg$FAILED) { 481 | end = ip + 3 + bc[ip + 1]; 482 | ip += 3; 483 | } else { 484 | end = ip + 3 + bc[ip + 1] + bc[ip + 2]; 485 | ip += 3 + bc[ip + 1]; 486 | } 487 | 488 | break; 489 | 490 | case 15: 491 | ends.push(end); 492 | ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); 493 | 494 | if (stack[stack.length - 1] !== peg$FAILED) { 495 | end = ip + 3 + bc[ip + 1]; 496 | ip += 3; 497 | } else { 498 | end = ip + 3 + bc[ip + 1] + bc[ip + 2]; 499 | ip += 3 + bc[ip + 1]; 500 | } 501 | 502 | break; 503 | 504 | case 16: 505 | if (stack[stack.length - 1] !== peg$FAILED) { 506 | ends.push(end); 507 | ips.push(ip); 508 | 509 | end = ip + 2 + bc[ip + 1]; 510 | ip += 2; 511 | } else { 512 | ip += 2 + bc[ip + 1]; 513 | } 514 | 515 | break; 516 | 517 | case 17: 518 | ends.push(end); 519 | ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); 520 | 521 | if (input.length > peg$currPos) { 522 | end = ip + 3 + bc[ip + 1]; 523 | ip += 3; 524 | } else { 525 | end = ip + 3 + bc[ip + 1] + bc[ip + 2]; 526 | ip += 3 + bc[ip + 1]; 527 | } 528 | 529 | break; 530 | 531 | case 18: 532 | ends.push(end); 533 | ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); 534 | 535 | if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) { 536 | end = ip + 4 + bc[ip + 2]; 537 | ip += 4; 538 | } else { 539 | end = ip + 4 + bc[ip + 2] + bc[ip + 3]; 540 | ip += 4 + bc[ip + 2]; 541 | } 542 | 543 | break; 544 | 545 | case 19: 546 | ends.push(end); 547 | ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); 548 | 549 | if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) { 550 | end = ip + 4 + bc[ip + 2]; 551 | ip += 4; 552 | } else { 553 | end = ip + 4 + bc[ip + 2] + bc[ip + 3]; 554 | ip += 4 + bc[ip + 2]; 555 | } 556 | 557 | break; 558 | 559 | case 20: 560 | ends.push(end); 561 | ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); 562 | 563 | if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) { 564 | end = ip + 4 + bc[ip + 2]; 565 | ip += 4; 566 | } else { 567 | end = ip + 4 + bc[ip + 2] + bc[ip + 3]; 568 | ip += 4 + bc[ip + 2]; 569 | } 570 | 571 | break; 572 | 573 | case 21: 574 | stack.push(input.substr(peg$currPos, bc[ip + 1])); 575 | peg$currPos += bc[ip + 1]; 576 | ip += 2; 577 | break; 578 | 579 | case 22: 580 | stack.push(peg$consts[bc[ip + 1]]); 581 | peg$currPos += peg$consts[bc[ip + 1]].length; 582 | ip += 2; 583 | break; 584 | 585 | case 23: 586 | stack.push(peg$FAILED); 587 | if (peg$silentFails === 0) { 588 | peg$fail(peg$consts[bc[ip + 1]]); 589 | } 590 | ip += 2; 591 | break; 592 | 593 | case 24: 594 | peg$savedPos = stack[stack.length - 1 - bc[ip + 1]]; 595 | ip += 2; 596 | break; 597 | 598 | case 25: 599 | peg$savedPos = peg$currPos; 600 | ip++; 601 | break; 602 | 603 | case 26: 604 | params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]); 605 | for (i = 0; i < bc[ip + 3]; i++) { 606 | params[i] = stack[stack.length - 1 - params[i]]; 607 | } 608 | 609 | stack.splice( 610 | stack.length - bc[ip + 2], 611 | bc[ip + 2], 612 | peg$consts[bc[ip + 1]].apply(null, params) 613 | ); 614 | 615 | ip += 4 + bc[ip + 3]; 616 | break; 617 | 618 | case 27: 619 | stack.push(peg$parseRule(bc[ip + 1])); 620 | ip += 2; 621 | break; 622 | 623 | case 28: 624 | peg$silentFails++; 625 | ip++; 626 | break; 627 | 628 | case 29: 629 | peg$silentFails--; 630 | ip++; 631 | break; 632 | 633 | default: 634 | throw new Error("Invalid opcode: " + bc[ip] + "."); 635 | } 636 | } 637 | 638 | if (ends.length > 0) { 639 | end = ends.pop(); 640 | ip = ips.pop(); 641 | } else { 642 | break; 643 | } 644 | } 645 | 646 | return stack[0]; 647 | } 648 | 649 | peg$result = peg$parseRule(peg$startRuleIndex); 650 | 651 | if (peg$result !== peg$FAILED && peg$currPos === input.length) { 652 | return peg$result; 653 | } else { 654 | if (peg$result !== peg$FAILED && peg$currPos < input.length) { 655 | peg$fail(peg$endExpectation()); 656 | } 657 | 658 | throw peg$buildStructuredError( 659 | peg$maxFailExpected, 660 | peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, 661 | peg$maxFailPos < input.length 662 | ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) 663 | : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) 664 | ); 665 | } 666 | } 667 | 668 | module.exports = { 669 | SyntaxError: peg$SyntaxError, 670 | parse: peg$parse 671 | }; 672 | -------------------------------------------------------------------------------- /src/ir/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Generated by PEG.js 0.10.0. 3 | * 4 | * http://pegjs.org/ 5 | */ 6 | 7 | "use strict"; 8 | 9 | function peg$subclass(child, parent) { 10 | function ctor() { this.constructor = child; } 11 | ctor.prototype = parent.prototype; 12 | child.prototype = new ctor(); 13 | } 14 | 15 | function peg$SyntaxError(message, expected, found, location) { 16 | this.message = message; 17 | this.expected = expected; 18 | this.found = found; 19 | this.location = location; 20 | this.name = "SyntaxError"; 21 | 22 | if (typeof Error.captureStackTrace === "function") { 23 | Error.captureStackTrace(this, peg$SyntaxError); 24 | } 25 | } 26 | 27 | peg$subclass(peg$SyntaxError, Error); 28 | 29 | peg$SyntaxError.buildMessage = function(expected, found) { 30 | var DESCRIBE_EXPECTATION_FNS = { 31 | literal: function(expectation) { 32 | return "\"" + literalEscape(expectation.text) + "\""; 33 | }, 34 | 35 | "class": function(expectation) { 36 | var escapedParts = "", 37 | i; 38 | 39 | for (i = 0; i < expectation.parts.length; i++) { 40 | escapedParts += expectation.parts[i] instanceof Array 41 | ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) 42 | : classEscape(expectation.parts[i]); 43 | } 44 | 45 | return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; 46 | }, 47 | 48 | any: function(expectation) { 49 | return "any character"; 50 | }, 51 | 52 | end: function(expectation) { 53 | return "end of input"; 54 | }, 55 | 56 | other: function(expectation) { 57 | return expectation.description; 58 | } 59 | }; 60 | 61 | function hex(ch) { 62 | return ch.charCodeAt(0).toString(16).toUpperCase(); 63 | } 64 | 65 | function literalEscape(s) { 66 | return s 67 | .replace(/\\/g, '\\\\') 68 | .replace(/"/g, '\\"') 69 | .replace(/\0/g, '\\0') 70 | .replace(/\t/g, '\\t') 71 | .replace(/\n/g, '\\n') 72 | .replace(/\r/g, '\\r') 73 | .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) 74 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); 75 | } 76 | 77 | function classEscape(s) { 78 | return s 79 | .replace(/\\/g, '\\\\') 80 | .replace(/\]/g, '\\]') 81 | .replace(/\^/g, '\\^') 82 | .replace(/-/g, '\\-') 83 | .replace(/\0/g, '\\0') 84 | .replace(/\t/g, '\\t') 85 | .replace(/\n/g, '\\n') 86 | .replace(/\r/g, '\\r') 87 | .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) 88 | .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); 89 | } 90 | 91 | function describeExpectation(expectation) { 92 | return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); 93 | } 94 | 95 | function describeExpected(expected) { 96 | var descriptions = new Array(expected.length), 97 | i, j; 98 | 99 | for (i = 0; i < expected.length; i++) { 100 | descriptions[i] = describeExpectation(expected[i]); 101 | } 102 | 103 | descriptions.sort(); 104 | 105 | if (descriptions.length > 0) { 106 | for (i = 1, j = 1; i < descriptions.length; i++) { 107 | if (descriptions[i - 1] !== descriptions[i]) { 108 | descriptions[j] = descriptions[i]; 109 | j++; 110 | } 111 | } 112 | descriptions.length = j; 113 | } 114 | 115 | switch (descriptions.length) { 116 | case 1: 117 | return descriptions[0]; 118 | 119 | case 2: 120 | return descriptions[0] + " or " + descriptions[1]; 121 | 122 | default: 123 | return descriptions.slice(0, -1).join(", ") 124 | + ", or " 125 | + descriptions[descriptions.length - 1]; 126 | } 127 | } 128 | 129 | function describeFound(found) { 130 | return found ? "\"" + literalEscape(found) + "\"" : "end of input"; 131 | } 132 | 133 | return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; 134 | }; 135 | 136 | function peg$parse(input, options) { 137 | options = options !== void 0 ? options : {}; 138 | 139 | var peg$FAILED = {}, 140 | 141 | peg$startRuleFunctions = { Execution: peg$parseExecution }, 142 | peg$startRuleFunction = peg$parseExecution, 143 | 144 | peg$c0 = "|", 145 | peg$c1 = peg$literalExpectation("|", false), 146 | peg$c2 = function(head, tail) { 147 | return { 148 | type: "Parallel", 149 | children: tail.reduce((acc, step) => { 150 | step.map((s) => { 151 | if(!s.type) return; 152 | acc.push(s) 153 | }) 154 | return acc 155 | }, [head]) 156 | } 157 | }, 158 | peg$c3 = ".", 159 | peg$c4 = peg$literalExpectation(".", false), 160 | peg$c5 = function(head, tail) { 161 | tail = tail.map(t => t[1]) 162 | tail = (function tree (t) { 163 | return t.length > 1 164 | ? [{ ...t[0], children: tree(t.slice(1)) }] 165 | : t 166 | })(tail) 167 | head.children = tail 168 | 169 | return { 170 | type: "Serial", 171 | children: [head] 172 | } 173 | }, 174 | peg$c6 = "(", 175 | peg$c7 = peg$literalExpectation("(", false), 176 | peg$c8 = ")", 177 | peg$c9 = peg$literalExpectation(")", false), 178 | peg$c10 = function(ex) { return { type: "Group", children: [ex] }; }, 179 | peg$c11 = "[]", 180 | peg$c12 = peg$literalExpectation("[]", false), 181 | peg$c13 = function(path) { return { "type": "Ambient", id: path.trim() }; }, 182 | peg$c14 = "[", 183 | peg$c15 = peg$literalExpectation("[", false), 184 | peg$c16 = "]", 185 | peg$c17 = peg$literalExpectation("]", false), 186 | peg$c18 = function(path, ex) { 187 | return { type: "Ambient", id: path.trim(), children: [ex] }; 188 | }, 189 | peg$c19 = "in_", 190 | peg$c20 = peg$literalExpectation("in_", false), 191 | peg$c21 = function(id) { return { "type": "In_", id: id[0] ? id[0].trim() : '*' }; }, 192 | peg$c22 = "in ", 193 | peg$c23 = peg$literalExpectation("in ", false), 194 | peg$c24 = function(id) { return { "type": "In", id: id.trim() }; }, 195 | peg$c25 = "open_", 196 | peg$c26 = peg$literalExpectation("open_", false), 197 | peg$c27 = function(id) { return { "type": "Open_", id: id[0] ? id[0].trim() : '*' }; }, 198 | peg$c28 = "open ", 199 | peg$c29 = peg$literalExpectation("open ", false), 200 | peg$c30 = function(id) { return { "type": "Open", id: id.trim() }; }, 201 | peg$c31 = "out_ ", 202 | peg$c32 = peg$literalExpectation("out_ ", false), 203 | peg$c33 = function(id) { return { "type": "Out_", id: id[0] ? id[0].trim() : '*' }; }, 204 | peg$c34 = "out ", 205 | peg$c35 = peg$literalExpectation("out ", false), 206 | peg$c36 = function(id) { return { "type": "Out", id: id.trim() }; }, 207 | peg$c37 = "nu", 208 | peg$c38 = peg$literalExpectation("nu", false), 209 | peg$c39 = function(id) { return id; }, 210 | peg$c40 = "rec", 211 | peg$c41 = peg$literalExpectation("rec", false), 212 | peg$c42 = function(pv) { return pv; }, 213 | peg$c43 = function(cap) { return cap; }, 214 | peg$c44 = peg$otherExpectation("string"), 215 | peg$c45 = /^[a-zA-Z0-0_\-]/, 216 | peg$c46 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "0"], "_", "-"], false, false), 217 | peg$c47 = function() { return text() }, 218 | peg$c48 = /^[A-Z]/, 219 | peg$c49 = peg$classExpectation([["A", "Z"]], false, false), 220 | peg$c50 = function() { return test() }, 221 | peg$c51 = peg$otherExpectation("whitespace"), 222 | peg$c52 = /^[ \t\n\r]/, 223 | peg$c53 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false), 224 | 225 | peg$currPos = 0, 226 | peg$savedPos = 0, 227 | peg$posDetailsCache = [{ line: 1, column: 1 }], 228 | peg$maxFailPos = 0, 229 | peg$maxFailExpected = [], 230 | peg$silentFails = 0, 231 | 232 | peg$result; 233 | 234 | if ("startRule" in options) { 235 | if (!(options.startRule in peg$startRuleFunctions)) { 236 | throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); 237 | } 238 | 239 | peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; 240 | } 241 | 242 | function text() { 243 | return input.substring(peg$savedPos, peg$currPos); 244 | } 245 | 246 | function location() { 247 | return peg$computeLocation(peg$savedPos, peg$currPos); 248 | } 249 | 250 | function expected(description, location) { 251 | location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) 252 | 253 | throw peg$buildStructuredError( 254 | [peg$otherExpectation(description)], 255 | input.substring(peg$savedPos, peg$currPos), 256 | location 257 | ); 258 | } 259 | 260 | function error(message, location) { 261 | location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos) 262 | 263 | throw peg$buildSimpleError(message, location); 264 | } 265 | 266 | function peg$literalExpectation(text, ignoreCase) { 267 | return { type: "literal", text: text, ignoreCase: ignoreCase }; 268 | } 269 | 270 | function peg$classExpectation(parts, inverted, ignoreCase) { 271 | return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; 272 | } 273 | 274 | function peg$anyExpectation() { 275 | return { type: "any" }; 276 | } 277 | 278 | function peg$endExpectation() { 279 | return { type: "end" }; 280 | } 281 | 282 | function peg$otherExpectation(description) { 283 | return { type: "other", description: description }; 284 | } 285 | 286 | function peg$computePosDetails(pos) { 287 | var details = peg$posDetailsCache[pos], p; 288 | 289 | if (details) { 290 | return details; 291 | } else { 292 | p = pos - 1; 293 | while (!peg$posDetailsCache[p]) { 294 | p--; 295 | } 296 | 297 | details = peg$posDetailsCache[p]; 298 | details = { 299 | line: details.line, 300 | column: details.column 301 | }; 302 | 303 | while (p < pos) { 304 | if (input.charCodeAt(p) === 10) { 305 | details.line++; 306 | details.column = 1; 307 | } else { 308 | details.column++; 309 | } 310 | 311 | p++; 312 | } 313 | 314 | peg$posDetailsCache[pos] = details; 315 | return details; 316 | } 317 | } 318 | 319 | function peg$computeLocation(startPos, endPos) { 320 | var startPosDetails = peg$computePosDetails(startPos), 321 | endPosDetails = peg$computePosDetails(endPos); 322 | 323 | return { 324 | start: { 325 | offset: startPos, 326 | line: startPosDetails.line, 327 | column: startPosDetails.column 328 | }, 329 | end: { 330 | offset: endPos, 331 | line: endPosDetails.line, 332 | column: endPosDetails.column 333 | } 334 | }; 335 | } 336 | 337 | function peg$fail(expected) { 338 | if (peg$currPos < peg$maxFailPos) { return; } 339 | 340 | if (peg$currPos > peg$maxFailPos) { 341 | peg$maxFailPos = peg$currPos; 342 | peg$maxFailExpected = []; 343 | } 344 | 345 | peg$maxFailExpected.push(expected); 346 | } 347 | 348 | function peg$buildSimpleError(message, location) { 349 | return new peg$SyntaxError(message, null, null, location); 350 | } 351 | 352 | function peg$buildStructuredError(expected, found, location) { 353 | return new peg$SyntaxError( 354 | peg$SyntaxError.buildMessage(expected, found), 355 | expected, 356 | found, 357 | location 358 | ); 359 | } 360 | 361 | function peg$parseExecution() { 362 | var s0, s1, s2, s3, s4, s5, s6, s7; 363 | 364 | s0 = peg$currPos; 365 | s1 = peg$parseSubExecution(); 366 | if (s1 !== peg$FAILED) { 367 | s2 = []; 368 | s3 = peg$currPos; 369 | s4 = peg$parse_(); 370 | if (s4 !== peg$FAILED) { 371 | if (input.charCodeAt(peg$currPos) === 124) { 372 | s5 = peg$c0; 373 | peg$currPos++; 374 | } else { 375 | s5 = peg$FAILED; 376 | if (peg$silentFails === 0) { peg$fail(peg$c1); } 377 | } 378 | if (s5 !== peg$FAILED) { 379 | s6 = peg$parse_(); 380 | if (s6 !== peg$FAILED) { 381 | s7 = peg$parseSubExecution(); 382 | if (s7 !== peg$FAILED) { 383 | s4 = [s4, s5, s6, s7]; 384 | s3 = s4; 385 | } else { 386 | peg$currPos = s3; 387 | s3 = peg$FAILED; 388 | } 389 | } else { 390 | peg$currPos = s3; 391 | s3 = peg$FAILED; 392 | } 393 | } else { 394 | peg$currPos = s3; 395 | s3 = peg$FAILED; 396 | } 397 | } else { 398 | peg$currPos = s3; 399 | s3 = peg$FAILED; 400 | } 401 | if (s3 !== peg$FAILED) { 402 | while (s3 !== peg$FAILED) { 403 | s2.push(s3); 404 | s3 = peg$currPos; 405 | s4 = peg$parse_(); 406 | if (s4 !== peg$FAILED) { 407 | if (input.charCodeAt(peg$currPos) === 124) { 408 | s5 = peg$c0; 409 | peg$currPos++; 410 | } else { 411 | s5 = peg$FAILED; 412 | if (peg$silentFails === 0) { peg$fail(peg$c1); } 413 | } 414 | if (s5 !== peg$FAILED) { 415 | s6 = peg$parse_(); 416 | if (s6 !== peg$FAILED) { 417 | s7 = peg$parseSubExecution(); 418 | if (s7 !== peg$FAILED) { 419 | s4 = [s4, s5, s6, s7]; 420 | s3 = s4; 421 | } else { 422 | peg$currPos = s3; 423 | s3 = peg$FAILED; 424 | } 425 | } else { 426 | peg$currPos = s3; 427 | s3 = peg$FAILED; 428 | } 429 | } else { 430 | peg$currPos = s3; 431 | s3 = peg$FAILED; 432 | } 433 | } else { 434 | peg$currPos = s3; 435 | s3 = peg$FAILED; 436 | } 437 | } 438 | } else { 439 | s2 = peg$FAILED; 440 | } 441 | if (s2 !== peg$FAILED) { 442 | peg$savedPos = s0; 443 | s1 = peg$c2(s1, s2); 444 | s0 = s1; 445 | } else { 446 | peg$currPos = s0; 447 | s0 = peg$FAILED; 448 | } 449 | } else { 450 | peg$currPos = s0; 451 | s0 = peg$FAILED; 452 | } 453 | if (s0 === peg$FAILED) { 454 | s0 = peg$parseSubExecution(); 455 | } 456 | 457 | return s0; 458 | } 459 | 460 | function peg$parseSubExecution() { 461 | var s0, s1, s2, s3, s4, s5; 462 | 463 | s0 = peg$currPos; 464 | s1 = peg$parseThirdTier(); 465 | if (s1 !== peg$FAILED) { 466 | s2 = []; 467 | s3 = peg$currPos; 468 | if (input.charCodeAt(peg$currPos) === 46) { 469 | s4 = peg$c3; 470 | peg$currPos++; 471 | } else { 472 | s4 = peg$FAILED; 473 | if (peg$silentFails === 0) { peg$fail(peg$c4); } 474 | } 475 | if (s4 !== peg$FAILED) { 476 | s5 = peg$parseThirdTier(); 477 | if (s5 !== peg$FAILED) { 478 | s4 = [s4, s5]; 479 | s3 = s4; 480 | } else { 481 | peg$currPos = s3; 482 | s3 = peg$FAILED; 483 | } 484 | } else { 485 | peg$currPos = s3; 486 | s3 = peg$FAILED; 487 | } 488 | if (s3 !== peg$FAILED) { 489 | while (s3 !== peg$FAILED) { 490 | s2.push(s3); 491 | s3 = peg$currPos; 492 | if (input.charCodeAt(peg$currPos) === 46) { 493 | s4 = peg$c3; 494 | peg$currPos++; 495 | } else { 496 | s4 = peg$FAILED; 497 | if (peg$silentFails === 0) { peg$fail(peg$c4); } 498 | } 499 | if (s4 !== peg$FAILED) { 500 | s5 = peg$parseThirdTier(); 501 | if (s5 !== peg$FAILED) { 502 | s4 = [s4, s5]; 503 | s3 = s4; 504 | } else { 505 | peg$currPos = s3; 506 | s3 = peg$FAILED; 507 | } 508 | } else { 509 | peg$currPos = s3; 510 | s3 = peg$FAILED; 511 | } 512 | } 513 | } else { 514 | s2 = peg$FAILED; 515 | } 516 | if (s2 !== peg$FAILED) { 517 | peg$savedPos = s0; 518 | s1 = peg$c5(s1, s2); 519 | s0 = s1; 520 | } else { 521 | peg$currPos = s0; 522 | s0 = peg$FAILED; 523 | } 524 | } else { 525 | peg$currPos = s0; 526 | s0 = peg$FAILED; 527 | } 528 | if (s0 === peg$FAILED) { 529 | s0 = peg$parseThirdTier(); 530 | } 531 | 532 | return s0; 533 | } 534 | 535 | function peg$parseThirdTier() { 536 | var s0, s1, s2, s3, s4, s5; 537 | 538 | s0 = peg$currPos; 539 | if (input.charCodeAt(peg$currPos) === 40) { 540 | s1 = peg$c6; 541 | peg$currPos++; 542 | } else { 543 | s1 = peg$FAILED; 544 | if (peg$silentFails === 0) { peg$fail(peg$c7); } 545 | } 546 | if (s1 !== peg$FAILED) { 547 | s2 = peg$parse_(); 548 | if (s2 !== peg$FAILED) { 549 | s3 = peg$parseExecution(); 550 | if (s3 !== peg$FAILED) { 551 | s4 = peg$parse_(); 552 | if (s4 !== peg$FAILED) { 553 | if (input.charCodeAt(peg$currPos) === 41) { 554 | s5 = peg$c8; 555 | peg$currPos++; 556 | } else { 557 | s5 = peg$FAILED; 558 | if (peg$silentFails === 0) { peg$fail(peg$c9); } 559 | } 560 | if (s5 !== peg$FAILED) { 561 | peg$savedPos = s0; 562 | s1 = peg$c10(s3); 563 | s0 = s1; 564 | } else { 565 | peg$currPos = s0; 566 | s0 = peg$FAILED; 567 | } 568 | } else { 569 | peg$currPos = s0; 570 | s0 = peg$FAILED; 571 | } 572 | } else { 573 | peg$currPos = s0; 574 | s0 = peg$FAILED; 575 | } 576 | } else { 577 | peg$currPos = s0; 578 | s0 = peg$FAILED; 579 | } 580 | } else { 581 | peg$currPos = s0; 582 | s0 = peg$FAILED; 583 | } 584 | if (s0 === peg$FAILED) { 585 | s0 = peg$parseAMBIENT(); 586 | if (s0 === peg$FAILED) { 587 | s0 = peg$parsePATH(); 588 | } 589 | } 590 | 591 | return s0; 592 | } 593 | 594 | function peg$parseAMBIENT() { 595 | var s0, s1, s2, s3, s4, s5, s6; 596 | 597 | s0 = peg$currPos; 598 | s1 = peg$parsePATH(); 599 | if (s1 !== peg$FAILED) { 600 | if (input.substr(peg$currPos, 2) === peg$c11) { 601 | s2 = peg$c11; 602 | peg$currPos += 2; 603 | } else { 604 | s2 = peg$FAILED; 605 | if (peg$silentFails === 0) { peg$fail(peg$c12); } 606 | } 607 | if (s2 !== peg$FAILED) { 608 | peg$savedPos = s0; 609 | s1 = peg$c13(s1); 610 | s0 = s1; 611 | } else { 612 | peg$currPos = s0; 613 | s0 = peg$FAILED; 614 | } 615 | } else { 616 | peg$currPos = s0; 617 | s0 = peg$FAILED; 618 | } 619 | if (s0 === peg$FAILED) { 620 | s0 = peg$currPos; 621 | s1 = peg$parsePATH(); 622 | if (s1 !== peg$FAILED) { 623 | if (input.charCodeAt(peg$currPos) === 91) { 624 | s2 = peg$c14; 625 | peg$currPos++; 626 | } else { 627 | s2 = peg$FAILED; 628 | if (peg$silentFails === 0) { peg$fail(peg$c15); } 629 | } 630 | if (s2 !== peg$FAILED) { 631 | s3 = peg$parse_(); 632 | if (s3 !== peg$FAILED) { 633 | s4 = peg$parseExecution(); 634 | if (s4 !== peg$FAILED) { 635 | s5 = peg$parse_(); 636 | if (s5 !== peg$FAILED) { 637 | if (input.charCodeAt(peg$currPos) === 93) { 638 | s6 = peg$c16; 639 | peg$currPos++; 640 | } else { 641 | s6 = peg$FAILED; 642 | if (peg$silentFails === 0) { peg$fail(peg$c17); } 643 | } 644 | if (s6 !== peg$FAILED) { 645 | peg$savedPos = s0; 646 | s1 = peg$c18(s1, s4); 647 | s0 = s1; 648 | } else { 649 | peg$currPos = s0; 650 | s0 = peg$FAILED; 651 | } 652 | } else { 653 | peg$currPos = s0; 654 | s0 = peg$FAILED; 655 | } 656 | } else { 657 | peg$currPos = s0; 658 | s0 = peg$FAILED; 659 | } 660 | } else { 661 | peg$currPos = s0; 662 | s0 = peg$FAILED; 663 | } 664 | } else { 665 | peg$currPos = s0; 666 | s0 = peg$FAILED; 667 | } 668 | } else { 669 | peg$currPos = s0; 670 | s0 = peg$FAILED; 671 | } 672 | } 673 | 674 | return s0; 675 | } 676 | 677 | function peg$parseCAPABILITY() { 678 | var s0, s1, s2, s3; 679 | 680 | s0 = peg$currPos; 681 | if (input.substr(peg$currPos, 3) === peg$c19) { 682 | s1 = peg$c19; 683 | peg$currPos += 3; 684 | } else { 685 | s1 = peg$FAILED; 686 | if (peg$silentFails === 0) { peg$fail(peg$c20); } 687 | } 688 | if (s1 !== peg$FAILED) { 689 | s2 = []; 690 | s3 = peg$parseID(); 691 | while (s3 !== peg$FAILED) { 692 | s2.push(s3); 693 | s3 = peg$parseID(); 694 | } 695 | if (s2 !== peg$FAILED) { 696 | peg$savedPos = s0; 697 | s1 = peg$c21(s2); 698 | s0 = s1; 699 | } else { 700 | peg$currPos = s0; 701 | s0 = peg$FAILED; 702 | } 703 | } else { 704 | peg$currPos = s0; 705 | s0 = peg$FAILED; 706 | } 707 | if (s0 === peg$FAILED) { 708 | s0 = peg$currPos; 709 | if (input.substr(peg$currPos, 3) === peg$c22) { 710 | s1 = peg$c22; 711 | peg$currPos += 3; 712 | } else { 713 | s1 = peg$FAILED; 714 | if (peg$silentFails === 0) { peg$fail(peg$c23); } 715 | } 716 | if (s1 !== peg$FAILED) { 717 | s2 = peg$parseID(); 718 | if (s2 !== peg$FAILED) { 719 | peg$savedPos = s0; 720 | s1 = peg$c24(s2); 721 | s0 = s1; 722 | } else { 723 | peg$currPos = s0; 724 | s0 = peg$FAILED; 725 | } 726 | } else { 727 | peg$currPos = s0; 728 | s0 = peg$FAILED; 729 | } 730 | if (s0 === peg$FAILED) { 731 | s0 = peg$currPos; 732 | if (input.substr(peg$currPos, 5) === peg$c25) { 733 | s1 = peg$c25; 734 | peg$currPos += 5; 735 | } else { 736 | s1 = peg$FAILED; 737 | if (peg$silentFails === 0) { peg$fail(peg$c26); } 738 | } 739 | if (s1 !== peg$FAILED) { 740 | s2 = []; 741 | s3 = peg$parseID(); 742 | while (s3 !== peg$FAILED) { 743 | s2.push(s3); 744 | s3 = peg$parseID(); 745 | } 746 | if (s2 !== peg$FAILED) { 747 | peg$savedPos = s0; 748 | s1 = peg$c27(s2); 749 | s0 = s1; 750 | } else { 751 | peg$currPos = s0; 752 | s0 = peg$FAILED; 753 | } 754 | } else { 755 | peg$currPos = s0; 756 | s0 = peg$FAILED; 757 | } 758 | if (s0 === peg$FAILED) { 759 | s0 = peg$currPos; 760 | if (input.substr(peg$currPos, 5) === peg$c28) { 761 | s1 = peg$c28; 762 | peg$currPos += 5; 763 | } else { 764 | s1 = peg$FAILED; 765 | if (peg$silentFails === 0) { peg$fail(peg$c29); } 766 | } 767 | if (s1 !== peg$FAILED) { 768 | s2 = peg$parseID(); 769 | if (s2 !== peg$FAILED) { 770 | peg$savedPos = s0; 771 | s1 = peg$c30(s2); 772 | s0 = s1; 773 | } else { 774 | peg$currPos = s0; 775 | s0 = peg$FAILED; 776 | } 777 | } else { 778 | peg$currPos = s0; 779 | s0 = peg$FAILED; 780 | } 781 | if (s0 === peg$FAILED) { 782 | s0 = peg$currPos; 783 | if (input.substr(peg$currPos, 5) === peg$c31) { 784 | s1 = peg$c31; 785 | peg$currPos += 5; 786 | } else { 787 | s1 = peg$FAILED; 788 | if (peg$silentFails === 0) { peg$fail(peg$c32); } 789 | } 790 | if (s1 !== peg$FAILED) { 791 | s2 = []; 792 | s3 = peg$parseID(); 793 | while (s3 !== peg$FAILED) { 794 | s2.push(s3); 795 | s3 = peg$parseID(); 796 | } 797 | if (s2 !== peg$FAILED) { 798 | peg$savedPos = s0; 799 | s1 = peg$c33(s2); 800 | s0 = s1; 801 | } else { 802 | peg$currPos = s0; 803 | s0 = peg$FAILED; 804 | } 805 | } else { 806 | peg$currPos = s0; 807 | s0 = peg$FAILED; 808 | } 809 | if (s0 === peg$FAILED) { 810 | s0 = peg$currPos; 811 | if (input.substr(peg$currPos, 4) === peg$c34) { 812 | s1 = peg$c34; 813 | peg$currPos += 4; 814 | } else { 815 | s1 = peg$FAILED; 816 | if (peg$silentFails === 0) { peg$fail(peg$c35); } 817 | } 818 | if (s1 !== peg$FAILED) { 819 | s2 = peg$parseID(); 820 | if (s2 !== peg$FAILED) { 821 | peg$savedPos = s0; 822 | s1 = peg$c36(s2); 823 | s0 = s1; 824 | } else { 825 | peg$currPos = s0; 826 | s0 = peg$FAILED; 827 | } 828 | } else { 829 | peg$currPos = s0; 830 | s0 = peg$FAILED; 831 | } 832 | } 833 | } 834 | } 835 | } 836 | } 837 | 838 | return s0; 839 | } 840 | 841 | function peg$parsePATH() { 842 | var s0, s1, s2, s3; 843 | 844 | s0 = peg$currPos; 845 | if (input.substr(peg$currPos, 2) === peg$c37) { 846 | s1 = peg$c37; 847 | peg$currPos += 2; 848 | } else { 849 | s1 = peg$FAILED; 850 | if (peg$silentFails === 0) { peg$fail(peg$c38); } 851 | } 852 | if (s1 !== peg$FAILED) { 853 | s2 = peg$parse_(); 854 | if (s2 !== peg$FAILED) { 855 | s3 = peg$parseID(); 856 | if (s3 !== peg$FAILED) { 857 | peg$savedPos = s0; 858 | s1 = peg$c39(s3); 859 | s0 = s1; 860 | } else { 861 | peg$currPos = s0; 862 | s0 = peg$FAILED; 863 | } 864 | } else { 865 | peg$currPos = s0; 866 | s0 = peg$FAILED; 867 | } 868 | } else { 869 | peg$currPos = s0; 870 | s0 = peg$FAILED; 871 | } 872 | if (s0 === peg$FAILED) { 873 | s0 = peg$currPos; 874 | if (input.substr(peg$currPos, 3) === peg$c40) { 875 | s1 = peg$c40; 876 | peg$currPos += 3; 877 | } else { 878 | s1 = peg$FAILED; 879 | if (peg$silentFails === 0) { peg$fail(peg$c41); } 880 | } 881 | if (s1 !== peg$FAILED) { 882 | s2 = peg$parse_(); 883 | if (s2 !== peg$FAILED) { 884 | s3 = peg$parsePROCVAR(); 885 | if (s3 !== peg$FAILED) { 886 | peg$savedPos = s0; 887 | s1 = peg$c42(s3); 888 | s0 = s1; 889 | } else { 890 | peg$currPos = s0; 891 | s0 = peg$FAILED; 892 | } 893 | } else { 894 | peg$currPos = s0; 895 | s0 = peg$FAILED; 896 | } 897 | } else { 898 | peg$currPos = s0; 899 | s0 = peg$FAILED; 900 | } 901 | if (s0 === peg$FAILED) { 902 | s0 = peg$currPos; 903 | s1 = peg$parsePROCVAR(); 904 | if (s1 !== peg$FAILED) { 905 | peg$savedPos = s0; 906 | s1 = peg$c42(s1); 907 | } 908 | s0 = s1; 909 | if (s0 === peg$FAILED) { 910 | s0 = peg$currPos; 911 | s1 = peg$parseCAPABILITY(); 912 | if (s1 !== peg$FAILED) { 913 | peg$savedPos = s0; 914 | s1 = peg$c43(s1); 915 | } 916 | s0 = s1; 917 | if (s0 === peg$FAILED) { 918 | s0 = peg$currPos; 919 | s1 = peg$parseID(); 920 | if (s1 !== peg$FAILED) { 921 | peg$savedPos = s0; 922 | s1 = peg$c39(s1); 923 | } 924 | s0 = s1; 925 | } 926 | } 927 | } 928 | } 929 | 930 | return s0; 931 | } 932 | 933 | function peg$parseID() { 934 | var s0, s1, s2, s3; 935 | 936 | peg$silentFails++; 937 | s0 = peg$currPos; 938 | s1 = peg$parse_(); 939 | if (s1 !== peg$FAILED) { 940 | s2 = []; 941 | if (peg$c45.test(input.charAt(peg$currPos))) { 942 | s3 = input.charAt(peg$currPos); 943 | peg$currPos++; 944 | } else { 945 | s3 = peg$FAILED; 946 | if (peg$silentFails === 0) { peg$fail(peg$c46); } 947 | } 948 | if (s3 !== peg$FAILED) { 949 | while (s3 !== peg$FAILED) { 950 | s2.push(s3); 951 | if (peg$c45.test(input.charAt(peg$currPos))) { 952 | s3 = input.charAt(peg$currPos); 953 | peg$currPos++; 954 | } else { 955 | s3 = peg$FAILED; 956 | if (peg$silentFails === 0) { peg$fail(peg$c46); } 957 | } 958 | } 959 | } else { 960 | s2 = peg$FAILED; 961 | } 962 | if (s2 !== peg$FAILED) { 963 | peg$savedPos = s0; 964 | s1 = peg$c47(); 965 | s0 = s1; 966 | } else { 967 | peg$currPos = s0; 968 | s0 = peg$FAILED; 969 | } 970 | } else { 971 | peg$currPos = s0; 972 | s0 = peg$FAILED; 973 | } 974 | peg$silentFails--; 975 | if (s0 === peg$FAILED) { 976 | s1 = peg$FAILED; 977 | if (peg$silentFails === 0) { peg$fail(peg$c44); } 978 | } 979 | 980 | return s0; 981 | } 982 | 983 | function peg$parsePROCVAR() { 984 | var s0, s1; 985 | 986 | peg$silentFails++; 987 | s0 = peg$currPos; 988 | if (peg$c48.test(input.charAt(peg$currPos))) { 989 | s1 = input.charAt(peg$currPos); 990 | peg$currPos++; 991 | } else { 992 | s1 = peg$FAILED; 993 | if (peg$silentFails === 0) { peg$fail(peg$c49); } 994 | } 995 | if (s1 !== peg$FAILED) { 996 | peg$savedPos = s0; 997 | s1 = peg$c50(); 998 | } 999 | s0 = s1; 1000 | peg$silentFails--; 1001 | if (s0 === peg$FAILED) { 1002 | s1 = peg$FAILED; 1003 | if (peg$silentFails === 0) { peg$fail(peg$c44); } 1004 | } 1005 | 1006 | return s0; 1007 | } 1008 | 1009 | function peg$parse_() { 1010 | var s0, s1; 1011 | 1012 | peg$silentFails++; 1013 | s0 = []; 1014 | if (peg$c52.test(input.charAt(peg$currPos))) { 1015 | s1 = input.charAt(peg$currPos); 1016 | peg$currPos++; 1017 | } else { 1018 | s1 = peg$FAILED; 1019 | if (peg$silentFails === 0) { peg$fail(peg$c53); } 1020 | } 1021 | while (s1 !== peg$FAILED) { 1022 | s0.push(s1); 1023 | if (peg$c52.test(input.charAt(peg$currPos))) { 1024 | s1 = input.charAt(peg$currPos); 1025 | peg$currPos++; 1026 | } else { 1027 | s1 = peg$FAILED; 1028 | if (peg$silentFails === 0) { peg$fail(peg$c53); } 1029 | } 1030 | } 1031 | peg$silentFails--; 1032 | if (s0 === peg$FAILED) { 1033 | s1 = peg$FAILED; 1034 | if (peg$silentFails === 0) { peg$fail(peg$c51); } 1035 | } 1036 | 1037 | return s0; 1038 | } 1039 | 1040 | peg$result = peg$startRuleFunction(); 1041 | 1042 | if (peg$result !== peg$FAILED && peg$currPos === input.length) { 1043 | return peg$result; 1044 | } else { 1045 | if (peg$result !== peg$FAILED && peg$currPos < input.length) { 1046 | peg$fail(peg$endExpectation()); 1047 | } 1048 | 1049 | throw peg$buildStructuredError( 1050 | peg$maxFailExpected, 1051 | peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, 1052 | peg$maxFailPos < input.length 1053 | ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) 1054 | : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) 1055 | ); 1056 | } 1057 | } 1058 | 1059 | module.exports = { 1060 | SyntaxError: peg$SyntaxError, 1061 | parse: peg$parse 1062 | }; 1063 | --------------------------------------------------------------------------------