├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── build.yml │ ├── check.yml │ ├── fuzz.yml │ ├── lint.yml │ ├── pages.yml │ ├── test-mbtq.yml │ └── test.yml ├── .gitignore ├── .node-version ├── CMakeLists.txt ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── binding.gyp ├── bindings ├── c │ ├── tree-sitter-moonbit.pc.in │ └── tree_sitter │ │ └── tree-sitter-moonbit.h ├── go │ ├── binding.go │ └── binding_test.go ├── node │ ├── binding.cc │ ├── binding_test.js │ ├── index.d.ts │ └── index.js ├── python │ ├── tests │ │ └── test_binding.py │ └── tree_sitter_moonbit │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── py.typed ├── rust │ ├── build.rs │ └── lib.rs └── zig │ └── root.zig ├── build.zig ├── build.zig.zon ├── eslint.config.mjs ├── go.mod ├── grammar.js ├── mbtq ├── .editorconfig ├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── Cargo.toml ├── Makefile ├── Package.swift ├── binding.gyp ├── bindings │ ├── c │ │ ├── tree-sitter-mbtq.pc.in │ │ └── tree_sitter │ │ │ └── tree-sitter-mbtq.h │ ├── go │ │ ├── binding.go │ │ └── binding_test.go │ ├── node │ │ ├── binding.cc │ │ ├── binding_test.js │ │ ├── index.d.ts │ │ └── index.js │ ├── python │ │ ├── tests │ │ │ └── test_binding.py │ │ └── tree_sitter_mbtq │ │ │ ├── __init__.py │ │ │ ├── __init__.pyi │ │ │ ├── binding.c │ │ │ └── py.typed │ ├── rust │ │ ├── build.rs │ │ └── lib.rs │ └── swift │ │ ├── TreeSitterMbtq │ │ └── mbtq.h │ │ └── TreeSitterMbtqTests │ │ └── TreeSitterMbtqTests.swift ├── go.mod ├── grammar.js ├── package.json ├── pyproject.toml ├── setup.py ├── src │ ├── grammar.json │ ├── node-types.json │ ├── parser.c │ ├── scanner.c │ └── tree_sitter │ │ ├── alloc.h │ │ ├── array.h │ │ └── parser.h └── test │ └── corpus │ └── quotation.txt ├── package-lock.json ├── package.json ├── pyproject.toml ├── queries ├── folds.scm ├── highlights.scm ├── indents.scm ├── injections.scm ├── locals.scm ├── tags.scm └── textobjects.scm ├── scripts └── test.py ├── setup.py ├── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c └── tree_sitter │ ├── alloc.h │ ├── array.h │ └── parser.h ├── test ├── corpus │ ├── alias.txt │ ├── apply.txt │ ├── asi.txt │ ├── asi │ │ ├── after.txt │ │ └── before.txt │ ├── assign.txt │ ├── async.txt │ ├── attribute.txt │ ├── comment.txt │ ├── constructor.txt │ ├── derive.txt │ ├── docstring.txt │ ├── enum.txt │ ├── expression.txt │ ├── for.txt │ ├── guard.txt │ ├── identifier.txt │ ├── impl.txt │ ├── lambda.txt │ ├── let_mut.txt │ ├── literal.txt │ ├── loop.txt │ ├── multiline_string.txt │ ├── new_type.txt │ ├── pattern.txt │ ├── pipe.txt │ ├── statements.txt │ ├── structure │ │ └── trait.txt │ ├── structure_items.txt │ ├── structures.txt │ ├── test.txt │ ├── try.txt │ ├── type.txt │ └── while.txt └── highlight │ ├── alias.mbt │ ├── as.mbt │ ├── attribute.mbt │ ├── call.mbt │ ├── char.mbt │ ├── const.mbt │ ├── dot_dot.mbt │ ├── enum.mbt │ ├── fib.mbt │ ├── for.mbt │ ├── operator.mbt │ ├── self.mbt │ └── struct.mbt ├── tree-sitter.json ├── tsconfig.json ├── vscode ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode-test.mjs ├── .vscode │ ├── .gitignore │ ├── extensions.json │ ├── launch.json │ └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── esbuild.mts ├── eslint.config.mjs ├── moon.mod.json ├── package-lock.json ├── package.json ├── src │ ├── extension.ts │ ├── grep │ │ ├── jsonrpc.mbt │ │ ├── jsonrpc_wbtest.mbt │ │ ├── main.mbt │ │ ├── moon.pkg.json │ │ ├── replace.mbt │ │ └── search.mbt │ ├── search.ts │ ├── sidebar.ts │ ├── sidebar │ │ ├── components │ │ │ ├── App.tsx │ │ │ ├── Codicon.tsx │ │ │ ├── ControlButton.tsx │ │ │ ├── FileItem.tsx │ │ │ ├── IconButton.tsx │ │ │ ├── InputBox.tsx │ │ │ ├── MatchItem.tsx │ │ │ ├── ReplaceInput.tsx │ │ │ ├── SearchDetails.tsx │ │ │ ├── SearchHeader.tsx │ │ │ ├── SearchInput.tsx │ │ │ ├── SearchReplaceGroup.tsx │ │ │ └── SearchResults.tsx │ │ ├── hooks │ │ │ └── useVSCode.ts │ │ ├── index.css │ │ ├── index.html │ │ ├── index.tsx │ │ ├── template.d.ts │ │ ├── tsconfig.json │ │ └── types.ts │ ├── test │ │ └── extension.test.ts │ ├── tsconfig.json │ └── types.d.ts ├── tsconfig.json └── vsc-extension-quickstart.md └── web ├── .gitignore ├── README.md ├── build.mjs ├── components ├── Checkbox.tsx ├── CodeMirror.tsx ├── LanguageSelect.tsx ├── MoonIcon.tsx ├── OutputContainer.tsx ├── QueryContainer.tsx ├── SunIcon.tsx ├── ThemeToggle.tsx └── TreeRow.tsx ├── esbuild.mts ├── eslint.config.js ├── hooks └── useParser.ts ├── index.html ├── index.tsx ├── package-lock.json ├── package.json ├── playground.ts ├── serve.mjs ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.node.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.{json,toml,yml,gyp}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.js] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.scm] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{c,cc,h}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.rs] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.{py,pyi}] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.swift] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [*.go] 35 | indent_style = tab 36 | indent_size = 8 37 | 38 | [Makefile] 39 | indent_style = tab 40 | indent_size = 8 41 | 42 | [parser.c] 43 | indent_size = 2 44 | 45 | [{alloc,array,parser}.h] 46 | indent_size = 2 47 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Generated source files 4 | src/*.json linguist-generated 5 | src/parser.c linguist-generated 6 | src/tree_sitter/* linguist-generated 7 | 8 | # C bindings 9 | bindings/c/** linguist-generated 10 | CMakeLists.txt linguist-generated 11 | Makefile linguist-generated 12 | 13 | # Rust bindings 14 | bindings/rust/* linguist-generated 15 | Cargo.toml linguist-generated 16 | Cargo.lock linguist-generated 17 | 18 | # Node.js bindings 19 | bindings/node/* linguist-generated 20 | binding.gyp linguist-generated 21 | package.json linguist-generated 22 | package-lock.json linguist-generated 23 | 24 | # Python bindings 25 | bindings/python/** linguist-generated 26 | setup.py linguist-generated 27 | pyproject.toml linguist-generated 28 | 29 | # Go bindings 30 | bindings/go/* linguist-generated 31 | go.mod linguist-generated 32 | go.sum linguist-generated 33 | 34 | # Swift bindings 35 | bindings/swift/** linguist-generated 36 | Package.swift linguist-generated 37 | Package.resolved linguist-generated 38 | 39 | # Zig bindings 40 | build.zig linguist-generated 41 | build.zig.zon linguist-generated 42 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | paths: 7 | - grammar.js 8 | - src/** 9 | - bindings/** 10 | - binding.gyp 11 | - mbtq/grammar.js 12 | - mbtq/src/** 13 | - mbtq/bindings/** 14 | - mbtq/binding.gyp 15 | 16 | jobs: 17 | build: 18 | permissions: 19 | contents: write 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout source code 23 | uses: actions/checkout@v4 24 | 25 | - name: Install tree-sitter CLI 26 | uses: tree-sitter/setup-action@v2 27 | with: 28 | tree-sitter-ref: v0.25.4 29 | 30 | - name: Generate tree-sitter grammar 31 | run: | 32 | tree-sitter generate 33 | (cd mbtq && tree-sitter generate) 34 | 35 | - name: Commit 36 | run: | 37 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 38 | git config --local user.name "github-actions[bot]" 39 | git add . 40 | if [ -n "$(git status --porcelain)" ]; then 41 | git commit -a -m "build: bump artifacts [skip ci]" 42 | git push origin HEAD:main 43 | fi 44 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - src/tree_sitter/** 7 | - src/grammar.json 8 | - src/node-types.json 9 | - src/parser.c 10 | 11 | jobs: 12 | check: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Failed 16 | run: 17 | echo "Please DO NOT commit generated parser files. They should be generated by the CI." 18 | exit 1 19 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | name: Fuzz 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | paths: 7 | - src/scanner.c 8 | pull_request: 9 | paths: 10 | - src/scanner.c 11 | 12 | jobs: 13 | fuzz: 14 | name: fuzz 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout source code 18 | uses: actions/checkout@v4 19 | 20 | - name: Install tree-sitter CLI 21 | uses: tree-sitter/setup-action@v2 22 | with: 23 | tree-sitter-ref: v0.25.4 24 | 25 | - name: Generate tree-sitter grammar 26 | run: tree-sitter generate 27 | 28 | - name: Run fuzz tests 29 | uses: tree-sitter/fuzz-action@v4 30 | with: 31 | corpus: test/corpus 32 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | paths: 7 | - grammar.js 8 | pull_request: 9 | branches: [ "main" ] 10 | paths: 11 | - grammar.js 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up Node.js 21 | uses: actions/setup-node@v4 22 | with: 23 | cache: npm 24 | node-version-file: '.node-version' 25 | 26 | - name: Install modules 27 | run: npm ci --legacy-peer-deps 28 | - name: Run ESLint 29 | run: npm run lint 30 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: read 10 | pages: write 11 | id-token: write 12 | 13 | concurrency: 14 | group: pages 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version-file: ".node-version" 28 | cache: "npm" 29 | 30 | - name: Setup tree-sitter CLI 31 | uses: tree-sitter/setup-action/cli@v2 32 | with: 33 | tree-sitter-ref: v0.25.4 34 | 35 | - name: Install dependencies 36 | working-directory: web 37 | run: npm ci 38 | 39 | - name: Setup Pages 40 | id: pages 41 | uses: actions/configure-pages@v4 42 | 43 | - name: Build web playground 44 | working-directory: web 45 | run: npm run build 46 | env: 47 | BASE_PATH: ${{ steps.pages.outputs.base_path }} 48 | 49 | - name: Upload artifact 50 | uses: actions/upload-pages-artifact@v3 51 | with: 52 | path: "./web" 53 | 54 | deploy: 55 | environment: 56 | name: github-pages 57 | url: ${{ steps.deployment.outputs.page_url }} 58 | runs-on: ubuntu-latest 59 | needs: build 60 | steps: 61 | - name: Deploy to GitHub Pages 62 | id: deployment 63 | uses: actions/deploy-pages@v4 64 | -------------------------------------------------------------------------------- /.github/workflows/test-mbtq.yml: -------------------------------------------------------------------------------- 1 | name: Test MBTQ 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | paths: 7 | - mbtq/grammar.js 8 | - mbtq/src/** 9 | - mbtq/bindings/** 10 | - mbtq/binding.gyp 11 | pull_request: 12 | paths: 13 | - mbtq/grammar.js 14 | - mbtq/src/** 15 | - mbtq/bindings/** 16 | - mbtq/binding.gyp 17 | 18 | jobs: 19 | test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout source code 23 | uses: actions/checkout@v4 24 | 25 | - name: Setup tree-sitter 26 | uses: tree-sitter/setup-action/cli@v2 27 | with: 28 | tree-sitter-ref: v0.25.4 29 | 30 | - name: Generate tree-sitter parser 31 | working-directory: mbtq 32 | run: tree-sitter generate 33 | 34 | - name: Run tests 35 | uses: tree-sitter/parser-test-action@v2 36 | with: 37 | generate: false 38 | test-parser-cmd: (cd mbtq && tree-sitter test) 39 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | paths: 7 | - grammar.js 8 | - src/** 9 | - bindings/** 10 | - binding.gyp 11 | pull_request: 12 | paths: 13 | - grammar.js 14 | - src/** 15 | - bindings/** 16 | - binding.gyp 17 | 18 | jobs: 19 | test: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout source code 23 | uses: actions/checkout@v4 24 | 25 | - name: Setup tree-sitter 26 | uses: tree-sitter/setup-action/cli@v2 27 | with: 28 | tree-sitter-ref: v0.25.4 29 | 30 | - name: Generate tree-sitter parser 31 | run: tree-sitter generate 32 | 33 | - name: Run tests 34 | uses: tree-sitter/parser-test-action@v2 35 | with: 36 | generate: false 37 | 38 | test-go: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout source code 42 | uses: actions/checkout@v4 43 | 44 | - name: Setup tree-sitter 45 | uses: tree-sitter/setup-action/cli@v2 46 | with: 47 | tree-sitter-ref: v0.25.4 48 | 49 | - name: Generate tree-sitter parser 50 | run: tree-sitter generate 51 | 52 | - name: Run tests 53 | uses: tree-sitter/parser-test-action@v2 54 | with: 55 | generate: false 56 | test-parser: false 57 | test-go: true 58 | 59 | test-rust: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - name: Checkout source code 63 | uses: actions/checkout@v4 64 | 65 | - name: Setup tree-sitter 66 | uses: tree-sitter/setup-action/cli@v2 67 | with: 68 | tree-sitter-ref: v0.25.4 69 | 70 | - name: Generate tree-sitter parser 71 | run: tree-sitter generate 72 | 73 | - name: Run tests 74 | uses: tree-sitter/parser-test-action@v2 75 | with: 76 | generate: false 77 | test-parser: false 78 | test-rust: true 79 | 80 | test-python: 81 | runs-on: ubuntu-latest 82 | steps: 83 | - name: Checkout source code 84 | uses: actions/checkout@v4 85 | 86 | - name: Setup tree-sitter 87 | uses: tree-sitter/setup-action/cli@v2 88 | with: 89 | tree-sitter-ref: v0.25.4 90 | 91 | - name: Generate tree-sitter parser 92 | run: tree-sitter generate 93 | 94 | - name: Run tests 95 | uses: tree-sitter/parser-test-action@v2 96 | with: 97 | generate: false 98 | test-parser: false 99 | test-python: true 100 | 101 | test-node: 102 | if: false 103 | runs-on: ubuntu-latest 104 | steps: 105 | - name: Checkout source code 106 | uses: actions/checkout@v4 107 | 108 | - name: Setup tree-sitter 109 | uses: tree-sitter/setup-action/cli@v2 110 | with: 111 | tree-sitter-ref: v0.25.4 112 | 113 | - name: Generate tree-sitter parser 114 | run: tree-sitter generate 115 | 116 | - name: Setup node 117 | uses: actions/setup-node@v4 118 | with: 119 | node-version-file: '.node-version' 120 | cache: 'npm' 121 | 122 | - name: Install npm dependencies 123 | run: npm ci 124 | 125 | - name: Run tests 126 | run: npm test 127 | 128 | test-core: 129 | runs-on: ubuntu-latest 130 | steps: 131 | - name: Checkout source code 132 | uses: actions/checkout@v4 133 | 134 | - name: Setup tree-sitter 135 | uses: tree-sitter/setup-action/cli@v2 136 | with: 137 | tree-sitter-ref: v0.25.4 138 | 139 | - name: Generate tree-sitter parser 140 | run: tree-sitter generate 141 | 142 | - name: Checkout moonbitlang/core 143 | run: git clone https://github.com/moonbitlang/core.git 144 | 145 | - name: Test core 146 | id: core 147 | uses: tree-sitter/parse-action@v4 148 | with: 149 | files: core/**/*.mbt 150 | 151 | - name: Upload failures 152 | uses: actions/upload-artifact@v4 153 | if: ${{ always() && steps.core.outputs.failures != '' }} 154 | with: 155 | name: failures 156 | path: ${{steps.core.outputs.failures}} 157 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust artifacts 2 | target/ 3 | 4 | # Node artifacts 5 | build/ 6 | prebuilds/ 7 | node_modules/ 8 | 9 | # Swift artifacts 10 | .build/ 11 | 12 | # Go artifacts 13 | _obj/ 14 | 15 | # Python artifacts 16 | .venv/ 17 | dist/ 18 | *.egg-info 19 | *.whl 20 | 21 | # C artifacts 22 | *.a 23 | *.so 24 | *.so.* 25 | *.dylib 26 | *.dll 27 | *.pc 28 | *.exp 29 | *.lib 30 | 31 | # Zig artifacts 32 | .zig-cache/ 33 | zig-cache/ 34 | zig-out/ 35 | 36 | # Example dirs 37 | /examples/*/ 38 | 39 | # Grammar volatiles 40 | *.wasm 41 | *.obj 42 | *.o 43 | 44 | # Archives 45 | *.tar.gz 46 | *.tgz 47 | *.zip 48 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v23.7.0 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-moonbit 4 | VERSION "0.1.0" 5 | DESCRIPTION "Moonbit grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/moonbitlang/tree-sitter-moonbit" 7 | LANGUAGES C) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) 11 | 12 | set(TREE_SITTER_ABI_VERSION 15 CACHE STRING "Tree-sitter ABI version") 13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") 14 | unset(TREE_SITTER_ABI_VERSION CACHE) 15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") 16 | endif() 17 | 18 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") 19 | 20 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" 21 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" 22 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json 23 | --abi=${TREE_SITTER_ABI_VERSION} 24 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 25 | COMMENT "Generating parser.c") 26 | 27 | add_library(tree-sitter-moonbit src/parser.c) 28 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 29 | target_sources(tree-sitter-moonbit PRIVATE src/scanner.c) 30 | endif() 31 | target_include_directories(tree-sitter-moonbit 32 | PRIVATE src 33 | INTERFACE $ 34 | $) 35 | 36 | target_compile_definitions(tree-sitter-moonbit PRIVATE 37 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 38 | $<$:TREE_SITTER_DEBUG>) 39 | 40 | set_target_properties(tree-sitter-moonbit 41 | PROPERTIES 42 | C_STANDARD 11 43 | POSITION_INDEPENDENT_CODE ON 44 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 45 | DEFINE_SYMBOL "") 46 | 47 | configure_file(bindings/c/tree-sitter-moonbit.pc.in 48 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-moonbit.pc" @ONLY) 49 | 50 | include(GNUInstallDirs) 51 | 52 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" 53 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 54 | FILES_MATCHING PATTERN "*.h") 55 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-moonbit.pc" 56 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") 57 | install(TARGETS tree-sitter-moonbit 58 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 59 | 60 | file(GLOB QUERIES queries/*.scm) 61 | install(FILES ${QUERIES} 62 | DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/moonbit") 63 | 64 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 65 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 66 | COMMENT "tree-sitter test") 67 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-moonbit" 3 | description = "Moonbit grammar for tree-sitter" 4 | version = "0.1.0" 5 | authors = ["Moonbit Language Team "] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | keywords = ["incremental", "parsing", "tree-sitter", "moonbit"] 9 | categories = ["parser-implementations", "parsing", "text-editors"] 10 | repository = "https://github.com/moonbitlang/tree-sitter-moonbit" 11 | edition = "2021" 12 | autoexamples = false 13 | 14 | build = "bindings/rust/build.rs" 15 | include = [ 16 | "bindings/rust/*", 17 | "grammar.js", 18 | "queries/*", 19 | "src/*", 20 | "tree-sitter.json", 21 | "LICENSE", 22 | ] 23 | 24 | [lib] 25 | path = "bindings/rust/lib.rs" 26 | 27 | [dependencies] 28 | tree-sitter-language = "0.1" 29 | 30 | [build-dependencies] 31 | cc = "1.2" 32 | 33 | [dev-dependencies] 34 | tree-sitter = "0.25.4" 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | $(error Windows is not supported) 3 | endif 4 | 5 | LANGUAGE_NAME := tree-sitter-moonbit 6 | HOMEPAGE_URL := https://github.com/moonbitlang/tree-sitter-moonbit 7 | VERSION := 0.1.0 8 | 9 | # repository 10 | SRC_DIR := src 11 | 12 | TS ?= tree-sitter 13 | 14 | # install directory layout 15 | PREFIX ?= /usr/local 16 | DATADIR ?= $(PREFIX)/share 17 | INCLUDEDIR ?= $(PREFIX)/include 18 | LIBDIR ?= $(PREFIX)/lib 19 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 20 | 21 | # source/object files 22 | PARSER := $(SRC_DIR)/parser.c 23 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 24 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 25 | 26 | # flags 27 | ARFLAGS ?= rcs 28 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 29 | 30 | # ABI versioning 31 | SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) 32 | SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) 33 | 34 | # OS-specific bits 35 | ifeq ($(shell uname),Darwin) 36 | SOEXT = dylib 37 | SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) 38 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) 39 | LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks 40 | else 41 | SOEXT = so 42 | SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) 43 | SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) 44 | LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) 45 | endif 46 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 47 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 48 | endif 49 | 50 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 51 | 52 | lib$(LANGUAGE_NAME).a: $(OBJS) 53 | $(AR) $(ARFLAGS) $@ $^ 54 | 55 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 56 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 57 | ifneq ($(STRIP),) 58 | $(STRIP) $@ 59 | endif 60 | 61 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 62 | sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ 63 | -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ 64 | -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ 65 | -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ 66 | -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ 67 | -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ 68 | 69 | $(PARSER): $(SRC_DIR)/grammar.json 70 | $(TS) generate $^ 71 | 72 | install: all 73 | install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/moonbit '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 74 | install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 75 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 76 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 77 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 78 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 79 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 80 | ifneq ($(wildcard queries/*.scm),) 81 | install -m644 queries/*.scm '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/moonbit 82 | endif 83 | 84 | uninstall: 85 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 86 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 87 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 88 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 89 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 90 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 91 | $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/moonbit 92 | 93 | clean: 94 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 95 | 96 | test: 97 | $(TS) test 98 | 99 | .PHONY: all install uninstall clean test 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-moonbit 2 | 3 | A [tree-sitter][] grammar for [MoonBit](https://www.moonbitlang.com). 4 | 5 | [tree-sitter]: https://github.com/tree-sitter/tree-sitter 6 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_moonbit_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_moonbit(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | auto language = Napi::External::New(env, tree_sitter_moonbit()); 14 | language.TypeTag(&LANGUAGE_TYPE_TAG); 15 | exports["language"] = language; 16 | return exports; 17 | } 18 | 19 | NODE_API_MODULE(tree_sitter_moonbit_binding, Init) 20 | -------------------------------------------------------------------------------- /bindings/node/binding_test.js: -------------------------------------------------------------------------------- 1 | const assert = require("node:assert"); 2 | const { test } = require("node:test"); 3 | 4 | const Parser = require("tree-sitter"); 5 | 6 | test("can load grammar", () => { 7 | const parser = new Parser(); 8 | assert.doesNotThrow(() => parser.setLanguage(require("."))); 9 | }); 10 | -------------------------------------------------------------------------------- /bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | language: unknown; 23 | nodeTypeInfo: NodeInfo[]; 24 | }; 25 | 26 | declare const language: Language; 27 | export = language; 28 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = 4 | typeof process.versions.bun === "string" 5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time 6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-moonbit.node`) 7 | : require("node-gyp-build")(root); 8 | 9 | try { 10 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 11 | } catch (_) {} 12 | -------------------------------------------------------------------------------- /bindings/python/tests/test_binding.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import tree_sitter 4 | import tree_sitter_moonbit 5 | 6 | 7 | class TestLanguage(TestCase): 8 | def test_can_load_grammar(self): 9 | try: 10 | tree_sitter.Language(tree_sitter_moonbit.language()) 11 | except Exception: 12 | self.fail("Error loading Moonbit grammar") 13 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_moonbit/__init__.py: -------------------------------------------------------------------------------- 1 | """Moonbit grammar for tree-sitter""" 2 | 3 | from importlib.resources import files as _files 4 | 5 | from ._binding import language 6 | 7 | 8 | def _get_query(name, file): 9 | query = _files(f"{__package__}.queries") / file 10 | globals()[name] = query.read_text() 11 | return globals()[name] 12 | 13 | 14 | def __getattr__(name): 15 | # NOTE: uncomment these to include any queries that this grammar contains: 16 | 17 | # if name == "HIGHLIGHTS_QUERY": 18 | # return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") 19 | # if name == "INJECTIONS_QUERY": 20 | # return _get_query("INJECTIONS_QUERY", "injections.scm") 21 | # if name == "LOCALS_QUERY": 22 | # return _get_query("LOCALS_QUERY", "locals.scm") 23 | # if name == "TAGS_QUERY": 24 | # return _get_query("TAGS_QUERY", "tags.scm") 25 | 26 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 27 | 28 | 29 | __all__ = [ 30 | "language", 31 | # "HIGHLIGHTS_QUERY", 32 | # "INJECTIONS_QUERY", 33 | # "LOCALS_QUERY", 34 | # "TAGS_QUERY", 35 | ] 36 | 37 | 38 | def __dir__(): 39 | return sorted(__all__ + [ 40 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 41 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 42 | ]) 43 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_moonbit/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | # NOTE: uncomment these to include any queries that this grammar contains: 4 | 5 | # HIGHLIGHTS_QUERY: Final[str] 6 | # INJECTIONS_QUERY: Final[str] 7 | # LOCALS_QUERY: Final[str] 8 | # TAGS_QUERY: Final[str] 9 | 10 | def language() -> object: ... 11 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_moonbit/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_moonbit(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_moonbit(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static struct PyModuleDef_Slot slots[] = { 12 | #ifdef Py_GIL_DISABLED 13 | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, 14 | #endif 15 | {0, NULL} 16 | }; 17 | 18 | static PyMethodDef methods[] = { 19 | {"language", _binding_language, METH_NOARGS, 20 | "Get the tree-sitter language for this grammar."}, 21 | {NULL, NULL, 0, NULL} 22 | }; 23 | 24 | static struct PyModuleDef module = { 25 | .m_base = PyModuleDef_HEAD_INIT, 26 | .m_name = "_binding", 27 | .m_doc = NULL, 28 | .m_size = 0, 29 | .m_methods = methods, 30 | .m_slots = slots, 31 | }; 32 | 33 | PyMODINIT_FUNC PyInit__binding(void) { 34 | return PyModuleDef_Init(&module); 35 | } 36 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_moonbit/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonbitlang/tree-sitter-moonbit/2ae65572ecc111655a30ffa6dcfc48d2ee37c3e1/bindings/python/tree_sitter_moonbit/py.typed -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.std("c11").include(src_dir); 6 | 7 | #[cfg(target_env = "msvc")] 8 | c_config.flag("-utf-8"); 9 | 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 13 | 14 | let scanner_path = src_dir.join("scanner.c"); 15 | if scanner_path.exists() { 16 | c_config.file(&scanner_path); 17 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 18 | } 19 | 20 | c_config.compile("tree-sitter-moonbit"); 21 | } 22 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides MoonBit language support for the [tree-sitter] parsing library. 2 | //! 3 | //! Typically, you will use the [`LANGUAGE`] constant to add this language to a 4 | //! tree-sitter [`Parser`], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! let code = r#" 8 | //! "#; 9 | //! let mut parser = tree_sitter::Parser::new(); 10 | //! let language = tree_sitter_moonbit::LANGUAGE; 11 | //! parser 12 | //! .set_language(&language.into()) 13 | //! .expect("Error loading Moonbit parser"); 14 | //! let tree = parser.parse(code, None).unwrap(); 15 | //! assert!(!tree.root_node().has_error()); 16 | //! ``` 17 | //! 18 | //! [`Parser`]: https://docs.rs/tree-sitter/0.25.4/tree_sitter/struct.Parser.html 19 | //! [tree-sitter]: https://tree-sitter.github.io/ 20 | 21 | use tree_sitter_language::LanguageFn; 22 | 23 | extern "C" { 24 | fn tree_sitter_moonbit() -> *const (); 25 | } 26 | 27 | /// The tree-sitter [`LanguageFn`] for this grammar. 28 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_moonbit) }; 29 | 30 | /// The content of the [`node-types.json`] file for this grammar. 31 | /// 32 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types 33 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 34 | 35 | // NOTE: uncomment these to include any queries that this grammar contains: 36 | 37 | // pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 38 | // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); 39 | // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); 40 | // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | #[test] 45 | fn test_can_load_grammar() { 46 | let mut parser = tree_sitter::Parser::new(); 47 | parser 48 | .set_language(&super::LANGUAGE.into()) 49 | .expect("Error loading Moonbit parser"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /bindings/zig/root.zig: -------------------------------------------------------------------------------- 1 | const testing = @import("std").testing; 2 | 3 | const ts = @import("tree-sitter"); 4 | const Language = ts.Language; 5 | const Parser = ts.Parser; 6 | 7 | pub extern fn tree_sitter_moonbit() callconv(.C) *const Language; 8 | 9 | pub export fn language() *const Language { 10 | return tree_sitter_moonbit(); 11 | } 12 | 13 | test "can load grammar" { 14 | const parser = Parser.create(); 15 | defer parser.destroy(); 16 | try testing.expectEqual(parser.setLanguage(language()), void{}); 17 | try testing.expectEqual(parser.getLanguage(), tree_sitter_moonbit()); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.Build) !void { 4 | const target = b.standardTargetOptions(.{}); 5 | const optimize = b.standardOptimizeOption(.{}); 6 | 7 | const shared = b.option(bool, "build-shared", "Build a shared library") orelse true; 8 | const reuse_alloc = b.option(bool, "reuse-allocator", "Reuse the library allocator") orelse false; 9 | 10 | const lib: *std.Build.Step.Compile = if (shared) b.addSharedLibrary(.{ 11 | .name = "tree-sitter-moonbit", 12 | .pic = true, 13 | .target = target, 14 | .optimize = optimize, 15 | .link_libc = true, 16 | }) else b.addStaticLibrary(.{ 17 | .name = "tree-sitter-moonbit", 18 | .target = target, 19 | .optimize = optimize, 20 | .link_libc = true, 21 | }); 22 | 23 | lib.addCSourceFile(.{ 24 | .file = b.path("src/parser.c"), 25 | .flags = &.{"-std=c11"}, 26 | }); 27 | if (hasScanner(b.build_root.handle)) { 28 | lib.addCSourceFile(.{ 29 | .file = b.path("src/scanner.c"), 30 | .flags = &.{"-std=c11"}, 31 | }); 32 | } 33 | 34 | if (reuse_alloc) { 35 | lib.root_module.addCMacro("TREE_SITTER_REUSE_ALLOCATOR", ""); 36 | } 37 | if (optimize == .Debug) { 38 | lib.root_module.addCMacro("TREE_SITTER_DEBUG", ""); 39 | } 40 | 41 | lib.addIncludePath(b.path("src")); 42 | 43 | b.installArtifact(lib); 44 | b.installFile("src/node-types.json", "node-types.json"); 45 | b.installDirectory(.{ .source_dir = b.path("queries"), .install_dir = .prefix, .install_subdir = "queries", .include_extensions = &.{"scm"} }); 46 | 47 | const module = b.addModule("tree-sitter-moonbit", .{ 48 | .root_source_file = b.path("bindings/zig/root.zig"), 49 | .target = target, 50 | .optimize = optimize, 51 | }); 52 | module.linkLibrary(lib); 53 | 54 | const ts_dep = b.dependency("tree-sitter", .{}); 55 | const ts_mod = ts_dep.module("tree-sitter"); 56 | module.addImport("tree-sitter", ts_mod); 57 | 58 | // ╭─────────────────╮ 59 | // │ Tests │ 60 | // ╰─────────────────╯ 61 | 62 | const tests = b.addTest(.{ 63 | .root_source_file = b.path("bindings/zig/root.zig"), 64 | .target = target, 65 | .optimize = optimize, 66 | }); 67 | tests.linkLibrary(lib); 68 | tests.root_module.addImport("tree-sitter", ts_mod); 69 | 70 | const run_tests = b.addRunArtifact(tests); 71 | 72 | const test_step = b.step("test", "Run unit tests"); 73 | test_step.dependOn(&run_tests.step); 74 | } 75 | 76 | inline fn hasScanner(dir: std.fs.Dir) bool { 77 | dir.access("src/scanner.c", .{}) catch return false; 78 | return true; 79 | } 80 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "tree-sitter-moonbit", 3 | .version = "0.1.0", 4 | .dependencies = .{ .@"tree-sitter" = .{ 5 | .url = "https://github.com/tree-sitter/zig-tree-sitter/archive/refs/tags/v0.25.0.tar.gz", 6 | .hash = "12201a8d5e840678bbbf5128e605519c4024af422295d68e2ba2090e675328e5811d", 7 | } }, 8 | .paths = .{ 9 | "build.zig", 10 | "build.zig.zon", 11 | "bindings/zig", 12 | "src", 13 | "queries", 14 | "LICENSE", 15 | "README.md", 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import treesitter from "eslint-config-treesitter"; 2 | import prettier from "eslint-config-prettier/flat"; 3 | 4 | export default [...treesitter, prettier]; 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/moonbitlang/tree-sitter-moonbit 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.0 6 | -------------------------------------------------------------------------------- /mbtq/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.{json,toml,yml,gyp}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.js] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.scm] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{c,cc,h}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.rs] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.{py,pyi}] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.swift] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [*.go] 35 | indent_style = tab 36 | indent_size = 8 37 | 38 | [Makefile] 39 | indent_style = tab 40 | indent_size = 8 41 | 42 | [parser.c] 43 | indent_size = 2 44 | 45 | [{alloc,array,parser}.h] 46 | indent_size = 2 47 | -------------------------------------------------------------------------------- /mbtq/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Generated source files 4 | src/*.json linguist-generated 5 | src/parser.c linguist-generated 6 | src/tree_sitter/* linguist-generated 7 | 8 | # C bindings 9 | bindings/c/** linguist-generated 10 | CMakeLists.txt linguist-generated 11 | Makefile linguist-generated 12 | 13 | # Rust bindings 14 | bindings/rust/* linguist-generated 15 | Cargo.toml linguist-generated 16 | Cargo.lock linguist-generated 17 | 18 | # Node.js bindings 19 | bindings/node/* linguist-generated 20 | binding.gyp linguist-generated 21 | package.json linguist-generated 22 | package-lock.json linguist-generated 23 | 24 | # Python bindings 25 | bindings/python/** linguist-generated 26 | setup.py linguist-generated 27 | pyproject.toml linguist-generated 28 | 29 | # Go bindings 30 | bindings/go/* linguist-generated 31 | go.mod linguist-generated 32 | go.sum linguist-generated 33 | 34 | # Swift bindings 35 | bindings/swift/** linguist-generated 36 | Package.swift linguist-generated 37 | Package.resolved linguist-generated 38 | 39 | # Zig bindings 40 | build.zig linguist-generated 41 | build.zig.zon linguist-generated 42 | -------------------------------------------------------------------------------- /mbtq/.gitignore: -------------------------------------------------------------------------------- 1 | # Rust artifacts 2 | target/ 3 | 4 | # Node artifacts 5 | build/ 6 | prebuilds/ 7 | node_modules/ 8 | 9 | # Swift artifacts 10 | .build/ 11 | 12 | # Go artifacts 13 | _obj/ 14 | 15 | # Python artifacts 16 | .venv/ 17 | dist/ 18 | *.egg-info 19 | *.whl 20 | 21 | # C artifacts 22 | *.a 23 | *.so 24 | *.so.* 25 | *.dylib 26 | *.dll 27 | *.pc 28 | *.exp 29 | *.lib 30 | 31 | # Zig artifacts 32 | .zig-cache/ 33 | zig-cache/ 34 | zig-out/ 35 | 36 | # Example dirs 37 | /examples/*/ 38 | 39 | # Grammar volatiles 40 | *.wasm 41 | *.obj 42 | *.o 43 | 44 | # Archives 45 | *.tar.gz 46 | *.tgz 47 | *.zip 48 | -------------------------------------------------------------------------------- /mbtq/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-mbtq 4 | VERSION "0.0.1" 5 | DESCRIPTION "Mbtq grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/moonbitlang/tree-sitter-moonbit" 7 | LANGUAGES C) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) 11 | 12 | set(TREE_SITTER_ABI_VERSION 15 CACHE STRING "Tree-sitter ABI version") 13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") 14 | unset(TREE_SITTER_ABI_VERSION CACHE) 15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") 16 | endif() 17 | 18 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") 19 | 20 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" 21 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" 22 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json 23 | --abi=${TREE_SITTER_ABI_VERSION} 24 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 25 | COMMENT "Generating parser.c") 26 | 27 | add_library(tree-sitter-mbtq src/parser.c) 28 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 29 | target_sources(tree-sitter-mbtq PRIVATE src/scanner.c) 30 | endif() 31 | target_include_directories(tree-sitter-mbtq 32 | PRIVATE src 33 | INTERFACE $ 34 | $) 35 | 36 | target_compile_definitions(tree-sitter-mbtq PRIVATE 37 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 38 | $<$:TREE_SITTER_DEBUG>) 39 | 40 | set_target_properties(tree-sitter-mbtq 41 | PROPERTIES 42 | C_STANDARD 11 43 | POSITION_INDEPENDENT_CODE ON 44 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 45 | DEFINE_SYMBOL "") 46 | 47 | configure_file(bindings/c/tree-sitter-mbtq.pc.in 48 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-mbtq.pc" @ONLY) 49 | 50 | include(GNUInstallDirs) 51 | 52 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" 53 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 54 | FILES_MATCHING PATTERN "*.h") 55 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-mbtq.pc" 56 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") 57 | install(TARGETS tree-sitter-mbtq 58 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 59 | 60 | file(GLOB QUERIES queries/*.scm) 61 | install(FILES ${QUERIES} 62 | DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/mbtq") 63 | 64 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 65 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 66 | COMMENT "tree-sitter test") 67 | -------------------------------------------------------------------------------- /mbtq/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-mbtq" 3 | description = "Mbtq grammar for tree-sitter" 4 | version = "0.0.1" 5 | authors = ["Moonbit Language Team "] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | keywords = ["incremental", "parsing", "tree-sitter", "mbtq"] 9 | categories = ["parser-implementations", "parsing", "text-editors"] 10 | repository = "https://github.com/moonbitlang/tree-sitter-moonbit" 11 | edition = "2021" 12 | autoexamples = false 13 | 14 | build = "bindings/rust/build.rs" 15 | include = [ 16 | "bindings/rust/*", 17 | "grammar.js", 18 | "queries/*", 19 | "src/*", 20 | "tree-sitter.json", 21 | "LICENSE", 22 | ] 23 | 24 | [lib] 25 | path = "bindings/rust/lib.rs" 26 | 27 | [dependencies] 28 | tree-sitter-language = "0.1" 29 | 30 | [build-dependencies] 31 | cc = "1.2" 32 | 33 | [dev-dependencies] 34 | tree-sitter = "0.25.4" 35 | -------------------------------------------------------------------------------- /mbtq/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | $(error Windows is not supported) 3 | endif 4 | 5 | LANGUAGE_NAME := tree-sitter-mbtq 6 | HOMEPAGE_URL := https://github.com/moonbitlang/tree-sitter-moonbit 7 | VERSION := 0.0.1 8 | 9 | # repository 10 | SRC_DIR := src 11 | 12 | TS ?= tree-sitter 13 | 14 | # install directory layout 15 | PREFIX ?= /usr/local 16 | DATADIR ?= $(PREFIX)/share 17 | INCLUDEDIR ?= $(PREFIX)/include 18 | LIBDIR ?= $(PREFIX)/lib 19 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 20 | 21 | # source/object files 22 | PARSER := $(SRC_DIR)/parser.c 23 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 24 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 25 | 26 | # flags 27 | ARFLAGS ?= rcs 28 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 29 | 30 | # ABI versioning 31 | SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) 32 | SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) 33 | 34 | # OS-specific bits 35 | ifeq ($(shell uname),Darwin) 36 | SOEXT = dylib 37 | SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) 38 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) 39 | LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks 40 | else 41 | SOEXT = so 42 | SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) 43 | SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) 44 | LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) 45 | endif 46 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 47 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 48 | endif 49 | 50 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 51 | 52 | lib$(LANGUAGE_NAME).a: $(OBJS) 53 | $(AR) $(ARFLAGS) $@ $^ 54 | 55 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 56 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 57 | ifneq ($(STRIP),) 58 | $(STRIP) $@ 59 | endif 60 | 61 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 62 | sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ 63 | -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ 64 | -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ 65 | -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ 66 | -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ 67 | -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ 68 | 69 | $(PARSER): $(SRC_DIR)/grammar.json 70 | $(TS) generate $^ 71 | 72 | install: all 73 | install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mbtq '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 74 | install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 75 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 76 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 77 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 78 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 79 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 80 | ifneq ($(wildcard queries/*.scm),) 81 | install -m644 queries/*.scm '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mbtq 82 | endif 83 | 84 | uninstall: 85 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 86 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 87 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 88 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 89 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 90 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 91 | $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mbtq 92 | 93 | clean: 94 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 95 | 96 | test: 97 | $(TS) test 98 | 99 | .PHONY: all install uninstall clean test 100 | -------------------------------------------------------------------------------- /mbtq/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import Foundation 4 | import PackageDescription 5 | 6 | var sources = ["src/parser.c"] 7 | if FileManager.default.fileExists(atPath: "src/scanner.c") { 8 | sources.append("src/scanner.c") 9 | } 10 | 11 | let package = Package( 12 | name: "TreeSitterMbtq", 13 | products: [ 14 | .library(name: "TreeSitterMbtq", targets: ["TreeSitterMbtq"]), 15 | ], 16 | dependencies: [ 17 | .package(url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.8.0"), 18 | ], 19 | targets: [ 20 | .target( 21 | name: "TreeSitterMbtq", 22 | dependencies: [], 23 | path: ".", 24 | sources: sources, 25 | resources: [ 26 | .copy("queries") 27 | ], 28 | publicHeadersPath: "bindings/swift", 29 | cSettings: [.headerSearchPath("src")] 30 | ), 31 | .testTarget( 32 | name: "TreeSitterMbtqTests", 33 | dependencies: [ 34 | "SwiftTreeSitter", 35 | "TreeSitterMbtq", 36 | ], 37 | path: "bindings/swift/TreeSitterMbtqTests" 38 | ) 39 | ], 40 | cLanguageStandard: .c11 41 | ) 42 | -------------------------------------------------------------------------------- /mbtq/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_mbtq_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_mbtq(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | auto language = Napi::External::New(env, tree_sitter_mbtq()); 14 | language.TypeTag(&LANGUAGE_TYPE_TAG); 15 | exports["language"] = language; 16 | return exports; 17 | } 18 | 19 | NODE_API_MODULE(tree_sitter_mbtq_binding, Init) 20 | -------------------------------------------------------------------------------- /mbtq/bindings/node/binding_test.js: -------------------------------------------------------------------------------- 1 | const assert = require("node:assert"); 2 | const { test } = require("node:test"); 3 | 4 | const Parser = require("tree-sitter"); 5 | 6 | test("can load grammar", () => { 7 | const parser = new Parser(); 8 | assert.doesNotThrow(() => parser.setLanguage(require("."))); 9 | }); 10 | -------------------------------------------------------------------------------- /mbtq/bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | language: unknown; 23 | nodeTypeInfo: NodeInfo[]; 24 | }; 25 | 26 | declare const language: Language; 27 | export = language; 28 | -------------------------------------------------------------------------------- /mbtq/bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = 4 | typeof process.versions.bun === "string" 5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time 6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-mbtq.node`) 7 | : require("node-gyp-build")(root); 8 | 9 | try { 10 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 11 | } catch (_) {} 12 | -------------------------------------------------------------------------------- /mbtq/bindings/python/tests/test_binding.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import tree_sitter 4 | import tree_sitter_mbtq 5 | 6 | 7 | class TestLanguage(TestCase): 8 | def test_can_load_grammar(self): 9 | try: 10 | tree_sitter.Language(tree_sitter_mbtq.language()) 11 | except Exception: 12 | self.fail("Error loading Mbtq grammar") 13 | -------------------------------------------------------------------------------- /mbtq/bindings/python/tree_sitter_mbtq/__init__.py: -------------------------------------------------------------------------------- 1 | """Mbtq grammar for tree-sitter""" 2 | 3 | from importlib.resources import files as _files 4 | 5 | from ._binding import language 6 | 7 | 8 | def _get_query(name, file): 9 | query = _files(f"{__package__}.queries") / file 10 | globals()[name] = query.read_text() 11 | return globals()[name] 12 | 13 | 14 | def __getattr__(name): 15 | # NOTE: uncomment these to include any queries that this grammar contains: 16 | 17 | # if name == "HIGHLIGHTS_QUERY": 18 | # return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") 19 | # if name == "INJECTIONS_QUERY": 20 | # return _get_query("INJECTIONS_QUERY", "injections.scm") 21 | # if name == "LOCALS_QUERY": 22 | # return _get_query("LOCALS_QUERY", "locals.scm") 23 | # if name == "TAGS_QUERY": 24 | # return _get_query("TAGS_QUERY", "tags.scm") 25 | 26 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 27 | 28 | 29 | __all__ = [ 30 | "language", 31 | # "HIGHLIGHTS_QUERY", 32 | # "INJECTIONS_QUERY", 33 | # "LOCALS_QUERY", 34 | # "TAGS_QUERY", 35 | ] 36 | 37 | 38 | def __dir__(): 39 | return sorted(__all__ + [ 40 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 41 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 42 | ]) 43 | -------------------------------------------------------------------------------- /mbtq/bindings/python/tree_sitter_mbtq/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | # NOTE: uncomment these to include any queries that this grammar contains: 4 | 5 | # HIGHLIGHTS_QUERY: Final[str] 6 | # INJECTIONS_QUERY: Final[str] 7 | # LOCALS_QUERY: Final[str] 8 | # TAGS_QUERY: Final[str] 9 | 10 | def language() -> object: ... 11 | -------------------------------------------------------------------------------- /mbtq/bindings/python/tree_sitter_mbtq/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_mbtq(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_mbtq(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static struct PyModuleDef_Slot slots[] = { 12 | #ifdef Py_GIL_DISABLED 13 | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, 14 | #endif 15 | {0, NULL} 16 | }; 17 | 18 | static PyMethodDef methods[] = { 19 | {"language", _binding_language, METH_NOARGS, 20 | "Get the tree-sitter language for this grammar."}, 21 | {NULL, NULL, 0, NULL} 22 | }; 23 | 24 | static struct PyModuleDef module = { 25 | .m_base = PyModuleDef_HEAD_INIT, 26 | .m_name = "_binding", 27 | .m_doc = NULL, 28 | .m_size = 0, 29 | .m_methods = methods, 30 | .m_slots = slots, 31 | }; 32 | 33 | PyMODINIT_FUNC PyInit__binding(void) { 34 | return PyModuleDef_Init(&module); 35 | } 36 | -------------------------------------------------------------------------------- /mbtq/bindings/python/tree_sitter_mbtq/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonbitlang/tree-sitter-moonbit/2ae65572ecc111655a30ffa6dcfc48d2ee37c3e1/mbtq/bindings/python/tree_sitter_mbtq/py.typed -------------------------------------------------------------------------------- /mbtq/bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.std("c11").include(src_dir); 6 | 7 | #[cfg(target_env = "msvc")] 8 | c_config.flag("-utf-8"); 9 | 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 13 | 14 | let scanner_path = src_dir.join("scanner.c"); 15 | if scanner_path.exists() { 16 | c_config.file(&scanner_path); 17 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 18 | } 19 | 20 | c_config.compile("tree-sitter-mbtq"); 21 | } 22 | -------------------------------------------------------------------------------- /mbtq/bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides Mbtq language support for the [tree-sitter] parsing library. 2 | //! 3 | //! Typically, you will use the [`LANGUAGE`] constant to add this language to a 4 | //! tree-sitter [`Parser`], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! let code = r#" 8 | //! "#; 9 | //! let mut parser = tree_sitter::Parser::new(); 10 | //! let language = tree_sitter_mbtq::LANGUAGE; 11 | //! parser 12 | //! .set_language(&language.into()) 13 | //! .expect("Error loading Mbtq parser"); 14 | //! let tree = parser.parse(code, None).unwrap(); 15 | //! assert!(!tree.root_node().has_error()); 16 | //! ``` 17 | //! 18 | //! [`Parser`]: https://docs.rs/tree-sitter/0.25.4/tree_sitter/struct.Parser.html 19 | //! [tree-sitter]: https://tree-sitter.github.io/ 20 | 21 | use tree_sitter_language::LanguageFn; 22 | 23 | extern "C" { 24 | fn tree_sitter_mbtq() -> *const (); 25 | } 26 | 27 | /// The tree-sitter [`LanguageFn`] for this grammar. 28 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_mbtq) }; 29 | 30 | /// The content of the [`node-types.json`] file for this grammar. 31 | /// 32 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types 33 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 34 | 35 | // NOTE: uncomment these to include any queries that this grammar contains: 36 | 37 | // pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 38 | // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); 39 | // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); 40 | // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | #[test] 45 | fn test_can_load_grammar() { 46 | let mut parser = tree_sitter::Parser::new(); 47 | parser 48 | .set_language(&super::LANGUAGE.into()) 49 | .expect("Error loading Mbtq parser"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /mbtq/bindings/swift/TreeSitterMbtq/mbtq.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_MBTQ_H_ 2 | #define TREE_SITTER_MBTQ_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_mbtq(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_MBTQ_H_ 17 | -------------------------------------------------------------------------------- /mbtq/bindings/swift/TreeSitterMbtqTests/TreeSitterMbtqTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftTreeSitter 3 | import TreeSitterMbtq 4 | 5 | final class TreeSitterMbtqTests: XCTestCase { 6 | func testCanLoadGrammar() throws { 7 | let parser = Parser() 8 | let language = Language(language: tree_sitter_mbtq()) 9 | XCTAssertNoThrow(try parser.setLanguage(language), 10 | "Error loading Mbtq grammar") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mbtq/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/moonbitlang/tree-sitter-moonbit 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.0 6 | -------------------------------------------------------------------------------- /mbtq/grammar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Mbtq grammar for tree-sitter 3 | * @author Haoxiang Fei 4 | * @license Apache-2.0 5 | */ 6 | 7 | /// 8 | // @ts-check 9 | 10 | const base = require('../grammar.js'); 11 | 12 | module.exports = grammar(base, { 13 | name: 'mbtq', 14 | 15 | extras: ($) => [$._comment, /\s/, $._scanner_reset], 16 | 17 | rules: { 18 | _simple_expression: $ => choice( 19 | base.grammar.rules._simple_expression, 20 | $.quotation_expression_expander, 21 | ), 22 | 23 | simple_pattern: $ => choice( 24 | base.grammar.rules.simple_pattern, 25 | $.quotation_pattern_expander, 26 | ), 27 | 28 | type: $ => choice( 29 | base.grammar.rules.type, 30 | $.quotation_type_expander, 31 | ), 32 | 33 | literal: $ => choice( 34 | base.grammar.rules.literal, 35 | $.quotation_literal_expander, 36 | ), 37 | 38 | string_literal: $ => choice( 39 | base.grammar.rules.string_literal, 40 | $.quotation_string_expander, 41 | ), 42 | 43 | quotation_variable: $ => $._lowercase_identifier, 44 | 45 | quotation_expression_expander: $ => seq( 46 | '$', 'exp', ':', $.quotation_variable, 47 | ), 48 | 49 | quotation_pattern_expander: $ => seq( 50 | '$', 'pat', ':', $.quotation_variable, 51 | ), 52 | 53 | quotation_lowercase_identifier_expander: $ => seq( 54 | '$', 'id', ':', $.quotation_variable, 55 | ), 56 | 57 | quotation_uppercase_identifier_expander: $ => seq( 58 | '$', 'Id', ':', $.quotation_variable, 59 | ), 60 | 61 | quotation_type_expander: $ => seq( 62 | '$', 'ty', ':', $.quotation_variable, 63 | ), 64 | 65 | quotation_literal_expander: $ => seq( 66 | '$', 'lit', ':', $.quotation_variable, 67 | ), 68 | 69 | quotation_string_expander: $ => seq( 70 | '$', 'str', ':', $.quotation_variable, 71 | ), 72 | 73 | _lowercase_identifier: $ => choice( 74 | $.quotation_lowercase_identifier_expander, 75 | $.lowercase_identifier, 76 | ), 77 | 78 | _uppercase_identifier: $ => choice( 79 | $.quotation_uppercase_identifier_expander, 80 | $.uppercase_identifier, 81 | ), 82 | 83 | _comment: (_) => /\/\/.*/, 84 | }, 85 | }); 86 | -------------------------------------------------------------------------------- /mbtq/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-mbtq", 3 | "version": "0.0.1", 4 | "description": "Mbtq grammar for tree-sitter", 5 | "repository": "https://github.com/moonbitlang/tree-sitter-moonbit", 6 | "license": "Apache-2.0", 7 | "author": { 8 | "name": "Moonbit Language Team", 9 | "email": "support@moonbitlang.com", 10 | "url": "https://www.moonbitlang.com/" 11 | }, 12 | "main": "bindings/node", 13 | "types": "bindings/node", 14 | "keywords": [ 15 | "incremental", 16 | "parsing", 17 | "tree-sitter", 18 | "mbtq" 19 | ], 20 | "files": [ 21 | "grammar.js", 22 | "tree-sitter.json", 23 | "binding.gyp", 24 | "prebuilds/**", 25 | "bindings/node/*", 26 | "queries/*", 27 | "src/**", 28 | "*.wasm" 29 | ], 30 | "dependencies": { 31 | "node-addon-api": "^8.2.1", 32 | "node-gyp-build": "^4.8.2" 33 | }, 34 | "devDependencies": { 35 | "prebuildify": "^6.0.1", 36 | "tree-sitter-cli": "^0.25.4" 37 | }, 38 | "peerDependencies": { 39 | "tree-sitter": "^0.21.1" 40 | }, 41 | "peerDependenciesMeta": { 42 | "tree-sitter": { 43 | "optional": true 44 | } 45 | }, 46 | "scripts": { 47 | "install": "node-gyp-build", 48 | "prestart": "tree-sitter build --wasm", 49 | "start": "tree-sitter playground", 50 | "test": "node --test bindings/node/*_test.js" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mbtq/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-mbtq" 7 | description = "Mbtq grammar for tree-sitter" 8 | version = "0.0.1" 9 | keywords = ["incremental", "parsing", "tree-sitter", "mbtq"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "Topic :: Software Development :: Compilers", 13 | "Topic :: Text Processing :: Linguistic", 14 | "Typing :: Typed", 15 | ] 16 | authors = [{ name = "Moonbit Language Team", email = "support@moonbitlang.com" }] 17 | requires-python = ">=3.10" 18 | license.text = "Apache-2.0" 19 | readme = "README.md" 20 | 21 | [project.urls] 22 | Homepage = "https://github.com/moonbitlang/tree-sitter-moonbit" 23 | 24 | [project.optional-dependencies] 25 | core = ["tree-sitter~=0.24"] 26 | 27 | [tool.cibuildwheel] 28 | build = "cp310-*" 29 | build-frontend = "build" 30 | -------------------------------------------------------------------------------- /mbtq/setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from platform import system 3 | from sysconfig import get_config_var 4 | 5 | from setuptools import Extension, find_packages, setup 6 | from setuptools.command.build import build 7 | from setuptools.command.egg_info import egg_info 8 | from wheel.bdist_wheel import bdist_wheel 9 | 10 | sources = [ 11 | "bindings/python/tree_sitter_mbtq/binding.c", 12 | "src/parser.c", 13 | ] 14 | if path.exists("src/scanner.c"): 15 | sources.append("src/scanner.c") 16 | 17 | macros: list[tuple[str, str | None]] = [ 18 | ("PY_SSIZE_T_CLEAN", None), 19 | ("TREE_SITTER_HIDE_SYMBOLS", None), 20 | ] 21 | if limited_api := not get_config_var("Py_GIL_DISABLED"): 22 | macros.append(("Py_LIMITED_API", "0x030A0000")) 23 | 24 | if system() != "Windows": 25 | cflags = ["-std=c11", "-fvisibility=hidden"] 26 | else: 27 | cflags = ["/std:c11", "/utf-8"] 28 | 29 | 30 | class Build(build): 31 | def run(self): 32 | if path.isdir("queries"): 33 | dest = path.join(self.build_lib, "tree_sitter_mbtq", "queries") 34 | self.copy_tree("queries", dest) 35 | super().run() 36 | 37 | 38 | class BdistWheel(bdist_wheel): 39 | def get_tag(self): 40 | python, abi, platform = super().get_tag() 41 | if python.startswith("cp"): 42 | python, abi = "cp310", "abi3" 43 | return python, abi, platform 44 | 45 | 46 | class EggInfo(egg_info): 47 | def find_sources(self): 48 | super().find_sources() 49 | self.filelist.recursive_include("queries", "*.scm") 50 | self.filelist.include("src/tree_sitter/*.h") 51 | 52 | 53 | setup( 54 | packages=find_packages("bindings/python"), 55 | package_dir={"": "bindings/python"}, 56 | package_data={ 57 | "tree_sitter_mbtq": ["*.pyi", "py.typed"], 58 | "tree_sitter_mbtq.queries": ["*.scm"], 59 | }, 60 | ext_package="tree_sitter_mbtq", 61 | ext_modules=[ 62 | Extension( 63 | name="_binding", 64 | sources=sources, 65 | extra_compile_args=cflags, 66 | define_macros=macros, 67 | include_dirs=["src"], 68 | py_limited_api=limited_api, 69 | ) 70 | ], 71 | cmdclass={ 72 | "build": Build, 73 | "bdist_wheel": BdistWheel, 74 | "egg_info": EggInfo, 75 | }, 76 | zip_safe=False 77 | ) 78 | -------------------------------------------------------------------------------- /mbtq/src/scanner.c: -------------------------------------------------------------------------------- 1 | #define TREE_SITTER_LANGUAGE mbtq 2 | #include "../../src/scanner.c" 3 | -------------------------------------------------------------------------------- /mbtq/src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t size); 16 | extern void *(*ts_current_calloc)(size_t count, size_t size); 17 | extern void *(*ts_current_realloc)(void *ptr, size_t size); 18 | extern void (*ts_current_free)(void *ptr); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-moonbit", 3 | "version": "0.1.0", 4 | "description": "Moonbit grammar for tree-sitter", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/moonbitlang/tree-sitter-moonbit.git" 8 | }, 9 | "license": "Apache-2.0", 10 | "author": { 11 | "name": "Moonbit Language Team", 12 | "email": "support@moonbitlang.com", 13 | "url": "https://www.moonbitlang.com" 14 | }, 15 | "main": "bindings/node", 16 | "types": "bindings/node", 17 | "keywords": [ 18 | "incremental", 19 | "parsing", 20 | "tree-sitter", 21 | "moonbit" 22 | ], 23 | "files": [ 24 | "grammar.js", 25 | "tree-sitter.json", 26 | "binding.gyp", 27 | "prebuilds/**", 28 | "bindings/node/*", 29 | "queries/*", 30 | "src/**", 31 | "*.wasm" 32 | ], 33 | "dependencies": { 34 | "node-addon-api": "^8.2.1", 35 | "node-gyp-build": "^4.8.2" 36 | }, 37 | "devDependencies": { 38 | "eslint": "^9.21.0", 39 | "eslint-config-prettier": "^10.1.5", 40 | "eslint-config-treesitter": "^1.0.2", 41 | "prebuildify": "^6.0.1", 42 | "tree-sitter-cli": "^0.25.4" 43 | }, 44 | "peerDependencies": { 45 | "tree-sitter": "^0.22.4" 46 | }, 47 | "peerDependenciesMeta": { 48 | "tree-sitter": { 49 | "optional": true 50 | } 51 | }, 52 | "scripts": { 53 | "install": "node-gyp-build", 54 | "prestart": "tree-sitter build --wasm", 55 | "start": "tree-sitter playground", 56 | "test": "node --test bindings/node/*_test.js", 57 | "lint": "eslint grammar.js" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-moonbit" 7 | description = "Moonbit grammar for tree-sitter" 8 | version = "0.1.0" 9 | keywords = ["incremental", "parsing", "tree-sitter", "moonbit"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "Topic :: Software Development :: Compilers", 13 | "Topic :: Text Processing :: Linguistic", 14 | "Typing :: Typed", 15 | ] 16 | authors = [{ name = "Moonbit Language Team", email = "support@moonbitlang.com" }] 17 | requires-python = ">=3.10" 18 | license.text = "Apache-2.0" 19 | readme = "README.md" 20 | 21 | [project.urls] 22 | Homepage = "https://github.com/moonbitlang/tree-sitter-moonbit" 23 | 24 | [project.optional-dependencies] 25 | core = ["tree-sitter~=0.24"] 26 | 27 | [tool.cibuildwheel] 28 | build = "cp310-*" 29 | build-frontend = "build" 30 | -------------------------------------------------------------------------------- /queries/folds.scm: -------------------------------------------------------------------------------- 1 | [ 2 | (block_expression) 3 | (match_expression) 4 | (nonempty_block_expression) 5 | (struct_definition) 6 | (enum_definition) 7 | (function_definition) 8 | (value_definition) 9 | (if_expression) 10 | (match_expression) 11 | ] @fold 12 | -------------------------------------------------------------------------------- /queries/indents.scm: -------------------------------------------------------------------------------- 1 | [ 2 | (block_expression) 3 | (loop_expression) 4 | (match_expression) 5 | (nonempty_block_expression) 6 | (struct_expression) 7 | ] @indent.begin 8 | 9 | [ 10 | ")" 11 | "}" 12 | "]" 13 | ] @indent.end 14 | 15 | [ 16 | ")" 17 | "}" 18 | "]" 19 | ] @indent.branch 20 | -------------------------------------------------------------------------------- /queries/injections.scm: -------------------------------------------------------------------------------- 1 | ((comment) @injection.content 2 | (#set! injection.language "comment")) 3 | 4 | ; (function_definition 5 | ; (external_linkage 6 | ; target: (string_literal (string_fragment) @injection.language)) 7 | ; (external_source 8 | ; (multiline_string_literal 9 | ; (multiline_string_fragment 10 | ; (multiline_string_content) 11 | ; @injection.content 12 | ; (#set! injection.combined) 13 | ; ) 14 | ; ) 15 | ; ) 16 | ; ) 17 | -------------------------------------------------------------------------------- /queries/locals.scm: -------------------------------------------------------------------------------- 1 | ;; Definitions 2 | 3 | ; Functions 4 | 5 | (function_definition (function_identifier) @local.definition) 6 | 7 | ; Variables 8 | 9 | (value_definition (lowercase_identifier) @local.definition) 10 | (positional_parameter (lowercase_identifier) @local.definition) 11 | (labelled_parameter (label (lowercase_identifier)) @local.definition) 12 | (optional_parameter (optional_label (lowercase_identifier)) @local.definition) 13 | (optional_parameter_with_default (label (lowercase_identifier)) @local.definition) 14 | (let_expression (pattern (simple_pattern (lowercase_identifier)) @local.definition)) 15 | (let_mut_expression (lowercase_identifier) @local.definition) 16 | 17 | ; Types 18 | 19 | (struct_definition (identifier) @local.definition) 20 | (enum_definition (identifier) @local.definition) 21 | (type_definition (identifier) @local.definition) 22 | (type_identifier) @local.definition 23 | 24 | ;; References 25 | 26 | ; Values 27 | (qualified_identifier) @local.reference 28 | 29 | ; Types 30 | (qualified_type_identifier) @local.reference 31 | 32 | ;; Scopes 33 | 34 | [ 35 | (structure) 36 | (function_definition) 37 | (anonymous_lambda_expression) 38 | (named_lambda_expression) 39 | (block_expression) 40 | ] @local.scope 41 | -------------------------------------------------------------------------------- /queries/tags.scm: -------------------------------------------------------------------------------- 1 | ((comment)* @doc 2 | . 3 | (function_definition 4 | (function_identifier) @name 5 | [ 6 | (external_source) 7 | (block_expression) 8 | ] 9 | ) @definition.function 10 | (#strip! @doc "^//[/]?\\s*") 11 | (#set-adjacent! @doc @definition.function)) 12 | 13 | 14 | ((comment)* @doc 15 | . 16 | [ 17 | (type_definition 18 | (identifier) @name) @definition.class 19 | (struct_definition 20 | (identifier) @name) @definition.class 21 | (enum_definition 22 | (identifier) @name) @definition.class 23 | (error_type_definition 24 | (identifier) @name) @definition.class 25 | ] 26 | (#strip! @doc "^//[/]?\\s*") 27 | (#set-adjacent! @doc @definition.class)) 28 | 29 | ((comment)* @doc 30 | . 31 | (trait_definition 32 | (identifier) @name) @definition.interface 33 | (#strip! @doc "^//[/]?\\s*") 34 | (#set-adjacent! @doc @definition.interface)) 35 | 36 | (impl_definition (type_name) @name) @reference.implementation 37 | 38 | (impl_definition (type) @name) @reference.class 39 | 40 | (apply_expression (lowercase_identifier) @name) @reference.call 41 | (apply_expression (qualified_identifier) @name) @reference.call 42 | (method_expression (lowercase_identifier) @name) @reference.call 43 | 44 | ((dot_apply_expression (dot_identifier) @name) @reference.call 45 | (#strip! @name "^\\.")) 46 | 47 | (qualified_type_identifier) @name @reference.class 48 | -------------------------------------------------------------------------------- /queries/textobjects.scm: -------------------------------------------------------------------------------- 1 | ; parameter 2 | 3 | ((parameters 4 | . 5 | (parameter) @parameter.inner 6 | . 7 | ","? @_end) 8 | (#make-range! "parameter.outer" @parameter.inner @_end)) 9 | 10 | ((type_parameters 11 | . 12 | (type_identifier) @parameter.inner 13 | . 14 | ","? @_end) 15 | (#make-range! "parameter.outer" @parameter.inner @_end)) 16 | 17 | ((trait_method_declaration 18 | (trait_method_parameter) @parameter.inner 19 | . 20 | ","? @_end) 21 | (#make-range! "parameter.outer" @parameter.inner @_end)) 22 | 23 | ; argument 24 | 25 | ((apply_expression 26 | (arguments 27 | (argument) @parameter.inner 28 | . 29 | ","? @_end)) 30 | (#make-range! "parameter.outer" @parameter.inner @_end)) 31 | 32 | ((dot_apply_expression 33 | (argument) @parameter.inner 34 | . 35 | ","? @_end) 36 | (#make-range! "parameter.outer" @parameter.inner @_end)) 37 | 38 | ((dot_dot_apply_expression 39 | (argument) @parameter.inner 40 | . 41 | ","? @_end) 42 | (#make-range! "parameter.outer" @parameter.inner @_end)) 43 | 44 | ((type_arguments 45 | (type) @parameter.inner 46 | . 47 | ","? @_end) 48 | (#make-range! "parameter.outer" @parameter.inner @_end)) 49 | 50 | ((array_expression 51 | (_) @parameter.inner 52 | . 53 | ","? @_end) 54 | (#make-range! "parameter.outer" @parameter.inner @_end)) 55 | 56 | ((string_interpolation 57 | (interpolator (_) @parameter.inner) 58 | @parameter.outer)) 59 | 60 | ; block 61 | 62 | (((nonempty_block_expression) @block.inner 63 | (#offset! @block.inner 0 1 0 -1)) 64 | @block.outer) 65 | 66 | ; assignment 67 | 68 | ((let_expression 69 | . 70 | ((pattern) @assignment.lhs) 71 | "=" 72 | ((_) @assignment.inner @assignment.rhs)) 73 | @assignment.outer) 74 | 75 | ((assign_expression 76 | . 77 | ((left_value) @assignment.lhs) 78 | (assign_operator) 79 | ((_) @assignment.inner @assignment.rhs)) 80 | @assignment.outer) 81 | 82 | ; function 83 | 84 | ((function_definition 85 | (external_source (_) @function.inner) 86 | .) 87 | @function.outer) 88 | 89 | ((function_definition 90 | ("fn" 91 | (block_expression) @function.inner) 92 | (#offset! @function.inner 0 1 0 -1)) 93 | @function.outer) 94 | 95 | ((test_definition 96 | ("test" 97 | (block_expression) @function.inner) 98 | (#offset! @function.inner 0 1 0 -1)) 99 | @function.outer) 100 | 101 | (trait_method_declaration) @function.outer 102 | 103 | ((impl_definition 104 | ("impl" 105 | (block_expression) @function.inner) 106 | (#offset! @function.inner 0 1 0 -1)) 107 | @function.outer) 108 | 109 | ; call 110 | 111 | (((apply_expression 112 | (arguments 113 | "(" 114 | (_) @_start (_)? @_end 115 | . ")" 116 | (#make-range! "call.inner" @_start @_end)))) 117 | @call.outer) 118 | 119 | (((dot_apply_expression 120 | "(" 121 | (_) @_start (_)? @_end 122 | . ")" 123 | (#make-range! "call.inner" @_start @_end))) 124 | @call.outer) 125 | 126 | (((dot_dot_apply_expression 127 | "(" 128 | (_) @_start (_)? @_end 129 | . ")" 130 | (#make-range! "call.inner" @_start @_end))) 131 | @call.outer) 132 | 133 | ; comment 134 | 135 | (comment) @comment.outer 136 | 137 | ; return 138 | 139 | ((return_expression 140 | (_)? @return.inner) 141 | @return.outer) 142 | 143 | ; statement 144 | 145 | (block_expression (_) @statement.outer) 146 | 147 | ; number 148 | 149 | [ 150 | (integer_literal) 151 | (float_literal) 152 | ] @number.inner 153 | 154 | ; conditional 155 | 156 | ((if_expression 157 | "if" 158 | (_) @conditional.inner 159 | . 160 | (block_expression)) 161 | @conditional.outer) 162 | 163 | ((if_expression 164 | ((block_expression) @conditional.inner) 165 | (#offset! @conditional.inner 0 1 0 -1) 166 | . (_)?) 167 | @conditional.outer) 168 | 169 | ((if_expression 170 | (else_clause 171 | ((block_expression) @conditional.inner)) 172 | (#offset! @conditional.inner 0 1 0 -1)) 173 | @conditional.outer) 174 | 175 | ((match_expression 176 | "match" 177 | . 178 | ((_) @conditional.inner)) 179 | @conditional.outer) 180 | 181 | ((match_expression 182 | ((case_clause) @conditional.inner))) 183 | -------------------------------------------------------------------------------- /scripts/test.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from pathlib import Path 3 | import sys 4 | 5 | 6 | def parse_file(path: Path): 7 | try: 8 | subprocess.run( 9 | ["pnpm", "exec", "tree-sitter", "parse", path], 10 | capture_output=True, 11 | check=True, 12 | text=True, 13 | ) 14 | print(f"[ OK ] {path}") 15 | except subprocess.CalledProcessError as e: 16 | print(f"[Fail] {path}") 17 | print("==== stderr ====") 18 | print(f"{e.stderr}") 19 | print("==== stdout ====") 20 | print(e.stdout) 21 | sys.exit(1) 22 | 23 | 24 | def parse_directory(directory: Path): 25 | for file in directory.iterdir(): 26 | if file.is_dir(): 27 | parse_directory(file) 28 | continue 29 | if file.suffix == ".mbt": 30 | parse_file(file) 31 | continue 32 | 33 | 34 | def main(): 35 | parse_directory(Path(sys.argv[1])) 36 | 37 | 38 | if __name__ == "__main__": 39 | main() 40 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from platform import system 3 | from sysconfig import get_config_var 4 | 5 | from setuptools import Extension, find_packages, setup 6 | from setuptools.command.build import build 7 | from setuptools.command.egg_info import egg_info 8 | from wheel.bdist_wheel import bdist_wheel 9 | 10 | sources = [ 11 | "bindings/python/tree_sitter_moonbit/binding.c", 12 | "src/parser.c", 13 | ] 14 | if path.exists("src/scanner.c"): 15 | sources.append("src/scanner.c") 16 | 17 | macros: list[tuple[str, str | None]] = [ 18 | ("PY_SSIZE_T_CLEAN", None), 19 | ("TREE_SITTER_HIDE_SYMBOLS", None), 20 | ] 21 | if limited_api := not get_config_var("Py_GIL_DISABLED"): 22 | macros.append(("Py_LIMITED_API", "0x030A0000")) 23 | 24 | if system() != "Windows": 25 | cflags = ["-std=c11", "-fvisibility=hidden"] 26 | else: 27 | cflags = ["/std:c11", "/utf-8"] 28 | 29 | 30 | class Build(build): 31 | def run(self): 32 | if path.isdir("queries"): 33 | dest = path.join(self.build_lib, "tree_sitter_moonbit", "queries") 34 | self.copy_tree("queries", dest) 35 | super().run() 36 | 37 | 38 | class BdistWheel(bdist_wheel): 39 | def get_tag(self): 40 | python, abi, platform = super().get_tag() 41 | if python.startswith("cp"): 42 | python, abi = "cp310", "abi3" 43 | return python, abi, platform 44 | 45 | 46 | class EggInfo(egg_info): 47 | def find_sources(self): 48 | super().find_sources() 49 | self.filelist.recursive_include("queries", "*.scm") 50 | self.filelist.include("src/tree_sitter/*.h") 51 | 52 | 53 | setup( 54 | packages=find_packages("bindings/python"), 55 | package_dir={"": "bindings/python"}, 56 | package_data={ 57 | "tree_sitter_moonbit": ["*.pyi", "py.typed"], 58 | "tree_sitter_moonbit.queries": ["*.scm"], 59 | }, 60 | ext_package="tree_sitter_moonbit", 61 | ext_modules=[ 62 | Extension( 63 | name="_binding", 64 | sources=sources, 65 | extra_compile_args=cflags, 66 | define_macros=macros, 67 | include_dirs=["src"], 68 | py_limited_api=limited_api, 69 | ) 70 | ], 71 | cmdclass={ 72 | "build": Build, 73 | "bdist_wheel": BdistWheel, 74 | "egg_info": EggInfo, 75 | }, 76 | zip_safe=False 77 | ) 78 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t size); 16 | extern void *(*ts_current_calloc)(size_t count, size_t size); 17 | extern void *(*ts_current_realloc)(void *ptr, size_t size); 18 | extern void (*ts_current_free)(void *ptr); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /test/corpus/asi.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | question 3 | ================================================================================ 4 | fn f() -> Result[Unit, String] { 5 | let x = f 6 | ?(1, 2) 7 | Ok(x) 8 | } 9 | -------------------------------------------------------------------------------- 10 | 11 | (structure 12 | (function_definition 13 | (function_identifier 14 | (lowercase_identifier)) 15 | (parameters) 16 | (return_type 17 | (type 18 | (apply_type 19 | (qualified_type_identifier 20 | (identifier 21 | (uppercase_identifier))) 22 | (type_arguments 23 | (type 24 | (apply_type 25 | (qualified_type_identifier 26 | (identifier 27 | (uppercase_identifier))))) 28 | (type 29 | (apply_type 30 | (qualified_type_identifier 31 | (identifier 32 | (uppercase_identifier))))))))) 33 | (block_expression 34 | (let_expression 35 | (pattern 36 | (simple_pattern 37 | (lowercase_identifier))) 38 | (apply_expression 39 | (lowercase_identifier) 40 | (arguments 41 | (argument 42 | (atomic_expression 43 | (literal 44 | (integer_literal)))) 45 | (argument 46 | (atomic_expression 47 | (literal 48 | (integer_literal))))))) 49 | (apply_expression 50 | (constructor_expression 51 | (uppercase_identifier)) 52 | (arguments 53 | (argument 54 | (qualified_identifier 55 | (lowercase_identifier)))))))) 56 | 57 | ================================================================================ 58 | comma 59 | ================================================================================ 60 | fn main { 61 | loop a { 62 | _ => { 63 | continue 1, 64 | 2 , 65 | 3 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- 70 | 71 | (structure 72 | (function_definition 73 | (function_identifier 74 | (lowercase_identifier)) 75 | (block_expression 76 | (loop_expression 77 | (qualified_identifier 78 | (lowercase_identifier)) 79 | (matrix_case_clause 80 | (pattern 81 | (simple_pattern)) 82 | (nonempty_block_expression 83 | (continue_expression 84 | (atomic_expression 85 | (literal 86 | (integer_literal))) 87 | (atomic_expression 88 | (literal 89 | (integer_literal))) 90 | (atomic_expression 91 | (literal 92 | (integer_literal)))))))))) 93 | -------------------------------------------------------------------------------- /test/corpus/assign.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | add 3 | ================================================================================ 4 | fn init { 5 | let mut a = 4 6 | a += 5 7 | } 8 | -------------------------------------------------------------------------------- 9 | 10 | (structure 11 | (function_definition 12 | (function_identifier 13 | (lowercase_identifier)) 14 | (block_expression 15 | (let_mut_expression 16 | (lowercase_identifier) 17 | (atomic_expression 18 | (literal 19 | (integer_literal)))) 20 | (assign_expression 21 | (left_value 22 | (qualified_identifier 23 | (lowercase_identifier))) 24 | (assign_operator) 25 | (atomic_expression 26 | (literal 27 | (integer_literal))))))) 28 | 29 | ================================================================================ 30 | add 31 | ================================================================================ 32 | fn init { 33 | let mut a = 4 34 | a -= 5 35 | } 36 | -------------------------------------------------------------------------------- 37 | 38 | (structure 39 | (function_definition 40 | (function_identifier 41 | (lowercase_identifier)) 42 | (block_expression 43 | (let_mut_expression 44 | (lowercase_identifier) 45 | (atomic_expression 46 | (literal 47 | (integer_literal)))) 48 | (assign_expression 49 | (left_value 50 | (qualified_identifier 51 | (lowercase_identifier))) 52 | (assign_operator) 53 | (atomic_expression 54 | (literal 55 | (integer_literal))))))) 56 | 57 | ================================================================================ 58 | mul 59 | ================================================================================ 60 | fn init { 61 | let mut a = 4 62 | a *= 5 63 | } 64 | -------------------------------------------------------------------------------- 65 | 66 | (structure 67 | (function_definition 68 | (function_identifier 69 | (lowercase_identifier)) 70 | (block_expression 71 | (let_mut_expression 72 | (lowercase_identifier) 73 | (atomic_expression 74 | (literal 75 | (integer_literal)))) 76 | (assign_expression 77 | (left_value 78 | (qualified_identifier 79 | (lowercase_identifier))) 80 | (assign_operator) 81 | (atomic_expression 82 | (literal 83 | (integer_literal))))))) 84 | 85 | ================================================================================ 86 | div 87 | ================================================================================ 88 | fn init { 89 | let mut a = 4 90 | a /= 5 91 | } 92 | -------------------------------------------------------------------------------- 93 | 94 | (structure 95 | (function_definition 96 | (function_identifier 97 | (lowercase_identifier)) 98 | (block_expression 99 | (let_mut_expression 100 | (lowercase_identifier) 101 | (atomic_expression 102 | (literal 103 | (integer_literal)))) 104 | (assign_expression 105 | (left_value 106 | (qualified_identifier 107 | (lowercase_identifier))) 108 | (assign_operator) 109 | (atomic_expression 110 | (literal 111 | (integer_literal))))))) 112 | 113 | ================================================================================ 114 | mod 115 | ================================================================================ 116 | fn init { 117 | a %= 5 118 | } 119 | -------------------------------------------------------------------------------- 120 | 121 | (structure 122 | (function_definition 123 | (function_identifier 124 | (lowercase_identifier)) 125 | (block_expression 126 | (assign_expression 127 | (left_value 128 | (qualified_identifier 129 | (lowercase_identifier))) 130 | (assign_operator) 131 | (atomic_expression 132 | (literal 133 | (integer_literal))))))) 134 | -------------------------------------------------------------------------------- /test/corpus/attribute.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | deprecation 3 | ================================================================================ 4 | #deprecated("This function is deprecated") 5 | fn fib(n : Int) -> Int { 6 | -1 7 | } 8 | -------------------------------------------------------------------------------- 9 | 10 | (structure 11 | (function_definition 12 | (attributes 13 | (attribute 14 | (attribute_expression 15 | (lowercase_identifier) 16 | (attribute_properties 17 | (attribute_property 18 | (attribute_expression 19 | (string_literal 20 | (string_fragment 21 | (unescaped_string_fragment))))))))) 22 | (function_identifier 23 | (lowercase_identifier)) 24 | (parameters 25 | (parameter 26 | (positional_parameter 27 | (lowercase_identifier) 28 | (type_annotation 29 | (type 30 | (apply_type 31 | (qualified_type_identifier 32 | (identifier 33 | (uppercase_identifier))))))))) 34 | (return_type 35 | (type 36 | (apply_type 37 | (qualified_type_identifier 38 | (identifier 39 | (uppercase_identifier)))))) 40 | (block_expression 41 | (unary_expression 42 | (atomic_expression 43 | (literal 44 | (integer_literal))))))) 45 | 46 | ================================================================================ 47 | coverage skip 48 | ================================================================================ 49 | #coverage.skip 50 | fn fib(n : Int) -> Int { 51 | -1 52 | } 53 | -------------------------------------------------------------------------------- 54 | 55 | (structure 56 | (function_definition 57 | (attributes 58 | (attribute 59 | (attribute_expression 60 | (lowercase_identifier) 61 | (dot_lowercase_identifier)))) 62 | (function_identifier 63 | (lowercase_identifier)) 64 | (parameters 65 | (parameter 66 | (positional_parameter 67 | (lowercase_identifier) 68 | (type_annotation 69 | (type 70 | (apply_type 71 | (qualified_type_identifier 72 | (identifier 73 | (uppercase_identifier))))))))) 74 | (return_type 75 | (type 76 | (apply_type 77 | (qualified_type_identifier 78 | (identifier 79 | (uppercase_identifier)))))) 80 | (block_expression 81 | (unary_expression 82 | (atomic_expression 83 | (literal 84 | (integer_literal))))))) 85 | -------------------------------------------------------------------------------- /test/corpus/comment.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | comment 3 | ================================================================================ 4 | // 5 | -------------------------------------------------------------------------------- 6 | 7 | (structure 8 | (comment)) 9 | 10 | ================================================================================ 11 | comment inside block 12 | ================================================================================ 13 | fn main { 14 | // 15 | } 16 | -------------------------------------------------------------------------------- 17 | 18 | (structure 19 | (function_definition 20 | (function_identifier 21 | (lowercase_identifier)) 22 | (block_expression 23 | (comment)))) 24 | -------------------------------------------------------------------------------- /test/corpus/constructor.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | unqualified 3 | ================================================================================ 4 | fn init { 5 | Some 6 | Some(2) 7 | } 8 | -------------------------------------------------------------------------------- 9 | 10 | (structure 11 | (function_definition 12 | (function_identifier 13 | (lowercase_identifier)) 14 | (block_expression 15 | (constructor_expression 16 | (uppercase_identifier)) 17 | (apply_expression 18 | (constructor_expression 19 | (uppercase_identifier)) 20 | (arguments 21 | (argument 22 | (atomic_expression 23 | (literal 24 | (integer_literal))))))))) 25 | 26 | ================================================================================ 27 | qualified 28 | ================================================================================ 29 | fn init { 30 | opt::Some 31 | Opt::Some 32 | } 33 | -------------------------------------------------------------------------------- 34 | 35 | (structure 36 | (function_definition 37 | (function_identifier 38 | (lowercase_identifier)) 39 | (block_expression 40 | (constructor_expression 41 | (type_name 42 | (qualified_type_identifier 43 | (identifier 44 | (lowercase_identifier)))) 45 | (uppercase_identifier)) 46 | (constructor_expression 47 | (type_name 48 | (qualified_type_identifier 49 | (identifier 50 | (uppercase_identifier)))) 51 | (uppercase_identifier))))) 52 | 53 | ================================================================================ 54 | package-qualified 55 | ================================================================================ 56 | fn init { 57 | @pkg.opt::Some 58 | @pkg.Opt::Some 59 | } 60 | -------------------------------------------------------------------------------- 61 | 62 | (structure 63 | (function_definition 64 | (function_identifier 65 | (lowercase_identifier)) 66 | (block_expression 67 | (constructor_expression 68 | (type_name 69 | (qualified_type_identifier 70 | (package_identifier) 71 | (dot_identifier 72 | (dot_lowercase_identifier)))) 73 | (uppercase_identifier)) 74 | (constructor_expression 75 | (type_name 76 | (qualified_type_identifier 77 | (package_identifier) 78 | (dot_identifier 79 | (dot_uppercase_identifier)))) 80 | (uppercase_identifier))))) 81 | -------------------------------------------------------------------------------- /test/corpus/derive.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | type 3 | ================================================================================ 4 | type X derive (A, B) 5 | -------------------------------------------------------------------------------- 6 | 7 | (structure 8 | (type_definition 9 | (identifier 10 | (uppercase_identifier)) 11 | (derive_directive 12 | (derive_item 13 | (type_name 14 | (qualified_type_identifier 15 | (identifier 16 | (uppercase_identifier))))) 17 | (derive_item 18 | (type_name 19 | (qualified_type_identifier 20 | (identifier 21 | (uppercase_identifier)))))))) 22 | 23 | ================================================================================ 24 | struct 25 | ================================================================================ 26 | struct A { 27 | } derive (C, D) 28 | -------------------------------------------------------------------------------- 29 | 30 | (structure 31 | (struct_definition 32 | (identifier 33 | (uppercase_identifier)) 34 | (derive_directive 35 | (derive_item 36 | (type_name 37 | (qualified_type_identifier 38 | (identifier 39 | (uppercase_identifier))))) 40 | (derive_item 41 | (type_name 42 | (qualified_type_identifier 43 | (identifier 44 | (uppercase_identifier)))))))) 45 | 46 | ================================================================================ 47 | enum 48 | ================================================================================ 49 | enum A { 50 | } derive (C, D) 51 | -------------------------------------------------------------------------------- 52 | 53 | (structure 54 | (enum_definition 55 | (identifier 56 | (uppercase_identifier)) 57 | (derive_directive 58 | (derive_item 59 | (type_name 60 | (qualified_type_identifier 61 | (identifier 62 | (uppercase_identifier))))) 63 | (derive_item 64 | (type_name 65 | (qualified_type_identifier 66 | (identifier 67 | (uppercase_identifier)))))))) 68 | 69 | ================================================================================ 70 | empty 71 | ================================================================================ 72 | enum A { 73 | } derive () 74 | -------------------------------------------------------------------------------- 75 | 76 | (structure 77 | (enum_definition 78 | (identifier 79 | (uppercase_identifier)) 80 | (derive_directive))) 81 | 82 | ================================================================================ 83 | one 84 | ================================================================================ 85 | enum A { 86 | } derive (C) 87 | -------------------------------------------------------------------------------- 88 | 89 | (structure 90 | (enum_definition 91 | (identifier 92 | (uppercase_identifier)) 93 | (derive_directive 94 | (derive_item 95 | (type_name 96 | (qualified_type_identifier 97 | (identifier 98 | (uppercase_identifier)))))))) 99 | 100 | ================================================================================ 101 | multiple 102 | ================================================================================ 103 | enum A { 104 | } derive (A, B, C, D, E, F, G) 105 | -------------------------------------------------------------------------------- 106 | 107 | (structure 108 | (enum_definition 109 | (identifier 110 | (uppercase_identifier)) 111 | (derive_directive 112 | (derive_item 113 | (type_name 114 | (qualified_type_identifier 115 | (identifier 116 | (uppercase_identifier))))) 117 | (derive_item 118 | (type_name 119 | (qualified_type_identifier 120 | (identifier 121 | (uppercase_identifier))))) 122 | (derive_item 123 | (type_name 124 | (qualified_type_identifier 125 | (identifier 126 | (uppercase_identifier))))) 127 | (derive_item 128 | (type_name 129 | (qualified_type_identifier 130 | (identifier 131 | (uppercase_identifier))))) 132 | (derive_item 133 | (type_name 134 | (qualified_type_identifier 135 | (identifier 136 | (uppercase_identifier))))) 137 | (derive_item 138 | (type_name 139 | (qualified_type_identifier 140 | (identifier 141 | (uppercase_identifier))))) 142 | (derive_item 143 | (type_name 144 | (qualified_type_identifier 145 | (identifier 146 | (uppercase_identifier)))))))) 147 | -------------------------------------------------------------------------------- /test/corpus/docstring.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | type definitions 3 | ================================================================================ 4 | ///hello 5 | /// here 6 | type X 7 | -------------------------------------------------------------------------------- 8 | 9 | (structure 10 | (comment) 11 | (comment) 12 | (type_definition 13 | (identifier 14 | (uppercase_identifier)))) 15 | 16 | ================================================================================ 17 | struct definitions 18 | ================================================================================ 19 | ///hello 20 | /// struct 21 | struct X {} 22 | -------------------------------------------------------------------------------- 23 | 24 | (structure 25 | (comment) 26 | (comment) 27 | (struct_definition 28 | (identifier 29 | (uppercase_identifier)))) 30 | 31 | ================================================================================ 32 | enum definitions 33 | ================================================================================ 34 | ///hello 35 | /// enum 36 | enum X {} 37 | -------------------------------------------------------------------------------- 38 | 39 | (structure 40 | (comment) 41 | (comment) 42 | (enum_definition 43 | (identifier 44 | (uppercase_identifier)))) 45 | 46 | ================================================================================ 47 | fn definitions 48 | ================================================================================ 49 | ///hello 50 | /// fn 51 | fn x {} 52 | -------------------------------------------------------------------------------- 53 | 54 | (structure 55 | (comment) 56 | (comment) 57 | (function_definition 58 | (function_identifier 59 | (lowercase_identifier)) 60 | (block_expression))) 61 | 62 | ================================================================================ 63 | trait definitions 64 | ================================================================================ 65 | ///hello 66 | /// trait 67 | // comment 68 | //comment 69 | trait X {} 70 | -------------------------------------------------------------------------------- 71 | 72 | (structure 73 | (comment) 74 | (comment) 75 | (comment) 76 | (comment) 77 | (trait_definition 78 | (identifier 79 | (uppercase_identifier)))) 80 | -------------------------------------------------------------------------------- /test/corpus/enum.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | enum definition 3 | ================================================================================ 4 | enum T { 5 | A 6 | B(Int) 7 | C(String, Int) 8 | D(String, label~: T) 9 | } 10 | -------------------------------------------------------------------------------- 11 | 12 | (structure 13 | (enum_definition 14 | (identifier 15 | (uppercase_identifier)) 16 | (enum_constructor 17 | (uppercase_identifier)) 18 | (enum_constructor 19 | (uppercase_identifier) 20 | (enum_constructor_payload 21 | (constructor_parameter 22 | (type 23 | (apply_type 24 | (qualified_type_identifier 25 | (identifier 26 | (uppercase_identifier)))))))) 27 | (enum_constructor 28 | (uppercase_identifier) 29 | (enum_constructor_payload 30 | (constructor_parameter 31 | (type 32 | (apply_type 33 | (qualified_type_identifier 34 | (identifier 35 | (uppercase_identifier)))))) 36 | (constructor_parameter 37 | (type 38 | (apply_type 39 | (qualified_type_identifier 40 | (identifier 41 | (uppercase_identifier)))))))) 42 | (enum_constructor 43 | (uppercase_identifier) 44 | (enum_constructor_payload 45 | (constructor_parameter 46 | (type 47 | (apply_type 48 | (qualified_type_identifier 49 | (identifier 50 | (uppercase_identifier)))))) 51 | (constructor_parameter 52 | (label 53 | (lowercase_identifier)) 54 | (type 55 | (apply_type 56 | (qualified_type_identifier 57 | (identifier 58 | (uppercase_identifier)))))))))) 59 | 60 | ================================================================================ 61 | extern enum with integer discriminants 62 | ================================================================================ 63 | enum T { 64 | A = 0 65 | B = 1N 66 | C = 3UL 67 | D = 4U 68 | } 69 | -------------------------------------------------------------------------------- 70 | 71 | (structure 72 | (enum_definition 73 | (identifier 74 | (uppercase_identifier)) 75 | (enum_constructor 76 | (uppercase_identifier) 77 | (enum_constructor_payload 78 | (integer_literal))) 79 | (enum_constructor 80 | (uppercase_identifier) 81 | (enum_constructor_payload 82 | (integer_literal))) 83 | (enum_constructor 84 | (uppercase_identifier) 85 | (enum_constructor_payload 86 | (integer_literal))) 87 | (enum_constructor 88 | (uppercase_identifier) 89 | (enum_constructor_payload 90 | (integer_literal))))) 91 | -------------------------------------------------------------------------------- /test/corpus/identifier.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | package identifier 3 | ================================================================================ 4 | fn main { 5 | @pkg.A 6 | @user/mod/pkg.A 7 | } 8 | -------------------------------------------------------------------------------- 9 | 10 | (structure 11 | (function_definition 12 | (function_identifier 13 | (lowercase_identifier)) 14 | (block_expression 15 | (constructor_expression 16 | (package_identifier) 17 | (dot_uppercase_identifier)) 18 | (constructor_expression 19 | (package_identifier) 20 | (dot_uppercase_identifier))))) 21 | -------------------------------------------------------------------------------- /test/corpus/let_mut.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | let mut 3 | ================================================================================ 4 | fn init { 5 | let mut x = 4 6 | x = x + 1 7 | } 8 | -------------------------------------------------------------------------------- 9 | 10 | (structure 11 | (function_definition 12 | (function_identifier 13 | (lowercase_identifier)) 14 | (block_expression 15 | (let_mut_expression 16 | (lowercase_identifier) 17 | (atomic_expression 18 | (literal 19 | (integer_literal)))) 20 | (assign_expression 21 | (left_value 22 | (qualified_identifier 23 | (lowercase_identifier))) 24 | (assign_operator) 25 | (binary_expression 26 | (qualified_identifier 27 | (lowercase_identifier)) 28 | (atomic_expression 29 | (literal 30 | (integer_literal)))))))) 31 | -------------------------------------------------------------------------------- /test/corpus/loop.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | loop expression 3 | ================================================================================ 4 | fn init { 5 | let x = loop x, 0 { 6 | a, b => continue c, d 7 | e, f => g 8 | } 9 | } 10 | -------------------------------------------------------------------------------- 11 | 12 | (structure 13 | (function_definition 14 | (function_identifier 15 | (lowercase_identifier)) 16 | (block_expression 17 | (let_expression 18 | (pattern 19 | (simple_pattern 20 | (lowercase_identifier))) 21 | (loop_expression 22 | (qualified_identifier 23 | (lowercase_identifier)) 24 | (atomic_expression 25 | (literal 26 | (integer_literal))) 27 | (matrix_case_clause 28 | (pattern 29 | (simple_pattern 30 | (lowercase_identifier))) 31 | (pattern 32 | (simple_pattern 33 | (lowercase_identifier))) 34 | (continue_expression 35 | (qualified_identifier 36 | (lowercase_identifier)) 37 | (qualified_identifier 38 | (lowercase_identifier)))) 39 | (matrix_case_clause 40 | (pattern 41 | (simple_pattern 42 | (lowercase_identifier))) 43 | (pattern 44 | (simple_pattern 45 | (lowercase_identifier))) 46 | (qualified_identifier 47 | (lowercase_identifier)))))))) 48 | 49 | ================================================================================ 50 | loop expression with multiple argument 51 | ================================================================================ 52 | fn init { 53 | let x = loop x, 0, 1 { 54 | a, b, c => continue c, d 55 | e, f => g 56 | } 57 | } 58 | -------------------------------------------------------------------------------- 59 | 60 | (structure 61 | (function_definition 62 | (function_identifier 63 | (lowercase_identifier)) 64 | (block_expression 65 | (let_expression 66 | (pattern 67 | (simple_pattern 68 | (lowercase_identifier))) 69 | (loop_expression 70 | (qualified_identifier 71 | (lowercase_identifier)) 72 | (atomic_expression 73 | (literal 74 | (integer_literal))) 75 | (atomic_expression 76 | (literal 77 | (integer_literal))) 78 | (matrix_case_clause 79 | (pattern 80 | (simple_pattern 81 | (lowercase_identifier))) 82 | (pattern 83 | (simple_pattern 84 | (lowercase_identifier))) 85 | (pattern 86 | (simple_pattern 87 | (lowercase_identifier))) 88 | (continue_expression 89 | (qualified_identifier 90 | (lowercase_identifier)) 91 | (qualified_identifier 92 | (lowercase_identifier)))) 93 | (matrix_case_clause 94 | (pattern 95 | (simple_pattern 96 | (lowercase_identifier))) 97 | (pattern 98 | (simple_pattern 99 | (lowercase_identifier))) 100 | (qualified_identifier 101 | (lowercase_identifier)))))))) 102 | 103 | ================================================================================ 104 | loop expression with label 105 | ================================================================================ 106 | fn init { 107 | ll~: loop x, 0 { 108 | a, b => continue ll~ c, d 109 | e, f => break ll~ Some(g) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- 113 | 114 | (structure 115 | (function_definition 116 | (function_identifier 117 | (lowercase_identifier)) 118 | (block_expression 119 | (loop_expression 120 | (loop_label 121 | (label 122 | (lowercase_identifier))) 123 | (qualified_identifier 124 | (lowercase_identifier)) 125 | (atomic_expression 126 | (literal 127 | (integer_literal))) 128 | (matrix_case_clause 129 | (pattern 130 | (simple_pattern 131 | (lowercase_identifier))) 132 | (pattern 133 | (simple_pattern 134 | (lowercase_identifier))) 135 | (continue_expression 136 | (label 137 | (lowercase_identifier)) 138 | (qualified_identifier 139 | (lowercase_identifier)) 140 | (qualified_identifier 141 | (lowercase_identifier)))) 142 | (matrix_case_clause 143 | (pattern 144 | (simple_pattern 145 | (lowercase_identifier))) 146 | (pattern 147 | (simple_pattern 148 | (lowercase_identifier))) 149 | (break_expression 150 | (label 151 | (lowercase_identifier)) 152 | (apply_expression 153 | (constructor_expression 154 | (uppercase_identifier)) 155 | (arguments 156 | (argument 157 | (qualified_identifier 158 | (lowercase_identifier))))))))))) 159 | -------------------------------------------------------------------------------- /test/corpus/new_type.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | new_type 3 | ================================================================================ 4 | type New(Int) 5 | -------------------------------------------------------------------------------- 6 | 7 | (structure 8 | (type_definition 9 | (identifier 10 | (uppercase_identifier)) 11 | (type 12 | (tuple_type 13 | (type 14 | (apply_type 15 | (qualified_type_identifier 16 | (identifier 17 | (uppercase_identifier))))))))) 18 | 19 | ================================================================================ 20 | phantom type 21 | ================================================================================ 22 | type Length[_] Int 23 | type Length[_] 24 | 25 | type Kilometer 26 | type Mile 27 | 28 | fn[T] add(x: Length[T], y:Length[T]) -> Length[T] { 29 | Length::Length(x.0 + y.0) 30 | } 31 | 32 | let d_km: Length[Kilometer] = Length(10) 33 | let d_mile: Length[Mile] = Length(16) 34 | -------------------------------------------------------------------------------- 35 | 36 | (structure 37 | (type_definition 38 | (identifier 39 | (uppercase_identifier)) 40 | (type_parameters 41 | (type_identifier 42 | (identifier 43 | (lowercase_identifier)))) 44 | (type 45 | (apply_type 46 | (qualified_type_identifier 47 | (identifier 48 | (uppercase_identifier)))))) 49 | (type_definition 50 | (identifier 51 | (uppercase_identifier)) 52 | (type_parameters 53 | (type_identifier 54 | (identifier 55 | (lowercase_identifier))))) 56 | (type_definition 57 | (identifier 58 | (uppercase_identifier))) 59 | (type_definition 60 | (identifier 61 | (uppercase_identifier))) 62 | (function_definition 63 | (type_parameters 64 | (type_identifier 65 | (identifier 66 | (uppercase_identifier)))) 67 | (function_identifier 68 | (lowercase_identifier)) 69 | (parameters 70 | (parameter 71 | (positional_parameter 72 | (lowercase_identifier) 73 | (type_annotation 74 | (type 75 | (apply_type 76 | (qualified_type_identifier 77 | (identifier 78 | (uppercase_identifier))) 79 | (type_arguments 80 | (type 81 | (apply_type 82 | (qualified_type_identifier 83 | (identifier 84 | (uppercase_identifier))))))))))) 85 | (parameter 86 | (positional_parameter 87 | (lowercase_identifier) 88 | (type_annotation 89 | (type 90 | (apply_type 91 | (qualified_type_identifier 92 | (identifier 93 | (uppercase_identifier))) 94 | (type_arguments 95 | (type 96 | (apply_type 97 | (qualified_type_identifier 98 | (identifier 99 | (uppercase_identifier)))))))))))) 100 | (return_type 101 | (type 102 | (apply_type 103 | (qualified_type_identifier 104 | (identifier 105 | (uppercase_identifier))) 106 | (type_arguments 107 | (type 108 | (apply_type 109 | (qualified_type_identifier 110 | (identifier 111 | (uppercase_identifier))))))))) 112 | (block_expression 113 | (apply_expression 114 | (constructor_expression 115 | (type_name 116 | (qualified_type_identifier 117 | (identifier 118 | (uppercase_identifier)))) 119 | (uppercase_identifier)) 120 | (arguments 121 | (argument 122 | (binary_expression 123 | (access_expression 124 | (qualified_identifier 125 | (lowercase_identifier)) 126 | (accessor)) 127 | (access_expression 128 | (qualified_identifier 129 | (lowercase_identifier)) 130 | (accessor)))))))) 131 | (value_definition 132 | (lowercase_identifier) 133 | (type_annotation 134 | (type 135 | (apply_type 136 | (qualified_type_identifier 137 | (identifier 138 | (uppercase_identifier))) 139 | (type_arguments 140 | (type 141 | (apply_type 142 | (qualified_type_identifier 143 | (identifier 144 | (uppercase_identifier))))))))) 145 | (apply_expression 146 | (constructor_expression 147 | (uppercase_identifier)) 148 | (arguments 149 | (argument 150 | (atomic_expression 151 | (literal 152 | (integer_literal))))))) 153 | (value_definition 154 | (lowercase_identifier) 155 | (type_annotation 156 | (type 157 | (apply_type 158 | (qualified_type_identifier 159 | (identifier 160 | (uppercase_identifier))) 161 | (type_arguments 162 | (type 163 | (apply_type 164 | (qualified_type_identifier 165 | (identifier 166 | (uppercase_identifier))))))))) 167 | (apply_expression 168 | (constructor_expression 169 | (uppercase_identifier)) 170 | (arguments 171 | (argument 172 | (atomic_expression 173 | (literal 174 | (integer_literal)))))))) 175 | -------------------------------------------------------------------------------- /test/corpus/statements.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | raise statement 3 | ================================================================================ 4 | fn init { 5 | raise @json.JsonDecodeError((path, "Expected an array")) 6 | } 7 | -------------------------------------------------------------------------------- 8 | 9 | (structure 10 | (function_definition 11 | (function_identifier 12 | (lowercase_identifier)) 13 | (block_expression 14 | (raise_expression 15 | (apply_expression 16 | (constructor_expression 17 | (package_identifier) 18 | (dot_uppercase_identifier)) 19 | (arguments 20 | (argument 21 | (tuple_expression 22 | (qualified_identifier 23 | (lowercase_identifier)) 24 | (atomic_expression 25 | (literal 26 | (string_literal 27 | (string_fragment 28 | (unescaped_string_fragment))))))))))))) 29 | 30 | ================================================================================ 31 | raise statement in match 32 | ================================================================================ 33 | fn init { 34 | match a { 35 | _ => raise @json.JsonDecodeError((path, "Expected an array")) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- 39 | 40 | (structure 41 | (function_definition 42 | (function_identifier 43 | (lowercase_identifier)) 44 | (block_expression 45 | (match_expression 46 | (qualified_identifier 47 | (lowercase_identifier)) 48 | (case_clause 49 | (pattern 50 | (simple_pattern)) 51 | (raise_expression 52 | (apply_expression 53 | (constructor_expression 54 | (package_identifier) 55 | (dot_uppercase_identifier)) 56 | (arguments 57 | (argument 58 | (tuple_expression 59 | (qualified_identifier 60 | (lowercase_identifier)) 61 | (atomic_expression 62 | (literal 63 | (string_literal 64 | (string_fragment 65 | (unescaped_string_fragment))))))))))))))) 66 | 67 | ================================================================================ 68 | unfinished code 69 | ================================================================================ 70 | fn main { 71 | ... 72 | } 73 | -------------------------------------------------------------------------------- 74 | 75 | (structure 76 | (function_definition 77 | (function_identifier 78 | (lowercase_identifier)) 79 | (block_expression 80 | (unfinished)))) 81 | 82 | ================================================================================ 83 | return expression 84 | ================================================================================ 85 | fn main { 86 | return 3 87 | } 88 | -------------------------------------------------------------------------------- 89 | 90 | (structure 91 | (function_definition 92 | (function_identifier 93 | (lowercase_identifier)) 94 | (block_expression 95 | (return_expression 96 | (atomic_expression 97 | (literal 98 | (integer_literal))))))) 99 | -------------------------------------------------------------------------------- /test/corpus/structures.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | dot 3 | ================================================================================ 4 | fn init { 5 | [1, 2, 3] 6 | [1, 2, 7 | 3, 4 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- 11 | 12 | (structure 13 | (function_definition 14 | (function_identifier 15 | (lowercase_identifier)) 16 | (block_expression 17 | (array_expression 18 | (atomic_expression 19 | (literal 20 | (integer_literal))) 21 | (atomic_expression 22 | (literal 23 | (integer_literal))) 24 | (atomic_expression 25 | (literal 26 | (integer_literal)))) 27 | (array_expression 28 | (atomic_expression 29 | (literal 30 | (integer_literal))) 31 | (atomic_expression 32 | (literal 33 | (integer_literal))) 34 | (atomic_expression 35 | (literal 36 | (integer_literal))) 37 | (atomic_expression 38 | (literal 39 | (integer_literal))))))) 40 | -------------------------------------------------------------------------------- /test/corpus/test.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | basic 3 | ================================================================================ 4 | test "t" { 5 | let x = 1 6 | } 7 | -------------------------------------------------------------------------------- 8 | 9 | (structure 10 | (test_definition 11 | (string_literal 12 | (string_fragment 13 | (unescaped_string_fragment))) 14 | (block_expression 15 | (let_expression 16 | (pattern 17 | (simple_pattern 18 | (lowercase_identifier))) 19 | (atomic_expression 20 | (literal 21 | (integer_literal))))))) 22 | 23 | ================================================================================ 24 | anonymous 25 | ================================================================================ 26 | test { 27 | let x = 1 28 | } 29 | -------------------------------------------------------------------------------- 30 | 31 | (structure 32 | (test_definition 33 | (block_expression 34 | (let_expression 35 | (pattern 36 | (simple_pattern 37 | (lowercase_identifier))) 38 | (atomic_expression 39 | (literal 40 | (integer_literal))))))) 41 | 42 | ================================================================================ 43 | snapshot 44 | ================================================================================ 45 | test "a" (it : @test.T) { 46 | it.writeln("hello") 47 | it.snapshot!(filename="test.txt") 48 | } 49 | -------------------------------------------------------------------------------- 50 | 51 | (structure 52 | (test_definition 53 | (string_literal 54 | (string_fragment 55 | (unescaped_string_fragment))) 56 | (parameters 57 | (parameter 58 | (positional_parameter 59 | (lowercase_identifier) 60 | (type_annotation 61 | (type 62 | (apply_type 63 | (qualified_type_identifier 64 | (package_identifier) 65 | (dot_identifier 66 | (dot_uppercase_identifier))))))))) 67 | (block_expression 68 | (dot_apply_expression 69 | (qualified_identifier 70 | (lowercase_identifier)) 71 | (dot_identifier 72 | (dot_lowercase_identifier)) 73 | (argument 74 | (atomic_expression 75 | (literal 76 | (string_literal 77 | (string_fragment 78 | (unescaped_string_fragment))))))) 79 | (apply_expression 80 | (access_expression 81 | (qualified_identifier 82 | (lowercase_identifier)) 83 | (accessor 84 | (dot_identifier 85 | (dot_lowercase_identifier)))) 86 | (apply_operator) 87 | (arguments 88 | (argument 89 | (labelled_argument 90 | (lowercase_identifier) 91 | (atomic_expression 92 | (literal 93 | (string_literal 94 | (string_fragment 95 | (unescaped_string_fragment)))))))))))) 96 | -------------------------------------------------------------------------------- /test/corpus/while.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | while expression 3 | ================================================================================ 4 | fn main { 5 | while true { 6 | println("Hello!") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- 10 | 11 | (structure 12 | (function_definition 13 | (function_identifier 14 | (lowercase_identifier)) 15 | (block_expression 16 | (while_expression 17 | (atomic_expression 18 | (literal 19 | (boolean_literal))) 20 | (block_expression 21 | (apply_expression 22 | (qualified_identifier 23 | (lowercase_identifier)) 24 | (arguments 25 | (argument 26 | (atomic_expression 27 | (literal 28 | (string_literal 29 | (string_fragment 30 | (unescaped_string_fragment))))))))))))) 31 | 32 | ================================================================================ 33 | while expression with else clause 34 | ================================================================================ 35 | fn main { 36 | while true { 37 | break 3 38 | } else { 39 | 4 40 | } 41 | } 42 | -------------------------------------------------------------------------------- 43 | 44 | (structure 45 | (function_definition 46 | (function_identifier 47 | (lowercase_identifier)) 48 | (block_expression 49 | (while_expression 50 | (atomic_expression 51 | (literal 52 | (boolean_literal))) 53 | (block_expression 54 | (break_expression 55 | (atomic_expression 56 | (literal 57 | (integer_literal))))) 58 | (else_clause 59 | (block_expression 60 | (atomic_expression 61 | (literal 62 | (integer_literal))))))))) 63 | 64 | ================================================================================ 65 | while expression with label 66 | ================================================================================ 67 | fn main { 68 | label~: while true { 69 | break label~ 3 70 | } else { 71 | 4 72 | } 73 | } 74 | -------------------------------------------------------------------------------- 75 | 76 | (structure 77 | (function_definition 78 | (function_identifier 79 | (lowercase_identifier)) 80 | (block_expression 81 | (while_expression 82 | (loop_label 83 | (label 84 | (lowercase_identifier))) 85 | (atomic_expression 86 | (literal 87 | (boolean_literal))) 88 | (block_expression 89 | (break_expression 90 | (label 91 | (lowercase_identifier)) 92 | (atomic_expression 93 | (literal 94 | (integer_literal))))) 95 | (else_clause 96 | (block_expression 97 | (atomic_expression 98 | (literal 99 | (integer_literal))))))))) 100 | -------------------------------------------------------------------------------- /test/highlight/alias.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub typealias A = Int 3 | // ^^^^^^^^^ keyword.type 4 | 5 | ///| 6 | pub traitalias @json.FromJson 7 | // ^^^^^^^^^^ keyword.type 8 | 9 | ///| 10 | pub fnalias @math.cos 11 | // ^^^^^^^ keyword.function 12 | // ^^^^^^^^^ function 13 | -------------------------------------------------------------------------------- /test/highlight/as.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test { 3 | let buf = @buffer.new() 4 | (buf as &Logger).write_string("a") 5 | // ^^ keyword 6 | let opt_int = Some(3) 7 | guard opt_int is Some(3) 8 | // ^^ keyword 9 | if opt_int is None { 10 | // ^^ keyword 11 | println("impossible") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/highlight/attribute.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | #deprecated("Use fib2 instead") 3 | // <- attribute.builtin 4 | #coverage.skip 5 | // <- attribute.builtin 6 | fn fib(n : Int) -> Int { 7 | -1 8 | } 9 | 10 | ///| 11 | #attribute 12 | // <- attribute 13 | fn fib2(n : Int) -> Int { 14 | -1 15 | } 16 | -------------------------------------------------------------------------------- /test/highlight/call.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn main { 3 | println("Hello, world") 4 | // <- function.call 5 | let a = 3.0 6 | println(a.sqrt()) 7 | // ^^^^ function.method.call 8 | } 9 | -------------------------------------------------------------------------------- /test/highlight/char.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn main { 3 | let a = 'a' 4 | // ^^^ character 5 | let b = '\u{1234}' 6 | // ^^^^^^^^^^ character 7 | } 8 | -------------------------------------------------------------------------------- /test/highlight/const.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub const PI = 3.14 3 | // ^^ constant 4 | 5 | ///| 6 | fn main { 7 | println(PI) 8 | // ^^ constant 9 | } 10 | -------------------------------------------------------------------------------- /test/highlight/dot_dot.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) type Type Int derive(Show) 3 | 4 | ///| 5 | fn Type::function(self : Type) -> Unit { 6 | ignore(self) 7 | } 8 | 9 | ///| 10 | fn main { 11 | let variable : Type = 0 12 | variable..function() 13 | // ^^ punctuation.delimiter 14 | // ^^^^^^^^ function.method.call 15 | let string = "hello" 16 | match string { 17 | [.. "hello", .. string] => 18 | // <- operator 19 | // ^^ operator 20 | println(string) 21 | [.. string] => println(string) 22 | } 23 | for i in 0..<3 { 24 | // ^^^ operator 25 | } 26 | for j in 0..=2 { 27 | // ^^^ operator 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/highlight/enum.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) enum Weekday { 3 | Monday 4 | // <- constructor 5 | Tuesday 6 | Wednesday 7 | Thursday 8 | Friday 9 | Sunday 10 | } derive(Show) 11 | 12 | ///| 13 | fn main { 14 | println(Monday) 15 | // ^^^^^^ constructor 16 | } 17 | -------------------------------------------------------------------------------- /test/highlight/fib.mbt: -------------------------------------------------------------------------------- 1 | fn fib(n : Int) -> Int { 2 | // <- keyword.function 3 | // ^^^ function 4 | // ^ punctuation.bracket 5 | // ^ variable.parameter 6 | // ^^^ type.builtin 7 | // ^ punctuation.bracket 8 | // ^^ operator 9 | // ^^^ type.builtin 10 | // ^ punctuation.bracket 11 | match n { 12 | // <- keyword.conditional 13 | // ^ variable 14 | // ^ punctuation.bracket 15 | 0 => 1 16 | // <- number 17 | //^^ operator 18 | // ^ number 19 | 1 => 1 20 | n => fib(n - 1) + fib(n - 2) 21 | // ^ operator 22 | // ^ operator 23 | // ^ operator 24 | } 25 | } 26 | // <- punctuation.bracket 27 | -------------------------------------------------------------------------------- /test/highlight/for.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn[T : Show] print_array(array : Array[T]) -> Unit { 3 | let buffer = StringBuilder::new() 4 | buffer.write_char('[') 5 | for i, value in array { 6 | // <- keyword.repeat 7 | //^ variable 8 | // ^^^^^ variable 9 | buffer.write_object(value) 10 | if i < array.length() - 1 { 11 | buffer.write_string(", ") 12 | } 13 | } 14 | buffer.write_char(']') 15 | } 16 | 17 | ///| 18 | pub fn sum(array : Array[Int]) -> Int { 19 | let mut sum = 0 20 | for i = 0; i < array.length(); i = i + 1 { 21 | //^ variable 22 | sum += array[i] 23 | } 24 | return sum 25 | } 26 | -------------------------------------------------------------------------------- /test/highlight/operator.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn main { 3 | println(1 + 1) 4 | // ^ operator 5 | println(6 - 7) 6 | // ^ operator 7 | println(2 * 3) 8 | // ^ operator 9 | println(4 / 5) 10 | // ^ operator 11 | println(2 % 3) 12 | // ^ operator 13 | println(4 | 3) 14 | // ^ operator 15 | println(4 & 3) 16 | // ^ operator 17 | println(4 ^ 3) 18 | // ^ operator 19 | println(2 << 3) 20 | // ^^ operator 21 | println(2 >> 3) 22 | // ^^ operator 23 | let mut number = 24 24 | // ^^^ keyword.modifier 25 | number += 1 26 | // ^^ operator 27 | number -= 1 28 | // ^^ operator 29 | number *= 2 30 | // ^^ operator 31 | number /= 3 32 | // ^^ operator 33 | number %= 2 34 | // ^^ operator 35 | println(number) 36 | println(1 > 2) 37 | // ^ operator 38 | println(1 >= 2) 39 | // ^^ operator 40 | println(1 < 2) 41 | // ^ operator 42 | println(1 <= 2) 43 | // ^^ operator 44 | println(1 == 2) 45 | // ^^ operator 46 | println(1 != 2) 47 | // ^^ operator 48 | try { 49 | fail!("a") 50 | // ^ operator 51 | let result : Result[Unit, Failure] = fail?("a") 52 | // ^ operator 53 | ignore(result) 54 | } catch { 55 | _ => () 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/highlight/self.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) type A Int 3 | 4 | ///| 5 | fn to_int(self : A) -> Int { 6 | // ^^^^ variable.parameter.builtin 7 | return self._ 8 | // ^ variable.member 9 | } 10 | -------------------------------------------------------------------------------- /test/highlight/struct.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn init { 3 | struct Struct { 4 | int : Int 5 | float : Float 6 | } derive(Show) 7 | let value = { int: 42, float: 1.0 } 8 | // ^^^ variable.member 9 | // ^^^^^ variable.member 10 | let value = { ..value, int: 42 } 11 | // ^^^ variable.member 12 | let float : Float = 42.0 13 | let value = { ..value, float, } 14 | // ^^^^^ variable.member 15 | println(value) 16 | } 17 | -------------------------------------------------------------------------------- /tree-sitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json", 3 | "grammars": [ 4 | { 5 | "name": "moonbit", 6 | "camelcase": "MoonBit", 7 | "scope": "source.moonbit", 8 | "file-types": ["mbt", "moonbit"], 9 | "injection-regex": "^(mbt|moonbit)$", 10 | "highlights": "queries/highlights.scm", 11 | "tags": "queries/tags.scm", 12 | "class-name": "TreeSitterMoonbit", 13 | "path": "." 14 | }, 15 | { 16 | "name": "mbtq", 17 | "camelcase": "Mbtq", 18 | "scope": "source.mbtq", 19 | "path": "mbtq", 20 | "external-files": ["src/scanner.c"], 21 | "injection-regex": "^mbtq$", 22 | "class-name": "TreeSitterMbtq" 23 | } 24 | ], 25 | "metadata": { 26 | "version": "0.1.0", 27 | "license": "Apache-2.0", 28 | "description": "Moonbit grammar for tree-sitter", 29 | "authors": [ 30 | { 31 | "name": "Moonbit Language Team", 32 | "email": "support@moonbitlang.com", 33 | "url": "https://www.moonbitlang.com" 34 | } 35 | ], 36 | "links": { 37 | "repository": "https://github.com/moonbitlang/tree-sitter-moonbit" 38 | } 39 | }, 40 | "bindings": { 41 | "c": true, 42 | "go": true, 43 | "node": true, 44 | "python": true, 45 | "rust": true, 46 | "swift": false, 47 | "zig": true 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2024", 4 | "lib": ["ES2024"], 5 | "module": "CommonJS", 6 | "moduleResolution": "node", 7 | "allowJs": true, 8 | "checkJs": true, 9 | "noEmit": true, 10 | "strict": false, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "resolveJsonModule": true, 14 | "allowSyntheticDefaultImports": true, 15 | "esModuleInterop": true 16 | }, 17 | "include": ["grammar.js"], 18 | "exclude": [ 19 | "node_modules", 20 | "dist", 21 | "src", 22 | "bindings", 23 | "test", 24 | "web", 25 | "vscode", 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /vscode/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | !.vscode/ 7 | *.tsbuildinfo 8 | target/ 9 | .mooncakes/ 10 | /wasi-sdk/ 11 | /build/ 12 | .cache/ 13 | -------------------------------------------------------------------------------- /vscode/.npmrc: -------------------------------------------------------------------------------- 1 | enable-pre-post-scripts = true -------------------------------------------------------------------------------- /vscode/.prettierignore: -------------------------------------------------------------------------------- 1 | # Build output 2 | dist/ 3 | out/ 4 | 5 | # Dependencies 6 | node_modules/ 7 | 8 | # VSCode specific files 9 | .vscode-test/ 10 | 11 | # Other 12 | pnpm-lock.yaml 13 | -------------------------------------------------------------------------------- /vscode/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": false, 4 | "tabWidth": 2, 5 | "printWidth": 100, 6 | "trailingComma": "es5", 7 | "bracketSpacing": true, 8 | "arrowParens": "always", 9 | "endOfLine": "lf" 10 | } 11 | -------------------------------------------------------------------------------- /vscode/.vscode-test.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@vscode/test-cli"; 2 | 3 | export default defineConfig({ 4 | files: "out/test/**/*.test.js", 5 | }); 6 | -------------------------------------------------------------------------------- /vscode/.vscode/.gitignore: -------------------------------------------------------------------------------- 1 | settings.json 2 | -------------------------------------------------------------------------------- /vscode/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "connor4312.esbuild-problem-matchers", 7 | "ms-vscode.extension-test-runner" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /vscode/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": ["--profile-temp", "--extensionDevelopmentPath=${workspaceFolder}/dist"], 13 | "outFiles": ["${workspaceFolder}/dist/**/*.js"] 14 | // "preLaunchTask": "${defaultBuildTask}" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /vscode/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "watch", 8 | "dependsOn": ["npm: watch:tsc", "npm: watch:esbuild"], 9 | "presentation": { 10 | "reveal": "never" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | } 16 | }, 17 | { 18 | "type": "npm", 19 | "script": "watch:esbuild", 20 | "group": "build", 21 | "problemMatcher": "$esbuild-watch", 22 | "isBackground": true, 23 | "label": "npm: watch:esbuild", 24 | "presentation": { 25 | "group": "watch", 26 | "reveal": "never" 27 | } 28 | }, 29 | { 30 | "type": "npm", 31 | "script": "watch:tsc", 32 | "group": "build", 33 | "problemMatcher": "$tsc-watch", 34 | "isBackground": true, 35 | "label": "npm: watch:tsc", 36 | "presentation": { 37 | "group": "watch", 38 | "reveal": "never" 39 | } 40 | }, 41 | { 42 | "type": "npm", 43 | "script": "watch-tests", 44 | "problemMatcher": "$tsc-watch", 45 | "isBackground": true, 46 | "presentation": { 47 | "reveal": "never", 48 | "group": "watchers" 49 | }, 50 | "group": "build" 51 | }, 52 | { 53 | "label": "tasks: watch-tests", 54 | "dependsOn": ["npm: watch", "npm: watch-tests"], 55 | "problemMatcher": [] 56 | } 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | node_modules/** 5 | src/** 6 | .gitignore 7 | .yarnrc 8 | esbuild.js 9 | vsc-extension-quickstart.md 10 | **/tsconfig.json 11 | **/eslint.config.mjs 12 | **/*.map 13 | **/*.ts 14 | **/.vscode-test.* 15 | -------------------------------------------------------------------------------- /vscode/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "moon-grep" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release 10 | -------------------------------------------------------------------------------- /vscode/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(tonyfettes/tree_sitter/vscode/grep) 3 | 4 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 5 | 6 | include(CMakePrintHelpers) 7 | set(MOON_HOME "$ENV{MOON_HOME}") 8 | 9 | add_library(moonbit STATIC "${MOON_HOME}/lib/runtime.c") 10 | target_include_directories(moonbit PUBLIC "${MOON_HOME}/include") 11 | 12 | add_custom_target( 13 | ${target_name}.c 14 | COMMAND 15 | moon build --target native --directory ${CMAKE_CURRENT_SOURCE_DIR}/src/grep 16 | --target-dir ${CMAKE_CURRENT_BINARY_DIR}/target 17 | BYPRODUCTS 18 | ${CMAKE_CURRENT_BINARY_DIR}/target/native/release/build/grep/grep.c 19 | ${CMAKE_CURRENT_BINARY_DIR}/target/native/release/build/grep/grep.exe) 20 | 21 | add_executable(grep 22 | target/native/release/build/grep/grep.c 23 | .mooncakes/tonyfettes/tree_sitter/src/tree-sitter.c 24 | .mooncakes/tonyfettes/c/src/c.c 25 | .mooncakes/illusory0x0/native/src/stub.c 26 | .mooncakes/tonyfettes/tree_sitter_moonbit/parser.c 27 | .mooncakes/tonyfettes/tree_sitter_moonbit/scanner.c) 28 | target_link_libraries(grep PRIVATE moonbit) 29 | -------------------------------------------------------------------------------- /vscode/README.md: -------------------------------------------------------------------------------- 1 | # moon-grep README 2 | 3 | ## Build 4 | 5 | ```bash 6 | cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=wasi-sdk/share/cmake/wasi-sdk.cmake 7 | cmake --build build 8 | ``` 9 | -------------------------------------------------------------------------------- /vscode/esbuild.mts: -------------------------------------------------------------------------------- 1 | import ESBuild from "esbuild"; 2 | import * as Fs from "node:fs"; 3 | import * as Path from "path"; 4 | import * as Module from "node:module"; 5 | import * as ChildProcess from "node:child_process"; 6 | 7 | const production = process.argv.includes("--production"); 8 | const watch = process.argv.includes("--watch"); 9 | const serve = process.argv.includes("--serve"); 10 | 11 | const esbuildProblemMatcherPlugin: ESBuild.Plugin = { 12 | name: "esbuild-problem-matcher", 13 | 14 | setup(build) { 15 | build.onStart(() => { 16 | console.log("[watch] build started"); 17 | }); 18 | build.onEnd((result) => { 19 | result.errors.forEach(({ text, location }) => { 20 | console.error(`✘ [ERROR] ${text}`); 21 | if (!location) { 22 | return; 23 | } 24 | console.error(` ${location.file}:${location.line}:${location.column}:`); 25 | }); 26 | console.log("[watch] build finished"); 27 | }); 28 | }, 29 | }; 30 | 31 | function findOutdir(buildOptions: ESBuild.BuildOptions): string | undefined { 32 | if (buildOptions.outdir) { 33 | return buildOptions.outdir; 34 | } else if (buildOptions.outfile) { 35 | return Path.dirname(buildOptions.outfile); 36 | } 37 | return undefined; 38 | } 39 | 40 | const vscodePlugin: ESBuild.Plugin = { 41 | name: "vscode-plugin", 42 | setup(build) { 43 | build.onEnd(async () => { 44 | const outfile = build.initialOptions.outfile; 45 | if (!outfile) { 46 | throw new Error(`Could not find outfile for vscode`); 47 | } 48 | const outdir = findOutdir(build.initialOptions); 49 | if (!outdir) { 50 | throw new Error(`Could not find outdir for vscode`); 51 | } 52 | const packageJSON = JSON.parse(await Fs.promises.readFile("package.json", "utf-8")); 53 | packageJSON["main"] = Path.relative(outdir, outfile); 54 | await Fs.promises.writeFile( 55 | Path.join(outdir, "package.json"), 56 | JSON.stringify(packageJSON, null, 2), 57 | "utf-8" 58 | ); 59 | }); 60 | }, 61 | }; 62 | 63 | const cmakePlugin: ESBuild.Plugin = { 64 | name: "cmake-plugin", 65 | setup(build) { 66 | build.onEnd(async () => { 67 | await new Promise((resolve, reject) => { 68 | const process = ChildProcess.spawn("cmake", ["--build", "build"]); 69 | process.on("close", (code) => { 70 | if (code === 0) { 71 | resolve(); 72 | } else { 73 | reject(new Error(`CMake build failed with code ${code}`)); 74 | } 75 | }); 76 | process.on("error", (error) => { 77 | reject(new Error(`CMake build failed with error: ${error.message}`)); 78 | }); 79 | }); 80 | const grepPath = Path.join("build", "grep"); 81 | if (!Fs.existsSync(grepPath)) { 82 | throw new Error(`Could not find grep executable`); 83 | } 84 | const outdir = findOutdir(build.initialOptions); 85 | if (!outdir) { 86 | throw new Error(`Could not find outdir for executable`); 87 | } 88 | await Fs.promises.copyFile(grepPath, Path.join(outdir, "grep.wasm")); 89 | }); 90 | }, 91 | }; 92 | 93 | async function webviewCtx(path: string): Promise { 94 | return await ESBuild.context({ 95 | entryPoints: [`src/${path}/index.tsx`], 96 | bundle: true, 97 | format: "iife", 98 | minify: production, 99 | sourcemap: !production, 100 | sourcesContent: false, 101 | platform: "browser", 102 | outfile: `dist/${path}/index.js`, 103 | logLevel: "silent", 104 | plugins: [esbuildProblemMatcherPlugin], 105 | loader: { 106 | ".ttf": "file", 107 | ".tsx": "tsx", 108 | ".jsx": "jsx", 109 | }, 110 | }); 111 | } 112 | 113 | async function main() { 114 | const extensionCtx = await ESBuild.context({ 115 | entryPoints: ["src/extension.ts"], 116 | bundle: true, 117 | format: "cjs", 118 | minify: production, 119 | sourcemap: !production, 120 | sourcesContent: false, 121 | platform: "node", 122 | outfile: "dist/extension.js", 123 | external: ["vscode"], 124 | logLevel: "silent", 125 | plugins: [esbuildProblemMatcherPlugin, cmakePlugin, vscodePlugin], 126 | loader: { 127 | ".html": "text", 128 | ".wasm": "binary", 129 | ".worker": "file", 130 | }, 131 | }); 132 | const sidebarCtx = await webviewCtx("sidebar"); 133 | 134 | if (watch) { 135 | await Promise.all([extensionCtx.watch(), sidebarCtx.watch()]); 136 | if (serve) { 137 | const { hosts, port } = await sidebarCtx.serve({ 138 | servedir: "dist/sidebar", 139 | }); 140 | for (const host of hosts) { 141 | console.log(`Serving sidebar on http://${host}:${port}`); 142 | } 143 | } 144 | } else { 145 | await Promise.all([extensionCtx.rebuild(), sidebarCtx.rebuild()]); 146 | await Promise.all([extensionCtx.dispose(), sidebarCtx.dispose()]); 147 | } 148 | } 149 | 150 | main().catch((e) => { 151 | console.error(e); 152 | process.exit(1); 153 | }); 154 | -------------------------------------------------------------------------------- /vscode/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import typescriptEslint from "@typescript-eslint/eslint-plugin"; 2 | import tsParser from "@typescript-eslint/parser"; 3 | import prettierConfig from "eslint-config-prettier"; 4 | 5 | export default [ 6 | { 7 | files: ["**/*.ts"], 8 | }, 9 | { 10 | plugins: { 11 | "@typescript-eslint": typescriptEslint, 12 | }, 13 | 14 | languageOptions: { 15 | parser: tsParser, 16 | ecmaVersion: 2022, 17 | sourceType: "module", 18 | }, 19 | 20 | rules: { 21 | "@typescript-eslint/naming-convention": [ 22 | "warn", 23 | { 24 | selector: "import", 25 | format: ["camelCase", "PascalCase"], 26 | }, 27 | ], 28 | 29 | curly: "warn", 30 | eqeqeq: "warn", 31 | "no-throw-literal": "warn", 32 | semi: "warn", 33 | }, 34 | }, 35 | // Add Prettier config to disable ESLint rules that conflict with Prettier 36 | prettierConfig, 37 | ]; 38 | -------------------------------------------------------------------------------- /vscode/moon.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tonyfettes/tree_sitter/vscode", 3 | "version": "0.1.0", 4 | "deps": { 5 | "tonyfettes/uv": "0.7.4", 6 | "tonyfettes/tree_sitter": "0.4.4", 7 | "tonyfettes/tree_sitter_moonbit": "0.1.22" 8 | }, 9 | "readme": "README.md", 10 | "repository": "", 11 | "license": "Apache-2.0", 12 | "keywords": [], 13 | "description": "", 14 | "source": "src" 15 | } 16 | -------------------------------------------------------------------------------- /vscode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moon-grep", 3 | "displayName": "moon-grep", 4 | "description": "", 5 | "version": "0.0.1", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/tonyfettes/tree-sitter.mbt.git" 9 | }, 10 | "engines": { 11 | "vscode": "^1.100.0" 12 | }, 13 | "categories": [ 14 | "Other" 15 | ], 16 | "activationEvents": [], 17 | "extensionDependencies": [ 18 | "ms-vscode.wasm-wasi-core" 19 | ], 20 | "main": "./src/extension.ts", 21 | "contributes": { 22 | "commands": [ 23 | { 24 | "command": "moon-grep.helloWorld", 25 | "title": "Hello World" 26 | }, 27 | { 28 | "command": "moon-grep.search", 29 | "title": "Moon Grep: Search" 30 | }, 31 | { 32 | "command": "moon-grep.refresh", 33 | "title": "Refresh", 34 | "icon": "$(refresh)" 35 | }, 36 | { 37 | "command": "moon-grep.clear", 38 | "title": "Clear", 39 | "icon": "$(clear-all)" 40 | }, 41 | { 42 | "command": "moon-grep.collapseAll", 43 | "title": "Collapse All", 44 | "icon": "$(collapse-all)" 45 | }, 46 | { 47 | "command": "moon-grep.expandAll", 48 | "title": "Expand All", 49 | "icon": "$(expand-all)" 50 | } 51 | ], 52 | "viewsContainers": { 53 | "activitybar": [ 54 | { 55 | "id": "moon-grep-sidebar", 56 | "title": "Moon Grep", 57 | "icon": "$(search)" 58 | } 59 | ] 60 | }, 61 | "views": { 62 | "moon-grep-sidebar": [ 63 | { 64 | "type": "webview", 65 | "id": "moon-grep-search", 66 | "name": "Search", 67 | "icon": "$(search)" 68 | } 69 | ] 70 | }, 71 | "menus": { 72 | "view/title": [ 73 | { 74 | "command": "moon-grep.refresh", 75 | "when": "view == moon-grep-search", 76 | "group": "navigation" 77 | }, 78 | { 79 | "command": "moon-grep.clear", 80 | "when": "view == moon-grep-search", 81 | "group": "navigation" 82 | }, 83 | { 84 | "command": "moon-grep.collapseAll", 85 | "when": "view == moon-grep-search", 86 | "group": "navigation" 87 | }, 88 | { 89 | "command": "moon-grep.expandAll", 90 | "when": "view == moon-grep-search", 91 | "group": "navigation" 92 | } 93 | ] 94 | } 95 | }, 96 | "scripts": { 97 | "compile": "npm run check-types && npm run lint && node --experimental-transform-types esbuild.mts", 98 | "watch": "npm-run-all -p watch:*", 99 | "watch:build": "node --experimental-transform-types esbuild.mts --watch", 100 | "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", 101 | "serve:sidebar": "node --experimental-transform-types esbuild.mts --watch --serve", 102 | "package": "npm run check-types && npm run lint && node --experimental-transform-types esbuild.mts --production", 103 | "compile-tests": "tsc -p . --outDir out", 104 | "watch-tests": "tsc -p . -w --outDir out", 105 | "pretest": "npm run compile-tests && npm run compile && npm run lint", 106 | "check-types": "tsc --noEmit", 107 | "lint": "eslint src", 108 | "test": "vscode-test", 109 | "format": "prettier --write \"**/*.{ts,mts,js,mjs,tsx,jsx,json,html,css,md}\"", 110 | "format:check": "prettier --check \"**/*.{ts,mts,js,mjs,tsx,jsx,json,html,css,md}\"" 111 | }, 112 | "devDependencies": { 113 | "@types/mocha": "^10.0.10", 114 | "@types/node": "~22.15.14", 115 | "@types/react": "^18.2.0", 116 | "@types/react-dom": "^18.2.0", 117 | "@types/vscode": "^1.99.1", 118 | "@typescript-eslint/eslint-plugin": "^8.32.0", 119 | "@typescript-eslint/parser": "^8.32.0", 120 | "@vscode/codicons": "^0.0.36", 121 | "@vscode/test-electron": "^2.5.2", 122 | "@vscode/test-web": "^0.0.69", 123 | "@vscode/wasm-wasi": "^1.0.1", 124 | "esbuild": "^0.25.4", 125 | "eslint": "^9.26.0", 126 | "eslint-config-prettier": "^10.1.3", 127 | "ignore": "^7.0.4", 128 | "npm-run-all": "^4.1.5", 129 | "prettier": "^3.5.3", 130 | "react": "^19.1.0", 131 | "react-dom": "^19.1.0", 132 | "typescript": "^5.8.3" 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /vscode/src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import * as Sidebar from "./sidebar"; 3 | import * as Search from "./search"; 4 | 5 | export async function activate(context: vscode.ExtensionContext) { 6 | const searchService = new Search.Service(context.extensionUri); 7 | const sidebarWebviewProvider = new Sidebar.WebviewViewProvider( 8 | context.extensionUri, 9 | searchService 10 | ); 11 | context.subscriptions.push( 12 | vscode.window.registerWebviewViewProvider( 13 | Sidebar.WebviewViewProvider.viewType, 14 | sidebarWebviewProvider 15 | ) 16 | ); 17 | 18 | // Register commands for the view title menu 19 | context.subscriptions.push( 20 | vscode.commands.registerCommand("moon-grep.refresh", () => { 21 | sidebarWebviewProvider.postMessage({ type: "refresh" }); 22 | }), 23 | vscode.commands.registerCommand("moon-grep.clear", () => { 24 | sidebarWebviewProvider.postMessage({ type: "clear" }); 25 | searchService.reset(); 26 | }), 27 | vscode.commands.registerCommand("moon-grep.collapseAll", () => { 28 | sidebarWebviewProvider.postMessage({ type: "collapseAll" }); 29 | }), 30 | vscode.commands.registerCommand("moon-grep.expandAll", () => { 31 | sidebarWebviewProvider.postMessage({ type: "expandAll" }); 32 | }) 33 | ); 34 | } 35 | 36 | export function deactivate() {} 37 | -------------------------------------------------------------------------------- /vscode/src/grep/jsonrpc.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn[Result : ToJson] jsonrpc_result(id~ : Json, result : Result) -> Unit { 3 | let response : Json = { 4 | "jsonrpc": "2.0", 5 | "result": result.to_json(), 6 | "id": id, 7 | } 8 | println(response.stringify()) 9 | } 10 | 11 | ///| 12 | fn jsonrpc_error(id~ : Json, error : Json) -> Unit { 13 | let response : Json = { 14 | "jsonrpc": "2.0", 15 | "error": { "code": -32603, "message": error }, 16 | "id": id, 17 | } 18 | println(response.stringify()) 19 | } 20 | -------------------------------------------------------------------------------- /vscode/src/grep/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | extern "c" fn getchar() -> Int = "getchar" 3 | 4 | ///| 5 | fn main { 6 | let buffer = @buffer.new() 7 | try { 8 | fn on_submit!() { 9 | if buffer.is_empty() { 10 | return 11 | } 12 | let content = @encoding.decode!(buffer.contents(), encoding=UTF8) 13 | let json = @json.parse!(content) 14 | match json { 15 | { 16 | "id": id, 17 | "method": "search", 18 | "params": { "content": String(content), "query": String(query), .. }, 19 | .. 20 | } => 21 | try { 22 | for result in search(query~, content~) { 23 | jsonrpc_result(id~, result) 24 | } 25 | jsonrpc_result(id~, Json::null()) 26 | } catch { 27 | error => jsonrpc_error(id~, error.to_json()) 28 | } 29 | { 30 | "id": id, 31 | "method": "replace", 32 | "params": { 33 | "captures": Object(captures_json), 34 | "replace": String(replace_string), 35 | .. 36 | }, 37 | .. 38 | } => { 39 | let captures : Map[@string.View, Array[Text]] = {} 40 | for name, capture_json in captures_json { 41 | captures[name.view()] = @json.from_json!(capture_json) 42 | } 43 | try jsonrpc_result(id~, replace(captures, replace_string)) catch { 44 | error => jsonrpc_error(id~, error.to_json()) 45 | } 46 | } 47 | { "id": id, .. } => 48 | jsonrpc_error(id~, "Invalid request: \{json.to_json().stringify()}") 49 | _ => 50 | jsonrpc_error( 51 | id=Json::null(), 52 | "Invalid request: \{json.to_json().stringify()}", 53 | ) 54 | } 55 | buffer.reset() 56 | } 57 | 58 | loop getchar() { 59 | '\n' => { 60 | try on_submit!() catch { 61 | error => jsonrpc_error(id=Json::null(), error.to_string().to_json()) 62 | } 63 | continue getchar() 64 | } 65 | 0..<_ as byte => { 66 | buffer.write_byte(byte.to_byte()) 67 | continue getchar() 68 | } 69 | _..<0 => on_submit!() 70 | } 71 | } catch { 72 | error => jsonrpc_error(id=Json::null(), error.to_string().to_json()) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vscode/src/grep/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | "tonyfettes/tree_sitter", 5 | "tonyfettes/tree_sitter_moonbit", 6 | "tonyfettes/encoding" 7 | ], 8 | "link": { 9 | "js": { 10 | "exports": ["setup", "compile", "search"] 11 | }, 12 | "native": { 13 | "exports": ["setup", "compile", "search"] 14 | } 15 | }, 16 | "supported-targets": ["native"], 17 | "test-import": [ 18 | "tonyfettes/uv/async" 19 | ], 20 | "wbtest-import": [ 21 | "tonyfettes/uv/async" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /vscode/src/grep/replace.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | priv enum Replace { 3 | Quote(String) 4 | Subst(String) 5 | } 6 | 7 | ///| 8 | type! ReplaceError { 9 | VariableNotFound(String) 10 | MismatchedType(expect~ : String, actual~ : String) 11 | } derive(Show, ToJson) 12 | 13 | ///| 14 | fn Replace::parse_identifier( 15 | source : @string.View, 16 | buffer : StringBuilder 17 | ) -> @string.View { 18 | loop source { 19 | ['a'..='z' | 'A'..='Z' | '_' | '0'..='9' as char, .. source] => { 20 | buffer.write_char(char) 21 | continue source 22 | } 23 | source => return source 24 | } 25 | } 26 | 27 | ///| 28 | fn Replace::parse_replaces( 29 | source : @string.View, 30 | replaces : Array[Replace] 31 | ) -> Unit { 32 | let buffer = StringBuilder::new() 33 | loop source { 34 | ['$', .. source] => { 35 | if not(buffer.is_empty()) { 36 | replaces.push(Replace::Quote(buffer.to_string())) 37 | buffer.reset() 38 | } 39 | let identifier = StringBuilder::new() 40 | let source = Replace::parse_identifier(source, identifier) 41 | replaces.push(Replace::Subst(identifier.to_string())) 42 | continue source 43 | } 44 | ['\\', '$', .. source] => { 45 | buffer.write_char('$') 46 | continue source 47 | } 48 | [char, .. source] => { 49 | buffer.write_char(char) 50 | continue source 51 | } 52 | [] => { 53 | if not(buffer.is_empty()) { 54 | replaces.push(Replace::Quote(buffer.to_string())) 55 | buffer.reset() 56 | } 57 | return 58 | } 59 | } 60 | } 61 | 62 | ///| 63 | fn Replace::parse(string : @string.View) -> Array[Replace] { 64 | let replaces = [] 65 | Replace::parse_replaces(string, replaces) 66 | return replaces 67 | } 68 | 69 | ///| 70 | fn replace( 71 | captures : Map[@string.View, Array[Text]], 72 | replace : @string.View 73 | ) -> @string.View!ReplaceError { 74 | let replaces = Replace::parse(replace) 75 | let replaced = StringBuilder::new() 76 | for replace in replaces { 77 | match replace { 78 | Quote(string) => replaced.write_string(string) 79 | Subst(name) => 80 | match captures.get(name) { 81 | None => raise VariableNotFound(name) 82 | Some([text]) => 83 | for char in text.text { 84 | replaced.write_char(char) 85 | } 86 | Some(_) => 87 | raise MismatchedType(expect="single node", actual="multiple nodes") 88 | } 89 | } 90 | } 91 | replaced.to_string() 92 | } 93 | 94 | ///| 95 | priv struct Text { 96 | range : @tree_sitter.Range 97 | text : @string.View 98 | } 99 | 100 | ///| 101 | impl ToJson for Text with to_json(self : Text) -> Json { 102 | { 103 | "range": { 104 | "start": { 105 | "row": self.range.start_point().row().to_json(), 106 | "column": self.range.start_point().column().to_json(), 107 | "byte": self.range.start_byte().to_json(), 108 | }, 109 | "end": { 110 | "row": self.range.end_point().row().to_json(), 111 | "column": self.range.end_point().column().to_json(), 112 | "byte": self.range.end_byte().to_json(), 113 | }, 114 | }, 115 | "text": self.text.to_json(), 116 | } 117 | } 118 | 119 | ///| 120 | impl @json.FromJson for Text with from_json( 121 | self : Json, 122 | path : @json.JsonPath 123 | ) -> Text!@json.JsonDecodeError { 124 | match self { 125 | { 126 | "range": { 127 | "start": { 128 | "row": Number(start_row), 129 | "column": Number(start_column), 130 | "byte": Number(start_byte), 131 | .. 132 | }, 133 | "end": { 134 | "row": Number(end_row), 135 | "column": Number(end_column), 136 | "byte": Number(end_byte), 137 | .. 138 | }, 139 | .. 140 | }, 141 | "text": String(text), 142 | .. 143 | } => 144 | Text::{ 145 | range: @tree_sitter.Range::new( 146 | @tree_sitter.Point::new(start_row.to_int(), start_column.to_int()), 147 | @tree_sitter.Point::new(end_row.to_int(), end_column.to_int()), 148 | start_byte.to_int(), 149 | end_byte.to_int(), 150 | ), 151 | text, 152 | } 153 | _ => raise @json.JsonDecodeError((path, "Invalid text")) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /vscode/src/sidebar/components/Codicon.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface CodiconProps { 4 | name: string; 5 | className?: string; 6 | } 7 | 8 | /** 9 | * A reusable component for rendering VSCode codicons 10 | */ 11 | export const Codicon: React.FC = ({ name, className = "" }) => { 12 | return ; 13 | }; 14 | 15 | export default Codicon; 16 | -------------------------------------------------------------------------------- /vscode/src/sidebar/components/ControlButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Codicon from "./Codicon"; 3 | 4 | interface ControlButtonProps { 5 | icon: string; 6 | title: string; 7 | onClick?: () => void; 8 | active?: boolean; 9 | id?: string; 10 | className?: string; 11 | } 12 | 13 | /** 14 | * A reusable control button component with codicon support 15 | */ 16 | export const ControlButton: React.FC = ({ 17 | icon, 18 | title, 19 | onClick, 20 | active = false, 21 | id, 22 | className = "", 23 | }) => { 24 | return ( 25 | 33 | ); 34 | }; 35 | 36 | export default ControlButton; 37 | -------------------------------------------------------------------------------- /vscode/src/sidebar/components/FileItem.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Result } from "../types"; 3 | import MatchItem from "./MatchItem"; 4 | import Codicon from "./Codicon"; 5 | 6 | interface FileItemProps { 7 | file: string; 8 | matches: Result[]; 9 | collapsed: boolean; 10 | onToggleCollapse: () => void; 11 | onReplaceMatch?: (id: string) => void; 12 | onDismissMatch?: (id: string) => void; 13 | } 14 | 15 | export const FileItem: React.FC = ({ 16 | file, 17 | matches, 18 | collapsed, 19 | onToggleCollapse, 20 | onReplaceMatch, 21 | onDismissMatch, 22 | }) => { 23 | return ( 24 |
25 |
26 | 27 | 28 | 29 | {file} 30 | {matches.length} 31 |
32 |
33 | {matches.map((match) => ( 34 | 43 | ))} 44 |
45 |
46 | ); 47 | }; 48 | 49 | export default FileItem; 50 | -------------------------------------------------------------------------------- /vscode/src/sidebar/components/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Codicon from "./Codicon"; 3 | 4 | interface IconButtonProps { 5 | icon: string; 6 | title: string; 7 | onClick: () => void; 8 | id?: string; 9 | className?: string; 10 | } 11 | 12 | /** 13 | * A reusable icon button component with codicon support 14 | */ 15 | export const IconButton: React.FC = ({ 16 | icon, 17 | title, 18 | onClick, 19 | id, 20 | className = "", 21 | }) => { 22 | return ( 23 | 26 | ); 27 | }; 28 | 29 | export default IconButton; 30 | -------------------------------------------------------------------------------- /vscode/src/sidebar/components/InputBox.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode, useRef, useEffect } from "react"; 2 | 3 | interface InputBoxProps { 4 | value: string; 5 | onChange: (value: string) => void; 6 | placeholder: string; 7 | id?: string; 8 | className?: string; 9 | onSubmit?: (e: React.KeyboardEvent) => void; 10 | multiline?: boolean; 11 | controls?: ReactNode; 12 | label?: string; 13 | } 14 | 15 | /** 16 | * A reusable input box component with optional controls and label 17 | * @param value - The current value of the input 18 | * @param onChange - Function to call when the value changes 19 | * @param placeholder - Placeholder text for the input 20 | * @param id - Optional ID for the textarea element 21 | * @param className - Optional additional CSS class names 22 | * @param onSubmit - Optional function to submit event 23 | * @param multiline - Optional flag to enable multiline input 24 | * @param controls - Optional React node to render as controls 25 | * @param label - Optional label text to display above the input 26 | */ 27 | export const InputBox: React.FC = ({ 28 | value, 29 | onChange, 30 | placeholder, 31 | id, 32 | className = "", 33 | onSubmit, 34 | multiline = false, 35 | controls, 36 | label, 37 | }) => { 38 | const textareaRef = useRef(null); 39 | 40 | // Function to adjust textarea height based on content 41 | const adjustHeight = () => { 42 | const textarea = textareaRef.current; 43 | if (textarea) { 44 | // Reset height to auto to get the correct scrollHeight 45 | textarea.style.height = "auto"; 46 | // Set the height to match the content (with a minimum height) 47 | const newHeight = Math.max(24, textarea.scrollHeight); 48 | textarea.style.height = `${newHeight}px`; 49 | } 50 | }; 51 | 52 | // Adjust height when value changes 53 | useEffect(() => { 54 | adjustHeight(); 55 | }, [value]); 56 | 57 | return ( 58 | <> 59 | {label && } 60 |
61 |