├── ast-website ├── CNAME ├── website │ ├── CACHE_BREAKER │ ├── .npmrc │ ├── src │ │ ├── parsers │ │ │ ├── regexp │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ ├── transformers │ │ │ │ │ └── regexp-tree │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ ├── regexp-tree.js │ │ │ │ ├── regexpp.js │ │ │ │ └── regjsparser.js │ │ │ ├── mathjs │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ └── mathjs.js │ │ │ ├── lucene │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ └── lucene.js │ │ │ ├── mdx │ │ │ │ ├── transformers │ │ │ │ │ └── mdx │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── mdxhast.js │ │ │ ├── json │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ ├── json-to-ast.js │ │ │ │ └── momoa.js │ │ │ ├── scala │ │ │ │ ├── codeExample.txt │ │ │ │ └── index.js │ │ │ ├── handlebars │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ ├── transformers │ │ │ │ │ ├── ember-template-recast │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── glimmer │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ └── glimmer-compiler │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ ├── handlebars.js │ │ │ │ ├── ember-template-recast.js │ │ │ │ ├── glimmer.js │ │ │ │ └── utils │ │ │ │ │ └── defaultHandlebarsParserInterface.js │ │ │ ├── icu │ │ │ │ ├── codeExample.txt │ │ │ │ └── index.js │ │ │ ├── reason │ │ │ │ ├── index.js │ │ │ │ └── codeExample.txt │ │ │ ├── monkey │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── monkey.js │ │ │ ├── wat │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── wat-parser.js │ │ │ ├── html │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ ├── transformers │ │ │ │ │ ├── posthtml │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ └── svelte │ │ │ │ │ │ └── codeExample.txt │ │ │ │ ├── posthtml.js │ │ │ │ └── svelte.js │ │ │ ├── graphviz │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── redot.js │ │ │ ├── go │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── go.js │ │ │ ├── sql │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ └── sqlite-parser.js │ │ │ ├── thrift │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── thrift-parser.js │ │ │ ├── lua │ │ │ │ ├── index.js │ │ │ │ └── codeExample.txt │ │ │ ├── pug │ │ │ │ ├── index.js │ │ │ │ └── codeExample.txt │ │ │ ├── vue │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ ├── vue-template-compiler.js │ │ │ │ └── vue-compiler-dom.js │ │ │ ├── rust │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── syn.js │ │ │ ├── san │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ └── san-template-parser.js │ │ │ ├── css │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ ├── transformers │ │ │ │ │ └── postcss │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ ├── utils │ │ │ │ │ └── defaultCSSParserInterface.js │ │ │ │ ├── rework.js │ │ │ │ ├── cssom.js │ │ │ │ └── postcss.js │ │ │ ├── markdown │ │ │ │ ├── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ └── transformers │ │ │ │ │ └── remark │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ └── index.js │ │ │ ├── python │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── python.js │ │ │ ├── js │ │ │ │ ├── transformers │ │ │ │ │ ├── eslint1 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ ├── loadRulesShim.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── eslint2 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── eslint3 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── babel │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── prettier │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── babel6 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── babel7 │ │ │ │ │ │ └── codeExample.txt │ │ │ │ │ ├── recast │ │ │ │ │ │ └── codeExample.txt │ │ │ │ │ ├── jscodeshift │ │ │ │ │ │ └── codeExample.txt │ │ │ │ │ ├── eslint4 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── eslint8 │ │ │ │ │ │ ├── codeExample.txt │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── tslint │ │ │ │ │ │ └── codeExample.txt │ │ │ │ │ └── typescript │ │ │ │ │ │ └── codeExample.txt │ │ │ │ ├── index.js │ │ │ │ ├── utils │ │ │ │ │ └── defaultESTreeParserInterface.js │ │ │ │ ├── codeExample.txt │ │ │ │ ├── babel-eslint9.js │ │ │ │ ├── babel-eslint.js │ │ │ │ ├── babel-eslint8.js │ │ │ │ ├── babel-eslint-parser.js │ │ │ │ ├── hermes │ │ │ │ │ └── hermes-worker.js │ │ │ │ ├── flow.js │ │ │ │ ├── esformatter.js │ │ │ │ └── acorn-to-esprima.js │ │ │ ├── php │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── php-parser.js │ │ │ ├── yaml │ │ │ │ ├── index.js │ │ │ │ ├── yaml-ast-parser.js │ │ │ │ └── yaml.js │ │ │ ├── solididy │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ ├── solidity-parser-antlr.js │ │ │ │ └── solidity-parser-diligence.js │ │ │ ├── webidl │ │ │ │ ├── index.js │ │ │ │ └── webidl2.js │ │ │ ├── graphql │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── graphql-js.js │ │ │ ├── glsl │ │ │ │ ├── index.js │ │ │ │ └── codeExample.txt │ │ │ ├── protobuf │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── pbkit.js │ │ │ ├── ocaml │ │ │ │ ├── refmt-ml.js │ │ │ │ ├── index.js │ │ │ │ └── codeExample.txt │ │ │ ├── java │ │ │ │ ├── index.js │ │ │ │ ├── codeExample.txt │ │ │ │ └── java-parser.js │ │ │ ├── transpilers │ │ │ │ ├── typescript.js │ │ │ │ └── babel.js │ │ │ └── utils │ │ │ │ ├── compileModule.js │ │ │ │ └── protectFromLoops.js │ │ ├── shims │ │ │ └── jest-validate.js │ │ ├── components │ │ │ ├── visualization │ │ │ │ ├── index.js │ │ │ │ ├── JSON.js │ │ │ │ ├── css │ │ │ │ │ └── tree.css │ │ │ │ ├── tree │ │ │ │ │ ├── CompactObjectView.js │ │ │ │ │ └── CompactArrayView.js │ │ │ │ └── SelectedNodeContext.js │ │ │ ├── LoadingIndicator.js │ │ │ ├── buttons │ │ │ │ ├── NewButton.js │ │ │ │ ├── ShareButton.js │ │ │ │ ├── SaveButton.js │ │ │ │ ├── PrettierButton.js │ │ │ │ ├── ForkButton.js │ │ │ │ └── KeyMapButton.js │ │ │ ├── LocalStorage.js │ │ │ ├── ErrorMessage.js │ │ │ ├── SettingsDrawer.js │ │ │ └── dialogs │ │ │ │ └── ShareDialog.js │ │ ├── storage │ │ │ ├── api.js │ │ │ └── index.js │ │ ├── utils │ │ │ ├── classnames.js │ │ │ ├── logger.js │ │ │ ├── debounce.js │ │ │ ├── stringify.js │ │ │ └── pubsub.js │ │ ├── containers │ │ │ ├── LoadingIndicatorContainer.js │ │ │ ├── ASTOutputContainer.js │ │ │ ├── PasteDropTargetContainer.js │ │ │ ├── ErrorMessageContainer.js │ │ │ ├── ShareDialogContainer.js │ │ │ ├── SettingsDrawerContainer.js │ │ │ ├── SettingsDialogContainer.js │ │ │ ├── CodeEditorContainer.js │ │ │ └── TransformerContainer.js │ │ └── core │ │ │ └── ParseResult.js │ ├── postcss.config.js │ ├── favicon.png │ ├── fontcustom │ │ ├── fontcustom_45cd59da2a1bc422647cab7f53639319.eot │ │ ├── fontcustom_45cd59da2a1bc422647cab7f53639319.ttf │ │ ├── fontcustom_45cd59da2a1bc422647cab7f53639319.woff │ │ ├── fontcustom_45cd59da2a1bc422647cab7f53639319.woff2 │ │ ├── input-svg │ │ │ ├── reason.svg │ │ │ └── scala.svg │ │ └── README.md │ └── index.ejs ├── .editorconfig ├── .gitignore ├── assets │ ├── ast.png │ └── source.png ├── .gitpod.yml ├── scripts │ ├── build-ci.sh │ ├── inject-rev.sh │ ├── deploy.sh │ ├── check-conflicts.sh │ └── publish-latest.sh ├── server │ ├── constants.js │ ├── package.json │ ├── handlers │ │ └── gist │ │ │ ├── loadGist.js │ │ │ └── index.js │ └── index.js ├── .travis.yml ├── .github │ └── ISSUE_TEMPLATE │ │ └── bug_report.md ├── LICENSE.txt └── .eslintrc ├── packages └── playground │ ├── .gitignore │ ├── src │ ├── vite-env.d.ts │ ├── main.tsx │ ├── index.css │ ├── Editor.tsx │ ├── App.css │ └── logo.svg │ ├── tsconfig.node.json │ ├── index.html │ ├── vite.config.ts │ ├── tsconfig.json │ └── package.json ├── rustfmt.toml ├── .prettierrc ├── wasm ├── .gitignore ├── tests │ └── web.rs ├── src │ ├── utils.rs │ └── lib.rs └── README.md ├── pnpm-workspace.yaml ├── Cargo.toml ├── .gitignore ├── lexer ├── snapshots │ ├── lexer__lexer_test__tests__comments.snap │ ├── lexer__lexer_test__tests__string.snap │ ├── lexer__lexer_test__tests__array.snap │ ├── lexer__lexer_test__tests__bool.snap │ ├── lexer__lexer_test__tests__let.snap │ ├── lexer__lexer_test__tests__let_with_space.snap │ └── lexer__lexer_test__tests__comments_then_blank_line.snap ├── main.rs ├── Cargo.toml └── README.md ├── compiler ├── lib.rs ├── frame.rs ├── symbol_table_test.rs ├── Cargo.toml └── README.md ├── .github ├── dependabot.yml └── workflows │ ├── rust.yml │ ├── prepare-release.yml │ └── doc-publish.yml ├── parser ├── snapshots │ ├── parser__ast_tree_test__tests__test_string.snap │ ├── parser__ast_tree_test__tests__test_return.snap │ ├── parser__ast_tree_test__tests__test_index.snap │ ├── parser__ast_tree_test__tests__test_unary.snap │ ├── parser__ast_tree_test__tests__test_array.snap │ ├── parser__ast_tree_test__tests__test_let.snap │ ├── parser__ast_tree_test__tests__test_hash.snap │ ├── parser__ast_tree_test__tests__test_func_call.snap │ └── parser__ast_tree_test__tests__test_func_declaration.snap ├── main.rs ├── Cargo.toml ├── precedences.rs └── README.md ├── .circleci └── config.yml ├── .gitpod.yml ├── Maintainer.md ├── object ├── Cargo.toml ├── README.md └── environment.rs ├── interpreter ├── Cargo.toml ├── main.rs └── README.md ├── tsconfig.json ├── examples └── hello.monkey ├── .gitpod.Dockerfile ├── LICENSE └── package.json /ast-website/CNAME: -------------------------------------------------------------------------------- 1 | astexplorer.net 2 | -------------------------------------------------------------------------------- /ast-website/website/CACHE_BREAKER: -------------------------------------------------------------------------------- 1 | 27 2 | -------------------------------------------------------------------------------- /packages/playground/.gitignore: -------------------------------------------------------------------------------- 1 | stats.html 2 | -------------------------------------------------------------------------------- /ast-website/website/.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /ast-website/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.js] 2 | quote_type = single 3 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/codeExample.txt: -------------------------------------------------------------------------------- 1 | /[a-z]/i -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | struct_lit_width=100 2 | fn_call_width=100 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mathjs/codeExample.txt: -------------------------------------------------------------------------------- 1 | (sin(2x) + e^x) / 2 2 | -------------------------------------------------------------------------------- /ast-website/.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | node_modules 3 | .idea 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /packages/playground/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | bin/ 5 | pkg/ 6 | wasm-pack.log 7 | -------------------------------------------------------------------------------- /ast-website/website/src/shims/jest-validate.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | validate(){}, 3 | }; 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - wasm/pkg 4 | - ast-website/website 5 | -------------------------------------------------------------------------------- /ast-website/assets/ast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/assets/ast.png -------------------------------------------------------------------------------- /ast-website/website/src/parsers/lucene/codeExample.txt: -------------------------------------------------------------------------------- 1 | name:frank OR job:engineer AND food:/marshmal+ows/ 2 | -------------------------------------------------------------------------------- /ast-website/assets/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/assets/source.png -------------------------------------------------------------------------------- /ast-website/website/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer') 4 | ] 5 | } -------------------------------------------------------------------------------- /ast-website/website/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/website/favicon.png -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mdx/transformers/mdx/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default { 2 | mdPlugins: [], 3 | hastPlugins: [], 4 | } 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "lexer", 4 | "parser", 5 | "object", 6 | "interpreter", 7 | "compiler", 8 | "wasm" 9 | ] 10 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/json/codeExample.txt: -------------------------------------------------------------------------------- 1 | { 2 | "key1": [true, false, null], 3 | "key2": { 4 | "key3": [1, 2, "3", 1e10, 1e-3] 5 | } 6 | } -------------------------------------------------------------------------------- /ast-website/website/src/parsers/scala/codeExample.txt: -------------------------------------------------------------------------------- 1 | object Main { 2 | def main(args: Array[String]): Unit = { 3 | println("Hello, World!") 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/codeExample.txt: -------------------------------------------------------------------------------- 1 |
2 |

{{title}}

3 |
4 | {{body}} 5 |
6 |
7 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/index.js: -------------------------------------------------------------------------------- 1 | import JSON from './JSON'; 2 | import Tree from './Tree'; 3 | 4 | export default [ 5 | Tree, 6 | JSON, 7 | ]; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | .idea/ 4 | .vscode/ 5 | .theia/ 6 | 7 | node_modules 8 | .DS_Store 9 | *.log 10 | dist/ 11 | out/ 12 | 13 | package-lock.json 14 | .pnpm-store/ -------------------------------------------------------------------------------- /ast-website/website/src/parsers/icu/codeExample.txt: -------------------------------------------------------------------------------- 1 | On {takenDate, date, short} {name} took {numPhotos, plural, 2 | =0 {no photos.} 3 | =1 {one photo.} 4 | other {# photos.} 5 | } -------------------------------------------------------------------------------- /ast-website/website/src/parsers/reason/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'reason'; 2 | export const displayName = 'Reason'; 3 | export const mimeTypes = []; 4 | export const fileExtension = 're'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/lucene/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'lucene'; 2 | export const displayName = 'Lucene'; 3 | export const mimeTypes = ['']; 4 | export const fileExtension = 'lucene'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mdx/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'mdx'; 2 | export const displayName = 'MDX'; 3 | export const mimeTypes = ['text/mdx']; 4 | export const fileExtension = 'mdx'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/monkey/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'monkey'; 2 | export const displayName = 'Monkey'; 3 | export const mimeTypes = []; 4 | export const fileExtension = 'monkey'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/wat/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'wat'; 2 | export const displayName = 'WAT'; 3 | export const mimeTypes = ['application/wasm']; 4 | export const fileExtension = 'wat'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/codeExample.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

My First Heading

6 |

My first paragraph.

7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'regexp'; 2 | export const displayName = 'RegExp'; 3 | export const mimeTypes = ['text/regexp']; 4 | export const fileExtension = 'regexp'; -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mathjs/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'mathjs'; 2 | export const displayName = 'Math.js'; 3 | export const mimeTypes = ['text/mathjs']; 4 | export const fileExtension = 'mathjs'; 5 | -------------------------------------------------------------------------------- /packages/playground/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.eot -------------------------------------------------------------------------------- /ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.ttf -------------------------------------------------------------------------------- /ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff -------------------------------------------------------------------------------- /ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gengjiawen/monkey-rust/HEAD/ast-website/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff2 -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphviz/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'graphviz'; 2 | export const displayName = 'Graphviz'; 3 | export const mimeTypes = ['text/vnd.graphviz']; 4 | export const fileExtension = 'gv'; 5 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/go/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/go/go'; 2 | 3 | export const id = 'go'; 4 | export const displayName = 'Go'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'go'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/sql/codeExample.txt: -------------------------------------------------------------------------------- 1 | -- 2 | -- This is an example query 3 | -- 4 | SELECT 5 | foo, bar as baz 6 | FROM 7 | mytable 8 | WHERE 9 | foo LIKE '%neat%' 10 | ORDER BY 11 | foo DESC 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/thrift/index.js: -------------------------------------------------------------------------------- 1 | export const id = 'thrift-idl'; 2 | export const displayName = 'Thrift IDL'; 3 | export const mimeTypes = ['text/x-thrift-idl']; 4 | export const fileExtension = 'thrift'; 5 | -------------------------------------------------------------------------------- /ast-website/.gitpod.yml: -------------------------------------------------------------------------------- 1 | 2 | tasks: 3 | - init: cd website && yarn 4 | command: yarn dev 5 | - init: fish 6 | 7 | ports: 8 | - port: 8080 9 | onOpen: open-preview 10 | visibility: public 11 | 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/lua/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/lua/lua'; 2 | 3 | export const id = 'lua'; 4 | export const displayName = 'Lua'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'lua'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/pug/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/pug/pug'; 2 | 3 | export const id = 'pug'; 4 | export const displayName = 'Pug'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'pug'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/vue/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/vue/vue'; 2 | 3 | export const id = 'vue'; 4 | export const displayName = 'Vue'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'vue'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/rust/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/rust/rust'; 2 | 3 | export const id = 'rust'; 4 | export const displayName = 'Rust'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'rs'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/san/codeExample.txt: -------------------------------------------------------------------------------- 1 |
2 |

{{title}}

3 |
4 | 5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /ast-website/scripts/build-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | rm -rf out/* 6 | ( 7 | cd website/ 8 | yarn 9 | if [ "$1" = "--dev" ]; then 10 | yarn build-dev 11 | else 12 | yarn build 13 | fi 14 | ) 15 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/css/css'; 2 | 3 | export const id = 'css'; 4 | export const displayName = 'CSS'; 5 | export const mimeTypes = ['text/css']; 6 | export const fileExtension = 'css'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/markdown/codeExample.txt: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | Some *emphasis*, **importance**, and `code`. 4 | 5 | --- 6 | 7 | ```javascript 8 | console.log('!'); 9 | ``` 10 | 11 | * foo 12 | * bar 13 | * baz 14 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/thrift/codeExample.txt: -------------------------------------------------------------------------------- 1 | namespace js test 2 | 3 | const string test = 'test' 4 | 5 | struct MyStruct { 6 | 1: optional string test 7 | } 8 | 9 | service MyService { 10 | void ping() 11 | } 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/python/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/python/python'; 2 | 3 | export const id = 'python'; 4 | export const displayName = 'Python'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'py'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/sql/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/sql/sql'; 2 | 3 | export const id = 'sql'; 4 | export const displayName = 'SQL'; 5 | export const mimeTypes = ['text/x-sql']; 6 | export const fileExtension = 'sql'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/storage/api.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch'; 2 | 3 | const API_HOST = process.env.API_HOST || ''; 4 | 5 | export default function api(path, options) { 6 | return fetch(`${API_HOST}/api/v1${path}`, options); 7 | } 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/icu/index.js: -------------------------------------------------------------------------------- 1 | // import 'codemirror/mode/html/html'; 2 | 3 | export const id = 'icu'; 4 | export const displayName = 'ICU'; 5 | export const mimeTypes = ['text/plain']; 6 | export const fileExtension = 'txt'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint1/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | return { 3 | TemplateLiteral(node) { 4 | context.report(node, 'Do not use template literals'); 5 | } 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint2/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | return { 3 | TemplateLiteral(node) { 4 | context.report(node, 'Do not use template literals'); 5 | } 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint3/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | return { 3 | TemplateLiteral(node) { 4 | context.report(node, 'Do not use template literals'); 5 | } 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/php/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/php/php'; 2 | 3 | export const id = 'php'; 4 | export const displayName = 'PHP'; 5 | export const mimeTypes = ['application/php']; 6 | export const fileExtension = 'php'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/scala/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/clike/clike'; 2 | 3 | export const id = 'text/x-scala'; 4 | export const displayName = 'Scala'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'scala'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/yaml/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/yaml/yaml'; 2 | 3 | export const id = 'yaml'; 4 | export const displayName = 'YAML'; 5 | export const mimeTypes = ['application/yaml']; 6 | export const fileExtension = 'yaml'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/solididy/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/javascript/javascript'; 2 | 3 | export const id = 'solididy'; 4 | export const displayName = 'Solidity'; 5 | export const mimeTypes = []; 6 | export const fileExtension = 'sol'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/htmlmixed/htmlmixed'; 2 | 3 | export const id = 'htmlmixed'; 4 | export const displayName = 'HTML'; 5 | export const mimeTypes = ['text/html']; 6 | export const fileExtension = 'html'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/json/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/javascript/javascript'; 2 | 3 | export const id = 'json'; 4 | export const displayName = 'JSON'; 5 | export const mimeTypes = ['application/json']; 6 | export const fileExtension = 'json'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/webidl/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/webidl/webidl'; 2 | 3 | export const id = 'webidl'; 4 | export const displayName = 'Web IDL'; 5 | export const mimeTypes = ['text/x-webidl']; 6 | export const fileExtension = 'webidl'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphql/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror-graphql/mode'; 2 | 3 | export const id = 'graphql'; 4 | export const displayName = 'GraphQL'; 5 | export const mimeTypes = ['application/graphql']; 6 | export const fileExtension = 'graphql'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/markdown/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/markdown/markdown'; 2 | 3 | export const id = 'markdown'; 4 | export const displayName = 'Markdown'; 5 | export const mimeTypes = ['text/markdown']; 6 | export const fileExtension = 'md'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/glsl/index.js: -------------------------------------------------------------------------------- 1 | import './codemirror-mode/glsl'; 2 | 3 | export const id = 'glsl'; 4 | export const displayName = 'GLSL'; 5 | export const mimeTypes = ['x-shader/x-vertex', 'x-shader/x-fragment']; 6 | export const fileExtension = 'glsl'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/javascript/javascript'; 2 | 3 | export const id = 'javascript'; 4 | export const displayName = 'JavaScript'; 5 | export const mimeTypes = ['text/javascript']; 6 | export const fileExtension = 'js'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/transformers/regexp-tree/codeExample.txt: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Char({node}) { 3 | // Replace 'a' chars with 'b'. 4 | if (node.kind === 'simple' && node.value === 'a') { 5 | node.value = 'b'; 6 | } 7 | } 8 | }; -------------------------------------------------------------------------------- /ast-website/website/src/utils/classnames.js: -------------------------------------------------------------------------------- 1 | export default function cx(...configs) { 2 | return configs.map( 3 | config => typeof config === 'string' ? 4 | config : 5 | Object.keys(config).filter(k => config[k]).join(' '), 6 | ).join(' '); 7 | } 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphviz/codeExample.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copy paste in a GraphViz dot file to explore the syntax tree 3 | */ 4 | 5 | digraph { 6 | rankdir=LR 7 | a [fillcolor=green] 8 | c [fillcolor=red] 9 | a -> b 10 | c -> a [dir="back"] 11 | } 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/protobuf/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/protobuf/protobuf'; 2 | 3 | export const id = 'protobuf'; 4 | export const displayName = 'Protocol Buffers'; 5 | export const mimeTypes = ['text/x-protobuf']; 6 | export const fileExtension = 'proto'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/ocaml/refmt-ml.js: -------------------------------------------------------------------------------- 1 | import config from '../reason/refmt'; 2 | 3 | const ID = 'refmt-ml'; 4 | 5 | export default { 6 | ...config, 7 | id: ID, 8 | parse: function(parser, code) { 9 | return parser.parseOcaml(code); 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/handlebars/handlebars'; 2 | 3 | export const id = 'handlebars'; 4 | export const displayName = 'Handlebars'; 5 | export const mimeTypes = ['text/x-handlebars-template']; 6 | export const fileExtension = 'handlebars'; 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/ocaml/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/mllike/mllike'; 2 | 3 | export const id = 'ocaml'; 4 | export const editorMode = 'text/x-ocaml'; 5 | export const displayName = 'OCaml'; 6 | export const mimeTypes = ['text/x-ocaml']; 7 | export const fileExtension = 'ml'; 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/san/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/htmlmixed/htmlmixed'; 2 | 3 | export const id = 'san'; 4 | export const displayName = 'San'; 5 | export const mimeTypes = ['text/html']; 6 | export const fileExtension = 'san.html'; 7 | export const editorMode = 'htmlmixed'; 8 | -------------------------------------------------------------------------------- /ast-website/website/src/utils/logger.js: -------------------------------------------------------------------------------- 1 | export function logEvent(category, action, label) { 2 | global.ga('send', 'event', category, action, label); 3 | } 4 | 5 | export function logError(message, fatal) { 6 | global.ga('send', 'exception', {exDescription: message, exFatal: fatal}); 7 | } 8 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/java/index.js: -------------------------------------------------------------------------------- 1 | import 'codemirror/mode/clike/clike'; 2 | 3 | export const id = 'java'; 4 | export const displayName = 'Java'; 5 | export const mimeTypes = ['text/x-java-source']; 6 | export const fileExtension = 'java'; 7 | export const editorMode = 'text/x-java'; 8 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__comments.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: // I am comments 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "EOF" 9 | }, 10 | "span": { 11 | "start": 16, 12 | "end": 17 13 | } 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/ember-template-recast/codeExample.txt: -------------------------------------------------------------------------------- 1 | module.exports = function(env) { 2 | let b = env.syntax.builders; 3 | 4 | return { 5 | ElementNode(node) { 6 | node.tag = node.tag.split('').reverse().join(''); 7 | } 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/solididy/codeExample.txt: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | contract SimpleStore { 3 | function set(uint _value) public { 4 | value = _value; 5 | } 6 | 7 | function get() public constant returns (uint) { 8 | return value; 9 | } 10 | 11 | uint value; 12 | } -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/glimmer/codeExample.txt: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | name: 'ast-transform', 4 | 5 | visitor: { 6 | ElementNode(node) { 7 | node.tag = node.tag.split('').reverse().join(''); 8 | } 9 | } 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/babel/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function ({Plugin, types: t}) { 2 | return new Plugin('ast-transform', { 3 | visitor: { 4 | Identifier(node) { 5 | return t.identifier(node.name.split('').reverse().join('')); 6 | } 7 | } 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /compiler/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | pub mod compiler; 5 | mod compiler_function_test; 6 | mod compiler_test; 7 | mod frame; 8 | pub mod op_code; 9 | mod op_code_test; 10 | pub mod symbol_table; 11 | mod symbol_table_test; 12 | pub mod vm; 13 | mod vm_function_test; 14 | mod vm_test; 15 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/glimmer-compiler/codeExample.txt: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | name: 'ast-transform', 4 | 5 | visitor: { 6 | ElementNode(node) { 7 | node.tag = node.tag.split('').reverse().join(''); 8 | } 9 | } 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/prettier/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": false, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false, 10 | 11 | "parser": "babel" 12 | } 13 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/transformers/posthtml/codeExample.txt: -------------------------------------------------------------------------------- 1 | const reverse = str => 2 | str 3 | .split("") 4 | .reverse() 5 | .join(""); 6 | 7 | export default function(tree) { 8 | tree.match({ tag: "h1" }, node => { 9 | 10 | node.content[0] = reverse(node.content[0]); 11 | 12 | return node; 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint1/loadRulesShim.js: -------------------------------------------------------------------------------- 1 | module.exports = function loadRules(/*rulesDir*/) { 2 | // By default, ESLint tries to load all available rules by looking for every 3 | // file in its "rules" directory. Since we don't care about any of the bundled 4 | // rules, just completely ignore them. 5 | return []; 6 | } 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: '/' 5 | schedule: 6 | interval: monthly 7 | time: '21:00' 8 | timezone: Asia/Shanghai 9 | open-pull-requests-limit: 10 10 | ignore: 11 | - dependency-name: wasm-bindgen-test 12 | versions: 13 | - 0.3.20 14 | -------------------------------------------------------------------------------- /ast-website/server/constants.js: -------------------------------------------------------------------------------- 1 | if (!process.env.AUTH_TOKEN) { 2 | console.error( 3 | 'AUTH_TOKEN is not set! That will result in all gists being anonymous, ' + 4 | 'which is probably not what you want.' 5 | ); 6 | process.exit(1); 7 | } 8 | 9 | module.exports = { 10 | AUTH_TOKEN: process.env.AUTH_TOKEN, 11 | SETTINGS_FORMAT: 2, 12 | }; 13 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/vue/codeExample.txt: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 21 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/babel6/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function (babel) { 2 | const { types: t } = babel; 3 | 4 | return { 5 | name: "ast-transform", // not required 6 | visitor: { 7 | Identifier(path) { 8 | path.node.name = path.node.name.split('').reverse().join(''); 9 | } 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/babel7/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function (babel) { 2 | const { types: t } = babel; 3 | 4 | return { 5 | name: "ast-transform", // not required 6 | visitor: { 7 | Identifier(path) { 8 | path.node.name = path.node.name.split('').reverse().join(''); 9 | } 10 | } 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/go/codeExample.txt: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const TIPS = ` 6 | Click on any AST node with a '+' to expand it 7 | Hovering over a node highlights the corresponding location in the source code 8 | Shift click on an AST node to expand the whole subtree 9 | `; 10 | 11 | func PrintTips() { 12 | fmt.Println(TIPS) 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - run: npx envinfo 16 | - name: Build 17 | run: cargo build 18 | - name: Run tests 19 | run: cargo test 20 | -------------------------------------------------------------------------------- /ast-website/scripts/inject-rev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script replaces the special character sequence @@COMMIT@@ in a file with 4 | # a link to the commit on GitHub. The file path is passed as argument but is 5 | # likely just out/index.html 6 | 7 | rev=$(git rev-parse --short HEAD) 8 | sed -i "s%@@COMMIT@@%Build: $rev%" "$1" 9 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/transpilers/typescript.js: -------------------------------------------------------------------------------- 1 | import ts from 'typescript'; 2 | import protect from '../utils/protectFromLoops'; 3 | 4 | let compilerOptions = { module: ts.ModuleKind.System }; 5 | 6 | export default function transpile(code) { 7 | let es5Code = ts.transpileModule(code, compilerOptions).outputText; 8 | es5Code = protect(es5Code); 9 | return es5Code; 10 | } 11 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/codeExample.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Paste or drop some CSS here and explore 3 | * the syntax tree created by chosen parser. 4 | * Enjoy! 5 | */ 6 | 7 | @media screen and (min-width: 480px) { 8 | body { 9 | background-color: lightgreen; 10 | } 11 | } 12 | 13 | #main { 14 | border: 1px solid black; 15 | } 16 | 17 | ul li { 18 | padding: 5px; 19 | } 20 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/ocaml/codeExample.txt: -------------------------------------------------------------------------------- 1 | let tips = [ 2 | "Click on any AST node with a '+' to expand it"; 3 | 4 | "Hovering over a node highlights the 5 | corresponding location in the source code"; 6 | 7 | "Shift click on an AST node to expand the whole subtree" 8 | ] 9 | 10 | let printTips () = 11 | tips |> (List.iteri (fun i tip -> Printf.printf "Tip %d: %s\n" i tip)) 12 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/LoadingIndicatorContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import LoadingIndicator from '../components/LoadingIndicator'; 3 | import {isLoadingSnippet} from '../store/selectors'; 4 | 5 | function mapStateToProps(state) { 6 | return { 7 | visible: isLoadingSnippet(state), 8 | }; 9 | } 10 | 11 | export default connect(mapStateToProps)(LoadingIndicator); 12 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/reason/codeExample.txt: -------------------------------------------------------------------------------- 1 | let tips = [ 2 | "Click on any AST node with a '+' to expand it", 3 | 4 | "Hovering over a node highlights the 5 | corresponding location in the source code", 6 | 7 | "Shift click on an AST node to expand the whole subtree", 8 | ]; 9 | 10 | let printTips = () => 11 | tips |> List.iteri((i, tip) => Printf.printf("Tip %d: %s\n", i, tip)); 12 | -------------------------------------------------------------------------------- /wasm/tests/web.rs: -------------------------------------------------------------------------------- 1 | //! Test suite for the Web and headless browsers. 2 | 3 | #![cfg(target_arch = "wasm32")] 4 | 5 | extern crate wasm_bindgen_test; 6 | use monkey_wasm::parse; 7 | use wasm_bindgen_test::*; 8 | 9 | wasm_bindgen_test_configure!(run_in_browser); 10 | 11 | #[wasm_bindgen_test] 12 | fn pass() { 13 | let input = "let a = 3"; 14 | let r = parse(input); 15 | println!("{}", r); 16 | } 17 | -------------------------------------------------------------------------------- /ast-website/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "astexplorer-server", 3 | "version": "2.0.0", 4 | "main": "index.js", 5 | "private": true, 6 | "author": "Felix Kling", 7 | "dependencies": { 8 | "body-parser": "^1.15.2", 9 | "express": "^4.14.0", 10 | "github-api": "https://github.com/fkling/github.git" 11 | }, 12 | "scripts": { 13 | "start": "STATIC=../out node index.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/playground/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | import "./index.css"; 5 | import { ChakraProvider } from "@chakra-ui/react"; 6 | 7 | ReactDOM.createRoot(document.getElementById("root")!).render( 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /ast-website/website/src/utils/debounce.js: -------------------------------------------------------------------------------- 1 | export default function debounce(f, timeout=100) { 2 | let timer; 3 | let lastArgs; 4 | let lastThis; 5 | 6 | return function(...args) { 7 | lastThis = this; 8 | lastArgs = args; 9 | if (timer) { 10 | return; 11 | } 12 | timer = setTimeout(() => { 13 | timer = null; 14 | f.apply(lastThis, lastArgs); 15 | }, timeout); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/recast/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function transformer(code, { recast, parsers }) { 2 | const ast = recast.parse(code, { parser: parsers.esprima }); 3 | 4 | recast.visit(ast, { 5 | visitIdentifier(path) { 6 | path.node.name = path.node.name.split("").reverse().join(""); 7 | return false; 8 | } 9 | }); 10 | 11 | return recast.print(ast).code; 12 | } 13 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/ASTOutputContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import ASTOutput from '../components/ASTOutput'; 3 | import * as selectors from '../store/selectors'; 4 | 5 | function mapStateToProps(state) { 6 | return { 7 | parseResult: selectors.getParseResult(state), 8 | position: selectors.getCursor(state), 9 | }; 10 | } 11 | 12 | export default connect(mapStateToProps)(ASTOutput); 13 | -------------------------------------------------------------------------------- /packages/playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Monkey Language App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/utils/compileModule.js: -------------------------------------------------------------------------------- 1 | export default function compileModule(code, globals = {}) { 2 | let exports = {}; 3 | let module = { exports }; 4 | let globalNames = Object.keys(globals); 5 | let keys = ['module', 'exports', ...globalNames]; 6 | let values = [module, exports, ...globalNames.map(key => globals[key])]; 7 | new Function(keys.join(), code).apply(exports, values); 8 | return module.exports; 9 | } 10 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: "\"a\"" 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "STRING", 9 | "value": "a" 10 | }, 11 | "span": { 12 | "start": 0, 13 | "end": 3 14 | } 15 | }, 16 | { 17 | "kind": { 18 | "type": "EOF" 19 | }, 20 | "span": { 21 | "start": 3, 22 | "end": 4 23 | } 24 | } 25 | ] 26 | -------------------------------------------------------------------------------- /packages/playground/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/wat/codeExample.txt: -------------------------------------------------------------------------------- 1 | ;; This is WebAssembly Text Format (WAT). 2 | ;; Paste or drop some WAT here and explore 3 | 4 | (module 5 | 6 | ;; this is simple function that adds a couple of parameters 7 | (func (param $a i32) (param $b i32) 8 | (get_local $a) 9 | (get_local $b) 10 | (i32.add) 11 | ) 12 | 13 | ;; this statement exports the function to the host environment 14 | (export "add" (func $add)) 15 | ) -------------------------------------------------------------------------------- /ast-website/website/src/parsers/java/codeExample.txt: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Example { 7 | private ArrayList names; 8 | 9 | public Example() { 10 | names = new ArrayList<>(); 11 | } 12 | 13 | public void addName(String name) { 14 | names.add(name); 15 | } 16 | 17 | public List getNames() { 18 | return new ArrayList<>(names); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mdx/codeExample.txt: -------------------------------------------------------------------------------- 1 | import MyComp from './components/MyComp' 2 | 3 | export const meta = { 4 | title: 'Page Title', 5 | description: 'This is a page description', 6 | } 7 | 8 | # Hello 9 | 10 | 11 | Component children 12 | 13 | 14 | Some *emphasis*, **importance**, and `code`. 15 | 16 | --- 17 | 18 | ```javascript 19 | console.log('!'); 20 | ``` 21 | 22 | * foo 23 | * bar 24 | * baz 25 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/rust/codeExample.txt: -------------------------------------------------------------------------------- 1 | const TIPS: &[&str] = &[ 2 | "Click on any AST node with a '+' to expand it", 3 | 4 | "Hovering over a node highlights the \ 5 | corresponding location in the source code", 6 | 7 | "Shift click on an AST node to expand the whole subtree", 8 | ]; 9 | 10 | pub fn print_tips() { 11 | for (i, tip) in TIPS.iter().enumerate() { 12 | println!("Tip {}: {}.", i, tip); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ast-website/scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | REMOTE=${1:-"server"} 6 | BRANCH=${2:-"master"} 7 | 8 | if ! git diff --quiet && git diff --cached --quiet; then 9 | echo >&2 "You have uncommitted changes, you probably don't want to update the server." 10 | exit 1 11 | fi 12 | 13 | for i in {5..1}; do 14 | printf "\rPushing '$BRANCH' to '$REMOTE' in $i ..." && sleep 1; 15 | done 16 | 17 | echo "\nPushing..." 18 | git push $REMOTE $BRANCH 19 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/php/codeExample.txt: -------------------------------------------------------------------------------- 1 | $tip) { 15 | echo "Tip $i: " . $tip; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_string.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "\"jw\"" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "String", 11 | "raw": "jw", 12 | "span": { 13 | "start": 0, 14 | "end": 4 15 | } 16 | } 17 | ], 18 | "span": { 19 | "start": 0, 20 | "end": 5 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ast-website/website/src/components/LoadingIndicator.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default function LoadingIndicator(props) { 5 | return props.visible ? 6 |
8 |
9 | 10 |
11 |
: 12 | null; 13 | } 14 | 15 | LoadingIndicator.propTypes = { 16 | visible: PropTypes.bool, 17 | }; 18 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphql/codeExample.txt: -------------------------------------------------------------------------------- 1 | # Paste or drop some GraphQL queries or schema 2 | # definitions here and explore the syntax tree 3 | # created by the GraphQL parser. 4 | 5 | query GetUser($userId: ID!) { 6 | user(id: $userId) { 7 | id, 8 | name, 9 | isViewerFriend, 10 | profilePicture(size: 50) { 11 | ...PictureFragment 12 | } 13 | } 14 | } 15 | 16 | fragment PictureFragment on Picture { 17 | uri, 18 | width, 19 | height 20 | } 21 | -------------------------------------------------------------------------------- /wasm/src/utils.rs: -------------------------------------------------------------------------------- 1 | pub fn set_panic_hook() { 2 | // When the `console_error_panic_hook` feature is enabled, we can call the 3 | // `set_panic_hook` function at least once during initialization, and then 4 | // we will get better error messages if our code ever panics. 5 | // 6 | // For more details see 7 | // https://github.com/rustwasm/console_error_panic_hook#readme 8 | #[cfg(feature = "console_error_panic_hook")] 9 | console_error_panic_hook::set_once(); 10 | } 11 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/JSON.js: -------------------------------------------------------------------------------- 1 | import JSONEditor from '../JSONEditor'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | import stringify from 'json-stringify-safe'; 6 | 7 | export default function JSON({parseResult}) { 8 | return ( 9 | 13 | ); 14 | } 15 | 16 | JSON.propTypes = { 17 | parseResult: PropTypes.object, 18 | }; 19 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | test: 5 | working_directory: ~/repo 6 | docker: 7 | - image: gengjiawen/node-build 8 | steps: 9 | - checkout 10 | - run: npx envinfo 11 | - run: 12 | name: test 13 | command: | 14 | cd wasm && wasm-pack build --scope=gengjiawen 15 | - store_artifacts: 16 | path: wasm/pkg 17 | 18 | workflows: 19 | version: 2 20 | build_and_test: 21 | jobs: 22 | - test 23 | -------------------------------------------------------------------------------- /ast-website/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - node 5 | cache: 6 | yarn: true 7 | directories: 8 | - website/node_modules 9 | before_install: 10 | - curl -o- -L https://yarnpkg.com/install.sh | bash 11 | - export PATH=$HOME/.yarn/bin:$PATH 12 | install: 13 | - cd website 14 | - yarn install --production=false 15 | before_script: 16 | - yarn lint 17 | script: 18 | - yarn watch -- --no-watch 19 | env: 20 | - NODE_ENV=development 21 | - NODE_ENV=production 22 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/markdown/transformers/remark/codeExample.txt: -------------------------------------------------------------------------------- 1 | // available utilities are: "unist-util-is", "unist-util-visit", and "unist-util-visit-parents" 2 | const visit = require("unist-util-visit"); 3 | 4 | module.exports = function attacher(options) { 5 | return function transformer(tree, vfile) { 6 | // add a level to headings, for example `# heading` to `## heading` 7 | visit(tree, "heading", (node) => { 8 | node.depth += 1 9 | }); 10 | return tree; 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/python/codeExample.txt: -------------------------------------------------------------------------------- 1 | print("Hello world") 2 | 3 | num1 = 1.5 4 | num2 = 6.3 5 | 6 | # Add two numbers 7 | sum = num1 + num2 8 | 9 | # Display the sum 10 | print('The sum of {0} and {1} is {2}'.format(num1, num2, sum)) 11 | 12 | # Note: change this value for a different result 13 | num = 8 14 | 15 | # To take the input from the user 16 | #num = float(input('Enter a number: ')) 17 | 18 | num_sqrt = num ** 0.5 19 | print('The square root of %0.3f is %0.3f'%(num ,num_sqrt)) 20 | 21 | -------------------------------------------------------------------------------- /compiler/frame.rs: -------------------------------------------------------------------------------- 1 | use crate::op_code::Instructions; 2 | use object::{Closure}; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct Frame { 6 | pub cl: Closure, 7 | pub ip: i32, 8 | pub base_pointer: usize, 9 | } 10 | 11 | impl Frame { 12 | pub fn new(func: Closure, base_pointer: usize) -> Self { 13 | Frame { cl: func, ip: -1, base_pointer } 14 | } 15 | 16 | pub fn instructions(&self) -> Instructions { 17 | return Instructions { data: self.cl.func.instructions.clone() }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ast-website/server/handlers/gist/loadGist.js: -------------------------------------------------------------------------------- 1 | const {AUTH_TOKEN} = require('../../constants'); 2 | const GitHub = require('github-api'); 3 | 4 | module.exports = function loadGist(req, res, next) { 5 | const gh = new GitHub({token: AUTH_TOKEN}); 6 | const gist = gh.getGist(req.params.snippetid); 7 | const latest = req.params.revisionid === 'latest'; 8 | (latest ? 9 | gist.read() : 10 | gist.getRevision(req.params.revisionid) 11 | ) 12 | .then(response => res.json(response.data)) 13 | .catch(next); 14 | }; 15 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | - init: time cargo build 6 | command: cargo test 7 | - init: cargo install cargo-insta && exit # cargo insta test && cargo insta accept to update snapshots 8 | - init: cargo install cargo-workspaces 9 | - init: cd wasm && wasm-pack build --release --scope=gengjiawen && cd .. && pnpm i 10 | 11 | vscode: 12 | extensions: 13 | - vadimcn.vscode-lldb 14 | - gengjiawen.vscode-wasm 15 | - gengjiawen.vscode-postfix-ts 16 | - rust-lang.rust-analyzer 17 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/PasteDropTargetContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import PasteDropTarget from '../components/PasteDropTarget'; 3 | import {setError, dropText} from '../store/actions'; 4 | 5 | function mapDispatchToProps(dispatch) { 6 | return { 7 | onText: (type, event, code, categoryId) => { 8 | dispatch(dropText(code, categoryId)); 9 | }, 10 | onError: error => dispatch(setError(error)), 11 | }; 12 | } 13 | 14 | export default connect(null, mapDispatchToProps)(PasteDropTarget); 15 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/utils/defaultESTreeParserInterface.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../../utils/defaultParserInterface'; 2 | 3 | export default { 4 | ...defaultParserInterface, 5 | 6 | opensByDefault(node, key) { 7 | return ( 8 | Boolean(node) && node.type === 'Program' || 9 | key === 'body' || 10 | key === 'elements' || // array literals 11 | key === 'declarations' || // variable declaration 12 | key === 'expression' // expression statements 13 | ); 14 | }, 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/NewButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default function SaveButton({saving, forking, onNew}) { 5 | return ( 6 | 12 | ); 13 | } 14 | 15 | SaveButton.propTypes = { 16 | saving: PropTypes.bool, 17 | forking: PropTypes.bool, 18 | onNew: PropTypes.func, 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/pug/codeExample.txt: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | head 4 | title Pug 5 | script(type='text/javascript'). 6 | const foo = true; 7 | let bar = function() {}; 8 | if (foo) { 9 | bar(1 + 5) 10 | } 11 | body 12 | h1 Pug - node template engine 13 | #container.col 14 | p You are amazing 15 | p 16 | | Pug is a terse and simple 17 | | templating language with a 18 | | strong focus on performance 19 | | and powerful features. 20 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/ShareButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default function ShareButton({onShareButtonClick, snippet}) { 5 | return ( 6 | 12 | ); 13 | } 14 | 15 | ShareButton.propTypes = { 16 | onShareButtonClick: PropTypes.func.isRequired, 17 | snippet: PropTypes.object, 18 | }; 19 | -------------------------------------------------------------------------------- /ast-website/server/handlers/gist/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const loadGist = require('./loadGist'); 3 | const saveAnonymousGist = require('./saveAnonymousGist'); 4 | 5 | module.exports = express.Router() 6 | // Load snippet 7 | .get('/:snippetid/:revisionid', loadGist) 8 | // Create new "anonymous" snippet 9 | .post('/', saveAnonymousGist.create) 10 | // Update "anonymous" snippet 11 | .patch('/:snippetid', saveAnonymousGist.update) 12 | // Fork "anonymous" snippet 13 | .post('/:snippetid/:revisionid', saveAnonymousGist.fork); 14 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/ErrorMessageContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import ErrorMessage from '../components/ErrorMessage'; 3 | import {clearError} from '../store/actions'; 4 | import {getError} from '../store/selectors'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | error: getError(state), 9 | }; 10 | } 11 | 12 | 13 | function mapDispatchToProps(dispatch) { 14 | return { 15 | onWantToClose: () => dispatch(clearError()), 16 | }; 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(ErrorMessage); 20 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/transformers/postcss/codeExample.txt: -------------------------------------------------------------------------------- 1 | const plugin = () => ({ 2 | postcssPlugin: 'postcss-reverse-props', 3 | Once(root) { 4 | // Transform CSS AST here 5 | root.walkRules(rule => { 6 | // Transform each rule here 7 | rule.walkDecls(decl => { 8 | // Transform each property declaration here 9 | decl.prop = decl.prop.split('').reverse().join(''); 10 | }); 11 | }); 12 | } 13 | }); 14 | 15 | plugin.postcss = true; 16 | 17 | export default plugin; 18 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/transformers/svelte/codeExample.txt: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | name: 'svelte-transform', 4 | 5 | // transform function for entire markup 6 | markup: function(content) { 7 | return content; 8 | }, 9 | 10 | // transform function for script tag 11 | script:function(content, attributes) { 12 | return content.replace(/foo/g, 'baz'); 13 | }, 14 | 15 | // transform function for style tag 16 | style: function(content, attributes) { 17 | return content; 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/handlebars.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface'; 2 | import pkg from 'handlebars/package.json'; 3 | 4 | const ID = 'handlebars'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | 14 | loadParser(callback) { 15 | require(['handlebars'], (handlebars) => callback(handlebars.parse)); 16 | }, 17 | 18 | opensByDefault(node, key) { 19 | return key === 'body'; 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/utils/defaultCSSParserInterface.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../../utils/defaultParserInterface'; 2 | 3 | export default { 4 | ...defaultParserInterface, 5 | 6 | getOffset({ line, column }) { 7 | return this.lineOffsets[line - 1] + column - 1; 8 | }, 9 | 10 | parse(parseCSS, code) { 11 | this.lineOffsets = []; 12 | let index = 0; 13 | do { 14 | this.lineOffsets.push(index); 15 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign 16 | return parseCSS(code); 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/codeExample.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Paste or drop some JavaScript here and explore 3 | * the syntax tree created by chosen parser. 4 | * You can use all the cool new features from ES6 5 | * and even more. Enjoy! 6 | */ 7 | 8 | let tips = [ 9 | "Click on any AST node with a '+' to expand it", 10 | 11 | "Hovering over a node highlights the \ 12 | corresponding location in the source code", 13 | 14 | "Shift click on an AST node to expand the whole subtree" 15 | ]; 16 | 17 | function printTips() { 18 | tips.forEach((tip, i) => console.log(`Tip ${i}:` + tip)); 19 | } 20 | -------------------------------------------------------------------------------- /Maintainer.md: -------------------------------------------------------------------------------- 1 | ## Version and Publish 2 | 3 | Now automated with release-please 4 | 5 | Version 6 | 7 | ```bash 8 | cargo install cargo-workspaces 9 | cargo workspaces version custom 0.7.0 --no-git-commit 10 | ``` 11 | 12 | Publish 13 | 14 | ```bash 15 | cargo workspaces publish --from-git --token $CARGO_TOKEN 16 | ``` 17 | 18 | ## Debug CI 19 | 20 | docker run -v $PWD:/pwd -w /pwd gengjiawen/node-build bash -c "npx envinfo" 21 | docker run -v $PWD:/pwd -w /pwd -it gengjiawen/node-build fish 22 | docker run -v $PWD:/pwd -w /pwd gengjiawen/node-build bash -c "cd wasm && wasm-pack build --release --scope=gengjiawen" 23 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/ember-template-recast.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface'; 2 | import pkg from 'ember-template-recast/package.json'; 3 | 4 | const ID = 'ember-template-recast'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | 14 | loadParser(callback) { 15 | require(['ember-template-recast'], (recast) => callback(recast.parse)); 16 | }, 17 | 18 | opensByDefault(node, key) { 19 | return key === 'body'; 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /ast-website/website/src/utils/stringify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a JS value to a sensible string representation. 3 | */ 4 | export default function stringify(value) { 5 | switch (typeof value) { 6 | case 'function': 7 | return value.toString().match(/function[^(]*\([^)]*\)/)[0]; 8 | case 'object': 9 | return value ? JSON.stringify(value, stringify) : 'null'; 10 | case 'undefined': 11 | return 'undefined'; 12 | case 'number': 13 | case 'bigint': 14 | return Number.isNaN(value) ? 'NaN' : String(value); 15 | default: 16 | return JSON.stringify(value); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/playground/src/Editor.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror'; 3 | import { vim } from '@replit/codemirror-vim'; 4 | 5 | interface EditorProps { 6 | extra?: ReactCodeMirrorProps, 7 | code?: string, 8 | onChange?: (code: string) => void; 9 | } 10 | 11 | export function Editor(editorProps? : EditorProps) { 12 | return ( 13 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /parser/main.rs: -------------------------------------------------------------------------------- 1 | use lexer::Lexer; 2 | use parser::Parser; 3 | use std::io::stdin; 4 | 5 | pub fn main() { 6 | println!("Welcome to monkey parser by gengjiawen"); 7 | loop { 8 | let mut input = String::new(); 9 | stdin().read_line(&mut input).unwrap(); 10 | 11 | if input.trim_end().is_empty() { 12 | println!("bye"); 13 | std::process::exit(0) 14 | } 15 | 16 | let lexer = Lexer::new(&input); 17 | let mut parser = Parser::new(lexer); 18 | let program = parser.parse_program().unwrap(); 19 | println!("{}", program); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/glimmer.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface'; 2 | import pkg from '@glimmer/syntax/package.json'; 3 | 4 | const ID = 'glimmer'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm', 13 | 14 | loadParser(callback) { 15 | require(['@glimmer/syntax'], (glimmer) => callback(glimmer.preprocess)); 16 | }, 17 | 18 | opensByDefault(node, key) { 19 | return key === 'body'; 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/jscodeshift/codeExample.txt: -------------------------------------------------------------------------------- 1 | // jscodeshift can take a parser, like "babel", "babylon", "flow", "ts", or "tsx" 2 | // Read more: https://github.com/facebook/jscodeshift#parser 3 | export const parser = '{{parser}}' 4 | 5 | // Press ctrl+space for code completion 6 | export default function transformer(file, api) { 7 | const j = api.jscodeshift; 8 | 9 | return j(file.source) 10 | .find(j.Identifier) 11 | .forEach(path => { 12 | j(path).replaceWith( 13 | j.identifier(path.node.name.split('').reverse().join('')) 14 | ); 15 | }) 16 | .toSource(); 17 | } 18 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/transpilers/babel.js: -------------------------------------------------------------------------------- 1 | import * as babel from 'babel-core'; 2 | import es2015 from 'babel-preset-es2015'; 3 | import stage0 from 'babel-preset-stage-0'; 4 | import flowStripTypes from 'babel-plugin-transform-flow-strip-types'; 5 | import protect from '../utils/protectFromLoops'; 6 | 7 | const options = { 8 | presets: [es2015, stage0], 9 | plugins: [flowStripTypes], 10 | ast: false, 11 | babelrc: false, 12 | highlightCode: false, 13 | }; 14 | 15 | export default function transpile(code) { 16 | let es5Code = babel.transform(code, options).code; 17 | es5Code = protect(es5Code); 18 | return es5Code; 19 | } 20 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_return.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: return 3 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "ReturnStatement", 11 | "argument": { 12 | "type": "Integer", 13 | "raw": 3, 14 | "span": { 15 | "start": 7, 16 | "end": 8 17 | } 18 | }, 19 | "span": { 20 | "start": 0, 21 | "end": 8 22 | } 23 | } 24 | ], 25 | "span": { 26 | "start": 0, 27 | "end": 9 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/ShareDialogContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import {closeShareDialog} from '../store/actions'; 3 | import {showShareDialog, getRevision} from '../store/selectors'; 4 | import ShareDialog from '../components/dialogs/ShareDialog'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | visible: showShareDialog(state), 9 | snippet: getRevision(state), 10 | }; 11 | } 12 | 13 | function mapDispatchToProps(dispatch) { 14 | return { 15 | onWantToClose: () => dispatch(closeShareDialog()), 16 | }; 17 | } 18 | 19 | export default connect(mapStateToProps, mapDispatchToProps)(ShareDialog); 20 | -------------------------------------------------------------------------------- /packages/playground/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | // @ts-ignore 4 | import topLevelAwait from "vite-plugin-top-level-await" 5 | import wasm from "vite-plugin-wasm" 6 | import visualizer from 'rollup-plugin-visualizer' 7 | 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | base: process.env.GITHUB_ACTION ? '/monkey-rust/' : '/', 11 | server: { 12 | port: 3000 13 | }, 14 | plugins: [ 15 | react(), 16 | wasm(), 17 | topLevelAwait() 18 | ], 19 | build: { 20 | rollupOptions: { 21 | plugins: [visualizer()], 22 | }, 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /object/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-object" 3 | version = "0.10.1" 4 | description = "a object system for monkey lang" 5 | homepage = "https://github.com/gengjiawen/monkey-rust" 6 | repository = "https://github.com/gengjiawen/monkey-rust" 7 | authors = ["gengjiawen "] 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [lib] 14 | name = "object" 15 | path= "object.rs" 16 | 17 | [dependencies] 18 | lazy_static = "1.5.0" 19 | monkey-parser = { path = "../parser", version = "0.10.0" } 20 | 21 | [dev-dependencies] 22 | insta = "1.42.2" 23 | -------------------------------------------------------------------------------- /packages/playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/prepare-release.yml: -------------------------------------------------------------------------------- 1 | name: prepare-dist 2 | on: 3 | push: 4 | branches: 5 | - 'release-*' 6 | - 'release/*' 7 | create: 8 | branches: 9 | - 'release-*' 10 | - 'release/*' 11 | workflow_dispatch: 12 | jobs: 13 | prepare-dist: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | steps: 18 | - uses: actions/checkout@v3 19 | - run: docker run -v $PWD:/pwd -w /pwd gengjiawen/node-build bash -c "yarn && pnpx ts-node scripts/bump_cargo_packages.ts" 20 | - uses: stefanzweifel/git-auto-commit-action@v4 21 | with: 22 | commit_message: 'chore: prepare rust packages' 23 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint4/codeExample.txt: -------------------------------------------------------------------------------- 1 | export default function(context) { 2 | return { 3 | TemplateLiteral(node) { 4 | context.report({ 5 | node, 6 | message: 'Do not use template literals', 7 | 8 | fix(fixer) { 9 | if (node.expressions.length) { 10 | // Can't auto-fix template literal with expressions 11 | return; 12 | } 13 | 14 | return [ 15 | fixer.replaceTextRange([node.start, node.start + 1], '"'), 16 | fixer.replaceTextRange([node.end - 1, node.end], '"'), 17 | ]; 18 | }, 19 | }); 20 | } 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/sql/sqlite-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'sqlite-parser/package.json'; 3 | 4 | const ID = 'sqlite-parser'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/codeschool/sqlite-parser', 13 | 14 | loadParser(callback) { 15 | require(['sqlite-parser'], callback); 16 | }, 17 | 18 | parse(sqliteParser, code) { 19 | return sqliteParser(code); 20 | }, 21 | 22 | opensByDefault(node, key) { 23 | return key === 'statement'; 24 | }, 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /compiler/symbol_table_test.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use crate::symbol_table::{SymbolScope, SymbolTable}; 4 | #[test] 5 | fn test_define() { 6 | let mut symbol_table = SymbolTable::new(); 7 | let symbol = symbol_table.define("x".to_string()); 8 | assert_eq!(symbol.name, "x"); 9 | assert_eq!(symbol.scope, SymbolScope::Global); 10 | assert_eq!(symbol.index, 0); 11 | } 12 | 13 | #[test] 14 | fn test_resolve() { 15 | let mut symbol_table = SymbolTable::new(); 16 | let symbol = symbol_table.define("x".to_string()); 17 | assert_eq!(symbol_table.resolve("x".to_string()), Some(symbol)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lexer/main.rs: -------------------------------------------------------------------------------- 1 | use lexer::token::TokenKind; 2 | use lexer::Lexer; 3 | use std::io::stdin; 4 | 5 | pub fn main() { 6 | println!("Welcome to monkey lexer by gengjiawen"); 7 | loop { 8 | let mut input = String::new(); 9 | stdin().read_line(&mut input).unwrap(); 10 | 11 | if input.trim_end().is_empty() { 12 | println!("bye"); 13 | std::process::exit(0) 14 | } 15 | 16 | let mut l = Lexer::new(&input); 17 | loop { 18 | let t = l.next_token(); 19 | if t.kind == TokenKind::EOF { 20 | break; 21 | } else { 22 | println!("{}", t) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lexer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-lexer" 3 | version = "0.10.1" 4 | description = "a lexer for monkey lang" 5 | homepage = "https://github.com/gengjiawen/monkey-rust" 6 | repository = "https://github.com/gengjiawen/monkey-rust" 7 | authors = ["gengjiawen "] 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [lib] 14 | name = "lexer" 15 | path= "lib.rs" 16 | 17 | [[bin]] 18 | name = "monkey-lexer" 19 | path = "main.rs" 20 | 21 | [dependencies] 22 | serde = {version = "1.0", features = ["derive"]} 23 | serde_json = "1.0" 24 | 25 | [dev-dependencies] 26 | insta = "1.42.2" 27 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/SettingsDrawerContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import { expandSettingsDrawer, collapseSettingsDrawer } from '../store/actions'; 3 | import { showSettingsDrawer } from '../store/selectors'; 4 | import SettingsDrawer from '../components/SettingsDrawer'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | isOpen: showSettingsDrawer(state), 9 | }; 10 | } 11 | 12 | function mapDispatchToProps(dispatch) { 13 | return { 14 | onWantToExpand: () => dispatch(expandSettingsDrawer()), 15 | onWantToCollapse: () => dispatch(collapseSettingsDrawer()), 16 | }; 17 | } 18 | 19 | export default connect( 20 | mapStateToProps, 21 | mapDispatchToProps, 22 | )(SettingsDrawer); 23 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/json/json-to-ast.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'json-to-ast/package.json'; 3 | 4 | const ID = 'jsonToAst'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc']), 14 | 15 | loadParser(callback) { 16 | require(['json-to-ast'], callback); 17 | }, 18 | 19 | parse(jsonToAst, code) { 20 | return jsonToAst(code); 21 | }, 22 | 23 | nodeToRange({loc}) { 24 | if (loc) { 25 | return [ 26 | loc.start.offset, 27 | loc.end.offset, 28 | ]; 29 | } 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /interpreter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-interpreter" 3 | version = "0.10.1" 4 | description = "an interpreter for monkeylang" 5 | homepage = "https://github.com/gengjiawen/monkey-rust" 6 | repository = "https://github.com/gengjiawen/monkey-rust" 7 | authors = ["gengjiawen "] 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [lib] 14 | name = "interpreter" 15 | path= "lib.rs" 16 | 17 | [[bin]] 18 | name = "monkey-interpreter" 19 | path = "main.rs" 20 | 21 | [dependencies] 22 | monkey-parser = { path = "../parser", version = "0.10.0" } 23 | monkey-object = { path = "../object", version = "0.10.0" } 24 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__array.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: "[3]" 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "LBRACKET" 9 | }, 10 | "span": { 11 | "start": 0, 12 | "end": 1 13 | } 14 | }, 15 | { 16 | "kind": { 17 | "type": "INT", 18 | "value": 3 19 | }, 20 | "span": { 21 | "start": 1, 22 | "end": 2 23 | } 24 | }, 25 | { 26 | "kind": { 27 | "type": "RBRACKET" 28 | }, 29 | "span": { 30 | "start": 2, 31 | "end": 3 32 | } 33 | }, 34 | { 35 | "kind": { 36 | "type": "EOF" 37 | }, 38 | "span": { 39 | "start": 3, 40 | "end": 4 41 | } 42 | } 43 | ] 44 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/monkey/codeExample.txt: -------------------------------------------------------------------------------- 1 | let version = 1 + (50 / 2) - (8 * 3); 2 | 3 | let name = "The Monkey programming language"; 4 | 5 | let isMonkeyFastNow = true; 6 | 7 | let people = [{"name": "Anna", "age": 24}, {"name": "Bob", "age": 99}]; 8 | 9 | let getName = fn(person) { person["name"]; }; 10 | getName(people[0]); 11 | getName(people[1]); 12 | 13 | puts(len(people)) 14 | 15 | let fibonacci = fn(x) { 16 | if (x == 0) { 17 | 0 18 | } else { 19 | if (x == 1) { 20 | return 1; 21 | } else { 22 | fibonacci(x - 1) + fibonacci(x - 2); 23 | } 24 | } 25 | }; 26 | 27 | 28 | let newAdder = fn(a, b) { 29 | fn(c) { a + b + c }; 30 | }; 31 | 32 | let adder = newAdder(1, 2); 33 | 34 | adder(8); 35 | -------------------------------------------------------------------------------- /compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-compiler" 3 | version = "0.10.1" 4 | description = "a compiler for monkeylang" 5 | homepage = "https://github.com/gengjiawen/monkey-rust" 6 | repository = "https://github.com/gengjiawen/monkey-rust" 7 | authors = ["gengjiawen "] 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | [lib] 12 | name = "compiler" 13 | path= "lib.rs" 14 | 15 | [[bin]] 16 | name = "monkey-compiler" 17 | path = "main.rs" 18 | 19 | [dependencies] 20 | lazy_static = "1.5.0" 21 | byteorder = "1.5.0" 22 | strum = { version = "0.25.0", features = ["derive"]} 23 | strum_macros = "0.26" 24 | monkey-parser = { path = "../parser", version = "0.10.0" } 25 | monkey-object = { path = "../object", version = "0.10.0" } 26 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/utils/protectFromLoops.js: -------------------------------------------------------------------------------- 1 | import halts, {loopProtect} from 'halting-problem'; 2 | 3 | export default function protect(jsCode) { 4 | // assert that there are no obvious infinite loops 5 | halts(jsCode); 6 | // guard against non-obvious loops with a timeout of 5 seconds 7 | let start = Date.now(); 8 | jsCode = loopProtect( 9 | jsCode, 10 | [ 11 | // this function gets called in all possible loops 12 | // it gets passed the line number as its only argument 13 | '(function (line) {', 14 | 'if (Date.now() > ' + (start + 5000) + ') {', 15 | ' throw new Error("Infinite loop detected on line " + line);', 16 | '}', 17 | '})', 18 | ].join(''), 19 | ); 20 | 21 | return jsCode; 22 | } 23 | -------------------------------------------------------------------------------- /ast-website/website/src/core/ParseResult.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Describes the result of a parse process. Only exists here for documentation 3 | * purposes. 4 | */ 5 | // eslint-disable-next-line no-unused-vars 6 | const ParseResult = { 7 | /** 8 | * The generated AST 9 | */ 10 | ast: 'any', 11 | 12 | /** 13 | * An error object, if parsing resulted in an error 14 | */ 15 | error: 'Object', 16 | 17 | /** 18 | * How long it took to generate the AST 19 | */ 20 | time: 'number', 21 | 22 | treeAdapter: { 23 | /** 24 | * The type of the adapter to use, as defined in TreeAdapters.js 25 | */ 26 | type: 'string', 27 | /** 28 | * Override the default options with these values 29 | */ 30 | options: 'Object', 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "declaration": true, 8 | "allowSyntheticDefaultImports": true, 9 | "removeComments": true, 10 | "noImplicitAny": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "strictNullChecks": true, 14 | "noUnusedLocals": false, 15 | "experimentalDecorators": true, 16 | "emitDecoratorMetadata": true, 17 | "strict": true, 18 | "outDir": "./build", 19 | "lib": [ 20 | "es2020", 21 | "dom" 22 | ] 23 | }, 24 | "exclude": [ 25 | "node_modules", 26 | "build", 27 | "test", 28 | "**/*.test.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /packages/playground/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-float infinite 3s ease-in-out; 13 | } 14 | } 15 | 16 | .App-header { 17 | min-height: 100vh; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | } 24 | 25 | .App-link { 26 | color: rgb(112, 76, 182); 27 | } 28 | 29 | @keyframes App-logo-float { 30 | 0% { 31 | transform: translateY(0); 32 | } 33 | 50% { 34 | transform: translateY(10px); 35 | } 36 | 100% { 37 | transform: translateY(0px); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-parser" 3 | version = "0.10.1" 4 | description = "a parser for monkey lang" 5 | homepage = "https://github.com/gengjiawen/monkey-rust" 6 | repository = "https://github.com/gengjiawen/monkey-rust" 7 | authors = ["gengjiawen "] 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [lib] 14 | name = "parser" 15 | path= "lib.rs" 16 | 17 | [[bin]] 18 | name = "monkey-parser" 19 | path = "main.rs" 20 | 21 | [dependencies] 22 | monkey-lexer = { path = "../lexer", version = "0.10.0" } 23 | serde = {version = "1.0", features = ["derive"]} 24 | serde_json = "1.0" 25 | 26 | [dev-dependencies] 27 | insta = "1.42.2" 28 | 29 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphviz/redot.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'redot/package.json'; 3 | 4 | const ID = 'redot'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['position']), 14 | 15 | loadParser(callback) { 16 | require(['redot'], callback); 17 | }, 18 | 19 | parse(redot, code) { 20 | return redot().parse(code); 21 | }, 22 | 23 | nodeToRange({ position }) { 24 | if (position) { 25 | return [position.start.offset, position.end.offset]; 26 | } 27 | }, 28 | 29 | opensByDefault(node, key) { 30 | return key === 'children'; 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/protobuf/codeExample.txt: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tutorial; 3 | 4 | import "google/protobuf/timestamp.proto"; 5 | 6 | option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"; 7 | 8 | message Person { 9 | string name = 1; 10 | int32 id = 2; // Unique ID number for this person. 11 | string email = 3; 12 | 13 | enum PhoneType { 14 | MOBILE = 0; 15 | HOME = 1; 16 | WORK = 2; 17 | } 18 | 19 | message PhoneNumber { 20 | string number = 1; 21 | PhoneType type = 2; 22 | } 23 | 24 | repeated PhoneNumber phones = 4; 25 | 26 | google.protobuf.Timestamp last_updated = 5; 27 | } 28 | 29 | // Our address book file is just one of these. 30 | message AddressBook { 31 | repeated Person people = 1; 32 | } 33 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint8/codeExample.txt: -------------------------------------------------------------------------------- 1 | export const meta = { 2 | type: 'problem', 3 | hasSuggestions: true, 4 | fixable: true, 5 | }; 6 | 7 | export function create(context) { 8 | return { 9 | TemplateLiteral(node) { 10 | context.report({ 11 | node, 12 | message: 'Do not use template literals', 13 | 14 | fix(fixer) { 15 | if (node.expressions.length) { 16 | // Can't auto-fix template literal with expressions 17 | return; 18 | } 19 | 20 | return [ 21 | fixer.replaceTextRange([node.start, node.start + 1], '"'), 22 | fixer.replaceTextRange([node.end - 1, node.end], '"'), 23 | ]; 24 | }, 25 | }); 26 | } 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /ast-website/website/src/components/LocalStorage.js: -------------------------------------------------------------------------------- 1 | const storage = global.localStorage; 2 | const key = 'explorerSettingsV1'; 3 | const noop = () => {}; 4 | 5 | export const writeState = storage ? 6 | state => { 7 | try { 8 | storage.setItem(key, JSON.stringify(state)); 9 | } catch(e) { 10 | // eslint-disable-next-line no-console 11 | console.warn('Unable to write to local storage.'); 12 | } 13 | } : 14 | noop; 15 | 16 | export const readState = storage ? 17 | () => { 18 | try { 19 | const state = storage.getItem(key); 20 | if (state) { 21 | return JSON.parse(state); 22 | } 23 | } catch(e) { 24 | // eslint-disable-next-line no-console 25 | console.warn('Unable to read from local storage.'); 26 | } 27 | } : 28 | noop; 29 | -------------------------------------------------------------------------------- /ast-website/website/fontcustom/input-svg/reason.svg: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint8/index.js: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint8/package.json'; 2 | 3 | const ID = 'eslint-v8'; 4 | const name = 'ESLint v8'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: name, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | 12 | defaultParserID: 'babel-eslint', 13 | 14 | loadTransformer(callback) { 15 | require([ 16 | 'eslint8/lib/linter', 17 | 'eslint8/lib/source-code', 18 | '../../utils/eslint4Utils', 19 | ], (Linter, sourceCode, utils) => 20 | callback({ eslint: new Linter.Linter(), sourceCode, utils })); 21 | }, 22 | 23 | transform({ eslint, sourceCode, utils }, transformCode, code) { 24 | utils.defineRule(eslint, transformCode); 25 | return utils.runRule(code, eslint, sourceCode); 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_index.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "a[1]" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "Index", 11 | "object": { 12 | "type": "IDENTIFIER", 13 | "name": "a", 14 | "span": { 15 | "start": 0, 16 | "end": 1 17 | } 18 | }, 19 | "index": { 20 | "type": "Integer", 21 | "raw": 1, 22 | "span": { 23 | "start": 2, 24 | "end": 3 25 | } 26 | }, 27 | "span": { 28 | "start": 1, 29 | "end": 4 30 | } 31 | } 32 | ], 33 | "span": { 34 | "start": 0, 35 | "end": 5 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/css/tree.css: -------------------------------------------------------------------------------- 1 | .tree-visualization { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .tree-visualization > .toolbar { 7 | padding: 5px; 8 | flex-shrink: 0; 9 | } 10 | 11 | .tree-visualization > .toolbar label { 12 | cursor: pointer; 13 | margin-right: 5px; 14 | -webkit-touch-callout: none; 15 | user-select: none; 16 | white-space: nowrap; 17 | } 18 | 19 | .tree-visualization ul { 20 | margin: 0; 21 | padding-left: 20px; 22 | overflow: auto; 23 | } 24 | 25 | .tree-visualization > ul { 26 | cursor: default; 27 | box-sizing: border-box; 28 | font-family: monospace; 29 | -webkit-touch-callout: none; 30 | user-select: none; 31 | flex: 1; 32 | } 33 | 34 | .tree-visualization .value-body { 35 | min-width: 300px; 36 | width: fit-content; 37 | } 38 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/SettingsDialogContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import {closeSettingsDialog, setParserSettings} from '../store/actions'; 3 | import {showSettingsDialog, getParser, getParserSettings} from '../store/selectors'; 4 | import SettingsDialog from '../components/dialogs/SettingsDialog'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | visible: showSettingsDialog(state), 9 | parser: getParser(state), 10 | parserSettings: getParserSettings(state), 11 | }; 12 | } 13 | 14 | function mapDispatchToProps(dispatch) { 15 | return { 16 | onSave: (parser, newSettings) => dispatch(setParserSettings(newSettings)), 17 | onWantToClose: () => dispatch(closeSettingsDialog()), 18 | }; 19 | } 20 | 21 | export default connect(mapStateToProps, mapDispatchToProps)(SettingsDialog); 22 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/rework.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultCSSParserInterface'; 2 | import pkg from 'css/package.json'; 3 | 4 | const ID = 'rework'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/reworkcss/rework', 13 | locationProps: new Set(['position']), 14 | 15 | loadParser(callback) { 16 | require(['css/lib/parse'], callback); 17 | }, 18 | 19 | nodeToRange({ position: range }) { 20 | if (!range) return; 21 | return [range.start, range.end].map(pos => this.getOffset(pos)); 22 | }, 23 | 24 | opensByDefault(node, key) { 25 | return key === 'rules'; 26 | }, 27 | 28 | _ignoredProperties: new Set(['parsingErrors', 'source', 'content']), 29 | }; 30 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint4/index.js: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint4/package.json'; 2 | 3 | const ID = 'eslint-v4'; 4 | const name = 'ESLint v4'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: name, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | 12 | defaultParserID: 'babel-eslint', 13 | 14 | loadTransformer(callback) { 15 | require( 16 | [ 17 | 'eslint4/lib/linter', 18 | 'eslint4/lib/util/source-code', 19 | '../../utils/eslint4Utils', 20 | ], 21 | (Linter, sourceCode, utils) => callback({eslint: new Linter(), sourceCode, utils}), 22 | ); 23 | }, 24 | 25 | transform({ eslint, sourceCode, utils }, transformCode, code) { 26 | utils.defineRule(eslint, transformCode); 27 | return utils.runRule(code, eslint, sourceCode); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/tslint/codeExample.txt: -------------------------------------------------------------------------------- 1 | export class Rule extends Lint.Rules.AbstractRule { 2 | public static FAILURE_STRING = "Do not use template literals"; 3 | 4 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 5 | return this.applyWithWalker(new NoTemplateExpressionWalker(sourceFile, this.getOptions())); 6 | } 7 | } 8 | 9 | // The walker takes care of all the work. 10 | class NoTemplateExpressionWalker extends Lint.RuleWalker { 11 | public visitTemplateExpression(node: ts.TemplateExpression) { 12 | // create a failure at the current position 13 | this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING)); 14 | 15 | // call the base version of this visitor to actually parse this node 16 | super.visitTemplateExpression(node); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_unary.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "-3" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "UnaryExpression", 11 | "op": { 12 | "kind": { 13 | "type": "MINUS" 14 | }, 15 | "span": { 16 | "start": 0, 17 | "end": 1 18 | } 19 | }, 20 | "operand": { 21 | "type": "Integer", 22 | "raw": 3, 23 | "span": { 24 | "start": 1, 25 | "end": 2 26 | } 27 | }, 28 | "span": { 29 | "start": 0, 30 | "end": 2 31 | } 32 | } 33 | ], 34 | "span": { 35 | "start": 0, 36 | "end": 3 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/tree/CompactObjectView.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default function CompactObjectView({keys, onClick}) { 5 | if (keys.length === 0) { 6 | return {'{ }'}; 7 | } else { 8 | if (keys.length > 5) { 9 | keys = keys.slice(0, 5).concat([`... +${keys.length - 5}`]); 10 | } 11 | return ( 12 | 13 | {'{'} 14 | 15 | {keys.join(', ')} 16 | 17 | {'}'} 18 | 19 | ); 20 | } 21 | } 22 | 23 | CompactObjectView.propTypes = { 24 | keys: PropTypes.arrayOf(PropTypes.string).isRequired, 25 | onClick: PropTypes.func, 26 | }; 27 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/SaveButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import cx from '../../utils/classnames.js'; 4 | 5 | export default function SaveButton({canSave, saving, forking, onSave}) { 6 | return ( 7 | 23 | ); 24 | } 25 | 26 | SaveButton.propTypes = { 27 | canSave: PropTypes.bool, 28 | saving: PropTypes.bool, 29 | forking: PropTypes.bool, 30 | onSave: PropTypes.func, 31 | }; 32 | -------------------------------------------------------------------------------- /ast-website/scripts/check-conflicts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SOURCE_DIR=$1 4 | TARGET_DIR=$2 5 | 6 | for source_file in $(ls $1); do 7 | target_path=$TARGET_DIR/$source_file 8 | source_path=$SOURCE_DIR/$source_file 9 | 10 | if ! [ -f $target_path ]; then 11 | # If a file with the same name doesn't exist in the target directory, all is 12 | # good. 13 | continue 14 | fi 15 | 16 | case $source_file in 17 | # These files are allowed to differ since the are 18 | # not cached 19 | index.html|favicon.png) 20 | continue 21 | ;; 22 | esac 23 | 24 | if ! diff --brief $target_path $source_path > /dev/null; then 25 | echo "File '$source_file' already exists but has different content." 26 | conflict=1 27 | fi 28 | done 29 | 30 | if [ -n "$conflict" ]; then 31 | echo "Bump the cache breaker." 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/PrettierButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import cx from '../../utils/classnames.js'; 4 | 5 | export default function PrettierButton(props) { 6 | return (); 20 | } 21 | 22 | PrettierButton.propTypes = { 23 | toggleFormatting: PropTypes.func, 24 | enableFormatting: PropTypes.bool, 25 | } 26 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/protobuf/pbkit.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'pbkit/package.json'; 3 | 4 | const ID = 'pbkit'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | id: ID, 9 | displayName: ID, 10 | version: pkg.version, 11 | homepage: 'https://github.com/riiid/pbkit', 12 | locationProps: new Set(['start', 'end']), 13 | typeProps: new Set(['type']), 14 | 15 | loadParser(callback) { 16 | require(['pbkit/core/parser/proto'], callback); 17 | }, 18 | 19 | parse(parser, code) { 20 | return parser.parse(code).ast; 21 | }, 22 | 23 | nodeToRange(node) { 24 | const { start, end } = node; 25 | return [start, end]; 26 | }, 27 | 28 | opensByDefault(node, key) { 29 | if (key === 'statements') { 30 | return true; 31 | } 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/go/go.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface' 2 | 3 | const ID = 'go' 4 | 5 | export default { 6 | ...defaultParserInterface, 7 | 8 | id: ID, 9 | displayName: ID, 10 | version: '1.13.4', 11 | homepage: 'https://golang.org/pkg/go/', 12 | _ignoredProperties: new Set(['_type']), 13 | locationProps: new Set(['Loc']), 14 | 15 | async loadParser(callback) { 16 | require(['astexplorer-go'], async parser => { 17 | await parser.init() 18 | callback(parser) 19 | }) 20 | }, 21 | 22 | parse(parser, code) { 23 | return parser.parseFile(code) 24 | }, 25 | 26 | getNodeName(node) { 27 | return node._type 28 | }, 29 | 30 | nodeToRange(node) { 31 | if (node.Loc) { 32 | return [node.Loc.Start, node.Loc.End].map(({ Offset }) => Offset) 33 | } 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/CodeEditorContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import {setCode, setCursor} from '../store/actions'; 3 | import Editor from '../components/Editor'; 4 | import {getCode, getParser, getParseResult, getKeyMap} from '../store/selectors'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | keyMap: getKeyMap(state), 9 | value: getCode(state), 10 | mode: getParser(state).category.editorMode || getParser(state).category.id, 11 | error: (getParseResult(state) || {}).error, 12 | }; 13 | } 14 | 15 | function mapDispatchToProps(dispatch) { 16 | return { 17 | onContentChange: ({value, cursor}) => { 18 | dispatch(setCode({code: value, cursor})); 19 | }, 20 | onActivity: cursor => dispatch(setCursor(cursor)), 21 | }; 22 | } 23 | 24 | export default connect(mapStateToProps, mapDispatchToProps)(Editor); 25 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/utils/defaultHandlebarsParserInterface.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../../utils/defaultParserInterface'; 2 | 3 | export default { 4 | ...defaultParserInterface, 5 | 6 | locationProps: new Set(['loc']), 7 | 8 | parse(parseHandlebars, code) { 9 | this.lineOffsets = []; 10 | let index = 0; 11 | do { 12 | this.lineOffsets.push(index); 13 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign 14 | return parseHandlebars(code); 15 | }, 16 | 17 | getOffset({ line, column }) { 18 | return this.lineOffsets[line - 1] + column; 19 | }, 20 | 21 | nodeToRange({ loc }) { 22 | if (!loc) return; 23 | const serializedLoc = 'toJSON' in loc ? loc.toJSON() : loc; 24 | return [serializedLoc.start, serializedLoc.end].map(pos => this.getOffset(pos)); 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/san/san-template-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'san/package.json'; 3 | 4 | const ID = 'san'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set([]), 14 | typeProps: new Set(['tag']), 15 | 16 | loadParser(callback) { 17 | require(['san'], callback); 18 | }, 19 | 20 | parse(parser, code, options) { 21 | return parser.parseTemplate(code, options).children[0]; 22 | }, 23 | 24 | opensByDefault(node, key) { 25 | return key === 'children'; 26 | }, 27 | 28 | getNodeName(node) { 29 | return node.tagName; 30 | }, 31 | 32 | getDefaultOptions() { 33 | return {}; 34 | }, 35 | _ignoredProperties: new Set([]), 36 | }; 37 | -------------------------------------------------------------------------------- /interpreter/main.rs: -------------------------------------------------------------------------------- 1 | use interpreter::eval; 2 | use object::environment::Env; 3 | use parser::parse; 4 | use std::cell::RefCell; 5 | use std::io::stdin; 6 | use std::rc::Rc; 7 | 8 | fn main() { 9 | println!("Welcome to monkey interpreter by gengjiawen"); 10 | let env: Env = Rc::new(RefCell::new(Default::default())); 11 | loop { 12 | let mut input = String::new(); 13 | stdin().read_line(&mut input).unwrap(); 14 | 15 | if input.trim_end().is_empty() { 16 | println!("bye"); 17 | std::process::exit(0) 18 | } 19 | 20 | match parse(&input) { 21 | Ok(node) => match eval(node, &env) { 22 | Ok(evaluated) => println!("{}", evaluated), 23 | Err(e) => eprintln!("{}", e), 24 | }, 25 | Err(e) => eprintln!("parse error: {}", e[0]), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_array.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "[1, true]" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "Array", 11 | "elements": [ 12 | { 13 | "type": "Integer", 14 | "raw": 1, 15 | "span": { 16 | "start": 1, 17 | "end": 2 18 | } 19 | }, 20 | { 21 | "type": "Boolean", 22 | "raw": true, 23 | "span": { 24 | "start": 4, 25 | "end": 8 26 | } 27 | } 28 | ], 29 | "span": { 30 | "start": 0, 31 | "end": 9 32 | } 33 | } 34 | ], 35 | "span": { 36 | "start": 0, 37 | "end": 10 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/posthtml.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'posthtml-parser/package.json'; 3 | 4 | const ID = 'posthtml-parser'; 5 | const name = 'posthtml-parser'; 6 | 7 | export default { 8 | ...defaultParserInterface, 9 | 10 | id: ID, 11 | displayName: name, 12 | version: pkg.version, 13 | homepage: pkg.homepage || 'https://github.com/fb55/htmlparser2', 14 | 15 | loadParser(callback) { 16 | require(['posthtml-parser'], callback); 17 | }, 18 | 19 | parse(posthtmlParser, code, options) { 20 | return posthtmlParser(code, options); 21 | }, 22 | 23 | opensByDefault(node, key) { 24 | return key === 'content'; 25 | }, 26 | 27 | getDefaultOptions() { 28 | return { lowerCaseTags: false, lowerCaseAttributeNames: false }; 29 | }, 30 | 31 | typeProps: new Set(['tag']), 32 | }; 33 | -------------------------------------------------------------------------------- /ast-website/website/src/utils/pubsub.js: -------------------------------------------------------------------------------- 1 | const subscribers = {}; 2 | 3 | export function subscribe(topic, handler) { 4 | let handlers = subscribers[topic]; 5 | if (!handlers) { 6 | handlers = subscribers[topic] = []; 7 | } 8 | if (handlers.indexOf(handler) === -1) { 9 | handlers.push(handler); 10 | } 11 | 12 | return () => handlers.splice(handlers.indexOf(handler), 1); 13 | } 14 | 15 | export function publish(topic, data) { 16 | if (subscribers[topic]) { 17 | setTimeout(function callSubscribers() { 18 | if (subscribers[topic]) { 19 | const handlers = subscribers[topic]; 20 | for (var i = 0; i < handlers.length; i++) { 21 | handlers[i](data); 22 | } 23 | } 24 | }, 0); 25 | } 26 | } 27 | 28 | export function clear(unsubscribers) { 29 | unsubscribers.forEach(call); 30 | } 31 | 32 | function call(f) { 33 | return f(); 34 | } 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/lua/codeExample.txt: -------------------------------------------------------------------------------- 1 | --[[ 2 | Paste or drop some Lua here and explore 3 | the syntax tree created by chosen parser. 4 | Enjoy! 5 | --]] 6 | 7 | function allwords () 8 | local line = io.read() -- current line 9 | local pos = 1 -- current position in the line 10 | return function () -- iterator function 11 | while line do -- repeat while there are lines 12 | local s, e = string.find(line, "%w+", pos) 13 | if s then -- found a word? 14 | pos = e + 1 -- update next position 15 | return string.sub(line, s, e) -- return the word 16 | else 17 | line = io.read() -- word not found; try next line 18 | pos = 1 -- restart from first position 19 | end 20 | end 21 | return nil -- no more lines: end of traversal 22 | end 23 | end -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/transformers/regexp-tree/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'regexp-tree/package.json'; 3 | 4 | const ID = 'regexp-tree'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | 12 | defaultParserID: ID, 13 | 14 | loadTransformer(callback) { 15 | require([ 16 | '../../../transpilers/babel', 17 | 'regexp-tree', 18 | ], (transpile, regexpTree) => callback({ transpile: transpile.default, regexpTree })); 19 | }, 20 | 21 | transform({ transpile, regexpTree }, transformCode, code) { 22 | transformCode = transpile(transformCode); 23 | let handler = compileModule( // eslint-disable-line no-shadow 24 | transformCode, 25 | ); 26 | 27 | return regexpTree.transform(code, handler).toString(); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/SelectedNodeContext.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SelectedNodeContext = React.createContext(); 4 | 5 | function useSelectedNode() { 6 | const context = React.useContext(SelectedNodeContext); 7 | if (!context) { 8 | throw new Error('useSelectedNode must be used within a SelectedNodeContext'); 9 | } 10 | return context; 11 | } 12 | 13 | let unselectCallback; 14 | 15 | function setSelectedNode(node, cb) { 16 | if (unselectCallback) { 17 | unselectCallback(); 18 | } 19 | if (node) { 20 | global.$node = node; 21 | unselectCallback = cb; 22 | } else { 23 | unselectCallback = null; 24 | delete global.$node; 25 | } 26 | } 27 | 28 | function SelectedNodeProvider(props) { 29 | return ; 30 | } 31 | 32 | export {SelectedNodeProvider, useSelectedNode}; 33 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/json/momoa.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from '@humanwhocodes/momoa/package.json'; 3 | 4 | const ID = 'momoa'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc']), 14 | 15 | loadParser(callback) { 16 | require(['@humanwhocodes/momoa'], callback); 17 | }, 18 | 19 | parse(momoa, code, options) { 20 | return momoa.parse(code, options); 21 | }, 22 | 23 | nodeToRange({loc}) { 24 | if (loc) { 25 | return [ 26 | loc.start.offset, 27 | loc.end.offset, 28 | ]; 29 | } 30 | }, 31 | 32 | getDefaultOptions() { 33 | return { 34 | comments: true, 35 | tokens: true, 36 | ranges: true, 37 | }; 38 | }, 39 | 40 | } 41 | -------------------------------------------------------------------------------- /ast-website/website/src/components/ErrorMessage.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default class ErrorMessage extends React.Component { 5 | render() { 6 | return this.props.error ? 7 |
8 |
9 |

10 | 11 | {' '} 12 | Error 13 |

14 |
{this.props.error.message}
15 |
16 | 21 |
22 |
23 |
: 24 | null; 25 | } 26 | } 27 | 28 | ErrorMessage.propTypes = { 29 | error: PropTypes.object, 30 | onWantToClose: PropTypes.func, 31 | }; 32 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__bool.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: let y=true 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "LET" 9 | }, 10 | "span": { 11 | "start": 0, 12 | "end": 3 13 | } 14 | }, 15 | { 16 | "kind": { 17 | "type": "IDENTIFIER", 18 | "value": { 19 | "name": "y" 20 | } 21 | }, 22 | "span": { 23 | "start": 4, 24 | "end": 5 25 | } 26 | }, 27 | { 28 | "kind": { 29 | "type": "ASSIGN" 30 | }, 31 | "span": { 32 | "start": 5, 33 | "end": 6 34 | } 35 | }, 36 | { 37 | "kind": { 38 | "type": "TRUE" 39 | }, 40 | "span": { 41 | "start": 6, 42 | "end": 10 43 | } 44 | }, 45 | { 46 | "kind": { 47 | "type": "EOF" 48 | }, 49 | "span": { 50 | "start": 10, 51 | "end": 11 52 | } 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_let.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: let a = 3 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "Let", 11 | "identifier": { 12 | "kind": { 13 | "type": "IDENTIFIER", 14 | "value": { 15 | "name": "a" 16 | } 17 | }, 18 | "span": { 19 | "start": 4, 20 | "end": 5 21 | } 22 | }, 23 | "expr": { 24 | "type": "Integer", 25 | "raw": 3, 26 | "span": { 27 | "start": 8, 28 | "end": 9 29 | } 30 | }, 31 | "span": { 32 | "start": 0, 33 | "end": 9 34 | } 35 | } 36 | ], 37 | "span": { 38 | "start": 0, 39 | "end": 10 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ast-website/scripts/publish-latest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | REMOTE=${1:-"server"} 6 | LATEST_BRANCH=${2:-"website-latest"} 7 | STABLE_BRANCH=${3:-"website-stable"} 8 | 9 | TARGETPATH="../$(basename $(pwd))_$STABLE_BRANCH" 10 | WORKING_DIR=$(pwd) 11 | 12 | trap cleanup EXIT 13 | 14 | function cleanup { 15 | if [ -d $TARGETPATH ]; then 16 | echo "Cleaning up worktree" 17 | git worktree remove -f $TARGETPATH 18 | fi 19 | cd $WORKING_DIR 20 | } 21 | 22 | echo "Creating worktree for $STABLE_BRANCH..." 23 | # Initialize worktree 24 | git worktree add $TARGETPATH $STABLE_BRANCH || exit 1 25 | 26 | cd $TARGETPATH 27 | 28 | echo "Merging $LATEST_BRANCH into $STABLE_BRANCH..." 29 | git merge --squash --strategy-option=theirs $LATEST_BRANCH 30 | 31 | if ! git diff --cached --quiet; then 32 | git commit -m"Publish" 33 | $WORKING_DIR/scripts/deploy.sh $REMOTE $STABLE_BRANCH 34 | else 35 | echo "Nothing to do" 36 | fi 37 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__let.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: let x=5 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "LET" 9 | }, 10 | "span": { 11 | "start": 0, 12 | "end": 3 13 | } 14 | }, 15 | { 16 | "kind": { 17 | "type": "IDENTIFIER", 18 | "value": { 19 | "name": "x" 20 | } 21 | }, 22 | "span": { 23 | "start": 4, 24 | "end": 5 25 | } 26 | }, 27 | { 28 | "kind": { 29 | "type": "ASSIGN" 30 | }, 31 | "span": { 32 | "start": 5, 33 | "end": 6 34 | } 35 | }, 36 | { 37 | "kind": { 38 | "type": "INT", 39 | "value": 5 40 | }, 41 | "span": { 42 | "start": 6, 43 | "end": 7 44 | } 45 | }, 46 | { 47 | "kind": { 48 | "type": "EOF" 49 | }, 50 | "span": { 51 | "start": 7, 52 | "end": 8 53 | } 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/glsl/codeExample.txt: -------------------------------------------------------------------------------- 1 | // Game Of Life ( https://gl-react-cookbook.surge.sh/gol ) 2 | precision highp float; 3 | varying vec2 uv; 4 | uniform float size; 5 | uniform sampler2D t; // the previous world state 6 | void main() { 7 | float prev = step(0.5, texture2D(t, uv).r); 8 | float c = 1.0 / size; 9 | float sum = 10 | step(0.5, texture2D(t, uv + vec2(-1.0, -1.0)*c).r) + 11 | step(0.5, texture2D(t, uv + vec2(-1.0, 0.0)*c).r) + 12 | step(0.5, texture2D(t, uv + vec2(-1.0, 1.0)*c).r) + 13 | step(0.5, texture2D(t, uv + vec2( 0.0, 1.0)*c).r) + 14 | step(0.5, texture2D(t, uv + vec2( 1.0, 1.0)*c).r) + 15 | step(0.5, texture2D(t, uv + vec2( 1.0, 0.0)*c).r) + 16 | step(0.5, texture2D(t, uv + vec2( 1.0, -1.0)*c).r) + 17 | step(0.5, texture2D(t, uv + vec2( 0.0, -1.0)*c).r); 18 | float next = prev==1.0 && sum >= 2.0 && sum <= 3.0 || sum == 3.0 ? 1.0 : 0.0; 19 | gl_FragColor = vec4(vec3(next), 1.0); 20 | } 21 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_hash.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "{\"a\": 1}" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "Hash", 11 | "elements": [ 12 | [ 13 | { 14 | "type": "String", 15 | "raw": "a", 16 | "span": { 17 | "start": 1, 18 | "end": 4 19 | } 20 | }, 21 | { 22 | "type": "Integer", 23 | "raw": 1, 24 | "span": { 25 | "start": 6, 26 | "end": 7 27 | } 28 | } 29 | ] 30 | ], 31 | "span": { 32 | "start": 0, 33 | "end": 8 34 | } 35 | } 36 | ], 37 | "span": { 38 | "start": 0, 39 | "end": 9 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__let_with_space.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: let x = 5 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "LET" 9 | }, 10 | "span": { 11 | "start": 0, 12 | "end": 3 13 | } 14 | }, 15 | { 16 | "kind": { 17 | "type": "IDENTIFIER", 18 | "value": { 19 | "name": "x" 20 | } 21 | }, 22 | "span": { 23 | "start": 4, 24 | "end": 5 25 | } 26 | }, 27 | { 28 | "kind": { 29 | "type": "ASSIGN" 30 | }, 31 | "span": { 32 | "start": 6, 33 | "end": 7 34 | } 35 | }, 36 | { 37 | "kind": { 38 | "type": "INT", 39 | "value": 5 40 | }, 41 | "span": { 42 | "start": 8, 43 | "end": 9 44 | } 45 | }, 46 | { 47 | "kind": { 48 | "type": "EOF" 49 | }, 50 | "span": { 51 | "start": 9, 52 | "end": 10 53 | } 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/ForkButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import cx from '../../utils/classnames.js'; 4 | 5 | export default class ForkButton extends React.Component { 6 | render() { 7 | const { canFork, saving, forking, onFork } = this.props; 8 | return ( 9 | 25 | ); 26 | } 27 | } 28 | 29 | ForkButton.propTypes = { 30 | canFork: PropTypes.bool, 31 | saving: PropTypes.bool, 32 | forking: PropTypes.bool, 33 | onFork: PropTypes.func, 34 | }; 35 | -------------------------------------------------------------------------------- /ast-website/website/fontcustom/README.md: -------------------------------------------------------------------------------- 1 | # Custom Fonts 2 | 3 | There's not a great way to customize font-awesome at the moment 4 | (see: https://github.com/FortAwesome/Font-Awesome/wiki/Customize-Font-Awesome). 5 | 6 | So we are using [fontcustom](https://github.com/FontCustom/fontcustom) to add 7 | custom logos / fonts to the app. 8 | 9 | ## Build Instructions 10 | 11 | - install fontcustom: https://github.com/FontCustom/fontcustom#installation 12 | - add the svgs you want to convert to the `./fontcustom/input-svg/` directory 13 | - in the root of the astexplorer project, run: 14 | ```bash 15 | yarn run fontcustom 16 | ``` 17 | - you can then confirm things worked by running 18 | `open ./fontcustom/fontcustom-preview.html` 19 | - now you can reference your icons in a very similar manner to font-awesome, 20 | for example: 21 | - font-awesome: `` 22 | - fontcustom: `` 23 | (if you added `./fontcustom/input-svg/myfoo.svg`) 24 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/thrift/thrift-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from '@creditkarma/thrift-parser/package.json'; 3 | 4 | const ID = 'ck-thrift-parser'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: 'https://github.com/creditkarma/thrift-parser', 13 | locationProps: new Set(['location']), 14 | 15 | loadParser(callback) { 16 | require(['@creditkarma/thrift-parser'], callback); 17 | }, 18 | 19 | parse({parse}, code) { 20 | return parse(code); 21 | }, 22 | 23 | getNodeName(node) { 24 | return node.type; 25 | }, 26 | 27 | nodeToRange({ loc }) { 28 | if (loc !== null && loc !== undefined) { 29 | return [loc.start.index, loc.end.index]; 30 | } 31 | }, 32 | 33 | opensByDefault(node, key) { 34 | return node === 'ThriftDocument' || key === 'body'; 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /.github/workflows/doc-publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | 9 | jobs: 10 | build-and-deploy: 11 | concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession. 12 | runs-on: ubuntu-latest 13 | # container: gengjiawen/node-build:latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | 18 | - name: Install and Build 19 | run: | 20 | curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 21 | npm i -g pnpm@8 22 | cargo build 23 | cd wasm && wasm-pack build --release --scope=gengjiawen 24 | pnpm i 25 | cd $GITHUB_WORKSPACE/packages/playground && pnpm build 26 | 27 | - name: Deploy 🚀 28 | uses: JamesIves/github-pages-deploy-action@v4 29 | with: 30 | folder: packages/playground/dist 31 | -------------------------------------------------------------------------------- /lexer/snapshots/lexer__lexer_test__tests__comments_then_blank_line.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: lexer/lexer_test.rs 3 | expression: "// comment\n\nlet x = 5" 4 | --- 5 | [ 6 | { 7 | "kind": { 8 | "type": "LET" 9 | }, 10 | "span": { 11 | "start": 12, 12 | "end": 15 13 | } 14 | }, 15 | { 16 | "kind": { 17 | "type": "IDENTIFIER", 18 | "value": { 19 | "name": "x" 20 | } 21 | }, 22 | "span": { 23 | "start": 16, 24 | "end": 17 25 | } 26 | }, 27 | { 28 | "kind": { 29 | "type": "ASSIGN" 30 | }, 31 | "span": { 32 | "start": 18, 33 | "end": 19 34 | } 35 | }, 36 | { 37 | "kind": { 38 | "type": "INT", 39 | "value": 5 40 | }, 41 | "span": { 42 | "start": 20, 43 | "end": 21 44 | } 45 | }, 46 | { 47 | "kind": { 48 | "type": "EOF" 49 | }, 50 | "span": { 51 | "start": 21, 52 | "end": 22 53 | } 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/prettier/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'prettier/package.json'; 3 | 4 | const ID = 'prettier'; 5 | const name = 'prettier'; 6 | 7 | export default { 8 | id: ID, 9 | displayName: name, 10 | version: pkg.version, 11 | homepage: pkg.homepage, 12 | 13 | defaultParserID: 'babylon7', 14 | 15 | loadTransformer(callback) { 16 | require( 17 | ['../../../transpilers/babel', 'prettier/standalone', 'prettier/parser-babel'], 18 | (transpile, prettier, babel) => callback({ transpile: transpile.default, prettier, babel }), 19 | ); 20 | }, 21 | 22 | transform({ transpile, prettier, babel }, transformCode, code) { 23 | transformCode = transpile(transformCode); 24 | const options = compileModule(transformCode); 25 | return prettier.format( 26 | code, 27 | Object.assign({plugins: [babel]}, options.default || options), 28 | ); 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/babel/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'babel5/package.json'; 3 | 4 | const ID = 'babel'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | showInMenu: false, 12 | 13 | defaultParserID: 'babylon', 14 | 15 | loadTransformer(callback) { 16 | require( 17 | ['../../../transpilers/babel', 'babel5'], 18 | (transpile, babel) => callback({ transpile: transpile.default, babel: babel }), 19 | ); 20 | }, 21 | 22 | transform({ transpile, babel }, transformCode, code) { 23 | transformCode = transpile(transformCode); 24 | let transform = compileModule( // eslint-disable-line no-shadow 25 | transformCode, 26 | ); 27 | 28 | return babel.transform(code, { 29 | whitelist: [], 30 | plugins: [transform.default || transform], 31 | sourceMaps: true, 32 | }); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/babel-eslint9.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'babel-eslint9/package.json'; 3 | 4 | const ID = 'babel-eslint9'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc', 'start', 'end', 'range']), 14 | 15 | loadParser(callback) { 16 | require(['babel-eslint9'], callback); 17 | }, 18 | 19 | parse(parser, code) { 20 | const opts = { 21 | sourceType: 'module', 22 | }; 23 | 24 | const ast = parser.parseNoPatch(code, opts); 25 | delete ast.tokens; 26 | return ast; 27 | }, 28 | 29 | nodeToRange(node) { 30 | if (typeof node.start !== 'undefined') { 31 | return [node.start, node.end]; 32 | } 33 | }, 34 | 35 | _ignoredProperties: new Set([ 36 | '_paths', 37 | '_babelType', 38 | '__clone', 39 | ]), 40 | }; 41 | -------------------------------------------------------------------------------- /ast-website/website/src/components/SettingsDrawer.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default class SettingsDrawer extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this._expand = this._expand.bind(this); 8 | this._collapse = this._collapse.bind(this); 9 | } 10 | 11 | _expand() { 12 | this.props.onWantToExpand(); 13 | } 14 | 15 | _collapse() { 16 | this.props.onWantToCollapse(); 17 | } 18 | 19 | render() { 20 | return ( 21 | this.props.isOpen ? 22 |
23 |

Settings

24 | 25 |
26 | : 27 |
28 | ); 29 | } 30 | } 31 | 32 | SettingsDrawer.propTypes = { 33 | onWantToExpand: PropTypes.func, 34 | onWantToCollapse: PropTypes.func, 35 | isOpen: PropTypes.bool, 36 | }; 37 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/babel-eslint.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'babel-eslint/package.json'; 3 | 4 | const ID = 'babel-eslint'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc', 'start', 'end', 'range']), 14 | showInMenu: false, 15 | 16 | loadParser(callback) { 17 | require(['babel-eslint'], callback); 18 | }, 19 | 20 | parse(parser, code) { 21 | const opts = { 22 | sourceType: 'module', 23 | }; 24 | 25 | const ast = parser.parseNoPatch(code, opts); 26 | delete ast.tokens; 27 | return ast; 28 | }, 29 | 30 | nodeToRange(node) { 31 | if (typeof node.start !== 'undefined') { 32 | return [node.start, node.end]; 33 | } 34 | }, 35 | 36 | _ignoredProperties: new Set([ 37 | '_paths', 38 | '_babelType', 39 | '__clone', 40 | ]), 41 | }; 42 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/babel-eslint8.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'babel-eslint8/package.json'; 3 | 4 | const ID = 'babel-eslint8'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc', 'start', 'end', 'range']), 14 | showInMenu: false, 15 | 16 | loadParser(callback) { 17 | require(['babel-eslint8'], callback); 18 | }, 19 | 20 | parse(parser, code) { 21 | const opts = { 22 | sourceType: 'module', 23 | }; 24 | 25 | const ast = parser.parseNoPatch(code, opts); 26 | delete ast.tokens; 27 | return ast; 28 | }, 29 | 30 | nodeToRange(node) { 31 | if (typeof node.start !== 'undefined') { 32 | return [node.start, node.end]; 33 | } 34 | }, 35 | 36 | _ignoredProperties: new Set([ 37 | '_paths', 38 | '_babelType', 39 | '__clone', 40 | ]), 41 | }; 42 | -------------------------------------------------------------------------------- /packages/playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monkey-playground", 3 | "private": true, 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@chakra-ui/react": "^2.2.4", 12 | "@emotion/react": "^11", 13 | "@emotion/styled": "^11", 14 | "@gengjiawen/monkey-wasm": "workspace:^0.10.1", 15 | "@replit/codemirror-vim": "^6.0.1", 16 | "@uiw/react-codemirror": "^4.11.4", 17 | "framer-motion": "^6", 18 | "lodash.debounce": "^4.0.8", 19 | "react": "18.2.0", 20 | "react-dom": "18.2.0" 21 | }, 22 | "devDependencies": { 23 | "@types/lodash.debounce": "^4.0.7", 24 | "@types/react": "^18.0.15", 25 | "@types/react-dom": "^18.0.6", 26 | "@vitejs/plugin-react": "^2.0.0", 27 | "rollup-plugin-visualizer": "^5.7.1", 28 | "typescript": "^4.7.4", 29 | "vite": "^3.0.4", 30 | "vite-plugin-top-level-await": "^1.1.1", 31 | "vite-plugin-wasm": "^2.1.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ast-website/.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Browser (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **astexplorer settings:** 29 | - Selected parser: [e.g. acorn] 30 | - Selected transformer (if applicable): [e.g. jscodeshift] 31 | - Contents of the local storage key `explorerSettingsV1` (code can be removed if you don't want it to be public) 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mathjs/mathjs.js: -------------------------------------------------------------------------------- 1 | import pkg from 'mathjs/package.json'; 2 | 3 | import defaultParserInterface from '../utils/defaultParserInterface' 4 | 5 | const ID = 'mathjs' 6 | 7 | export default { 8 | ...defaultParserInterface, 9 | 10 | id: ID, 11 | displayName: ID, 12 | version: pkg.version, 13 | homepage: 'https://mathjs.org/', 14 | locationProps: new Set(['span']), 15 | 16 | defaultParserID: 'mathjs', 17 | 18 | async loadParser(callback) { 19 | require(['mathjs'], callback); 20 | }, 21 | 22 | parse(parser, code) { 23 | try { 24 | return parser.parse(code) 25 | } catch (message) { 26 | // AST Explorer expects the thrown error to be an object, not a string. 27 | throw new SyntaxError(message); 28 | } 29 | }, 30 | 31 | getNodeName(node) { 32 | return node.type 33 | }, 34 | 35 | // TODO once this feature is added to mathjs 36 | // nodeToRange(node) { 37 | // }, 38 | 39 | opensByDefault(node) { 40 | return node.type === 'BlockNode' 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /examples/hello.monkey: -------------------------------------------------------------------------------- 1 | // Integers & arithmetic expressions... 2 | let version = 1 + (50 / 2) - (8 * 3); 3 | 4 | // ... and strings 5 | let name = "The Monkey programming language"; 6 | 7 | // ... booleans 8 | let isMonkeyFastNow = true; 9 | 10 | // ... arrays & hash maps 11 | let people = [{"name": "Anna", "age": 24}, {"name": "Bob", "age": 99}]; 12 | 13 | // User-defined functions... 14 | let getName = fn(person) { person["name"]; }; 15 | getName(people[0]); // => "Anna" 16 | getName(people[1]); // => "Bob" 17 | 18 | // and built-in functions 19 | puts(len(people)) // prints: 2 20 | 21 | let fibonacci = fn(x) { 22 | if (x == 0) { 23 | 0 24 | } else { 25 | if (x == 1) { 26 | return 1; 27 | } else { 28 | fibonacci(x - 1) + fibonacci(x - 2); 29 | } 30 | } 31 | }; 32 | 33 | // `newAdder` returns a closure that makes use of the free variables `a` and `b`: 34 | let newAdder = fn(a, b) { 35 | fn(c) { a + b + c }; 36 | }; 37 | // This constructs a new `adder` function: 38 | let adder = newAdder(1, 2); 39 | 40 | adder(8); // => 11 -------------------------------------------------------------------------------- /parser/precedences.rs: -------------------------------------------------------------------------------- 1 | use lexer::token::TokenKind; 2 | 3 | #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] 4 | pub enum Precedence { 5 | LOWEST, 6 | EQUALS, // == 7 | LessGreater, // > or < 8 | SUM, // + or = 9 | PRODUCT, // * or / 10 | PREFIX, // -X or !X 11 | CALL, // myFunction(x) 12 | INDEX, // array[index] 13 | } 14 | 15 | pub fn get_token_precedence(token: &TokenKind) -> Precedence { 16 | match token { 17 | TokenKind::EQ => Precedence::EQUALS, 18 | TokenKind::NotEq => Precedence::EQUALS, 19 | TokenKind::LT => Precedence::LessGreater, 20 | TokenKind::GT => Precedence::LessGreater, 21 | TokenKind::PLUS => Precedence::SUM, 22 | TokenKind::MINUS => Precedence::SUM, 23 | TokenKind::ASTERISK => Precedence::PRODUCT, 24 | TokenKind::SLASH => Precedence::PRODUCT, 25 | TokenKind::LPAREN => Precedence::CALL, 26 | TokenKind::LBRACKET => Precedence::INDEX, 27 | _ => Precedence::LOWEST, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/monkey/monkey.js: -------------------------------------------------------------------------------- 1 | import pkg from '@gengjiawen/monkey-wasm/package.json'; 2 | 3 | import defaultParserInterface from '../utils/defaultParserInterface' 4 | 5 | const ID = 'monkey' 6 | 7 | export default { 8 | ...defaultParserInterface, 9 | 10 | id: ID, 11 | displayName: ID, 12 | version: pkg.version, 13 | homepage: 'https://monkeylang.org/', 14 | locationProps: new Set(['span']), 15 | 16 | async loadParser(callback) { 17 | require(['@gengjiawen/monkey-wasm/monkey_wasm.js'], callback); 18 | }, 19 | 20 | parse(parser, code) { 21 | try { 22 | return JSON.parse(parser.parse(code)); 23 | } catch (message) { 24 | // AST Explorer expects the thrown error to be an object, not a string. 25 | throw new SyntaxError(message); 26 | } 27 | }, 28 | 29 | getNodeName(node) { 30 | return node.type 31 | }, 32 | 33 | nodeToRange(node) { 34 | if (node && node.span && typeof node.span.start === 'number') { 35 | return [node.span.start, node.span.end]; 36 | } 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/python/python.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'filbert/package.json'; 3 | 4 | const ID = 'python'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/differentmatt/filbert', 13 | locationProps: new Set(['range', 'loc', 'start', 'end']), 14 | 15 | loadParser(callback) { 16 | require(['filbert'], (parser) => { 17 | callback({ parser }); 18 | }); 19 | }, 20 | 21 | parse({ parser }, code) { 22 | return parser.parse(code, { 23 | locations: true, 24 | ranges: true, 25 | }); 26 | }, 27 | 28 | opensByDefault(node, key) { 29 | switch (key) { 30 | case 'block': 31 | case 'nodes': 32 | return true; 33 | } 34 | }, 35 | 36 | nodeToRange(node) { 37 | const { range } = node; 38 | if (typeof range === 'object') { 39 | return range; 40 | } 41 | }, 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/transformers/posthtml/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'posthtml/package.json'; 3 | 4 | const ID = 'posthtml'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage || 'https://github.com/posthtml/posthtml', 11 | 12 | defaultParserID: 'posthtml-parser', 13 | 14 | loadTransformer(callback) { 15 | require(['../../../transpilers/babel', 'posthtml'], (transpile, posthtml) => 16 | callback({ transpile: transpile.default, posthtml })); 17 | }, 18 | 19 | transform({ transpile, posthtml }, transformCode, code) { 20 | // transpile with babel for es6+ support 21 | transformCode = transpile(transformCode); 22 | // compile to turn from string into a module 23 | let transform = compileModule( 24 | // eslint-disable-line no-shadow 25 | transformCode, 26 | ); 27 | return posthtml() 28 | .use(transform.default || transform) 29 | .process(code, { sync: true }).html; 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/graphql/graphql-js.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'graphql/package.json'; 3 | 4 | const ID = 'graphql-js'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc']), 14 | typeProps: new Set(['kind']), 15 | 16 | loadParser(callback) { 17 | require(['graphql/language'], ({ parse }) => { 18 | callback({ parse }); 19 | }); 20 | }, 21 | 22 | parse({ parse }, code, options) { 23 | return parse(code, options); 24 | }, 25 | 26 | nodeToRange(node) { 27 | if (node.loc) { 28 | return [node.loc.start, node.loc.end]; 29 | } 30 | }, 31 | 32 | getNodeName(node) { 33 | return node.kind; 34 | }, 35 | 36 | opensByDefault(node, key) { 37 | return key === 'definitions'; 38 | }, 39 | 40 | getDefaultOptions() { 41 | return { 42 | noLocation: false, 43 | noSource: false, 44 | }; 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /compiler/README.md: -------------------------------------------------------------------------------- 1 | # monkey-rust 2 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 4 | 5 | This is a compiler for the Monkey programming language written in Rust 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /object/README.md: -------------------------------------------------------------------------------- 1 | # monkey-rust 2 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 4 | 5 | This is a object for the Monkey programming language written in Rust 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /parser/README.md: -------------------------------------------------------------------------------- 1 | # monkey-rust 2 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 4 | 5 | This is a parser for the Monkey programming language written in Rust 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_func_call.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "add(1, 2)" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "FunctionCall", 11 | "callee": { 12 | "type": "IDENTIFIER", 13 | "name": "add", 14 | "span": { 15 | "start": 0, 16 | "end": 3 17 | } 18 | }, 19 | "arguments": [ 20 | { 21 | "type": "Integer", 22 | "raw": 1, 23 | "span": { 24 | "start": 4, 25 | "end": 5 26 | } 27 | }, 28 | { 29 | "type": "Integer", 30 | "raw": 2, 31 | "span": { 32 | "start": 7, 33 | "end": 8 34 | } 35 | } 36 | ], 37 | "span": { 38 | "start": 0, 39 | "end": 9 40 | } 41 | } 42 | ], 43 | "span": { 44 | "start": 0, 45 | "end": 10 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint1/index.js: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint1/package.json'; 2 | 3 | const ID = 'eslint-v1'; 4 | const name = 'ESLint v1' 5 | 6 | export default { 7 | id: ID, 8 | displayName: name, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | showInMenu: false, 12 | 13 | defaultParserID: 'acorn-to-esprima', 14 | 15 | loadTransformer(callback) { 16 | require( 17 | [ 18 | // Explicitly require just the stuff we care about to avoid loading 19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the 20 | // package size. 21 | 'eslint1/lib/eslint', 22 | 'eslint1/lib/util/source-code', 23 | 'eslint1/lib/rules', 24 | '../../utils/eslintUtils', 25 | ], 26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}), 27 | ); 28 | }, 29 | 30 | transform({ eslint, sourceCode, rules, utils }, transformCode, code) { 31 | utils.defineRule(rules, transformCode); 32 | return utils.runRule(code, eslint, sourceCode); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint2/index.js: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint2/package.json'; 2 | 3 | const ID = 'eslint-v2'; 4 | const name = 'ESLint v2' 5 | 6 | export default { 7 | id: ID, 8 | displayName: name, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | showInMenu: false, 12 | 13 | defaultParserID: 'babel-eslint', 14 | 15 | loadTransformer(callback) { 16 | require( 17 | [ 18 | // Explicitly require just the stuff we care about to avoid loading 19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the 20 | // package size. 21 | 'eslint2/lib/eslint', 22 | 'eslint2/lib/util/source-code', 23 | 'eslint2/lib/rules', 24 | '../../utils/eslintUtils', 25 | ], 26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}), 27 | ); 28 | }, 29 | 30 | transform({ eslint, rules, sourceCode, utils }, transformCode, code) { 31 | utils.defineRule(rules, transformCode); 32 | return utils.runRule(code, eslint, sourceCode); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/eslint3/index.js: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint3/package.json'; 2 | 3 | const ID = 'eslint-v3'; 4 | const name = 'ESLint v3' 5 | 6 | export default { 7 | id: ID, 8 | displayName: name, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | showInMenu: false, 12 | 13 | defaultParserID: 'babel-eslint', 14 | 15 | loadTransformer(callback) { 16 | require( 17 | [ 18 | // Explicitly require just the stuff we care about to avoid loading 19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the 20 | // package size. 21 | 'eslint3/lib/eslint', 22 | 'eslint3/lib/util/source-code', 23 | 'eslint3/lib/rules', 24 | '../../utils/eslintUtils', 25 | ], 26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}), 27 | ); 28 | }, 29 | 30 | transform({ eslint, rules, sourceCode, utils }, transformCode, code) { 31 | utils.defineRule(rules, transformCode); 32 | return utils.runRule(code, eslint, sourceCode); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /interpreter/README.md: -------------------------------------------------------------------------------- 1 | # monkey-rust 2 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 4 | 5 | This is a interpreter for the Monkey programming language written in Rust 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /lexer/README.md: -------------------------------------------------------------------------------- 1 | # monkey-rust 2 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 4 | 5 | This is lexer for the Monkey programming language written in Rust 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/html/svelte.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'svelte/package.json'; 3 | 4 | const ID = 'svelte'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['start', 'end']), 14 | typeProps: new Set(['tag']), 15 | 16 | loadParser(callback) { 17 | require(['svelte/compiler'], callback); 18 | }, 19 | 20 | parse(parser, code, options) { 21 | return parser.compile(code, options).ast; 22 | }, 23 | 24 | nodeToRange(node) { 25 | if (node.type || node.name) { 26 | return [node.start, node.end]; 27 | } 28 | }, 29 | 30 | opensByDefault(node, key) { 31 | return key === 'children'; 32 | }, 33 | 34 | getNodeName(node) { 35 | return node.tag; 36 | }, 37 | 38 | getDefaultOptions() { 39 | return { 40 | preserveWhitespace: true, 41 | preserveComments: true, 42 | }; 43 | }, 44 | _ignoredProperties: new Set(['parent']), 45 | }; 46 | -------------------------------------------------------------------------------- /wasm/README.md: -------------------------------------------------------------------------------- 1 | ![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) 2 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust) 3 | 4 | This lib designed for compiling monkey-parser into WebAssembly and 5 | publishing the resulting package to NPM. 6 | 7 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 8 | 9 | ## What’s Monkey? 10 | 11 | Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in. 12 | 13 | Official site is: https://monkeylang.org/. It's has various implementation languages :). 14 | 15 | There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from. 16 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/wat/wat-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from '@webassemblyjs/wast-parser/package.json'; 3 | 4 | const ID = 'wat-parser'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: 'https://webassembly.js.org/', 13 | 14 | locationProps: new Set(['loc']), 15 | 16 | getOffset({ line, column }) { 17 | return this.lineOffsets[line - 1] + column; 18 | }, 19 | 20 | nodeToRange({ loc }) { 21 | if (!loc) return; 22 | return [loc.start, loc.end].map(pos => this.getOffset(pos)); 23 | }, 24 | 25 | loadParser(callback) { 26 | require(['@webassemblyjs/wast-parser'], function(parser) { 27 | callback(parser); 28 | }); 29 | }, 30 | 31 | parse({ parse }, code) { 32 | this.lineOffsets = []; 33 | let index = 0; 34 | do { 35 | this.lineOffsets.push(index); 36 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign 37 | return parse(code); 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/webidl/webidl2.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'webidl2/package.json'; 3 | 4 | const ID = 'webidl2'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/w3c/webidl2.js', 13 | typeProps: new Set(['name', 'type', 'idlType', 'escapedName']), 14 | 15 | getNodeName(node) { 16 | if (node.name) { 17 | return node.name + (node.optional ? '?' : ''); 18 | } else if (node.type) { 19 | return node.type; 20 | } else if (node.idlType) { 21 | return node.idlType.idlType || node.idlType; 22 | } 23 | }, 24 | 25 | loadParser(callback) { 26 | require(['webidl2'], callback); 27 | }, 28 | 29 | parse({ parse }, code, options) { 30 | return parse(code, options); 31 | }, 32 | 33 | opensByDefault(node, key) { 34 | return key === 'members'; 35 | }, 36 | 37 | getDefaultOptions() { 38 | return { 39 | concrete: false, 40 | }; 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/yaml/yaml-ast-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'yaml-ast-parser/package.json'; 3 | 4 | const ID = 'yaml-ast-parser'; 5 | let Kind = null; 6 | 7 | export default { 8 | ...defaultParserInterface, 9 | 10 | id: ID, 11 | displayName: ID, 12 | version: pkg.version, 13 | homepage: pkg.homepage || 'https://www.npmjs.com/package/yaml-ast-parser', 14 | 15 | _ignoredProperties: new Set(['parent', 'errors']), 16 | locationProps: new Set(['startPosition', 'endPosition']), 17 | typeProps: new Set(['kind']), 18 | 19 | nodeToRange(node) { 20 | if (typeof node.startPosition === 'number') { 21 | return [node.startPosition, node.endPosition]; 22 | } 23 | }, 24 | 25 | getNodeName(node) { 26 | return Kind[node.kind]; 27 | }, 28 | 29 | loadParser(callback) { 30 | require(['yaml-ast-parser'], function(yamlAstParser) { 31 | Kind = yamlAstParser.Kind; 32 | callback(yamlAstParser); 33 | }); 34 | }, 35 | 36 | parse({ load }, code) { 37 | return load(code); 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /packages/playground/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/transformers/postcss/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'postcss/package.json'; 3 | 4 | const ID = 'postcss'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | 12 | defaultParserID: 'postcss', 13 | 14 | loadTransformer(callback) { 15 | require(['../../../transpilers/babel', 'postcss'], (transpile, postcss) => { 16 | callback({ transpile: transpile.default, postcss }); 17 | }); 18 | }, 19 | 20 | transform({ transpile, postcss }, transformCode, code) { 21 | transformCode = transpile( transformCode); 22 | let transform = compileModule( // eslint-disable-line no-shadow 23 | transformCode, 24 | { 25 | require(name) { 26 | switch (name) { 27 | case 'postcss': return postcss; 28 | default: throw new Error(`Cannot find module '${name}'`); 29 | } 30 | }, 31 | }, 32 | ); 33 | return postcss([ (transform.default || transform)() ]).process(code).css; 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /object/environment.rs: -------------------------------------------------------------------------------- 1 | use crate::Object; 2 | use std::cell::RefCell; 3 | use std::collections::HashMap; 4 | use std::rc::Rc; 5 | 6 | pub type Env = Rc>; 7 | 8 | #[derive(Debug, Default, Eq, Clone, PartialEq)] 9 | pub struct Environment { 10 | store: HashMap>, 11 | outer: Option, 12 | } 13 | 14 | impl Environment { 15 | pub fn new_enclosed_environment(outer: &Env) -> Self { 16 | let mut env: Environment = Default::default(); 17 | env.outer = Some(Rc::clone(outer)); 18 | return env; 19 | } 20 | 21 | pub fn get(&self, name: &str) -> Option> { 22 | match self.store.get(name) { 23 | Some(obj) => Some(Rc::clone(obj)), 24 | None => { 25 | if let Some(outer) = &self.outer { 26 | return outer.borrow().get(name); 27 | } else { 28 | return None; 29 | } 30 | } 31 | } 32 | } 33 | 34 | pub fn set(&mut self, name: String, val: Rc) { 35 | self.store.insert(name, val); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/rust/syn.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'astexplorer-syn/package.json'; 3 | 4 | const ID = 'syn'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: `https://docs.rs/syn/${pkg.version}/syn/`, 13 | _ignoredProperties: new Set(['_type']), 14 | locationProps: new Set(['span']), 15 | 16 | loadParser(callback) { 17 | require(['astexplorer-syn'], callback); 18 | }, 19 | 20 | parse(parser, code) { 21 | this.lineOffsets = []; 22 | let index = 0; 23 | do { 24 | this.lineOffsets.push(index); 25 | } while ((index = code.indexOf('\n', index) + 1)); // eslint-disable-line no-cond-assign 26 | return parser.parseFile(code); 27 | }, 28 | 29 | getNodeName(node) { 30 | return node._type; 31 | }, 32 | 33 | nodeToRange(node) { 34 | if (node.span) { 35 | return [node.span.start, node.span.end].map( 36 | ({ line, column }) => this.lineOffsets[line - 1] + column, 37 | ); 38 | } 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/regexp-tree.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'regexp-tree/package.json'; 3 | 4 | const ID = 'regexp-tree'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc']), 14 | 15 | loadParser(callback) { 16 | require(['regexp-tree'], (regexpTree) => { 17 | callback(regexpTree); 18 | }); 19 | }, 20 | 21 | parse(regexpTree, code, options={}) { 22 | regexpTree 23 | .parser 24 | .setOptions(options); 25 | 26 | return regexpTree.parse(code); 27 | }, 28 | 29 | nodeToRange(node) { 30 | if (node.loc != null) { 31 | return [node.loc.start, node.loc.end]; 32 | } 33 | }, 34 | 35 | opensByDefault(node, key) { 36 | return ( 37 | node.type === 'RegExp' || 38 | key === 'body' || 39 | key === 'expressions' 40 | ); 41 | }, 42 | 43 | getDefaultOptions() { 44 | return { 45 | captureLocations: true, 46 | }; 47 | }, 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/java/java-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'java-parser/package.json'; 3 | 4 | const ID = 'java-parser'; 5 | 6 | export const parserSettingsConfiguration = { 7 | fields: [], 8 | }; 9 | 10 | export default { 11 | ...defaultParserInterface, 12 | 13 | id: ID, 14 | displayName: ID, 15 | version: pkg.version, 16 | homepage: 17 | pkg.homepage || 18 | 'https://github.com/jhipster/prettier-java/tree/master/packages/java-parser', 19 | 20 | locationProps: new Set(['location']), 21 | typeProps: new Set(['name']), 22 | 23 | loadParser(callback) { 24 | require(['java-parser'], callback); 25 | }, 26 | 27 | parse(parser, code) { 28 | return parser.parse(code); 29 | }, 30 | 31 | _ignoredProperties: new Set(['tokenType']), 32 | 33 | getDefaultOptions() { 34 | return {}; 35 | }, 36 | 37 | getNodeName({ name }) { 38 | return name; 39 | }, 40 | 41 | nodeToRange({ location }) { 42 | if (!location) { 43 | return; 44 | } 45 | return [location.startOffset, location.endOffset + 1]; 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/ember-template-recast/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'ember-template-recast/package.json'; 3 | 4 | const ID = 'ember-template-recast'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage || 'https://github.com/ember-template-lint/ember-template-recast', 11 | 12 | defaultParserID: 'ember-template-recast', 13 | 14 | loadTransformer(callback) { 15 | require( 16 | ['../../../transpilers/babel', 'ember-template-recast'], 17 | (transpile, recast) => callback({ transpile: transpile.default, recast }), 18 | ); 19 | }, 20 | 21 | transform({ transpile, recast }, transformCode, code) { 22 | transformCode = transpile(transformCode); 23 | const transformModule = compileModule(transformCode); 24 | 25 | // allow "export default" instead of "module.exports = " 26 | const transform = transformModule.__esModule ? 27 | transformModule.default : 28 | transformModule; 29 | 30 | return recast.transform(code, transform).code; 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/vue/vue-template-compiler.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'vue-template-compiler/package.json'; 3 | 4 | const ID = 'vue-template-compiler'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['start', 'end']), 14 | typeProps: new Set(['tag']), 15 | 16 | loadParser(callback) { 17 | require(['vue-template-compiler/browser'], callback); 18 | }, 19 | 20 | parse(parser, code, options) { 21 | return parser.compile(code, options).ast; 22 | }, 23 | 24 | nodeToRange(node) { 25 | if (node.type || node.name) { 26 | return [node.start, node.end]; 27 | } 28 | }, 29 | 30 | opensByDefault(node, key) { 31 | return key === 'children'; 32 | }, 33 | 34 | getNodeName(node) { 35 | return node.tag; 36 | }, 37 | 38 | getDefaultOptions() { 39 | return { 40 | outputSourceRange: true, 41 | whitespace: 'preserve', 42 | }; 43 | }, 44 | _ignoredProperties: new Set(['parent']), 45 | }; 46 | -------------------------------------------------------------------------------- /ast-website/website/src/components/visualization/tree/CompactArrayView.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default class CompactArrayView extends React.Component { 5 | shouldComponentUpdate(nextProps) { 6 | return nextProps.array.length !== this.props.array.length; 7 | } 8 | 9 | render() { 10 | let {array} = this.props; 11 | let count = array.length; 12 | 13 | if (count === 0) { 14 | return {'[ ]'}; 15 | } 16 | else { 17 | return ( 18 | 19 | {'['} 20 | 21 | {count + ' element' + (count > 1 ? 's' : '')} 22 | 23 | {']'} 24 | 25 | ); 26 | } 27 | } 28 | } 29 | 30 | CompactArrayView.propTypes = { 31 | /** 32 | * The array of elements to represent. 33 | */ 34 | array: PropTypes.oneOfType([ 35 | PropTypes.array, 36 | PropTypes.shape({ length: PropTypes.number }), 37 | ]).isRequired, 38 | onClick: PropTypes.func, 39 | }; 40 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/php/php-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'php-parser/package.json'; 3 | 4 | const ID = 'php-parser'; 5 | 6 | const defaultOptions = { 7 | parser: { 8 | extractDoc: true, 9 | }, 10 | ast: { 11 | withPositions: true, 12 | }, 13 | }; 14 | 15 | export default { 16 | ...defaultParserInterface, 17 | 18 | id: ID, 19 | displayName: ID, 20 | version: pkg.version, 21 | homepage: pkg.homepage, 22 | locationProps: new Set(['loc']), 23 | typeProps: new Set(['kind']), 24 | 25 | loadParser(callback) { 26 | require(['php-parser'], callback); 27 | }, 28 | 29 | parse(Engine, code) { 30 | const parser = new Engine(defaultOptions); 31 | return parser.parseCode(code, ''); 32 | }, 33 | 34 | getNodeName(node) { 35 | return node.kind; 36 | }, 37 | 38 | nodeToRange(node) { 39 | if (node.loc && node.loc.start && node.loc.end) { 40 | return [node.loc.start.offset, node.loc.end.offset]; 41 | } 42 | }, 43 | 44 | opensByDefault(node, key) { 45 | return key === 'body' || key === 'what' || key === 'items'; 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full-vnc 2 | 3 | ENV TRIGGER_REBUILD=12 4 | 5 | RUN rustup target add wasm32-unknown-unknown 6 | 7 | RUN bash -cl "cargo install cargo-wasm cargo-generate \ 8 | && curl -fsSL https://wasmtime.dev/install.sh | bash; \ 9 | rustup target add wasm32-wasi" 10 | 11 | RUN mkdir /tmp/wasm-sdk \ 12 | && cd /tmp/wasm-sdk \ 13 | && wget "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sdk_16.0_amd64.deb" \ 14 | && sudo dpkg -i wasi-sdk_16.0_amd64.deb \ 15 | && rm -rf /tmp/wasi-sdk 16 | 17 | RUN git clone --depth 1 "https://github.com/emscripten-core/emsdk.git" $HOME/.emsdk \ 18 | && cd $HOME/.emsdk \ 19 | && ./emsdk install latest \ 20 | && ./emsdk activate latest \ 21 | && printf "\nsource $HOME/.emsdk/emsdk_env.sh\nclear\n" >> ~/.bashrc 22 | 23 | RUN brew install binaryen wabt wasm-pack 24 | 25 | # fix Node.js path and use latest Node.js 26 | RUN brew install n && sudo /home/linuxbrew/.linuxbrew/bin/n latest && sudo /usr/local/bin/npm i -g yarn npm pnpm npm-check-updates 27 | ENV PATH=/usr/local/bin/:$PATH 28 | RUN printf "\nexport PATH="/usr/local/bin/:$PATH"\n" >> ~/.bashrc 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Jiawen Geng 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/babel-eslint-parser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from '@babel/eslint-parser/package.json'; 3 | 4 | const ID = '@babel/eslint-parser'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc', 'start', 'end', 'range']), 14 | 15 | loadParser(callback) { 16 | require(['@babel/eslint-parser'], callback); 17 | }, 18 | 19 | parse(parser, code) { 20 | const opts = { 21 | sourceType: 'module', 22 | requireConfigFile: false, 23 | babelOptions: { 24 | parserOpts: { 25 | plugins: ['jsx'], 26 | }, 27 | }, 28 | }; 29 | 30 | const ast = parser.parse(code, opts); 31 | delete ast.tokens; 32 | return ast; 33 | }, 34 | 35 | nodeToRange(node) { 36 | if (typeof node.start !== 'undefined') { 37 | return [node.start, node.end]; 38 | } 39 | }, 40 | 41 | _ignoredProperties: new Set([ 42 | '_paths', 43 | '_babelType', 44 | '__clone', 45 | ]), 46 | }; 47 | -------------------------------------------------------------------------------- /parser/snapshots/parser__ast_tree_test__tests__test_func_declaration.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: parser/ast_tree_test.rs 3 | expression: "fn(x) { x };" 4 | --- 5 | { 6 | "Program": { 7 | "type": "Program", 8 | "body": [ 9 | { 10 | "type": "FunctionDeclaration", 11 | "params": [ 12 | { 13 | "type": "IDENTIFIER", 14 | "name": "x", 15 | "span": { 16 | "start": 3, 17 | "end": 4 18 | } 19 | } 20 | ], 21 | "body": { 22 | "type": "BlockStatement", 23 | "body": [ 24 | { 25 | "type": "IDENTIFIER", 26 | "name": "x", 27 | "span": { 28 | "start": 8, 29 | "end": 9 30 | } 31 | } 32 | ], 33 | "span": { 34 | "start": 6, 35 | "end": 11 36 | } 37 | }, 38 | "span": { 39 | "start": 0, 40 | "end": 11 41 | }, 42 | "name": "" 43 | } 44 | ], 45 | "span": { 46 | "start": 0, 47 | "end": 13 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monkey-rust", 3 | "version": "0.10.1", 4 | "description": "![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust)", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "scripts": { 10 | "format": "npx prettier .github/**/*.yml *.yml README.md Maintainer.md --write", 11 | "ua": "npx @gengjiawen/git-repo-cli clone fkling/astexplorer ./ast-website/", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/gengjiawen/monkey-rust.git" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/gengjiawen/monkey-rust/issues" 23 | }, 24 | "homepage": "https://github.com/gengjiawen/monkey-rust#readme", 25 | "devDependencies": { 26 | "@types/node": "18.15.11", 27 | "prettier": "^2.8.7", 28 | "ts-node": "^10.9.1", 29 | "typescript": "^5.0.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ast-website/server/index.js: -------------------------------------------------------------------------------- 1 | const bodyParser = require('body-parser'); 2 | const express = require('express'); 3 | const path = require('path'); 4 | 5 | const app = express(); 6 | app.use(bodyParser.json()); 7 | 8 | app.use('/api/v1/gist', require('./handlers/gist')); 9 | 10 | if (process.env.SNIPPET_FILE && process.env.REVISION_FILE) { 11 | console.log('Serving Parse snippets enabled.'); 12 | app.use('/api/v1/parse', require('./handlers/parse')); 13 | } 14 | 15 | // `next` is needed here to mark this as an error handler 16 | // eslint-disable-next-line no-unused-vars 17 | app.use((err, req, res, next) => { 18 | console.error((new Date()).toLocaleString(), err); 19 | if (err.response) { 20 | res.status(err.response.status).send(err.response.statusText); 21 | return; 22 | } 23 | // eslint-disable-next-line no-console 24 | res.status(500).send('Something went wrong'); 25 | }); 26 | 27 | if (process.env.STATIC) { 28 | app.use(express.static(path.join(__dirname, process.env.STATIC))); 29 | } 30 | 31 | const PORT = process.env.PORT || 8080; 32 | app.listen( 33 | PORT, 34 | 'localhost', 35 | () => { 36 | console.log(`Server listening on port ${PORT}!`); 37 | } 38 | ); 39 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/glimmer/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from '@glimmer/syntax/package.json'; 3 | 4 | const ID = 'glimmer'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm', 11 | 12 | defaultParserID: 'glimmer', 13 | 14 | loadTransformer(callback) { 15 | require( 16 | ['../../../transpilers/babel', '@glimmer/syntax'], 17 | (transpile, glimmer) => callback({ transpile: transpile.default, glimmer }), 18 | ); 19 | }, 20 | 21 | transform({ transpile, glimmer }, transformCode, code) { 22 | transformCode = transpile(transformCode); 23 | const transformModule = compileModule(transformCode); 24 | 25 | // allow "export default" instead of "module.exports = " 26 | const transform = transformModule.__esModule ? 27 | transformModule.default : 28 | transformModule; 29 | 30 | let ast = glimmer.preprocess(code, { 31 | plugins: { 32 | ast: [transform], 33 | }, 34 | }); 35 | 36 | return glimmer.print(ast); 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /ast-website/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014-2021 Felix Kling and astexplorer contributors https://astexplorer.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the “Software”), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | 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 | -------------------------------------------------------------------------------- /ast-website/website/src/components/dialogs/ShareDialog.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | export default class ShareDialog extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this._outerClick = this._outerClick.bind(this); 8 | } 9 | 10 | _outerClick(event) { 11 | if (event.target === document.getElementById('ShareDialog')) { 12 | this.props.onWantToClose(); 13 | } 14 | } 15 | 16 | render() { 17 | if (this.props.visible) { 18 | return ( 19 |
20 |
21 |
22 | {this.props.snippet.getShareInfo()} 23 |
24 |
25 | 26 |
27 |
28 |
29 | ); 30 | } 31 | return null; 32 | } 33 | } 34 | 35 | ShareDialog.propTypes = { 36 | onWantToClose: PropTypes.func.isRequired, 37 | visible: PropTypes.bool.isRequired, 38 | snippet: PropTypes.object, 39 | }; 40 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/cssom.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'cssom/package.json'; 3 | 4 | const ID = 'cssom'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/NV/CSSOM', 13 | locationProps: new Set(['__starts', '__ends']), 14 | typeProps: new Set(), 15 | 16 | loadParser(callback) { 17 | require(['cssom/lib/parse'], callback); 18 | }, 19 | 20 | parse(CSSOM, code) { 21 | return CSSOM.parse(code); 22 | }, 23 | 24 | getNodeName(node) { 25 | return node.constructor.name; 26 | }, 27 | 28 | nodeToRange(node) { 29 | let { __starts, __ends } = node; 30 | if (__ends === undefined && node.parentRule) { 31 | ({ __ends } = node.parentRule); 32 | } 33 | if (__ends !== undefined) { 34 | return [__starts, __ends]; 35 | } 36 | }, 37 | 38 | opensByDefault(node, key) { 39 | return key === 'cssRules' || key === 'style'; 40 | }, 41 | 42 | _ignoredProperties: new Set(['parentRule', 'parentStyleSheet', '_importants']), 43 | }; 44 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/solididy/solidity-parser-antlr.js: -------------------------------------------------------------------------------- 1 | import pkg from 'solidity-parser-antlr/package.json'; 2 | import defaultParserInterface from '../utils/defaultParserInterface'; 3 | 4 | const ID = 'solidity-parser-antlr'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/federicobond/solidity-parser-antlr', 13 | 14 | loadParser(callback) { 15 | require(['solidity-parser-antlr'], callback); 16 | }, 17 | 18 | parse(parser, code, options) { 19 | return parser.parse(code, options); 20 | }, 21 | 22 | opensByDefault(node, key) { 23 | return node.type === 'SourceUnit' || 24 | node.type === 'ContractDefinition' || 25 | key === 'children' || 26 | key === 'subNodes' || 27 | key === 'body' 28 | }, 29 | 30 | getDefaultOptions() { 31 | return { 32 | range: true, 33 | loc: false, 34 | tolerant: false, 35 | }; 36 | }, 37 | 38 | _getSettingsConfiguration() { 39 | return { 40 | fields: [ 41 | 'range', 42 | 'loc', 43 | 'tolerant', 44 | ], 45 | }; 46 | }, 47 | 48 | }; 49 | 50 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/solididy/solidity-parser-diligence.js: -------------------------------------------------------------------------------- 1 | import pkg from 'solidity-parser-diligence/package.json'; 2 | import defaultParserInterface from '../utils/defaultParserInterface'; 3 | 4 | const ID = 'solidity-parser-diligence'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage || 'https://github.com/consensys/solidity-parser-antlr', 13 | 14 | loadParser(callback) { 15 | require(['solidity-parser-diligence'], callback); 16 | }, 17 | 18 | parse(parser, code, options) { 19 | return parser.parse(code, options); 20 | }, 21 | 22 | opensByDefault(node, key) { 23 | return node.type === 'SourceUnit' || 24 | node.type === 'ContractDefinition' || 25 | key === 'children' || 26 | key === 'subNodes' || 27 | key === 'body' 28 | }, 29 | 30 | getDefaultOptions() { 31 | return { 32 | range: true, 33 | loc: false, 34 | tolerant: false, 35 | }; 36 | }, 37 | 38 | _getSettingsConfiguration() { 39 | return { 40 | fields: [ 41 | 'range', 42 | 'loc', 43 | 'tolerant', 44 | ], 45 | }; 46 | }, 47 | 48 | }; 49 | 50 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/vue/vue-compiler-dom.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from '@vue/compiler-dom/package.json'; 3 | 4 | const ID = '@vue/compiler-dom'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['start', 'end']), 14 | typeProps: new Set(['tag']), 15 | 16 | loadParser(callback) { 17 | require(['@vue/compiler-dom'], callback); 18 | }, 19 | 20 | parse(parser, code, options) { 21 | return parser.parse(code, options); 22 | }, 23 | 24 | nodeToRange(node) { 25 | if (node.type || node.name) { 26 | return [node.loc.start.offset, node.loc.end.offset]; 27 | } 28 | }, 29 | 30 | opensByDefault(node, key) { 31 | return key === 'children'; 32 | }, 33 | 34 | getNodeName(node) { 35 | return node.tag; 36 | }, 37 | 38 | getDefaultOptions() { 39 | return {}; 40 | }, 41 | 42 | _ignoredProperties: new Set([ 43 | 'components', 44 | 'directives', 45 | 'codegenNode', 46 | 'helpers', 47 | 'hoists', 48 | 'imports', 49 | 'cached', 50 | 'temps', 51 | ]), 52 | }; 53 | -------------------------------------------------------------------------------- /wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod utils; 2 | 3 | use crate::utils::set_panic_hook; 4 | use compiler::compiler::Compiler; 5 | use parser::parse as parser_pase; 6 | use parser::parse_ast_json_string; 7 | use wasm_bindgen::prelude::*; 8 | use wasm_bindgen::throw_str; 9 | 10 | // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global 11 | // allocator. 12 | #[cfg(feature = "wee_alloc")] 13 | #[global_allocator] 14 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 15 | 16 | #[wasm_bindgen] 17 | pub fn parse(input: &str) -> String { 18 | set_panic_hook(); 19 | match parse_ast_json_string(input) { 20 | Ok(node) => node.to_string(), 21 | Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()), 22 | } 23 | } 24 | 25 | #[wasm_bindgen] 26 | pub fn compile(input: &str) -> String { 27 | set_panic_hook(); 28 | 29 | let program = match parser_pase(input) { 30 | Ok(ast) => ast, 31 | Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()), 32 | }; 33 | let mut compiler = Compiler::new(); 34 | match compiler.compile(&program) { 35 | Ok(bytecode) => return bytecode.instructions.string(), 36 | Err(e) => throw_str(format!("compile error: {}", e).as_str()), 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/markdown/transformers/remark/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'remark/package.json'; 3 | 4 | const ID = 'remark'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | 12 | defaultParserID: ID, 13 | 14 | loadTransformer(callback) { 15 | require([ 16 | 'remark', 17 | 'unist-util-is', 18 | 'unist-util-visit', 19 | 'unist-util-visit-parents', 20 | ], ({ remark }, { is }, { visit }, { visitParents }) => { 21 | callback({ 22 | remark, 23 | 'unist-util-is': is, 24 | 'unist-util-visit': visit, 25 | 'unist-util-visit-parents': visitParents, 26 | }); 27 | }); 28 | }, 29 | 30 | transform({ remark, ...availableModules }, transformCode, code) { 31 | function sandboxRequire(name) { 32 | if (!Object.getOwnPropertyNames(availableModules).includes(name)) 33 | throw new Error(`Cannot find module '${name}'`); 34 | return availableModules[name]; 35 | } 36 | 37 | const transform = compileModule(transformCode, { require: sandboxRequire }); 38 | return remark().use(transform).processSync(code).value; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/hermes/hermes-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-env worker */ 2 | 3 | // A Web Worker that wraps methods from the hermes-parser package behind a 4 | // minimal request/response protocol. 5 | 6 | import hermesParser from 'hermes-parser'; 7 | 8 | const handlers = { 9 | parse(code, options) { 10 | return hermesParser.parse(code, options); 11 | }, 12 | }; 13 | 14 | onmessage = async function(e) { 15 | const {type, requestId, args = []} = e.data; 16 | let handler = () => { 17 | throw new Error('No handler in Hermes worker for message type: ' + type); 18 | }; 19 | if (Object.hasOwnProperty.call(handlers, type)) { 20 | handler = handlers[type]; 21 | } 22 | let value; 23 | try { 24 | value = handler(...args); 25 | } catch (e) { 26 | postMessage({ 27 | type, 28 | requestId, 29 | action: 'reject', 30 | // Errors don't survive the structured clone algorithm very well across 31 | // browsers - they're either not allowed or lose some of their properties. 32 | // Send a plain-object copy to be reconstituted by the client. 33 | value: {name: e.name, stack: e.stack, message: e.message, ...e}, 34 | }); 35 | return; 36 | } 37 | postMessage({type, requestId, action: 'resolve', value}); 38 | }; 39 | -------------------------------------------------------------------------------- /ast-website/website/src/storage/index.js: -------------------------------------------------------------------------------- 1 | export default class StorageHandler { 2 | constructor(backends) { 3 | this._backends = backends; 4 | } 5 | 6 | _first() { 7 | return this._backends[0]; 8 | } 9 | 10 | _owns(revision) { 11 | for (const backend of this._backends) { 12 | if (backend.owns(revision)) { 13 | return backend; 14 | } 15 | } 16 | return null; 17 | } 18 | 19 | updateHash(revision) { 20 | global.location.hash = revision.getPath(); 21 | } 22 | 23 | fetchFromURL() { 24 | if (/^#?\/?$/.test(global.location.hash)) { 25 | return Promise.resolve(null); 26 | } 27 | for (const backend of this._backends) { 28 | if (backend.matchesURL()) { 29 | return backend.fetchFromURL(); 30 | } 31 | } 32 | return Promise.reject(new Error('Unknown URL format.')); 33 | } 34 | 35 | /** 36 | * Create a new snippet. 37 | */ 38 | create(data) { 39 | return this._first().create(data); 40 | } 41 | 42 | /** 43 | * Update an existing snippet. 44 | */ 45 | update(revision, data) { 46 | return this._first().update(revision, data); 47 | } 48 | 49 | /** 50 | * Fork existing snippet. 51 | */ 52 | fork(revision, data) { 53 | return this._first().fork(revision, data); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mdx/transformers/mdx/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from '@mdx-js/mdx/package.json'; 3 | 4 | const ID = 'mdx'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: 'https://mdxjs.com', 11 | 12 | defaultParserID: 'mdxhast', 13 | 14 | loadTransformer(callback) { 15 | require([ 16 | '../../../transpilers/babel', 17 | '@mdx-js/mdx', 18 | 'prettier/standalone', 19 | 'prettier/parser-babel', 20 | ], (transpile, mdx, prettier, babel) => { 21 | callback({ transpile: transpile.default, mdx, prettier, babel }); 22 | }); 23 | }, 24 | 25 | transform({ transpile, mdx, prettier, babylon }, transformCode, code) { 26 | transformCode = transpile(transformCode); 27 | const transform = compileModule(transformCode); 28 | const jsxCode = mdx.sync(code, { 29 | ...(transform.default || transform), 30 | }); 31 | try { 32 | return prettier.format(jsxCode, { 33 | parser: 'babylon', 34 | plugins: [babylon], 35 | }); 36 | } catch (err) { 37 | return ` 38 | ${err.message} 39 | 40 | ------------ 41 | Full output: 42 | ------------ 43 | 44 | ${jsxCode.trim()} 45 | `.trim(); 46 | } 47 | }, 48 | }; 49 | -------------------------------------------------------------------------------- /ast-website/.eslintrc: -------------------------------------------------------------------------------- 1 | extends: 2 | - eslint:recommended 3 | - plugin:react/recommended 4 | - plugin:import/errors 5 | - plugin:import/warnings 6 | 7 | parserOptions: 8 | ecmaVersion: 2018 9 | sourceType: module 10 | ecmaFeatures: 11 | jsx: true 12 | experimentalObjectRestSpread: true 13 | 14 | plugins: 15 | - react 16 | - import 17 | - require-in-package 18 | 19 | rules: 20 | comma-dangle: ["error", "always-multiline"] 21 | new-cap: "off" 22 | no-path-concat: "off" 23 | no-undef: "error" 24 | no-underscore-dangle: "off" 25 | no-unused-vars: 26 | - "warn" 27 | - varsIgnorePattern: "^_" 28 | argsIgnorePattern: "^_" 29 | no-use-before-define: "off" 30 | quotes: ["error", "single", "avoid-escape"] 31 | strict: "off" 32 | import/no-unresolved: ["error", {commonjs: true, amd: true}] 33 | import/named: "error" 34 | import/default: "error" 35 | import/namespace: "error" 36 | import/export: "error" 37 | require-in-package/require-in-package: "error" 38 | react/display-name: off 39 | 40 | settings: 41 | import/resolver: "webpack" 42 | import/ignore: 43 | - node_modules 44 | - \.json 45 | 46 | env: 47 | browser: true 48 | node: true 49 | 50 | globals: 51 | loadjs: true 52 | Promise: true 53 | Map: true 54 | Set: true 55 | WeakMap: true 56 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/yaml/yaml.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'yaml/package.json'; 3 | 4 | const ID = 'yaml'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['position']), 14 | 15 | loadParser(callback) { 16 | require(['yaml'], callback); 17 | }, 18 | 19 | nodeToRange(node) { 20 | if (node.range) { 21 | return node.range; 22 | } 23 | if (node.type === 'PAIR' && (node.key || node.value)) { 24 | if (node.key && node.value) { 25 | return [node.key.range[0], node.value.range[1]]; 26 | } else if (node.key) { 27 | return node.key.range; 28 | } else { 29 | return node.value.range; 30 | } 31 | } 32 | }, 33 | 34 | parse({ parseAllDocuments }, code, options) { 35 | return parseAllDocuments(code, options); 36 | }, 37 | 38 | getDefaultOptions() { 39 | return { 40 | keepBlobsInJSON: true, 41 | keepCstNodes: false, 42 | keepNodeTypes: true, 43 | merge: false, 44 | mapAsMap: false, 45 | simpleKeys: false, 46 | maxAliasCount: 100, 47 | prettyErrors: true, 48 | }; 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /ast-website/website/src/components/buttons/KeyMapButton.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import cx from '../../utils/classnames.js'; 4 | 5 | const keyMappings = ['default', 'vim', 'emacs', 'sublime'] 6 | 7 | class KeyMapButton extends React.Component { 8 | render() { 9 | return ( 10 |
14 | 25 | {
    26 | {keyMappings.map(keyMap => ( 27 |
  • this.props.onKeyMapChange(keyMap)}> 31 | 34 |
  • 35 | ))} 36 |
} 37 |
38 | ); 39 | } 40 | } 41 | 42 | KeyMapButton.propTypes = { 43 | onKeyMapChange: PropTypes.func, 44 | keyMap: PropTypes.string, 45 | } 46 | 47 | export default KeyMapButton 48 | -------------------------------------------------------------------------------- /ast-website/website/fontcustom/input-svg/scala.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Svg Vector Icons : http://www.onlinewebfonts.com/icon 6 | 7 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/mdx/mdxhast.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from '@mdx-js/mdx/package.json'; 3 | 4 | const ID = 'mdxhast'; 5 | 6 | function removeNewlines(node) { 7 | if (node.children != null) { 8 | node.children = node.children.filter(node => node.value !== '\n'); 9 | node.children.forEach(removeNewlines); 10 | } 11 | } 12 | 13 | export default { 14 | ...defaultParserInterface, 15 | 16 | id: ID, 17 | displayName: ID, 18 | version: pkg.version, 19 | homepage: 'https://mdxjs.com', 20 | locationProps: new Set(['position']), 21 | 22 | loadParser(callback) { 23 | require(['@mdx-js/mdx', '@mdx-js/mdx/mdx-ast-to-mdx-hast'], (mdx, mdxAstToMdxHast) => callback({mdx, mdxAstToMdxHast})); 24 | }, 25 | 26 | parse({mdx, mdxAstToMdxHast}, code) { 27 | let result; 28 | mdx.sync(code, { 29 | hastPlugins: [ 30 | mdxAstToMdxHast, 31 | () => removeNewlines, 32 | () => tree => { 33 | result = tree; 34 | }, 35 | ], 36 | }); 37 | 38 | return result; 39 | }, 40 | 41 | nodeToRange({ position }) { 42 | if (position) { 43 | return [position.start.offset, position.end.offset]; 44 | } 45 | }, 46 | 47 | opensByDefault(node, key) { 48 | return key === 'children'; 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/lucene/lucene.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'lucene/package.json'; 3 | 4 | const ID = 'lucene'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['fieldLocation', 'termLocation', 'location']), 14 | 15 | loadParser(callback) { 16 | require(['lucene'], callback); 17 | }, 18 | 19 | parse({parse}, code) { 20 | return parse(code); 21 | }, 22 | 23 | nodeToRange(node) { 24 | let start = []; 25 | let end = []; 26 | 27 | if (node.location) { 28 | start.push(node.location.start.offset); 29 | end.push(node.location.end.offset); 30 | } 31 | if (node.fieldLocation) { 32 | start.push(node.fieldLocation.start.offset); 33 | end.push(node.fieldLocation.end.offset); 34 | } 35 | if (node.termLocation) { 36 | start.push(node.termLocation.start.offset); 37 | end.push(node.termLocation.end.offset); 38 | } 39 | 40 | if (start.length === 0 || end.length === 0) { 41 | return; 42 | } 43 | 44 | return [start.reduce((a, b) => Math.min(a, b)), end.reduce((a, b) => Math.max(a, b))]; 45 | }, 46 | 47 | getDefaultOptions() { 48 | return {}; 49 | }, 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/handlebars/transformers/glimmer-compiler/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from '@glimmer/compiler/package.json'; 3 | 4 | const ID = 'glimmer-compiler'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm', 11 | 12 | defaultParserID: 'glimmer', 13 | 14 | loadTransformer(callback) { 15 | require( 16 | ['../../../transpilers/babel', '@glimmer/compiler'], 17 | (transpile, glimmer) => callback({ transpile: transpile.default, glimmer }), 18 | ); 19 | }, 20 | 21 | transform({ transpile, glimmer }, transformCode, code) { 22 | transformCode = transpile(transformCode); 23 | const transformModule = compileModule(transformCode); 24 | 25 | // allow "export default" instead of "module.exports = " 26 | const transform = transformModule.__esModule ? 27 | transformModule.default : 28 | transformModule; 29 | 30 | // compile template to wireformat 31 | let result = glimmer.precompile(code, { 32 | plugins: { 33 | ast: [transform], 34 | }, 35 | }); 36 | 37 | // parse wireformat into JSON 38 | let json = JSON.parse(JSON.parse(result).block); 39 | 40 | // pretty print JSON 41 | return { code: json }; 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /ast-website/website/src/containers/TransformerContainer.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import Transformer from '../components/Transformer'; 3 | import {setTransformState, toggleFormatting} from '../store/actions'; 4 | import * as selectors from '../store/selectors'; 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | transformer: selectors.getTransformer(state), 9 | // Either the transform example or the transform code from the current 10 | // revision. This is what we compare against to determine whether something 11 | // changed and we can save. 12 | defaultTransformCode: selectors.getInitialTransformCode(state), 13 | transformCode: selectors.getTransformCode(state), 14 | mode: 15 | selectors.getParser(state).category.editorMode || 16 | selectors.getParser(state).category.id, 17 | enableFormatting: selectors.getFormattingState(state), 18 | keyMap: selectors.getKeyMap(state), 19 | transformResult: selectors.getTransformResult(state), 20 | }; 21 | } 22 | 23 | function mapDispatchToProps(dispatch) { 24 | return { 25 | onContentChange: ({value, cursor}) => { 26 | dispatch(setTransformState({code: value, cursor})); 27 | }, 28 | toggleFormatting: () => { 29 | dispatch(toggleFormatting()); 30 | }, 31 | }; 32 | } 33 | 34 | export default connect(mapStateToProps, mapDispatchToProps)(Transformer); 35 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/regexpp.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'regexpp/package.json'; 3 | 4 | const ID = 'regexpp'; 5 | 6 | /** @type {import("regexpp").RegExpParser.Options} */ 7 | export const defaultOptions = { 8 | strict: false, 9 | ecmaVersion: 2020, 10 | }; 11 | 12 | export default { 13 | ...defaultParserInterface, 14 | 15 | id: ID, 16 | displayName: ID, 17 | version: pkg.version, 18 | homepage: pkg.homepage, 19 | locationProps: new Set(['end', 'start']), 20 | 21 | loadParser(callback) { 22 | require(['regexpp'], callback); 23 | }, 24 | 25 | parse(regexpp, code, options) { 26 | if (Object.keys(options).length === 0) { 27 | options = this.getDefaultOptions(); 28 | } 29 | return regexpp.parseRegExpLiteral(code, options); 30 | }, 31 | 32 | nodeToRange(node) { 33 | if (typeof node.start === 'number' && typeof node.end === 'number') { 34 | return [node.start, node.end]; 35 | } 36 | }, 37 | 38 | opensByDefault(node, key) { 39 | return ( 40 | key === 'pattern' || 41 | key === 'elements' || 42 | key === 'element' || 43 | key === 'alternatives' 44 | ); 45 | }, 46 | 47 | getDefaultOptions() { 48 | return defaultOptions; 49 | }, 50 | 51 | _ignoredProperties: new Set(['parent', 'references', 'resolved']), 52 | 53 | }; 54 | -------------------------------------------------------------------------------- /ast-website/website/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AST explorer 5 | 6 | 7 | <%= htmlWebpackPlugin.files.webpackManifest %> 8 | 9 | 10 |
11 |
12 |
13 | Built with 14 | React, 15 | Babel, 16 | Font Awesome, 17 | CodeMirror, 18 | Express, 19 | and 20 | webpack 21 | | 22 | GitHub 23 | | 24 | @@COMMIT@@ 25 |
26 |
27 | 28 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/typescript/codeExample.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * The transformer signature is based on https://github.com/cevek/ttypescript#program 3 | */ 4 | export default function (program) { 5 | const checker = program.getTypeChecker(); 6 | return (context) => { 7 | return (sourceFile) => { 8 | const visitor = (node) => { 9 | // This branch evaluates '2 + 2' like expressions and replaces the node with the result (in this case '4') 10 | if (ts.isBinaryExpression(node)) { 11 | if (ts.isNumericLiteral(node.left) && ts.isNumericLiteral(node.right)) { 12 | // We could parse `node.text` as a number, or we can use the typechecker to get type info for nodes 13 | const lhs = checker.getTypeAtLocation(node.left); 14 | const rhs = checker.getTypeAtLocation(node.right); 15 | 16 | switch (node.operatorToken.kind) { 17 | case ts.SyntaxKind.PlusToken: 18 | return context.factory.createNumericLiteral(lhs.value + rhs.value); 19 | } 20 | } 21 | } 22 | // 23 | if (ts.isIdentifier(node) && node.text === 'printTips' || node.text === 'tips') { 24 | return context.factory.createIdentifier(node.text.split('').reverse().join('')); 25 | } 26 | return ts.visitEachChild(node, visitor, context); 27 | }; 28 | return ts.visitNode(sourceFile, visitor); 29 | }; 30 | }; 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/flow.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'flow-parser/package.json'; 3 | 4 | const ID = 'flow'; 5 | export const defaultOptions = { 6 | enums: false, 7 | esproposal_class_instance_fields: true, 8 | esproposal_class_static_fields: true, 9 | esproposal_decorators: true, 10 | esproposal_export_star_as: true, 11 | esproposal_optional_chaining: true, 12 | esproposal_nullish_coalescing: true, 13 | tokens: false, 14 | types: true, 15 | }; 16 | export const parserSettingsConfiguration = { 17 | fields: [ 18 | 'enums', 19 | 'esproposal_class_instance_fields', 20 | 'esproposal_class_static_fields', 21 | 'esproposal_decorators', 22 | 'esproposal_export_star_as', 23 | 'esproposal_optional_chaining', 24 | 'esproposal_nullish_coalescing', 25 | 'tokens', 26 | 'types', 27 | ], 28 | }; 29 | 30 | export default { 31 | ...defaultParserInterface, 32 | 33 | id: ID, 34 | displayName: ID, 35 | version: pkg.version, 36 | homepage: pkg.homepage || 'https://flow.org/', 37 | locationProps: new Set(['range', 'loc']), 38 | 39 | loadParser(callback) { 40 | require(['flow-parser'], callback); 41 | }, 42 | 43 | parse(flowParser, code, options) { 44 | return flowParser.parse(code, options); 45 | }, 46 | 47 | getDefaultOptions() { 48 | return defaultOptions; 49 | }, 50 | 51 | _getSettingsConfiguration() { 52 | return parserSettingsConfiguration; 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/regexp/regjsparser.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from '../utils/defaultParserInterface'; 2 | import pkg from 'regjsparser/package.json'; 3 | 4 | const ID = 'regjsparser'; 5 | 6 | export const defaultOptions = { 7 | unicodePropertyEscape: true, 8 | namedGroups: true, 9 | lookbehind: true, 10 | }; 11 | 12 | export default { 13 | ...defaultParserInterface, 14 | 15 | id: ID, 16 | displayName: ID, 17 | version: pkg.version, 18 | homepage: pkg.homepage, 19 | locationProps: new Set(['range']), 20 | 21 | loadParser(callback) { 22 | require(['regjsparser'], callback); 23 | }, 24 | 25 | parse(regjsparser, code, options) { 26 | if (Object.keys(options).length === 0) { 27 | options = this.getDefaultOptions(); 28 | } 29 | var firstSlash = code.indexOf('/'); 30 | var lastSlash = code.lastIndexOf('/'); 31 | if (firstSlash !== 0 || lastSlash < 1) { 32 | throw new Error('Please wrap the regex pattern by slash `/`, i.e. /foo/'); 33 | } 34 | var flags = code.slice(lastSlash + 1); 35 | var pattern = code.slice(firstSlash + 1, lastSlash); 36 | return regjsparser.parse(pattern, flags, options); 37 | }, 38 | 39 | nodeToRange(node) { 40 | if (node.range != null) { 41 | return [node.range[0] + 1, node.range[1] + 1]; 42 | } 43 | }, 44 | 45 | opensByDefault(node, key) { 46 | return ( 47 | key === 'body' 48 | ); 49 | }, 50 | 51 | getDefaultOptions() { 52 | return defaultOptions; 53 | }, 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/esformatter.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'esformatter-parser/package.json'; 3 | 4 | const ID = 'esformatter-parser'; 5 | const name = 'esformatter'; 6 | 7 | export default { 8 | ...defaultParserInterface, 9 | 10 | id: ID, 11 | displayName: name, 12 | version: pkg.version, 13 | homepage: pkg.homepage, 14 | locationProps: new Set(['loc', 'start', 'end', 'range']), 15 | 16 | loadParser(callback) { 17 | require(['esformatter-parser'], (parser) => { 18 | callback(parser); 19 | }); 20 | }, 21 | 22 | parse(parser, code) { 23 | return parser.parse(code); 24 | }, 25 | 26 | *forEachProperty(node) { 27 | if (node && typeof node === 'object') { 28 | for (let prop in node) { 29 | if (this._ignoredProperties.has(prop)) { 30 | continue; 31 | } 32 | 33 | let value = node[prop]; 34 | 35 | if (node.type !== 'Program' && prop === 'parent') { 36 | value = '[Circular]'; 37 | } 38 | 39 | yield { 40 | value, 41 | key: prop, 42 | computed: false, 43 | } 44 | } 45 | } 46 | }, 47 | 48 | _ignoredProperties: new Set([ 49 | '_paths', 50 | '_babelType', 51 | '__clone', 52 | // hide some extra properties to reduce noise 53 | 'comments', 54 | 'directives', 55 | 'extra', 56 | 'leadingComments', 57 | 'root', 58 | 'sourceType', 59 | 'tokens', 60 | 'trailingComments', 61 | ]), 62 | }; 63 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/css/postcss.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultCSSParserInterface'; 2 | import pkg from 'postcss/package.json'; 3 | 4 | const ID = 'postcss'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['source']), 14 | 15 | loadParser(callback) { 16 | require(['postcss/lib/parse', 'postcss-scss/lib/scss-parse', 'postcss-less/lib/', 'postcss-safe-parser'], (builtIn, scss, less, safe) => { 17 | callback({ 18 | 'built-in': builtIn, 19 | scss, 20 | less: less.parse, 21 | 'safe-parser': safe, 22 | }); 23 | }); 24 | }, 25 | 26 | parse(parsers, code, options) { 27 | return defaultParserInterface.parse.call( 28 | this, 29 | parsers[options.parser], 30 | code, 31 | ); 32 | }, 33 | 34 | nodeToRange({ source: range }) { 35 | if (!range || !range.end) return; 36 | return [ 37 | this.getOffset(range.start), 38 | this.getOffset(range.end) + 1, 39 | ]; 40 | }, 41 | 42 | opensByDefault(node, key) { 43 | return key === 'nodes'; 44 | }, 45 | 46 | _ignoredProperties: new Set(['parent', 'input']), 47 | 48 | getDefaultOptions() { 49 | return { 50 | parser: 'built-in', 51 | }; 52 | }, 53 | 54 | _getSettingsConfiguration() { 55 | return { 56 | fields: [ 57 | ['parser', ['built-in', 'scss', 'less', 'safe-parser']], 58 | ], 59 | }; 60 | }, 61 | }; 62 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/acorn-to-esprima.js: -------------------------------------------------------------------------------- 1 | import defaultParserInterface from './utils/defaultESTreeParserInterface'; 2 | import pkg from 'acorn-to-esprima/package.json'; 3 | 4 | const ID = 'acorn-to-esprima'; 5 | 6 | export default { 7 | ...defaultParserInterface, 8 | 9 | id: ID, 10 | displayName: ID, 11 | version: pkg.version, 12 | homepage: pkg.homepage, 13 | locationProps: new Set(['loc', 'start', 'end', 'range']), 14 | showInMenu: false, 15 | 16 | loadParser(callback) { 17 | require(['acorn-to-esprima', 'babel5'], (acornToEsprima, {acorn: {tokTypes}, traverse, parse}) => { 18 | callback({ 19 | ...acornToEsprima, 20 | tokTypes, 21 | traverse, 22 | parse, 23 | }); 24 | }); 25 | }, 26 | 27 | parse(parser, code) { 28 | const opts = { 29 | locations: true, 30 | ranges: true, 31 | }; 32 | 33 | const comments = opts.onComment = []; 34 | const tokens = opts.onToken = []; 35 | 36 | let ast = parser.parse(code, opts); 37 | 38 | ast.tokens = parser.toTokens(tokens, parser.tokTypes, code); 39 | parser.convertComments(comments); 40 | ast.comments = comments; 41 | parser.attachComments(ast, comments, ast.tokens); 42 | parser.toAST(ast, parser.traverse); 43 | 44 | return ast; 45 | }, 46 | 47 | nodeToRange(node) { 48 | if (typeof node.start !== 'undefined') { 49 | return [node.start, node.end]; 50 | } 51 | }, 52 | 53 | _ignoredProperties: new Set([ 54 | '_paths', 55 | '_babelType', 56 | '__clone', 57 | ]), 58 | }; 59 | -------------------------------------------------------------------------------- /ast-website/website/src/parsers/js/transformers/babel6/index.js: -------------------------------------------------------------------------------- 1 | import compileModule from '../../../utils/compileModule'; 2 | import pkg from 'babel6/package.json'; 3 | 4 | const ID = 'babelv6'; 5 | 6 | export default { 7 | id: ID, 8 | displayName: ID, 9 | version: pkg.version, 10 | homepage: pkg.homepage, 11 | showInMenu: false, 12 | 13 | defaultParserID: 'babylon6', 14 | 15 | loadTransformer(callback) { 16 | require([ 17 | '../../../transpilers/babel', 18 | 'babel6', 19 | 'recast', 20 | ], (transpile, babel, recast) => callback({ transpile: transpile.default, babel, recast })); 21 | }, 22 | 23 | transform({ transpile, babel, recast }, transformCode, code) { 24 | transformCode = transpile(transformCode); 25 | let transform = compileModule( // eslint-disable-line no-shadow 26 | transformCode, 27 | ); 28 | 29 | return babel.transform(code, { 30 | parserOpts: { 31 | parser: recast.parse, 32 | plugins: [ 33 | 'asyncGenerators', 34 | 'classConstructorCall', 35 | 'classProperties', 36 | 'decorators', 37 | 'doExpressions', 38 | 'exportExtensions', 39 | 'flow', 40 | 'functionSent', 41 | 'functionBind', 42 | 'jsx', 43 | 'objectRestSpread', 44 | 'dynamicImport', 45 | ], 46 | }, 47 | generatorOpts: { 48 | generator: recast.print, 49 | }, 50 | plugins: [(transform.default || transform)(babel)], 51 | sourceMaps: true, 52 | }); 53 | }, 54 | }; 55 | --------------------------------------------------------------------------------