├── .github ├── FUNDING.yml └── workflows │ ├── add-discuss-during-sync.yml │ ├── announce-a-release.yml │ ├── breakage-against-ponyc-latest.yml │ ├── changelog-bot.yml │ ├── generate-documentation.yml │ ├── lint-action-workflows.yml │ ├── pr.yml │ ├── prepare-for-a-release.yml │ ├── release-notes-reminder.yml │ ├── release-notes.yml │ ├── release.yml │ └── remove-discuss-during-sync.yml ├── .markdownlintignore ├── .release-notes ├── 0.2.1.md ├── 0.2.2.md └── next-release.md ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── build.sh ├── build_ci.ps1 ├── build_ci.sh ├── client_vscode ├── .vscodeignore ├── LICENSE ├── Makefile ├── README.md ├── language-configuration.json ├── package-lock.json ├── package.json ├── packages │ ├── assert │ │ └── assert.pony │ ├── backpressure │ │ ├── auth.pony │ │ └── backpressure.pony │ ├── buffered │ │ ├── _test.pony │ │ ├── benchmarks │ │ │ └── main.pony │ │ ├── buffered.pony │ │ ├── reader.pony │ │ └── writer.pony │ ├── builtin │ │ ├── _arithmetic.pony │ │ ├── _to_string.pony │ │ ├── ambient_auth.pony │ │ ├── any.pony │ │ ├── array.pony │ │ ├── asio_event.pony │ │ ├── bool.pony │ │ ├── builtin.pony │ │ ├── compare.pony │ │ ├── disposable_actor.pony │ │ ├── do_not_optimise.pony │ │ ├── env.pony │ │ ├── float.pony │ │ ├── iterator.pony │ │ ├── none.pony │ │ ├── nullable_pointer.pony │ │ ├── platform.pony │ │ ├── pointer.pony │ │ ├── read_seq.pony │ │ ├── real.pony │ │ ├── runtime_options.pony │ │ ├── seq.pony │ │ ├── signed.pony │ │ ├── source_loc.pony │ │ ├── std_stream.pony │ │ ├── stdin.pony │ │ ├── string.pony │ │ ├── stringable.pony │ │ └── unsigned.pony │ ├── builtin_test │ │ ├── _test.pony │ │ └── _test_valtrace.pony │ ├── bureaucracy │ │ ├── _test.pony │ │ ├── bureaucracy.pony │ │ ├── custodian.pony │ │ └── registrar.pony │ ├── capsicum │ │ ├── cap.pony │ │ ├── cap_rights.pony │ │ └── capsicum.pony │ ├── cli │ │ ├── _test.pony │ │ ├── cli.pony │ │ ├── command.pony │ │ ├── command_help.pony │ │ ├── command_parser.pony │ │ ├── command_spec.pony │ │ └── env_vars.pony │ ├── collections │ │ ├── _test.pony │ │ ├── collections.pony │ │ ├── flag.pony │ │ ├── hashable.pony │ │ ├── heap.pony │ │ ├── list.pony │ │ ├── list_node.pony │ │ ├── map.pony │ │ ├── persistent │ │ │ ├── _bits.pony │ │ │ ├── _map_node.pony │ │ │ ├── _test.pony │ │ │ ├── _vec_node.pony │ │ │ ├── benchmarks │ │ │ │ └── main.pony │ │ │ ├── list.pony │ │ │ ├── map.pony │ │ │ ├── persistent.pony │ │ │ ├── set.pony │ │ │ └── vec.pony │ │ ├── range.pony │ │ ├── reverse.pony │ │ ├── ring_buffer.pony │ │ ├── set.pony │ │ └── sort.pony │ ├── constrained_types │ │ ├── _test.pony │ │ ├── constrained.pony │ │ └── constrained_types.pony │ ├── debug │ │ └── debug.pony │ ├── encode │ │ └── base64 │ │ │ ├── _test.pony │ │ │ └── base64.pony │ ├── files │ │ ├── _file_des.pony │ │ ├── _test.pony │ │ ├── auth.pony │ │ ├── directory.pony │ │ ├── file.pony │ │ ├── file_caps.pony │ │ ├── file_info.pony │ │ ├── file_lines.pony │ │ ├── file_mode.pony │ │ ├── file_path.pony │ │ ├── file_stream.pony │ │ ├── files.pony │ │ └── path.pony │ ├── format │ │ ├── _format_float.pony │ │ ├── _format_int.pony │ │ ├── _test.pony │ │ ├── align.pony │ │ ├── format.pony │ │ ├── format_spec.pony │ │ └── prefix_spec.pony │ ├── ini │ │ ├── _test.pony │ │ ├── ini.pony │ │ └── ini_map.pony │ ├── itertools │ │ ├── _test.pony │ │ ├── iter.pony │ │ └── itertools.pony │ ├── json │ │ ├── _json_print.pony │ │ ├── _test.pony │ │ ├── json.pony │ │ ├── json_doc.pony │ │ └── json_type.pony │ ├── math │ │ ├── _test.pony │ │ ├── fibonacci.pony │ │ ├── greatest_common_divisor.pony │ │ ├── is_prime.pony │ │ ├── least_common_multiple.pony │ │ └── math.pony │ ├── net │ │ ├── _test.pony │ │ ├── auth.pony │ │ ├── dns.pony │ │ ├── net.pony │ │ ├── net_address.pony │ │ ├── ossocket.pony │ │ ├── ossockopt.pony │ │ ├── proxy.pony │ │ ├── tcp_connection.pony │ │ ├── tcp_connection_notify.pony │ │ ├── tcp_listen_notify.pony │ │ ├── tcp_listener.pony │ │ ├── udp_notify.pony │ │ └── udp_socket.pony │ ├── pony_bench │ │ ├── _aggregator.pony │ │ ├── _output_manager.pony │ │ ├── _results.pony │ │ ├── _runner.pony │ │ ├── benchmark.pony │ │ └── pony_bench.pony │ ├── pony_check │ │ ├── _test.pony │ │ ├── ascii_range.pony │ │ ├── for_all.pony │ │ ├── generator.pony │ │ ├── int_properties.pony │ │ ├── pony_check.pony │ │ ├── poperator.pony │ │ ├── property.pony │ │ ├── property_helper.pony │ │ ├── property_runner.pony │ │ ├── property_unit_test.pony │ │ └── randomness.pony │ ├── pony_test │ │ ├── _color.pony │ │ ├── _group.pony │ │ ├── _test_record.pony │ │ ├── _test_runner.pony │ │ ├── pony_test.pony │ │ ├── test_helper.pony │ │ ├── test_list.pony │ │ └── unit_test.pony │ ├── process │ │ ├── _pipe.pony │ │ ├── _process.pony │ │ ├── _test.pony │ │ ├── auth.pony │ │ ├── process.pony │ │ ├── process_error.pony │ │ ├── process_monitor.pony │ │ └── process_notify.pony │ ├── promises │ │ ├── _test.pony │ │ ├── _then.pony │ │ ├── fulfill.pony │ │ ├── promise.pony │ │ └── promises.pony │ ├── random │ │ ├── _test.pony │ │ ├── benchmarks │ │ │ └── main.pony │ │ ├── dice.pony │ │ ├── mt.pony │ │ ├── random.pony │ │ ├── splitmix64.pony │ │ ├── xoroshiro.pony │ │ └── xorshift.pony │ ├── runtime_info │ │ ├── _actor_stats.pony │ │ ├── _scheduler_stats.pony │ │ ├── _test.pony │ │ ├── actor_stats.pony │ │ ├── auth.pony │ │ ├── runtime_info.pony │ │ ├── scheduler.pony │ │ └── scheduler_stats.pony │ ├── serialise │ │ ├── _test.pony │ │ └── serialise.pony │ ├── signals │ │ ├── _test.pony │ │ ├── sig.pony │ │ ├── signal_handler.pony │ │ ├── signal_notify.pony │ │ └── signals.pony │ ├── stdlib │ │ └── _test.pony │ ├── strings │ │ ├── _test.pony │ │ ├── common_prefix.pony │ │ └── strings.pony │ ├── term │ │ ├── ansi.pony │ │ ├── ansi_notify.pony │ │ ├── ansi_term.pony │ │ ├── readline.pony │ │ ├── readline_notify.pony │ │ └── term.pony │ └── time │ │ ├── _test.pony │ │ ├── _timing_wheel.pony │ │ ├── nanos.pony │ │ ├── posix_date.pony │ │ ├── time.pony │ │ ├── timer.pony │ │ ├── timer_notify.pony │ │ └── timers.pony ├── pony.tmLanguage ├── src │ └── extension.ts ├── tsconfig.json └── webpack.config.js ├── corral.json ├── lock.json └── lsp ├── channel_stdio.pony ├── corral.pony ├── diagnostics.pony ├── language_server.pony ├── lsp_base.pony ├── lsp_document.pony ├── lsp_language.pony ├── main.pony ├── message.pony ├── options.pony ├── pony_compiler.pony ├── position.pony ├── symbols.pony ├── test ├── _workspace_tests.pony ├── main.pony └── workspace │ ├── corral.json │ └── main.pony ├── uri.pony └── workspace ├── data.pony ├── manager.pony ├── router.pony ├── scanner.pony └── state.pony /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: ponyc 2 | -------------------------------------------------------------------------------- /.github/workflows/add-discuss-during-sync.yml: -------------------------------------------------------------------------------- 1 | name: Add discuss during sync label 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - reopened 8 | issue_comment: 9 | types: 10 | - created 11 | pull_request_target: 12 | types: 13 | - opened 14 | - edited 15 | - ready_for_review 16 | - reopened 17 | pull_request_review: 18 | types: 19 | - submitted 20 | 21 | jobs: 22 | add-label: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Add "discuss during sync" label to active GH entity 26 | uses: andymckay/labeler@467347716a3bdbca7f277cb6cd5fa9c5205c5412 27 | with: 28 | repo-token: ${{ secrets.PONYLANG_MAIN_API_TOKEN }} 29 | add-labels: "discuss during sync" 30 | -------------------------------------------------------------------------------- /.github/workflows/announce-a-release.yml: -------------------------------------------------------------------------------- 1 | name: Announce a release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'announce-[0-9]+.[0-9]+.[0-9]+' 7 | 8 | concurrency: announce-a-release 9 | 10 | jobs: 11 | announce: 12 | name: Announcements 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout main 16 | uses: actions/checkout@v4.1.1 17 | with: 18 | ref: "main" 19 | token: ${{ secrets.RELEASE_TOKEN }} 20 | - name: Release notes 21 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 22 | with: 23 | entrypoint: publish-release-notes-to-github 24 | env: 25 | RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} 26 | - name: Zulip 27 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 28 | with: 29 | entrypoint: send-announcement-to-pony-zulip 30 | env: 31 | ZULIP_API_KEY: ${{ secrets.ZULIP_RELEASE_API_KEY }} 32 | ZULIP_EMAIL: ${{ secrets.ZULIP_RELEASE_EMAIL }} 33 | - name: Last Week in Pony 34 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 35 | with: 36 | entrypoint: add-announcement-to-last-week-in-pony 37 | env: 38 | RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} 39 | 40 | post-announcement: 41 | name: Tasks to run after the release has been announced 42 | needs: 43 | - announce 44 | runs-on: ubuntu-latest 45 | steps: 46 | - name: Checkout main 47 | uses: actions/checkout@v4.1.1 48 | with: 49 | ref: "main" 50 | token: ${{ secrets.RELEASE_TOKEN }} 51 | - name: Rotate release notes 52 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 53 | with: 54 | entrypoint: rotate-release-notes 55 | env: 56 | GIT_USER_NAME: "Ponylang Main Bot" 57 | GIT_USER_EMAIL: "ponylang.main@gmail.com" 58 | - name: Delete announcement trigger tag 59 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 60 | with: 61 | entrypoint: delete-announcement-tag 62 | env: 63 | GIT_USER_NAME: "Ponylang Main Bot" 64 | GIT_USER_EMAIL: "ponylang.main@gmail.com" 65 | -------------------------------------------------------------------------------- /.github/workflows/breakage-against-ponyc-latest.yml: -------------------------------------------------------------------------------- 1 | name: ponyc update breakage test 2 | 3 | on: 4 | repository_dispatch: 5 | types: [shared-docker-linux-builders-updated] 6 | 7 | jobs: 8 | vs-ponyc-latest: 9 | name: Test against ponyc main 10 | runs-on: ubuntu-latest 11 | container: 12 | image: ghcr.io/ponylang/shared-docker-ci-x86-64-unknown-linux-builder-with-libressl-3.9.1:latest 13 | steps: 14 | - uses: actions/checkout@v4.1.1 15 | - name: Test 16 | run: make test config=debug 17 | - name: Send alert on failure 18 | if: ${{ failure() }} 19 | uses: zulip/github-actions-zulip/send-message@08b6fbd07f5834e5b930a85bc7740e9fd44ab2e7 20 | with: 21 | api-key: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_API_KEY }} 22 | email: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_EMAIL }} 23 | organization-url: 'https://ponylang.zulipchat.com/' 24 | to: notifications 25 | type: stream 26 | topic: ${{ github.repository }} scheduled job failure 27 | content: ${{ github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }} failed. 28 | -------------------------------------------------------------------------------- /.github/workflows/changelog-bot.yml: -------------------------------------------------------------------------------- 1 | name: Changelog Bot 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | tags-ignore: 8 | - '**' 9 | paths-ignore: 10 | - CHANGELOG.md 11 | 12 | jobs: 13 | changelog-bot: 14 | runs-on: ubuntu-latest 15 | name: Update CHANGELOG.md 16 | steps: 17 | - name: Update Changelog 18 | uses: docker://ghcr.io/ponylang/changelog-bot-action:0.3.5 19 | with: 20 | git_user_name: "Ponylang Main Bot" 21 | git_user_email: "ponylang.main@gmail.com" 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | - name: Send alert on failure 25 | if: ${{ failure() }} 26 | uses: zulip/github-actions-zulip/send-message@08b6fbd07f5834e5b930a85bc7740e9fd44ab2e7 27 | with: 28 | api-key: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_API_KEY }} 29 | email: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_EMAIL }} 30 | organization-url: 'https://ponylang.zulipchat.com/' 31 | to: notifications 32 | type: stream 33 | topic: ${{ github.repository }} unattended job failure 34 | content: ${{ github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }} failed. 35 | -------------------------------------------------------------------------------- /.github/workflows/generate-documentation.yml: -------------------------------------------------------------------------------- 1 | name: Manually generate documentation 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | permissions: 7 | contents: read 8 | pages: write 9 | id-token: write 10 | packages: read 11 | 12 | concurrency: 13 | group: "update-documentation" 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | generate-documentation: 18 | name: Generate documentation for release 19 | environment: 20 | name: github-pages 21 | url: ${{ steps.deployment.outputs.page_url }} 22 | runs-on: ubuntu-latest 23 | container: 24 | image: ghcr.io/ponylang/library-documentation-action-v2-insiders:release 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4.1.1 28 | - name: Generate documentation 29 | run: /entrypoint.py 30 | env: 31 | INPUT_SITE_URL: "https://ponylang.github.io/lsp/" 32 | INPUT_LIBRARY_NAME: "lsp" 33 | INPUT_DOCS_BUILD_DIR: "build/lsp-docs" 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v2 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v1 38 | with: 39 | path: 'build/lsp-docs/site/' 40 | - name: Deploy to GitHub Pages 41 | id: deployment 42 | uses: actions/deploy-pages@v1 43 | -------------------------------------------------------------------------------- /.github/workflows/lint-action-workflows.yml: -------------------------------------------------------------------------------- 1 | name: Lint GitHub Action Workflows 2 | 3 | on: pull_request 4 | 5 | concurrency: 6 | group: lint-actions-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | lint: 11 | name: Lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4.1.1 16 | - name: Check workflow files 17 | uses: docker://ghcr.io/ponylang/shared-docker-ci-actionlint:20240224 18 | with: 19 | args: -color 20 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | 3 | on: pull_request 4 | 5 | concurrency: 6 | group: pr-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | superlinter: 11 | name: Lint bash, docker, markdown, and yaml 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4.1.1 15 | - name: Lint codebase 16 | uses: docker://github/super-linter:v3.8.3 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | VALIDATE_ALL_CODEBASE: true 20 | VALIDATE_BASH: true 21 | VALIDATE_DOCKERFILE: true 22 | VALIDATE_MD: true 23 | VALIDATE_YAML: true 24 | 25 | verify-changelog: 26 | name: Verify CHANGELOG is valid 27 | runs-on: ubuntu-latest 28 | container: 29 | image: ghcr.io/ponylang/changelog-tool:release 30 | steps: 31 | - uses: actions/checkout@v4.1.1 32 | - name: Verify CHANGELOG 33 | run: changelog-tool verify 34 | 35 | vs-ponyc-release: 36 | name: Test against recent ponyc release 37 | runs-on: ubuntu-latest 38 | container: 39 | image: ghcr.io/ponylang/shared-docker-ci-x86-64-unknown-linux-builder:release 40 | steps: 41 | - uses: actions/checkout@v4.1.1 42 | - name: Test 43 | run: make test config=debug 44 | - name: Install npm 45 | run: apk add --update --no-cache npm 46 | - name: Install vsce 47 | run: npm install -g @vscode/vsce 48 | - name: Test creation of vscode extension 49 | run: make vscode_extension config=debug 50 | -------------------------------------------------------------------------------- /.github/workflows/release-notes-reminder.yml: -------------------------------------------------------------------------------- 1 | name: Release Notes Reminder 2 | 3 | on: 4 | pull_request_target: 5 | types: [labeled] 6 | 7 | jobs: 8 | release-note-reminder: 9 | runs-on: ubuntu-latest 10 | name: Prompt to add release notes 11 | steps: 12 | - name: Prompt to add release notes 13 | uses: docker://ghcr.io/ponylang/release-notes-reminder-bot-action:0.1.1 14 | env: 15 | API_CREDENTIALS: ${{ secrets.PONYLANG_MAIN_API_TOKEN }} 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/release-notes.yml: -------------------------------------------------------------------------------- 1 | name: Release Notes 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | tags-ignore: 8 | - '**' 9 | paths-ignore: 10 | - .release-notes/next-release.md 11 | - .release-notes/\d+.\d+.\d+.md 12 | 13 | jobs: 14 | release-notes: 15 | runs-on: ubuntu-latest 16 | name: Update release notes 17 | steps: 18 | - name: Update 19 | uses: docker://ghcr.io/ponylang/release-notes-bot-action:0.3.7 20 | with: 21 | git_user_name: "Ponylang Main Bot" 22 | git_user_email: "ponylang.main@gmail.com" 23 | env: 24 | API_CREDENTIALS: ${{ secrets.GITHUB_TOKEN }} 25 | - name: Send alert on failure 26 | if: ${{ failure() }} 27 | uses: zulip/github-actions-zulip/send-message@08b6fbd07f5834e5b930a85bc7740e9fd44ab2e7 28 | with: 29 | api-key: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_API_KEY }} 30 | email: ${{ secrets.ZULIP_SCHEDULED_JOB_FAILURE_EMAIL }} 31 | organization-url: 'https://ponylang.zulipchat.com/' 32 | to: notifications 33 | type: stream 34 | topic: ${{ github.repository }} scheduled job failure 35 | content: ${{ github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }} failed. 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+.[0-9]+' 7 | 8 | concurrency: release 9 | 10 | permissions: 11 | contents: read 12 | pages: write 13 | id-token: write 14 | packages: read 15 | 16 | jobs: 17 | # validation to assure that we should in fact continue with the release should 18 | # be done here. the primary reason for this step is to verify that the release 19 | # was started correctly by pushing a `release-X.Y.Z` tag rather than `X.Y.Z`. 20 | pre-artefact-creation: 21 | name: Tasks to run before artefact creation 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Checkout main 25 | uses: actions/checkout@v4.1.1 26 | with: 27 | ref: "main" 28 | token: ${{ secrets.RELEASE_TOKEN }} 29 | - name: Validate CHANGELOG 30 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 31 | with: 32 | entrypoint: pre-artefact-changelog-check 33 | 34 | generate-documentation: 35 | name: Generate documentation for release 36 | environment: 37 | name: github-pages 38 | url: ${{ steps.deployment.outputs.page_url }} 39 | runs-on: ubuntu-latest 40 | needs: 41 | - pre-artefact-creation 42 | container: 43 | image: ghcr.io/ponylang/library-documentation-action-v2-insiders:release 44 | steps: 45 | - name: Checkout 46 | uses: actions/checkout@v4.1.1 47 | with: 48 | ref: "main" 49 | token: ${{ secrets.RELEASE_TOKEN }} 50 | - name: Generate documentation 51 | run: /entrypoint.py 52 | env: 53 | INPUT_SITE_URL: "https://ponylang.github.io/pony_language_server/" 54 | INPUT_LIBRARY_NAME: "lsp" 55 | INPUT_DOCS_BUILD_DIR: "build/lsp-docs" 56 | - name: Setup Pages 57 | uses: actions/configure-pages@v2 58 | - name: Upload artifact 59 | uses: actions/upload-pages-artifact@v1 60 | with: 61 | path: 'build/lsp-docs/site/' 62 | - name: Deploy to GitHub Pages 63 | id: deployment 64 | uses: actions/deploy-pages@v1 65 | 66 | trigger-release-announcement: 67 | name: Trigger release announcement 68 | runs-on: ubuntu-latest 69 | needs: 70 | - generate-documentation 71 | steps: 72 | - uses: actions/checkout@v4.1.1 73 | with: 74 | ref: "main" 75 | token: ${{ secrets.RELEASE_TOKEN }} 76 | - name: Trigger 77 | uses: docker://ghcr.io/ponylang/release-bot-action:0.6.3 78 | with: 79 | entrypoint: trigger-release-announcement 80 | env: 81 | GIT_USER_NAME: "Ponylang Main Bot" 82 | GIT_USER_EMAIL: "ponylang.main@gmail.com" 83 | -------------------------------------------------------------------------------- /.github/workflows/remove-discuss-during-sync.yml: -------------------------------------------------------------------------------- 1 | name: Remove discuss during sync label 2 | 3 | on: 4 | issues: 5 | types: 6 | - closed 7 | pull_request_target: 8 | types: 9 | - closed 10 | 11 | jobs: 12 | remove-label: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Remove label 16 | uses: andymckay/labeler@467347716a3bdbca7f277cb6cd5fa9c5205c5412 17 | with: 18 | repo-token: ${{ secrets.PONYLANG_MAIN_API_TOKEN }} 19 | remove-labels: "discuss during sync" 20 | -------------------------------------------------------------------------------- /.markdownlintignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | .release-notes/ 3 | -------------------------------------------------------------------------------- /.release-notes/0.2.1.md: -------------------------------------------------------------------------------- 1 | ## Fix resolving definition for implicit create sugar 2 | 3 | Previously constructs like the right hand side of this expression: `let foo = Bar` couldn't be resolved properly although they are widely used in Pony. The issue was that the simple identifier `Bar` get desugared to `Bar.create()` with all AST nodes at the same position, which confused the LSP. 4 | 5 | -------------------------------------------------------------------------------- /.release-notes/0.2.2.md: -------------------------------------------------------------------------------- 1 | ## Fix textDocumentSync server capability 2 | 3 | Previously the `textDocumentSync` property was malformed and not according to spec. 4 | It seemed vscode did the right thing and fell back to sending both `didChange` and `didSave` notifications anyways. 5 | Neovim didn't, so we didn't receive any `didSave` notifications. Now everything is working as expected with neovim and vscode. 6 | 7 | -------------------------------------------------------------------------------- /.release-notes/next-release.md: -------------------------------------------------------------------------------- 1 | ## Fix workspace discovery of folders without corral.json 2 | 3 | Now every folder not inside a folder having a `corral.json`, but with a `main.pony` is now properly discovered 4 | as a workspace by the language server. A workspace is a sub-project inside the folder opened in the editor. 5 | The Pony language server can only work with folders marked as workspaces. 6 | 7 | ## Properly discover all packages of a program 8 | 9 | Previously the Language server was only discovering packages mentioned in `corral.json` as packages and dependencies. Now it is considering all packages being part of a program and creating internal data-structures for them. `corral.json` is now only used for discovery of workspaces and populating the programs dependencies. 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "name": "Launch Client", 9 | "runtimeExecutable": "${execPath}", 10 | "args": [ 11 | "--extensionDevelopmentPath=${workspaceRoot}/client_vscode" 12 | ], 13 | "outFiles": [ 14 | "${workspaceRoot}/client_vscode/out/**/*.js" 15 | ], 16 | "autoAttachChildProcesses": true, 17 | "sourceMaps": true, 18 | "preLaunchTask": "build" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "pass.h": "c", 4 | "package.h": "c" 5 | }, 6 | "cmake.sourceDirectory": "${workspaceFolder}/ponyc" 7 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "bash", 7 | "args": ["build.sh"], 8 | "type": "shell" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a CHANGELOG](http://keepachangelog.com/). 4 | 5 | ## [unreleased] - unreleased 6 | 7 | ### Fixed 8 | 9 | - Fixed workspace discovery of folders without `corral.json` but containing a `main.pony` file ([PR #9](https://github.com/ponylang/pony-language-server/pull/9)) 10 | - Properly discover all packages in a program, not only the packages and dependencies provided in `corral.json` ([PR #8](https://github.com/ponylang/pony-language-server/pull/9)) 11 | 12 | ### Added 13 | 14 | ### Changed 15 | 16 | ## [0.2.2] - 2024-07-27 17 | 18 | ### Fixed 19 | 20 | - Properly set textDocumentSync properties of the serverCapabilities ([PR #7](https://github.com/ponylang/pony-language-server/pull/7)) 21 | 22 | ## [0.2.1] - 2024-06-24 23 | 24 | ### Fixed 25 | 26 | - Upgrade pony-ast dependency to 0.2.1 ([PR #1](https://github.com/ponylang/pony-language-server/pull/1)) 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pagar.me Pagamentos S/A 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | config ?= release 2 | 3 | PACKAGE := lsp 4 | GET_DEPENDENCIES_WITH := corral fetch 5 | CLEAN_DEPENDENCIES_WITH := corral clean 6 | PONYC ?= ponyc 7 | COMPILE_WITH := corral run -- $(PONYC) 8 | 9 | 10 | BUILD_DIR ?= build/$(config) 11 | SRC_DIR ?= $(PACKAGE) 12 | TEST_SRC_DIR ?= $(PACKAGE)/test 13 | binary := $(BUILD_DIR)/pony-lsp 14 | tests_binary := $(BUILD_DIR)/test 15 | docs_dir := build/$(BUNDLE)-docs 16 | 17 | ifdef config 18 | ifeq (,$(filter $(config),debug release)) 19 | $(error Unknown configuration "$(config)") 20 | endif 21 | endif 22 | 23 | PONYC ?= ponyc 24 | 25 | ifeq ($(config),release) 26 | PONYC := $(COMPILE_WITH) 27 | else 28 | PONYC := $(COMPILE_WITH) --debug 29 | endif 30 | 31 | ifneq ($(arch),) 32 | arch_arg := --cpu $(arch) 33 | endif 34 | 35 | SOURCE_FILES := $(shell find $(SRC_DIR) -name *.pony) 36 | 37 | all: language_server test vscode_extension 38 | 39 | language_server: $(binary) 40 | 41 | vscode_extension: language_server 42 | $(MAKE) -C client_vscode 43 | 44 | test: $(tests_binary) 45 | $^ --exclude=integration 46 | 47 | $(tests_binary): $(SOURCE_FILES) | $(BUILD_DIR) 48 | $(GET_DEPENDENCIES_WITH) 49 | $(PONYC) -o $(BUILD_DIR) --bin-name $(notdir $(tests_binary)) $(TEST_SRC_DIR) 50 | 51 | $(binary): $(SOURCE_FILES) | $(BUILD_DIR) 52 | $(GET_DEPENDENCIES_WITH) 53 | $(PONYC) -o $(BUILD_DIR) --bin-name $(notdir $(binary)) $(SRC_DIR) 54 | 55 | clean: 56 | $(CLEAN_DEPENDENCIES_WITH) 57 | rm -rf $(BUILD_DIR) 58 | $(MAKE) -C client_vscode clean 59 | 60 | $(docs_dir): $(SOURCE_FILES) 61 | rm -rf $(docs_dir) 62 | $(GET_DEPENDENCIES_WITH) 63 | $(PONYC) --docs-public --pass=docs --output build $(SRC_DIR) 64 | 65 | docs: $(docs_dir) 66 | 67 | .coverage: 68 | mkdir -p .coverage 69 | 70 | coverage: .coverage $(tests_binary) 71 | kcov --include-pattern="$(SRC_DIR)" --exclude-pattern="*/test/*.pony,*/_test.pony" .coverage $(tests_binary) 72 | 73 | TAGS: 74 | ctags --recurse=yes $(SRC_DIR) 75 | 76 | 77 | $(BUILD_DIR): 78 | mkdir -p $(BUILD_DIR) 79 | 80 | .PHONY: all clean TAGS test 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pony Language Server 2 | 3 | Language server for Pony. For more information see the [Language Server Standard](https://github.com/Microsoft/language-server-protocol). 4 | 5 | --- 6 | 7 | ## Structure 8 | 9 | The language server is started as a separate actor, 10 | which is given a channel for communication with the language-server client. 11 | After initialization it starts one actor for each workspace it is invoked for 12 | and routes requests to one of those workspace actors. 13 | They implement the actual LSP logic. 14 | It is also those actors that invoke the compiler actor, 15 | which executes a subset of the pony compiler passes in-process 16 | in order to get an AST to do LSP analysis on. 17 | 18 | --- 19 | 20 | ## Extensions 21 | 22 | The VSCode extension resides in the folder `client_vscode`. 23 | 24 | --- 25 | 26 | ## Development 27 | 28 | - Build ponyc: `cd ponyc`, `make libs`, `make configure`, `make build` 29 | 30 | - Prepare VSCode extension: `cd client_vscode`, `npm i` 31 | 32 | - To debug in VSCode, press `F5`, this will compile both the vscode extension 33 | in the client folder and the pony server, using the `build.sh` script. 34 | 35 | If pony compilation fails, the process will stop, so you can press `F5` without fear. 36 | 37 | --- 38 | 39 | ## Creating the Language Server binary 40 | 41 | To compile the binary in release mode: 42 | 43 | ```sh 44 | make language_server 45 | ``` 46 | 47 | In order to compile the language server in `debug` mode, 48 | set the `config` variable to `debug`: 49 | 50 | ```sh 51 | make config=debug language_server 52 | ``` 53 | 54 | ## Creating the VSCode extension 55 | 56 | ```sh 57 | make vscode_extension 58 | ``` 59 | 60 | This will create the extension package as a `.vsix` file 61 | in the `build/release` folder. E.g. `build/release/pony-lsp-0.58.4.vsix`. 62 | 63 | ## Installing the VSCode extension 64 | 65 | ```sh 66 | code --uninstall-extension undefined_publisher.pony-lsp 67 | code --install-extension build/release/pony-lsp-0.58.4.vsix 68 | ``` 69 | 70 | Check the actual folder and version of the extension being built. 71 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.2.2 2 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # prepare environment 3 | set -ex 4 | 5 | make 6 | -------------------------------------------------------------------------------- /build_ci.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | Set-Location $Env:GITHUB_WORKSPACE 3 | # install ponyup 4 | Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/ponylang/ponyup/latest-release/ponyup-init.ps1' -Outfile ponyup-init.ps1 5 | .\ponyup-init.ps1 6 | ponyup update ponyc release-$Env:PONY_VERSION 7 | ponyup update corral release 8 | Set-Location ponyc 9 | git fetch origin 10 | git checkout tags/$Env:PONY_VERSION 11 | Set-Location $Env:GITHUB_WORKSPACE 12 | corral fetch 13 | corral run -- ponyc --bin-name pony-lsp -o client_vscode lsp 14 | Copy-Item pony-lsp client_vscode 15 | Copy-Item -force -r ponyc/packages client_vscode 16 | Set-Location $Env:GITHUB_WORKSPACE/client_vscode 17 | # compile the extension 18 | npm i 19 | npm i -g vsce 20 | npm run compile 21 | vsce package -------------------------------------------------------------------------------- /build_ci.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | sudo apt update && sudo apt install gcc -y 3 | # SCRIPT 4 | set -e 5 | set -x 6 | export SHELL=/bin/bash 7 | # Linux 8 | export PATH=/home/runner/.local/share/ponyup/bin:$PATH 9 | # MacOS 10 | export PATH=/Users/runner/.local/share/ponyup/bin:$PATH 11 | sh -c "$(curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ponylang/ponyup/latest-release/ponyup-init.sh)" 12 | 13 | ponyup update corral release 14 | 15 | function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; } 16 | 17 | git clone https://github.com/ponylang/ponyc.git ponyc-repo 18 | cd ponyc-repo && git fetch --all --tags 19 | 20 | for PONY_VERSION in $(git tag); do 21 | if [ "$(version "$PONY_VERSION")" -ge "$(version "0.54.0")" ]; then 22 | echo "Building with ponyc version: $PONY_VERSION" 23 | ponyup update ponyc "release-$PONY_VERSION" 24 | # copy stdlib to extension 25 | git checkout tags/"$PONY_VERSION" 26 | cd "$GITHUB_WORKSPACE" && cp -r ponyc-repo/packages client_vscode 27 | # build pony-lsp 28 | cd "$GITHUB_WORKSPACE" 29 | corral fetch 30 | corral run -- ponyc --bin-name pony-lsp lsp 31 | cp pony-lsp client_vscode 32 | # compile the extension 33 | cd "$GITHUB_WORKSPACE/client_vscode" 34 | npm i 35 | npm i -g vsce 36 | npm run compile 37 | vsce package "$PONY_VERSION" 38 | else 39 | echo "Only versions greater than 0.54.0 are supported. Discarding $PONY_VERSION" 40 | fi 41 | done 42 | -------------------------------------------------------------------------------- /client_vscode/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules 3 | src/ 4 | tsconfig.json 5 | -------------------------------------------------------------------------------- /client_vscode/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pagar.me Pagamentos S/A 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /client_vscode/Makefile: -------------------------------------------------------------------------------- 1 | PONY_VERSION := 0.58.4 2 | 3 | config ?= release 4 | ifdef config 5 | ifeq (,$(filter $(config),debug release)) 6 | $(error Unknown configuration "$(config)") 7 | endif 8 | endif 9 | 10 | 11 | BUILD_DIR := ../build/$(config) 12 | DIST_DIR := dist 13 | SRC_DIR := src 14 | EXTENSION_JS := $(DIST_DIR)/extension.js 15 | EXTENSION := $(BUILD_DIR)/pony-lsp-$(PONY_VERSION).vsix 16 | SOURCE_FILES := $(shell find $(SRC_DIR) -name *.ts) 17 | 18 | all: $(EXTENSION) 19 | 20 | $(EXTENSION): $(SOURCE_FILES) pony-lsp node_modules 21 | vsce package -o $(BUILD_DIR) $(PONY_VERSION) 22 | 23 | node_modules: 24 | npm install 25 | 26 | pony-lsp: $(BUILD_DIR)/pony-lsp 27 | cp $(BUILD_DIR)/pony-lsp pony-lsp 28 | 29 | $(BUILD_DIR)/pony-lsp: 30 | $(MAKE) -C .. 31 | 32 | clean: 33 | rm -rf dist $(BUILD_DIR) 34 | 35 | 36 | .PHONY: clean 37 | -------------------------------------------------------------------------------- /client_vscode/README.md: -------------------------------------------------------------------------------- 1 | # Ponylang Language Server Client for VS-Code 2 | 3 | ## How to Build 4 | 5 | ```bash 6 | # compile the code 7 | $ npm install 8 | $ npm run compile 9 | # build the package 10 | $ vsce package 11 | # uninstall any previously installed packages 12 | $ code --uninstall-extension undefined_publisher.pony-lsp 13 | # install the package 14 | $ code --install-extension pony-lsp-.vsix 15 | ``` 16 | -------------------------------------------------------------------------------- /client_vscode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | ["{", "}"], 17 | ["[", "]"], 18 | ["(", ")"], 19 | ["\"", "\""], 20 | ["'", "'"] 21 | ], 22 | // symbols that that can be used to surround a selection 23 | "surroundingPairs": [ 24 | ["{", "}"], 25 | ["[", "]"], 26 | ["(", ")"], 27 | ["\"", "\""], 28 | ["'", "'"] 29 | ] 30 | } -------------------------------------------------------------------------------- /client_vscode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pony-lsp", 3 | "description": "Ponylang Language Server", 4 | "license": "MIT", 5 | "version": "0.58.4", 6 | "categories": [], 7 | "repository": "https://github.com/ponylang/pony-language-server", 8 | "publisher": "ponylang", 9 | "displayName": "Ponylang Language Server", 10 | "engines": { 11 | "vscode": "^1.75.0" 12 | }, 13 | "activationEvents": [ 14 | "onLanguage:pony" 15 | ], 16 | "main": "./dist/extension", 17 | "contributes": { 18 | "configuration": { 19 | "type": "object", 20 | "title": "Pony configuration", 21 | "properties": { 22 | "pony.trace.server": { 23 | "scope": "window", 24 | "type": "string", 25 | "enum": [ 26 | "off", 27 | "messages", 28 | "verbose" 29 | ], 30 | "default": "off", 31 | "description": "Traces the communication between VS Code and the Pony language server." 32 | } 33 | } 34 | }, 35 | "languages": [ 36 | { 37 | "id": "pony", 38 | "aliases": [ 39 | "Pony", 40 | "pony" 41 | ], 42 | "filenames": [ 43 | "corral.json" 44 | ], 45 | "extensions": [ 46 | ".pony" 47 | ], 48 | "configuration": "./language-configuration.json" 49 | } 50 | ], 51 | "grammars": [ 52 | { 53 | "language": "pony", 54 | "scopeName": "source.pony", 55 | "path": "./pony.tmLanguage" 56 | } 57 | ] 58 | }, 59 | "scripts": { 60 | "vscode:prepublish": "webpack --mode production", 61 | "compile": "webpack --mode none", 62 | "watch": "webpack --mode none --watch" 63 | }, 64 | "devDependencies": { 65 | "@types/bluebird": "^3.5.32", 66 | "@types/mocha": "^9.1.0", 67 | "@types/node": "^16.18.93", 68 | "@types/vscode": "^1.75.0", 69 | "@types/which": "^2.0.1", 70 | "ts-loader": "^9.5.1", 71 | "typescript": "^4.8.4", 72 | "webpack": "^5.94.0", 73 | "webpack-cli": "^5.1.4" 74 | }, 75 | "dependencies": { 76 | "vscode-languageclient": "^9.0.1" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /client_vscode/packages/assert/assert.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Assert package 3 | 4 | Contains runtime assertions. If you are looking for assertion that only run 5 | when your code was compiled with the `debug` flag, check out `Assert`. For 6 | assertions that are always enabled, check out `Fact`. 7 | """ 8 | 9 | use @pony_os_stderr[Pointer[U8]]() 10 | use @fprintf[I32](stream: Pointer[U8] tag, fmt: Pointer[U8] tag, ...) 11 | 12 | primitive Assert 13 | """ 14 | This is a debug only assertion. If the test is false, it will print any 15 | supplied error message to stderr and raise an error. 16 | """ 17 | fun apply(test: Bool, msg: String = "") ? => 18 | ifdef debug then 19 | Fact(test, msg)? 20 | end 21 | 22 | primitive Fact 23 | """ 24 | This is an assertion that is always enabled. If the test is false, it will 25 | print any supplied error message to stderr and raise an error. 26 | """ 27 | fun apply(test: Bool, msg: String = "") ? => 28 | if not test then 29 | if msg.size() > 0 then 30 | @fprintf(@pony_os_stderr(), "%s\n".cstring(), msg.cstring()) 31 | end 32 | error 33 | end 34 | -------------------------------------------------------------------------------- /client_vscode/packages/backpressure/auth.pony: -------------------------------------------------------------------------------- 1 | primitive ApplyReleaseBackpressureAuth 2 | new create(from: AmbientAuth) => 3 | None 4 | -------------------------------------------------------------------------------- /client_vscode/packages/buffered/buffered.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Buffered Package 3 | 4 | The Buffered package provides two classes, `Writer` and `Reader`, for 5 | writing and reading messages using common encodings. These classes are 6 | useful when dealing with things like network data and binary file 7 | formats. 8 | 9 | ## Example program 10 | 11 | ```pony 12 | use "buffered" 13 | 14 | actor Main 15 | new create(env: Env) => 16 | let reader = Reader 17 | let writer = Writer 18 | 19 | writer.u32_be(42) 20 | writer.f32_be(3.14) 21 | 22 | let b = recover iso Array[U8] end 23 | 24 | for chunk in writer.done().values() do 25 | b.append(chunk) 26 | end 27 | 28 | reader.append(consume b) 29 | 30 | try 31 | env.out.print(reader.u32_be()?.string()) // prints 42 32 | env.out.print(reader.f32_be()?.string()) // prints 3.14 33 | end 34 | ``` 35 | """ 36 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/_to_string.pony: -------------------------------------------------------------------------------- 1 | use @snprintf[I32](str: Pointer[U8] tag, size: USize, fmt: Pointer[U8] tag, ...) 2 | if not windows 3 | use @_snprintf[I32](str: Pointer[U8] tag, count: USize, fmt: Pointer[U8] tag, ...) 4 | if windows 5 | 6 | primitive _ToString 7 | """ 8 | Worker type providing simple to string conversions for numbers. 9 | """ 10 | fun _u64(x: U64, neg: Bool): String iso^ => 11 | let table = "0123456789" 12 | let base: U64 = 10 13 | 14 | recover 15 | var s = String(31) 16 | var value = x 17 | 18 | try 19 | if value == 0 then 20 | s.push(table(0)?) 21 | else 22 | while value != 0 do 23 | let index = ((value = value / base) - (value * base)) 24 | s.push(table(index.usize())?) 25 | end 26 | end 27 | end 28 | 29 | if neg then s.push('-') end 30 | s .> reverse_in_place() 31 | end 32 | 33 | fun _u128(x: U128, neg: Bool): String iso^ => 34 | let table = "0123456789" 35 | let base: U128 = 10 36 | 37 | recover 38 | var s = String(31) 39 | var value = x 40 | 41 | try 42 | if value == 0 then 43 | s.push(table(0)?) 44 | else 45 | while value != 0 do 46 | let index = (value = value / base) - (value * base) 47 | s.push(table(index.usize())?) 48 | end 49 | end 50 | end 51 | 52 | if neg then s.push('-') end 53 | s .> reverse_in_place() 54 | end 55 | 56 | fun _f64(x: F64): String iso^ => 57 | recover 58 | var s = String(31) 59 | var f = String(31) .> append("%g") 60 | 61 | ifdef windows then 62 | @_snprintf(s.cstring(), s.space(), f.cstring(), x) 63 | else 64 | @snprintf(s.cstring(), s.space(), f.cstring(), x) 65 | end 66 | 67 | s .> recalc() 68 | end 69 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/ambient_auth.pony: -------------------------------------------------------------------------------- 1 | primitive AmbientAuth 2 | """ 3 | This type represents the root capability. When a Pony program starts, the 4 | Env passed to the Main actor contains an instance of the root capability. 5 | 6 | Ambient access to the root capability is denied outside of the builtin 7 | package. Inside the builtin package, only Env creates a Root. 8 | 9 | The root capability can be used by any package that wants to establish a 10 | principle of least authority. A typical usage is to have a parameter on a 11 | constructor for some resource that expects a limiting capability specific to 12 | the package, but will also accept the root capability as representing 13 | unlimited access. 14 | """ 15 | new _create() => 16 | None 17 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/any.pony: -------------------------------------------------------------------------------- 1 | interface tag Any 2 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/asio_event.pony: -------------------------------------------------------------------------------- 1 | type AsioEventID is Pointer[AsioEvent] tag 2 | 3 | trait tag AsioEventNotify 4 | be _event_notify(event: AsioEventID, flags: U32, arg: U32) 5 | 6 | primitive AsioEvent 7 | """ 8 | Functions for asynchronous event notification. 9 | """ 10 | fun none(): AsioEventID => 11 | """ 12 | An empty event. 13 | """ 14 | AsioEventID 15 | 16 | fun readable(flags: U32): Bool => 17 | """ 18 | Returns true if the flags contain the readable flag. 19 | """ 20 | (flags and (1 << 0)) != 0 21 | 22 | fun writeable(flags: U32): Bool => 23 | """ 24 | Returns true if the flags contain the writeable flag. 25 | """ 26 | (flags and (1 << 1)) != 0 27 | 28 | fun disposable(flags: U32): Bool => 29 | """ 30 | Returns true if the event should be disposed of. 31 | """ 32 | flags == 0 33 | 34 | fun oneshotable(flags: U32): Bool => 35 | """ 36 | Returns true if the flags contain the oneshot flag. 37 | """ 38 | (flags and (1 << 8)) != 0 39 | 40 | fun dispose(): U32 => 0 41 | 42 | fun read(): U32 => 1 << 0 43 | 44 | fun write(): U32 => 1 << 1 45 | 46 | fun timer(): U32 => 1 << 2 47 | 48 | fun signal(): U32 => 1 << 3 49 | 50 | fun read_write(): U32 => read() or write() 51 | 52 | fun oneshot(): U32 => 1 << 8 53 | 54 | fun read_write_oneshot(): U32 => read() or write() or oneshot() 55 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/bool.pony: -------------------------------------------------------------------------------- 1 | primitive Bool is Stringable 2 | new create(from: Bool) => from 3 | 4 | fun eq(y: Bool): Bool => this == y 5 | fun ne(y: Bool): Bool => this != y 6 | fun op_and(y: Bool): Bool => this and y 7 | fun op_or(y: Bool): Bool => this or y 8 | fun op_xor(y: Bool): Bool => this xor y 9 | fun op_not(): Bool => not this 10 | 11 | fun string(): String iso^ => 12 | (if this then "true" else "false" end).string() 13 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/builtin.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Builtin package 3 | 4 | The builtin package is home to the following standard library members: 5 | 6 | 1. Types the compiler needs to know exist, such as None. 7 | 2. Types with "magic" internal workings that must be supplied directly by the 8 | compiler, such as U32. 9 | 3. Any types needed by others in builtin. 10 | 11 | The public types that are defined in this package will always be in scope for 12 | every Pony source file. For details on specific packages, see their individual 13 | entity entries. 14 | """ 15 | 16 | use @pony_ctx[Pointer[None]]() 17 | use @pony_alloc[Pointer[U8]](ctx: Pointer[None], size: USize) 18 | use @pony_alloc_final[Pointer[U8]](ctx: Pointer[None], size: USize) 19 | use @pony_exitcode[None](code: I32) 20 | use @pony_get_exitcode[I32]() 21 | use @pony_triggergc[None](ctx: Pointer[None]) 22 | use @ponyint_hash_block[USize](ptr: Pointer[None] tag, size: USize) 23 | use @ponyint_hash_block64[U64](ptr: Pointer[None] tag, size: USize) 24 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/compare.pony: -------------------------------------------------------------------------------- 1 | primitive Less is Equatable[Compare] 2 | fun string(): String iso^ => 3 | "Less".string() 4 | 5 | primitive Equal is Equatable[Compare] 6 | fun string(): String iso^ => 7 | "Equal".string() 8 | 9 | primitive Greater is Equatable[Compare] 10 | fun string(): String iso^ => 11 | "Greater".string() 12 | 13 | type Compare is (Less | Equal | Greater) 14 | 15 | interface HasEq[A] 16 | fun eq(that: box->A): Bool 17 | 18 | interface Equatable[A: Equatable[A] #read] 19 | fun eq(that: box->A): Bool => this is that 20 | fun ne(that: box->A): Bool => not eq(that) 21 | 22 | interface Comparable[A: Comparable[A] #read] is Equatable[A] 23 | fun lt(that: box->A): Bool 24 | fun le(that: box->A): Bool => lt(that) or eq(that) 25 | fun ge(that: box->A): Bool => not lt(that) 26 | fun gt(that: box->A): Bool => not le(that) 27 | 28 | fun compare(that: box->A): Compare => 29 | if eq(that) then 30 | Equal 31 | elseif lt(that) then 32 | Less 33 | else 34 | Greater 35 | end 36 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/disposable_actor.pony: -------------------------------------------------------------------------------- 1 | interface tag DisposableActor 2 | """ 3 | An interface used to asynchronously dispose of an actor. 4 | """ 5 | be dispose() 6 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/do_not_optimise.pony: -------------------------------------------------------------------------------- 1 | primitive DoNotOptimise 2 | """ 3 | Contains functions preventing some compiler optimisations, namely dead code 4 | removal. This is useful for benchmarking purposes. 5 | """ 6 | 7 | fun apply[A](obj: A) => 8 | """ 9 | Prevent the compiler from optimising out obj and any computation it is 10 | derived from. This doesn't prevent constant propagation. 11 | """ 12 | compile_intrinsic 13 | 14 | fun observe() => 15 | """ 16 | Prevent the compiler from optimising out writes to an object marked by 17 | the apply function. 18 | """ 19 | compile_intrinsic 20 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/env.pony: -------------------------------------------------------------------------------- 1 | use @pony_os_stdin_setup[Bool]() 2 | use @pony_os_stdout_setup[None]() 3 | 4 | class val Env 5 | """ 6 | An environment holds the command line and other values injected into the 7 | program by default by the runtime. 8 | """ 9 | let root: AmbientAuth 10 | """ 11 | The root capability. 12 | """ 13 | 14 | let input: InputStream 15 | """ 16 | Stdin represented as an actor. 17 | """ 18 | 19 | let out: OutStream 20 | """Stdout""" 21 | 22 | let err: OutStream 23 | """Stderr""" 24 | 25 | let args: Array[String] val 26 | """The command line used to start the program.""" 27 | 28 | let vars: Array[String] val 29 | """The program's environment variables.""" 30 | 31 | let exitcode: {(I32)} val 32 | """ 33 | Sets the environment's exit code. The exit code of the root environment will 34 | be the exit code of the application, which defaults to 0. 35 | """ 36 | 37 | new _create( 38 | argc: U32, 39 | argv: Pointer[Pointer[U8]] val, 40 | envp: Pointer[Pointer[U8]] val) 41 | => 42 | """ 43 | Builds an environment from the command line. This is done before the Main 44 | actor is created. 45 | """ 46 | root = AmbientAuth._create() 47 | @pony_os_stdout_setup() 48 | 49 | input = Stdin._create(@pony_os_stdin_setup()) 50 | out = StdStream._out() 51 | err = StdStream._err() 52 | 53 | args = _strings_from_pointers(argv, argc.usize()) 54 | vars = _strings_from_pointers(envp, _count_strings(envp)) 55 | 56 | exitcode = {(code: I32) => @pony_exitcode(code) } 57 | 58 | new val create( 59 | root': AmbientAuth, 60 | input': InputStream, out': OutStream, 61 | err': OutStream, args': Array[String] val, 62 | vars': Array[String] val, 63 | exitcode': {(I32)} val) 64 | => 65 | """ 66 | Build an artificial environment. A root capability must be supplied. 67 | """ 68 | root = root' 69 | input = input' 70 | out = out' 71 | err = err' 72 | args = args' 73 | vars = vars' 74 | exitcode = exitcode' 75 | 76 | fun tag _count_strings(data: Pointer[Pointer[U8]] val): USize => 77 | if data.is_null() then 78 | return 0 79 | end 80 | 81 | var i: USize = 0 82 | 83 | while 84 | let entry = data._apply(i) 85 | not entry.is_null() 86 | do 87 | i = i + 1 88 | end 89 | i 90 | 91 | fun tag _strings_from_pointers( 92 | data: Pointer[Pointer[U8]] val, 93 | len: USize) 94 | : Array[String] iso^ 95 | => 96 | let array = recover Array[String](len) end 97 | var i: USize = 0 98 | 99 | while i < len do 100 | let entry = data._apply(i = i + 1) 101 | array.push(recover String.copy_cstring(entry) end) 102 | end 103 | 104 | array 105 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/iterator.pony: -------------------------------------------------------------------------------- 1 | interface Iterator[A] 2 | """ 3 | 4 | Iterators generate a series of values, one value at a time on each call to `next()`. 5 | 6 | An Iterator is considered exhausted, once its `has_next()` method returns `false`. 7 | Thus every call to `next()` should be preceeded with a call to `has_next()` to 8 | check for exhaustiveness. 9 | 10 | ## Usage 11 | 12 | Given the rules for using Iterators mentioned above, basic usage 13 | of an iterator looks like this: 14 | 15 | ```pony 16 | while iterator.has_next() do 17 | let elem = iterator.next()? 18 | // do something with elem 19 | end 20 | ``` 21 | 22 | The `For`-loop provides a more concise way of iteration: 23 | 24 | ```pony 25 | for elem in iterator do 26 | // do something with elem 27 | end 28 | ``` 29 | 30 | Iteration using `While` is more flexible as it allows to continue iterating if a call to `next()` errors. 31 | The `For`-loop does not allow this. 32 | 33 | ## Implementing Iterators 34 | 35 | Iterator implementations need to adhere to the following rules to be considered well-behaved: 36 | 37 | * If the Iterator is exhausted, `has_next()` needs to return `false`. 38 | * Once `has_next()` returned `false` it is not allowed to switch back to `true` 39 | (Unless the Iterator supports rewinding) 40 | * `has_next()` does not change its returned value if `next()` has not been called. 41 | That means, that between two calls to `next()` any number of calls to `has_next()` 42 | need to return the same value. (Unless the Iterator supports rewinding) 43 | * A call to `next()` erroring does not necessarily denote exhaustiveness. 44 | 45 | ### Example 46 | 47 | ```pony 48 | // Generates values from `from` to 0 49 | class ref Countdown is Iterator[USize] 50 | var _cur: USize 51 | var _has_next: Bool = true 52 | 53 | new ref create(from: USize) => 54 | _cur = from 55 | 56 | fun ref has_next(): Bool => 57 | _has_next 58 | 59 | fun ref next(): USize => 60 | let elem = _cur = _cur - 1 61 | if elem == 0 then 62 | _has_next = false 63 | end 64 | elem 65 | ``` 66 | 67 | """ 68 | 69 | fun ref has_next(): Bool 70 | """ 71 | Returns `true` if this Iterator is not yet exhausted. 72 | That means that a value returned from a subsequent call to `next()` 73 | is a valid part of this iterator. 74 | 75 | Returns `false` if this Iterator is exhausted. 76 | 77 | The behavior of `next()` after this function returned `false` is undefined, 78 | it might throw an error or return values which are not part of this Iterator. 79 | """ 80 | 81 | fun ref next(): A ? 82 | """ 83 | Generate the next value. 84 | 85 | This might error, which does not necessarily mean that the Iterator is exhausted. 86 | """ 87 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/none.pony: -------------------------------------------------------------------------------- 1 | primitive None is Stringable 2 | fun string(): String iso^ => 3 | "None".string() 4 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/nullable_pointer.pony: -------------------------------------------------------------------------------- 1 | struct NullablePointer[A] 2 | """ 3 | A NullablePointer[A] is used to encode a possibly-null type. It should 4 | _only_ be used for structs that need to be passed to and from the C FFI. 5 | 6 | An optional type for anything that isn't a struct should be encoded as a 7 | union type, for example (A | None). 8 | """ 9 | new create(that: A) => 10 | """ 11 | This re-encodes the type of `that` from A to NullablePointer[A], allowing 12 | `that` to be assigned to a field or variable of type NullablePointer[A]. It 13 | doesn't allocate a wrapper object: there is no containing object for `that`. 14 | """ 15 | compile_intrinsic 16 | 17 | new none() => 18 | """ 19 | This returns a null pointer typed as a NullablePointer[A]. 20 | """ 21 | compile_intrinsic 22 | 23 | fun apply(): this->A ? => 24 | """ 25 | This re-encodes the type of `this` from NullablePointer[A] to A, allowing 26 | `this` to be assigned to a field of variable of type A. If `this` is a null 27 | pointer, an error is raised. 28 | """ 29 | compile_intrinsic 30 | 31 | fun is_none(): Bool => 32 | """ 33 | Returns true if `this` is null (ie apply would raise an error). 34 | """ 35 | compile_intrinsic 36 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/platform.pony: -------------------------------------------------------------------------------- 1 | primitive Platform 2 | fun bsd(): Bool => freebsd() or dragonfly() or openbsd() 3 | fun freebsd(): Bool => compile_intrinsic 4 | fun dragonfly(): Bool => compile_intrinsic 5 | fun openbsd(): Bool => compile_intrinsic 6 | fun linux(): Bool => compile_intrinsic 7 | fun osx(): Bool => compile_intrinsic 8 | fun posix(): Bool => bsd() or linux() or osx() 9 | fun windows(): Bool => compile_intrinsic 10 | 11 | fun x86(): Bool => compile_intrinsic 12 | fun arm(): Bool => compile_intrinsic 13 | fun riscv(): Bool => compile_intrinsic 14 | 15 | fun lp64(): Bool => compile_intrinsic 16 | fun llp64(): Bool => compile_intrinsic 17 | fun ilp32(): Bool => compile_intrinsic 18 | 19 | fun bigendian(): Bool => compile_intrinsic 20 | fun littleendian(): Bool => compile_intrinsic 21 | 22 | fun native128(): Bool => compile_intrinsic 23 | fun debug(): Bool => compile_intrinsic 24 | fun runtimestats(): Bool => compile_intrinsic 25 | fun runtimestatsmessages(): Bool => compile_intrinsic 26 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/read_seq.pony: -------------------------------------------------------------------------------- 1 | interface box ReadSeq[A] 2 | """ 3 | The readable interface of a sequence. 4 | """ 5 | fun size(): USize 6 | """ 7 | Returns the number of elements in the sequence. 8 | """ 9 | 10 | fun apply(i: USize): this->A ? 11 | """ 12 | Returns the i-th element of the sequence. Raises an error if the index 13 | is out of bounds. Note that this returns this->A, not A. 14 | """ 15 | 16 | fun values(): Iterator[this->A]^ 17 | """ 18 | Returns an iterator over the elements of the sequence. Note that this 19 | iterates over this->A, not A. 20 | """ 21 | 22 | interface box ReadElement[A] 23 | """ 24 | Used to show that a ReadSeq can return an element of a specific unmodified 25 | type. 26 | """ 27 | fun apply(i: USize): A ? 28 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/seq.pony: -------------------------------------------------------------------------------- 1 | interface Seq[A] 2 | """ 3 | A sequence of elements. 4 | """ 5 | new create(len: USize = 0) 6 | """ 7 | Create a sequence, reserving space for len elements. 8 | """ 9 | 10 | fun ref reserve(len: USize) 11 | """ 12 | Reserve space for len elements. 13 | """ 14 | 15 | fun size(): USize 16 | """ 17 | Returns the number of elements in the sequence. 18 | """ 19 | 20 | fun apply(i: USize): this->A ? 21 | """ 22 | Returns the i-th element of the sequence. Raises an error if the index 23 | is out of bounds. 24 | """ 25 | 26 | fun ref update(i: USize, value: A): A^ ? 27 | """ 28 | Replaces the i-th element of the sequence. Returns the previous value. 29 | Raises an error if the index is out of bounds. 30 | """ 31 | 32 | fun ref clear() 33 | """ 34 | Removes all elements from the sequence. 35 | """ 36 | 37 | fun ref push(value: A) 38 | """ 39 | Adds an element to the end of the sequence. 40 | """ 41 | 42 | fun ref pop(): A^ ? 43 | """ 44 | Removes an element from the end of the sequence. 45 | """ 46 | 47 | fun ref unshift(value: A) 48 | """ 49 | Adds an element to the beginning of the sequence. 50 | """ 51 | 52 | fun ref shift(): A^ ? 53 | """ 54 | Removes an element from the beginning of the sequence. 55 | """ 56 | 57 | fun ref append( 58 | seq: (ReadSeq[A] & ReadElement[A^]), 59 | offset: USize = 0, 60 | len: USize = -1) 61 | """ 62 | Add len elements to the end of the list, starting from the given 63 | offset. 64 | """ 65 | 66 | fun ref concat(iter: Iterator[A^], offset: USize = 0, len: USize = -1) 67 | """ 68 | Add len iterated elements to the end of the list, starting from the given 69 | offset. 70 | """ 71 | 72 | fun ref truncate(len: USize) 73 | """ 74 | Truncate the sequence to the given length, discarding excess elements. 75 | If the sequence is already smaller than len, do nothing. 76 | """ 77 | 78 | fun values(): Iterator[this->A]^ 79 | """ 80 | Returns an iterator over the elements of the sequence. 81 | """ 82 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/source_loc.pony: -------------------------------------------------------------------------------- 1 | interface val SourceLoc 2 | """ 3 | Represents a location in a Pony source file, as reported by `__loc`. 4 | """ 5 | fun file(): String 6 | """ 7 | Name and path of source file. 8 | """ 9 | 10 | fun type_name(): String 11 | """ 12 | Name of nearest class, actor, primitive, struct, interface, or trait. 13 | """ 14 | 15 | fun method_name(): String 16 | """ 17 | Name of containing method. 18 | """ 19 | 20 | fun line(): USize 21 | """ 22 | Line number within file. 23 | Line numbers start at 1. 24 | """ 25 | 26 | fun pos(): USize 27 | """ 28 | Character position on line. 29 | Character positions start at 1. 30 | """ 31 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/std_stream.pony: -------------------------------------------------------------------------------- 1 | use @pony_os_stdout[Pointer[U8]]() 2 | use @pony_os_stderr[Pointer[U8]]() 3 | use @pony_os_std_flush[None](file: Pointer[None] tag) 4 | use @pony_os_std_print[None](file: Pointer[None] tag, buffer: Pointer[U8] tag, 5 | size: USize) 6 | use @pony_os_std_write[None](file: Pointer[None] tag, buffer: Pointer[U8] tag, 7 | size: USize) 8 | type ByteSeq is (String | Array[U8] val) 9 | 10 | interface val ByteSeqIter 11 | """ 12 | Accept an iterable collection of String or Array[U8] val. 13 | """ 14 | fun values(): Iterator[this->ByteSeq box] 15 | 16 | interface tag OutStream 17 | """ 18 | Asnychronous access to some output stream. 19 | """ 20 | be print(data: ByteSeq) 21 | """ 22 | Print some bytes and insert a newline afterwards. 23 | """ 24 | 25 | be write(data: ByteSeq) 26 | """ 27 | Print some bytes without inserting a newline afterwards. 28 | """ 29 | 30 | be printv(data: ByteSeqIter) 31 | """ 32 | Print an iterable collection of ByteSeqs. 33 | """ 34 | 35 | be writev(data: ByteSeqIter) 36 | """ 37 | Write an iterable collection of ByteSeqs. 38 | """ 39 | 40 | be flush() 41 | """ 42 | Flush the stream. 43 | """ 44 | 45 | actor StdStream 46 | """ 47 | Asynchronous access to stdout and stderr. The constructors are private to 48 | ensure that access is provided only via an environment. 49 | """ 50 | var _stream: Pointer[U8] 51 | 52 | new _out() => 53 | """ 54 | Create an async stream for stdout. 55 | """ 56 | _stream = @pony_os_stdout() 57 | 58 | new _err() => 59 | """ 60 | Create an async stream for stderr. 61 | """ 62 | _stream = @pony_os_stderr() 63 | 64 | be print(data: ByteSeq) => 65 | """ 66 | Print some bytes and insert a newline afterwards. 67 | """ 68 | _print(data) 69 | 70 | be write(data: ByteSeq) => 71 | """ 72 | Print some bytes without inserting a newline afterwards. 73 | """ 74 | _write(data) 75 | 76 | be printv(data: ByteSeqIter) => 77 | """ 78 | Print an iterable collection of ByteSeqs. 79 | """ 80 | for bytes in data.values() do 81 | _print(bytes) 82 | end 83 | 84 | be writev(data: ByteSeqIter) => 85 | """ 86 | Write an iterable collection of ByteSeqs. 87 | """ 88 | for bytes in data.values() do 89 | _write(bytes) 90 | end 91 | 92 | be flush() => 93 | """ 94 | Flush any data out to the os (ignoring failures). 95 | """ 96 | @pony_os_std_flush(_stream) 97 | 98 | fun ref _write(data: ByteSeq) => 99 | """ 100 | Write the bytes without explicitly flushing. 101 | """ 102 | @pony_os_std_write(_stream, data.cpointer(), data.size()) 103 | 104 | fun ref _print(data: ByteSeq) => 105 | """ 106 | Write the bytes and a newline without explicitly flushing. 107 | """ 108 | @pony_os_std_print(_stream, data.cpointer(), data.size()) 109 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin/stringable.pony: -------------------------------------------------------------------------------- 1 | interface box Stringable 2 | """ 3 | Things that can be turned into a String. 4 | """ 5 | fun string(): String iso^ 6 | """ 7 | Generate a string representation of this object. 8 | """ 9 | -------------------------------------------------------------------------------- /client_vscode/packages/builtin_test/_test_valtrace.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | class \nodoc\ iso _TestValtrace is UnitTest 4 | """ 5 | Test val trace optimisation 6 | """ 7 | fun name(): String => "builtin/Valtrace" 8 | 9 | fun apply(h: TestHelper) => 10 | _Valtrace.one(h) 11 | h.long_test(10_000_000_000) // 10 second timeout 12 | 13 | actor \nodoc\ _Valtrace 14 | var count: U32 = 0 15 | 16 | be one(h: TestHelper) => 17 | """ 18 | Create a String iso, send it to a new actor. 19 | """ 20 | @pony_triggergc(@pony_ctx()) 21 | let s = recover String .> append("test") end 22 | _Valtrace.two(this, h, consume s) 23 | 24 | be two(a1: _Valtrace, h: TestHelper, s: String iso) => 25 | """ 26 | Receive a String iso allocated by a different actor. 27 | Append to it. 28 | Send it as a val to a third actor. 29 | """ 30 | @pony_triggergc(@pony_ctx()) 31 | s.append("ing") 32 | _Valtrace.three(a1, this, h, consume s) 33 | 34 | be three(a1: _Valtrace, a2: _Valtrace, h: TestHelper, s: String) => 35 | """ 36 | Receive a String that was an iso that passed through another actor. 37 | """ 38 | @pony_triggergc(@pony_ctx()) 39 | h.assert_eq[String]("testing", s) 40 | _Valtrace.four(a1, a2, this, h, s) 41 | 42 | be four(a1: _Valtrace, a2: _Valtrace, a3: _Valtrace, 43 | h: TestHelper, s: String) 44 | => 45 | """ 46 | Ask all actors to test the string. 47 | """ 48 | @pony_triggergc(@pony_ctx()) 49 | a1.gc(a1, h, s) 50 | a2.gc(a1, h, s) 51 | a3.gc(a1, h, s) 52 | gc(a1, h, s) 53 | 54 | be gc(a: _Valtrace, h: TestHelper, s: String) => 55 | @pony_triggergc(@pony_ctx()) 56 | h.assert_eq[String]("testing", s) 57 | a.done(h) 58 | 59 | be done(h: TestHelper) => 60 | count = count + 1 61 | 62 | if count == 4 then 63 | h.complete(true) 64 | end 65 | -------------------------------------------------------------------------------- /client_vscode/packages/bureaucracy/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | // Tests below function across all systems and are listed alphabetically 9 | test(_TestCustodian) 10 | test(_TestRegistrar) 11 | 12 | class \nodoc\ iso _TestCustodian is UnitTest 13 | """ 14 | Dispose of an actor using a Custodian. 15 | """ 16 | fun name(): String => "bureaucracy/Custodian" 17 | 18 | fun ref apply(h: TestHelper) => 19 | h.long_test(2_000_000_000) // 2 second timeout 20 | let c = Custodian 21 | c(_TestDisposable(h)) 22 | c.dispose() 23 | 24 | class \nodoc\ iso _TestRegistrar is UnitTest 25 | """ 26 | Register an actor and retrieve it. 27 | """ 28 | fun name(): String => "bureaucracy/Registrar" 29 | 30 | fun ref apply(h: TestHelper) => 31 | h.long_test(2_000_000_000) // 2 second timeout 32 | let r = Registrar 33 | r("test") = _TestDisposable(h) 34 | 35 | r[_TestDisposable]("test").next[None]({(value) => value.dispose() }) 36 | 37 | actor \nodoc\ _TestDisposable 38 | let _h: TestHelper 39 | 40 | new create(h: TestHelper) => 41 | _h = h 42 | 43 | be dispose() => 44 | _h.complete(true) 45 | -------------------------------------------------------------------------------- /client_vscode/packages/bureaucracy/bureaucracy.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Bureaucracy package 3 | 4 | It happens to almost every program. It starts small, tiny if you will, like a 5 | village where every actor knows every other actor and shutdown is easy. One day 6 | you realize your program is no longer a cute seaside hamlet, its a bustling 7 | metropolis and you are doing way too much work to keep track of everything. 8 | What do you do? Call for a little bureaucracy. 9 | 10 | The bureaucracy contains objects designed to ease your bookkeeping burdens. 11 | Need to shutdown a number of actors together? Check out `Custodian`. Need 12 | to keep track of a lot of stuff and be able to look it up by name? Check out 13 | `Registrar`. 14 | 15 | Put bureaucracy to use today and before long, your sprawling metropolis of a 16 | code base will be manageable again in no time. 17 | """ 18 | -------------------------------------------------------------------------------- /client_vscode/packages/bureaucracy/custodian.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | actor Custodian 4 | """ 5 | A Custodian keeps a set of actors to dispose. When the Custodian is disposed, 6 | it disposes of the actors in its set and then clears the set. 7 | 8 | ## Example program 9 | 10 | Imagine you have a program with 3 actors that you need to shutdown when it 11 | receives a TERM signal. We can set up a Custodian that knows about each 12 | of our actors and when a TERM signal is received, is disposed of. 13 | 14 | ```pony 15 | use "bureaucracy" 16 | use "signals" 17 | 18 | actor Actor1 19 | be dispose() => None // dispose of resources here. 20 | 21 | actor Actor2 22 | be dispose() => None // dispose of resources here. 23 | 24 | actor Actor3 25 | be dispose() => None // dispose of resources here. 26 | 27 | actor Main 28 | new create(env: Env) => 29 | let actor1 = Actor1 30 | let actor2 = Actor2 31 | let actor3 = Actor3 32 | 33 | let custodian = Custodian 34 | custodian(actor1) 35 | custodian(actor2) 36 | custodian(actor3) 37 | 38 | SignalHandler(TermHandler(custodian), Sig.term()) 39 | 40 | class TermHandler is SignalNotify 41 | let _custodian: Custodian 42 | 43 | new iso create(custodian: Custodian) => 44 | _custodian = custodian 45 | 46 | fun ref apply(count: U32): Bool => 47 | _custodian.dispose() 48 | true 49 | ``` 50 | """ 51 | embed _workers: SetIs[DisposableActor] = _workers.create() 52 | 53 | be apply(worker: DisposableActor) => 54 | """ 55 | Add an actor to be disposed of. 56 | """ 57 | _workers.set(worker) 58 | 59 | be remove(worker: DisposableActor) => 60 | """ 61 | Removes an actor from the set of things to be disposed. 62 | """ 63 | _workers.unset(worker) 64 | 65 | be dispose() => 66 | """ 67 | Dispose of the actors in the set and then clear the set. 68 | """ 69 | for worker in _workers.values() do 70 | worker.dispose() 71 | end 72 | 73 | _workers.clear() 74 | -------------------------------------------------------------------------------- /client_vscode/packages/bureaucracy/registrar.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "promises" 3 | 4 | actor Registrar 5 | """ 6 | A Registrar keeps a map of lookup string to anything. Generally, this is used 7 | to keep a directory of long-lived service-providing actors that can be 8 | looked up name. 9 | """ 10 | embed _registry: Map[String, Any tag] = _registry.create() 11 | 12 | be update(key: String, value: Any tag) => 13 | """ 14 | Add, or change, a lookup mapping. 15 | """ 16 | _registry(key) = value 17 | 18 | be remove(key: String, value: Any tag) => 19 | """ 20 | Remove a mapping. This only takes effect if provided key currently maps to 21 | the provided value. If the key maps to some other value (perhaps after 22 | updating), the mapping won't be removed. 23 | """ 24 | try 25 | if _registry(key)? is value then 26 | _registry.remove(key)? 27 | end 28 | end 29 | 30 | fun tag apply[A: Any tag = Any tag](key: String): Promise[A] => 31 | """ 32 | Lookup by name. Returns a promise that will be fulfilled with the mapped 33 | value if it exists and is a subtype of A. Otherwise, the promise will be 34 | rejected. 35 | """ 36 | let promise = Promise[A] 37 | _fetch[A](key, promise) 38 | promise 39 | 40 | be _fetch[A: Any tag](key: String, promise: Promise[A]) => 41 | """ 42 | Fulfills or rejects the promise. 43 | """ 44 | try 45 | promise(_registry(key)? as A) 46 | else 47 | promise.reject() 48 | end 49 | -------------------------------------------------------------------------------- /client_vscode/packages/capsicum/capsicum.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Capsicum package 3 | 4 | Access to Capsicum capabilities for UNIX systems -- primarily in use by BSD-based systems. 5 | """ 6 | -------------------------------------------------------------------------------- /client_vscode/packages/cli/env_vars.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | primitive EnvVars 4 | fun apply( 5 | envs: (Array[String] box | None), 6 | prefix: String = "", 7 | squash: Bool = false): 8 | Map[String, String] val 9 | => 10 | """ 11 | Turns an array of strings that look like environment variables, ie. 12 | key=value, into a map of string to string. Can optionally filter for 13 | keys matching a 'prefix', and will squash resulting keys to lowercase 14 | iff 'squash' is true. 15 | 16 | So: 17 | `=` 18 | becomes: 19 | `{KEY, VALUE}` or `{key, VALUE}` 20 | """ 21 | let envsmap = recover Map[String, String]() end 22 | match envs 23 | | let envsarr: Array[String] box => 24 | let prelen = prefix.size().isize() 25 | for e in envsarr.values() do 26 | let eqpos = try e.find("=")? else ISize.max_value() end 27 | let ek: String val = e.substring(0, eqpos) 28 | let ev: String val = e.substring(eqpos + 1) 29 | if (prelen == 0) or ek.at(prefix, 0) then 30 | if squash then 31 | envsmap.update(ek.substring(prelen).lower(), ev) 32 | else 33 | envsmap.update(ek.substring(prelen), ev) 34 | end 35 | end 36 | end 37 | end 38 | envsmap 39 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/collections.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Collections package 3 | 4 | The Collections package provides a variety of collection classes, 5 | including map, set, range, heap, ring buffer, list, and flags. 6 | 7 | `Map` - Hashmap by strutural equality (use `MapIs` for identity equality). 8 | 9 | `Set` - A set built on top of `Map` using structural equility (use `SetIs` for identity equality). 10 | 11 | `Range` - Iterate over a range of numbers with optional step size. 12 | 13 | `BinaryHeap` - A priority queue implemented as a binary heap -- use a `BinaryHeapPriority` parameter to determine priority. 14 | 15 | `RingBuffer` - A ring buffer with fixed size. 16 | 17 | `List` - A doubly linked list. 18 | 19 | `Flags` - A set of single bit flags (size determined upon creation). 20 | """ 21 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/persistent/_bits.pony: -------------------------------------------------------------------------------- 1 | primitive _Bits 2 | fun collision_depth(): U32 => 6 3 | 4 | fun set_bit(bm: U32, i: U32): U32 => 5 | bm or (U32(1) <<~ i) 6 | 7 | fun clear_bit(bm: U32, i: U32): U32 => 8 | bm and (not (U32(1) <<~ i)) 9 | 10 | fun check_bit(bm: U32, i: U32): Bool => 11 | (bm and (U32(1) <<~ i)) != 0 12 | 13 | fun mask32(n: U32, d: U32): U32 => 14 | (n >> (d *~ 5)) and 0b11111 15 | 16 | fun mask(n: USize, d: USize): USize => 17 | (n >> (d *~ 5)) and 0b11111 18 | 19 | fun next_pow32(n: USize): USize => 20 | USize(32) << (n *~ 5) 21 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/persistent/_vec_node.pony: -------------------------------------------------------------------------------- 1 | type _VecSubNodes[A: Any #share] is Array[_VecNode[A]] 2 | 3 | class val _VecNode[A: Any #share] 4 | let _entries: (Array[A] val | _VecSubNodes[A] val) 5 | 6 | new val empty(depth: USize) => 7 | _entries = 8 | recover 9 | if depth == 0 10 | then Array[A] 11 | else _VecSubNodes[A] 12 | end 13 | end 14 | 15 | new val create(entries': (Array[A] val | _VecSubNodes[A] val)) => 16 | _entries = entries' 17 | 18 | fun val grow_root(): _VecNode[A] => 19 | create(recover Array[_VecNode[A]](1) .> push(this) end) 20 | 21 | fun apply(depth: USize, i: USize): A ? => 22 | let idx = _Bits.mask(i, depth) 23 | match _entries 24 | | let ls: Array[A] box => ls(idx)? 25 | | let ns: _VecSubNodes[A] box => ns(idx)?(depth - 1, i)? 26 | end 27 | 28 | fun val push(depth: USize, i: USize, tail: Array[A] val): _VecNode[A] ? => 29 | let ns = _entries as _VecSubNodes[A] val 30 | if depth == 1 then 31 | let ls = create(tail) 32 | create(recover ns.clone() .> push(ls) end) 33 | else 34 | let idx = _Bits.mask(i, depth) 35 | if _entries.size() > idx then 36 | let sn = ns(idx)?.push(depth - 1, i, tail)? 37 | create(recover ns.clone() .> update(idx, sn)? end) 38 | else 39 | let sn = empty(depth - 1).push(depth - 1, i, tail)? 40 | create(recover ns.clone() .> push(sn) end) 41 | end 42 | end 43 | 44 | fun val pop(depth: USize, i: USize): (_VecNode[A], Array[A] val) ? => 45 | match _entries 46 | | let ls: Array[A] val => (this, ls) 47 | | let ns: _VecSubNodes[A] val => 48 | let idx = _Bits.mask(i, depth) 49 | if depth == 1 then 50 | let tail = ns(idx)?.pop(depth - 1, i)?._2 51 | (create(ns.trim(0, ns.size() - 1)), tail) 52 | else 53 | (let sn, let tail) = ns(idx)?.pop(depth - 1, i)? 54 | (create(recover ns.clone() .> update(idx, sn)? end), tail) 55 | end 56 | end 57 | 58 | fun val update(depth: USize, i: USize, v: A): _VecNode[A] ? => 59 | let idx = _Bits.mask(i, depth) 60 | match _entries 61 | | let ls: Array[A] val => 62 | create(recover ls.clone() .> update(idx, v)? end) 63 | | let ns: _VecSubNodes[A] val => 64 | let sn = ns(idx)?.update(depth - 1, i, v)? 65 | create(recover ns.clone() .> update(idx, sn)? end) 66 | end 67 | 68 | fun val leaf_nodes(lns: Array[Array[A] val]): Array[Array[A] val]^ => 69 | match _entries 70 | | let lns': Array[A] val => 71 | lns.push(lns') 72 | | let ns: _VecSubNodes[A] val => 73 | for sn in ns.values() do sn.leaf_nodes(lns) end 74 | end 75 | lns 76 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/persistent/benchmarks/main.pony: -------------------------------------------------------------------------------- 1 | use ".." 2 | use mut = "collections" 3 | use "pony_bench" 4 | 5 | type K is String 6 | type V is U64 7 | 8 | actor Main is BenchmarkList 9 | new create(env: Env) => 10 | PonyBench(env, this) 11 | 12 | fun tag benchmarks(bench: PonyBench) => 13 | let size: USize = 32 * 32 14 | let ns = [as USize: 0; 4; 17; 21; 24; 30] 15 | 16 | for n in ns.values() do bench(MapApply(size, n)) end 17 | for n in ns.values() do bench(MapInsert(size, n)) end 18 | for n in ns.values() do bench(MapUpdate(size, n)) end 19 | bench(MapIter(32)) 20 | bench(MapIter(32 * 32)) 21 | bench(MapIter(32 * 32 * 32)) 22 | 23 | class iso MapApply is MicroBenchmark 24 | let _size: USize 25 | let _n: USize 26 | let _map: Map[K, V] 27 | 28 | new iso create(size: USize, n: USize) => 29 | _size = size 30 | _n = n 31 | _map = GenMap(_size) 32 | 33 | fun name(): String => 34 | " ".join(["apply"; _n; "size"; _size].values()) 35 | 36 | fun apply() ? => 37 | let x = _map(_n.string())? 38 | DoNotOptimise[V](x) 39 | DoNotOptimise.observe() 40 | 41 | class iso MapInsert is MicroBenchmark 42 | let _size: USize 43 | let _n: USize 44 | let _map: Map[K, V] 45 | 46 | new iso create(size: USize, n: USize) => 47 | _size = size 48 | _n = n 49 | _map = try GenMap(size).remove(n.string())? else GenMap(0) end 50 | 51 | fun name(): String => 52 | " ".join(["insert"; _n; "size"; _size].values()) 53 | 54 | fun apply() => 55 | let m = _map(_n.string()) = _n.u64() 56 | DoNotOptimise[Map[K, V]](m) 57 | DoNotOptimise.observe() 58 | 59 | class iso MapUpdate is MicroBenchmark 60 | let _size: USize 61 | let _n: USize 62 | let _map: Map[K, V] 63 | 64 | new iso create(size: USize, n: USize) => 65 | _size = size 66 | _n = n 67 | _map = GenMap(_size) 68 | 69 | fun name(): String => 70 | " ".join(["update"; _n; "size"; _size].values()) 71 | 72 | fun apply() => 73 | let m = _map.update(_n.string(), -_n.u64()) 74 | DoNotOptimise[Map[K, V]](m) 75 | DoNotOptimise.observe() 76 | 77 | class iso MapIter is MicroBenchmark 78 | let _size: USize 79 | let _map: Map[K, V] 80 | 81 | new iso create(size: USize) => 82 | _size = size 83 | _map = GenMap(_size) 84 | 85 | fun name(): String => 86 | " ".join(["iter size"; _size].values()) 87 | 88 | fun apply() ? => 89 | for i in mut.Range(0, _size) do 90 | let x = _map(i.string())? 91 | DoNotOptimise[V](x) 92 | end 93 | DoNotOptimise.observe() 94 | 95 | primitive GenMap 96 | fun apply(size: USize): Map[K, V] => 97 | var m = Map[K, V] 98 | for i in mut.Range(0, size) do 99 | m = m(i.string()) = i.u64() 100 | end 101 | m 102 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/persistent/persistent.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Persistent Collections Package 3 | 4 | `List` - A persistent list with functional transformations. 5 | 6 | `Map` - A persistent map based on the Compressed Hash Array Mapped Prefix-tree 7 | from 'Optimizing Hash-Array Mapped Tries for Fast and Lean Immutable JVM 8 | Collections' by Michael J. Steindorfer and Jurgen J. Vinju. 9 | 10 | `Set` - A persistent set implemented as a persistent map of an alias of a type 11 | to itself. 12 | 13 | `Vec` - A persistent vector based on the Hash Array Mapped Trie from 'Ideal Hash 14 | Trees' by Phil Bagwell. 15 | """ 16 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/reverse.pony: -------------------------------------------------------------------------------- 1 | class Reverse[A: (Real[A] val & Number) = USize] is Iterator[A] 2 | """ 3 | Produces a decreasing range [max, min] with step `dec`, for any `Number` type. 4 | (i.e. the reverse of `Range`) 5 | 6 | Example program: 7 | 8 | ```pony 9 | use "collections" 10 | actor Main 11 | new create(env: Env) => 12 | for e in Reverse(10, 2, 2) do 13 | env.out.print(e.string()) 14 | end 15 | ``` 16 | Which outputs: 17 | ``` 18 | 10 19 | 8 20 | 6 21 | 4 22 | 2 23 | ``` 24 | 25 | If `dec` is 0, produces an infinite series of `max`. 26 | 27 | If `dec` is negative, produces a range with `max` as the only value. 28 | 29 | """ 30 | 31 | let _min: A 32 | let _max: A 33 | let _dec: A 34 | var _idx: A 35 | 36 | new create(max: A, min: A, dec: A = 1) => 37 | _min = min 38 | _max = max 39 | _dec = dec 40 | _idx = max 41 | 42 | fun has_next(): Bool => 43 | (_idx >= _min) and (_idx <= _max) 44 | 45 | fun ref next(): A => 46 | if has_next() then 47 | _idx = _idx - _dec 48 | else 49 | _idx + _dec 50 | end 51 | 52 | fun ref rewind() => 53 | _idx = _max 54 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/ring_buffer.pony: -------------------------------------------------------------------------------- 1 | class RingBuffer[A] 2 | """ 3 | A ring buffer. 4 | """ 5 | embed _array: Array[A] 6 | let _mod: USize 7 | var _write: USize = 0 8 | 9 | new create(len: USize) => 10 | """ 11 | Create a ring buffer with a fixed size. The size will be rounded up to the 12 | next power of 2. 13 | """ 14 | let n = len.max(2).next_pow2() 15 | _mod = n - 1 16 | _array = Array[A](n) 17 | 18 | fun head(): USize ? => 19 | """ 20 | The first read that will succeed. If nothing has been written to the ring, 21 | this will raise an error. 22 | """ 23 | if _write > 0 then 24 | if _write > space() then 25 | _write - space() 26 | else 27 | 0 28 | end 29 | else 30 | error 31 | end 32 | 33 | fun size(): USize => 34 | """ 35 | The number of elements that have been added to the ring. 36 | """ 37 | _write 38 | 39 | fun space(): USize => 40 | """ 41 | The available space in the ring. 42 | """ 43 | _mod + 1 44 | 45 | fun apply(i: USize): this->A ? => 46 | """ 47 | Get the i-th element from the ring. If the i-th element has not yet been 48 | added or is no longer available, this will raise an error. 49 | """ 50 | if (i >= _write) or ((_write - i) > space()) then 51 | error 52 | end 53 | 54 | _array(i and _mod)? 55 | 56 | fun ref push(value: A): Bool => 57 | """ 58 | Add an element to the ring. If the ring is full, this will drop the oldest 59 | element in the ring. Returns true if an element was dropped. 60 | """ 61 | var full = false 62 | 63 | if _write < space() then 64 | _array.push(consume value) 65 | else 66 | try _array(_write and _mod)? = consume value end 67 | full = true 68 | end 69 | 70 | _write = _write + 1 71 | full 72 | 73 | fun ref clear() => 74 | """ 75 | Clear the queue. 76 | """ 77 | _array.clear() 78 | _write = 0 79 | -------------------------------------------------------------------------------- /client_vscode/packages/collections/sort.pony: -------------------------------------------------------------------------------- 1 | primitive Sort[A: Seq[B] ref, B: Comparable[B] #read] 2 | """ 3 | Implementation of dual-pivot quicksort. It operates in-place on the provided Seq, using 4 | a small amount of additional memory. The nature of the element-realation is expressed via 5 | the supplied comparator. 6 | 7 | (The following is paraphrased from [Wikipedia](https://en.wikipedia.org/wiki/Quicksort).) 8 | 9 | Quicksort is a common implementation of a sort algorithm which can sort items of any type 10 | for which a "less-than" relation (formally, a total order) is defined. 11 | 12 | On average, the algorithm takes O(n log n) comparisons to sort n items. In the worst case, 13 | it makes O(n2) comparisons, though this behavior is rare. Multi-pivot implementations 14 | (of which dual-pivot is one) make efficient use of modern processor caches. 15 | 16 | ## Example program 17 | The following takes an reverse-alphabetical array of Strings ("third", "second", "first"), 18 | and sorts it in place alphabetically using the default String Comparator. 19 | 20 | It outputs: 21 | 22 | > first 23 | > second 24 | > third 25 | 26 | ```pony 27 | use "collections" 28 | 29 | actor Main 30 | new create(env:Env) => 31 | let array = [ "third"; "second"; "first" ] 32 | let sorted_array = Sort[Array[String], String](array) 33 | for e in sorted_array.values() do 34 | env.out.print(e) // prints "first \n second \n third" 35 | end 36 | ``` 37 | """ 38 | fun apply(a: A): A^ => 39 | """ 40 | Sort the given seq. 41 | """ 42 | try _sort(a, 0, a.size().isize() - 1)? end 43 | a 44 | 45 | fun _sort(a: A, lo: ISize, hi: ISize) ? => 46 | if hi <= lo then return end 47 | // choose outermost elements as pivots 48 | if a(lo.usize())? > a(hi.usize())? then _swap(a, lo, hi)? end 49 | (var p, var q) = (a(lo.usize())?, a(hi.usize())?) 50 | // partition according to invariant 51 | (var l, var g) = (lo + 1, hi - 1) 52 | var k = l 53 | while k <= g do 54 | if a(k.usize())? < p then 55 | _swap(a, k, l)? 56 | l = l + 1 57 | elseif a(k.usize())? >= q then 58 | while (a(g.usize())? > q) and (k < g) do g = g - 1 end 59 | _swap(a, k, g)? 60 | g = g - 1 61 | if a(k.usize())? < p then 62 | _swap(a, k, l)? 63 | l = l + 1 64 | end 65 | end 66 | k = k + 1 67 | end 68 | (l, g) = (l - 1, g + 1) 69 | // swap pivots to final positions 70 | _swap(a, lo, l)? 71 | _swap(a, hi, g)? 72 | // recursively sort 3 partitions 73 | _sort(a, lo, l - 1)? 74 | _sort(a, l + 1, g - 1)? 75 | _sort(a, g + 1, hi)? 76 | 77 | fun _swap(a: A, i: ISize, j: ISize) ? => 78 | a(j.usize())? = a(i.usize())? = a(j.usize())? 79 | -------------------------------------------------------------------------------- /client_vscode/packages/constrained_types/constrained.pony: -------------------------------------------------------------------------------- 1 | type ValidationResult is (ValidationSuccess | ValidationFailure) 2 | 3 | primitive ValidationSuccess 4 | 5 | class val ValidationFailure 6 | """ 7 | Collection of validation errors. 8 | """ 9 | let _errors: Array[String val] = _errors.create() 10 | 11 | new create(e: (String val | None) = None) => 12 | match e 13 | | let s: String val => _errors.push(s) 14 | end 15 | 16 | fun ref apply(e: String val) => 17 | """ 18 | Add an error to the failure. 19 | """ 20 | _errors.push(e) 21 | 22 | fun errors(): this->Array[String val] => 23 | """ 24 | Get list of validation errors. 25 | """ 26 | _errors 27 | 28 | interface val Validator[T] 29 | """ 30 | Interface validators must implement. 31 | 32 | We strongly suggest you use a `primitive` for your `Validator` as validators 33 | are required to be stateless. 34 | """ 35 | new val create() 36 | fun apply(i: T): ValidationResult 37 | """ 38 | Takes an instance and returns either `ValidationSuccess` if it meets the 39 | constraint criteria or `ValidationFailure` if it doesn't. 40 | """ 41 | 42 | class val Constrained[T: Any val, F: Validator[T]] 43 | """ 44 | Wrapper class for a constrained type. 45 | """ 46 | let _value: T val 47 | 48 | new val _create(value: T val) => 49 | """ 50 | Private constructor that guarantees that `Constrained` can only be created 51 | by the `MakeConstrained` primitive in this package. 52 | """ 53 | _value = value 54 | 55 | fun val apply(): T val => 56 | """ 57 | Unwraps and allows access to the constrained object. 58 | """ 59 | _value 60 | 61 | primitive MakeConstrained[T: Any val, F: Validator[T] val] 62 | """ 63 | Builder of `Constrained` instances. 64 | """ 65 | fun apply(value: T): (Constrained[T, F] | ValidationFailure) => 66 | match F(value) 67 | | ValidationSuccess => Constrained[T, F]._create(value) 68 | | let e: ValidationFailure => e 69 | end 70 | -------------------------------------------------------------------------------- /client_vscode/packages/debug/debug.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Debug package 3 | 4 | Provides facilities to create output to either `STDOUT` or `STDERR` that will 5 | only appear when the platform is debug configured. To create a binary with 6 | debug configured, pass the `-d` flag to `ponyc` when compiling e.g.: 7 | 8 | `ponyc -d` 9 | 10 | ## Example code 11 | 12 | ```pony 13 | use "debug" 14 | 15 | actor Main 16 | new create(env: Env) => 17 | Debug.out("This will only be seen when configured for debug info") 18 | env.out.print("This will always be seen") 19 | ``` 20 | """ 21 | use @fprintf[I32](stream: Pointer[U8] tag, fmt: Pointer[U8] tag, ...) 22 | use @pony_os_stdout[Pointer[U8]]() 23 | use @pony_os_stderr[Pointer[U8]]() 24 | 25 | primitive DebugOut 26 | primitive DebugErr 27 | 28 | type DebugStream is (DebugOut | DebugErr) 29 | 30 | primitive Debug 31 | """ 32 | This is a debug only print utility. 33 | """ 34 | fun apply( 35 | msg: (Stringable | ReadSeq[Stringable]), 36 | sep: String = ", ", 37 | stream: DebugStream = DebugOut) 38 | => 39 | """ 40 | If platform is debug configured, print either a single stringable or a 41 | sequence of stringables. The default separator is ", ", and the default 42 | output stream is stdout. 43 | """ 44 | ifdef debug then 45 | match msg 46 | | let m: Stringable => 47 | _print(m.string(), stream) 48 | | let m: ReadSeq[Stringable] => 49 | _print(sep.join(m.values()), stream) 50 | end 51 | end 52 | 53 | fun out(msg: Stringable = "") => 54 | """ 55 | If platform is debug configured, print message to standard output 56 | """ 57 | _print(msg.string(), DebugOut) 58 | 59 | fun err(msg: Stringable = "") => 60 | """ 61 | If platform is debug configured, print message to standard error 62 | """ 63 | _print(msg.string(), DebugErr) 64 | 65 | fun _print(msg: String, stream: DebugStream) => 66 | ifdef debug then 67 | @fprintf(_stream(stream), "%s\n".cstring(), msg.cstring()) 68 | end 69 | 70 | fun _stream(stream: DebugStream): Pointer[U8] => 71 | match stream 72 | | DebugOut => @pony_os_stdout() 73 | | DebugErr => @pony_os_stderr() 74 | end 75 | -------------------------------------------------------------------------------- /client_vscode/packages/files/_file_des.pony: -------------------------------------------------------------------------------- 1 | use "time" 2 | use "capsicum" 3 | 4 | use @fchmod[I32](fildes: I32, mode: U32) 5 | if not windows 6 | use @fchown[I32](fd: I32, uid: U32, gid: U32) 7 | if not windows 8 | 9 | primitive _FileDes 10 | """ 11 | Convenience operations on file descriptors. 12 | """ 13 | fun chmod(fd: I32, path: FilePath, mode: FileMode box): Bool => 14 | """ 15 | Set the FileMode for this fd. 16 | """ 17 | if not path.caps(FileChmod) or (fd == -1) then 18 | return false 19 | end 20 | 21 | ifdef windows then 22 | path.chmod(mode) 23 | else 24 | @fchmod(fd, mode.u32()) == 0 25 | end 26 | 27 | fun chown(fd: I32, path: FilePath, uid: U32, gid: U32): Bool => 28 | """ 29 | Set the owner and group for this file. Does nothing on Windows. 30 | """ 31 | ifdef windows then 32 | false 33 | else 34 | if (fd != -1) and path.caps(FileChown) then 35 | @fchown(fd, uid, gid) == 0 36 | else 37 | false 38 | end 39 | end 40 | 41 | fun touch(fd: I32, path: FilePath): Bool => 42 | """ 43 | Set the last access and modification times of the file to now. 44 | """ 45 | set_time(fd, path, Time.now(), Time.now()) 46 | 47 | fun set_time( 48 | fd: I32, 49 | path: FilePath, 50 | atime: (I64, I64), 51 | mtime: (I64, I64)) 52 | : Bool 53 | => 54 | """ 55 | Set the last access and modification times of the file to the given values. 56 | """ 57 | if (fd == -1) or not path.caps(FileTime) then 58 | return false 59 | end 60 | 61 | ifdef windows then 62 | path.set_time(atime, mtime) 63 | else 64 | var tv: (ILong, ILong, ILong, ILong) = 65 | ( atime._1.ilong(), atime._2.ilong() / 1000, 66 | mtime._1.ilong(), mtime._2.ilong() / 1000 ) 67 | @futimes(fd, addressof tv) == 0 68 | end 69 | 70 | fun set_rights(fd: I32, path: FilePath, writeable: Bool = true) ? => 71 | """ 72 | Set the Capsicum rights on the file descriptor. 73 | """ 74 | ifdef freebsd or "capsicum" then 75 | if fd != -1 then 76 | let cap = CapRights.from(path.caps) 77 | 78 | if not writeable then 79 | cap.unset(Cap.write()) 80 | end 81 | 82 | if not cap.limit(fd) then 83 | error 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /client_vscode/packages/files/auth.pony: -------------------------------------------------------------------------------- 1 | primitive FileAuth 2 | new create(from: AmbientAuth) => 3 | None 4 | -------------------------------------------------------------------------------- /client_vscode/packages/files/file_caps.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | primitive FileCreate 4 | fun value(): U32 => 1 << 0 5 | 6 | primitive FileChmod 7 | fun value(): U32 => 1 << 1 8 | 9 | primitive FileChown 10 | fun value(): U32 => 1 << 2 11 | 12 | primitive FileLink 13 | fun value(): U32 => 1 << 3 14 | 15 | primitive FileLookup 16 | fun value(): U32 => 1 << 4 17 | 18 | primitive FileMkdir 19 | fun value(): U32 => 1 << 5 20 | 21 | primitive FileRead 22 | fun value(): U32 => 1 << 6 23 | 24 | primitive FileRemove 25 | fun value(): U32 => 1 << 7 26 | 27 | primitive FileRename 28 | fun value(): U32 => 1 << 8 29 | 30 | primitive FileSeek 31 | fun value(): U32 => 1 << 9 32 | 33 | primitive FileStat 34 | fun value(): U32 => 1 << 10 35 | 36 | primitive FileSync 37 | fun value(): U32 => 1 << 11 38 | 39 | primitive FileTime 40 | fun value(): U32 => 1 << 12 41 | 42 | primitive FileTruncate 43 | fun value(): U32 => 1 << 13 44 | 45 | primitive FileWrite 46 | fun value(): U32 => 1 << 14 47 | 48 | primitive FileExec 49 | fun value(): U32 => 1 << 15 50 | 51 | type FileCaps is Flags[ 52 | ( FileCreate 53 | | FileChmod 54 | | FileChown 55 | | FileLink 56 | | FileLookup 57 | | FileMkdir 58 | | FileRead 59 | | FileRemove 60 | | FileRename 61 | | FileSeek 62 | | FileStat 63 | | FileSync 64 | | FileTime 65 | | FileTruncate 66 | | FileWrite 67 | | FileExec 68 | ), 69 | U32 ] 70 | -------------------------------------------------------------------------------- /client_vscode/packages/files/file_mode.pony: -------------------------------------------------------------------------------- 1 | class FileMode 2 | """ 3 | This stores a UNIX-style mode broken out into a Bool for each bit. For other 4 | operating systems, the mapping will be approximate. For example, on Windows, 5 | if the file is readable all the read Bools will be set, and if the file is 6 | writeable, all the write Bools will be set. 7 | 8 | The default mode is read/write for the owner, read-only for everyone else. 9 | """ 10 | var setuid: Bool = false 11 | """`true` if the SETUID bit is set.""" 12 | 13 | var setgid: Bool = false 14 | """`true` if the SETGID bit is set.""" 15 | 16 | var sticky: Bool = false 17 | """`true` if the sticky bit is set.""" 18 | 19 | var owner_read: Bool = true 20 | """`true` if the owning user can read the file.""" 21 | 22 | var owner_write: Bool = true 23 | """`true` if the owning user can write to the file.""" 24 | 25 | var owner_exec: Bool = false 26 | """`true` if the owning user can execute the file.""" 27 | 28 | var group_read: Bool = true 29 | """`true` if members of the owning group can read the file.""" 30 | 31 | var group_write: Bool = false 32 | """`true` if members of the owning group can write to the file.""" 33 | 34 | var group_exec: Bool = false 35 | """`true` if members of the owning group can execute the file.""" 36 | 37 | var any_read: Bool = true 38 | """`true` if every user can read the file.""" 39 | 40 | var any_write: Bool = false 41 | """`true` if every user can write to the file.""" 42 | 43 | var any_exec: Bool = false 44 | """`true if every user can execute the file.""" 45 | 46 | fun ref exec() => 47 | """ 48 | Set the executable flag for everyone. 49 | """ 50 | owner_exec = true 51 | group_exec = true 52 | any_exec = true 53 | 54 | fun ref shared() => 55 | """ 56 | Set the write flag for everyone to the same as owner_write. 57 | """ 58 | group_write = owner_write 59 | any_write = owner_write 60 | 61 | fun ref group() => 62 | """ 63 | Clear all of the any-user flags. 64 | """ 65 | any_read = false 66 | any_write = false 67 | any_exec = false 68 | 69 | fun ref private() => 70 | """ 71 | Clear all of the group and any-user flags. 72 | """ 73 | group_read = false 74 | group_write = false 75 | group_exec = false 76 | any_read = false 77 | any_write = false 78 | any_exec = false 79 | 80 | fun u32(): U32 => 81 | """ 82 | Get the OS specific integer for a file mode. On Windows, if any read flag 83 | is set, the path is made readable, and if any write flag is set, the path 84 | is made writeable. 85 | """ 86 | var m: U32 = 0 87 | 88 | ifdef windows then 89 | if owner_read or group_read or any_read then 90 | m = m or 0x100 91 | end 92 | 93 | if owner_write or group_write or any_write then 94 | m = m or 0x80 95 | end 96 | else 97 | if setuid then m = m or 0x800 end 98 | if setgid then m = m or 0x400 end 99 | if sticky then m = m or 0x200 end 100 | if owner_read then m = m or 0x100 end 101 | if owner_write then m = m or 0x80 end 102 | if owner_exec then m = m or 0x40 end 103 | if group_read then m = m or 0x20 end 104 | if group_write then m = m or 0x10 end 105 | if group_exec then m = m or 0x8 end 106 | if any_read then m = m or 0x4 end 107 | if any_write then m = m or 0x2 end 108 | if any_exec then m = m or 0x1 end 109 | end 110 | m 111 | -------------------------------------------------------------------------------- /client_vscode/packages/files/file_stream.pony: -------------------------------------------------------------------------------- 1 | actor FileStream is OutStream 2 | """ 3 | Asynchronous access to a File object. Wraps file operations print, write, 4 | printv and writev. The File will be disposed through File._final. 5 | """ 6 | let _file: File 7 | 8 | new create(file: File iso) => 9 | _file = consume file 10 | 11 | be print(data: ByteSeq) => 12 | """ 13 | Print some bytes and insert a newline afterwards. 14 | """ 15 | _file.print(data) 16 | 17 | be write(data: ByteSeq) => 18 | """ 19 | Print some bytes without inserting a newline afterwards. 20 | """ 21 | _file.write(data) 22 | 23 | be printv(data: ByteSeqIter) => 24 | """ 25 | Print an iterable collection of ByteSeqs. 26 | """ 27 | _file.printv(data) 28 | 29 | be writev(data: ByteSeqIter) => 30 | """ 31 | Write an iterable collection of ByteSeqs. 32 | """ 33 | _file.writev(data) 34 | 35 | be flush() => 36 | """ 37 | Flush pending data to write. 38 | """ 39 | _file.flush() 40 | -------------------------------------------------------------------------------- /client_vscode/packages/files/files.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Files package 3 | 4 | The Files package provides classes for working with files and 5 | directories. 6 | 7 | Files are identified by `FilePath` objects, which represent both the 8 | path to the file and the capabilites for accessing the file at that 9 | path. `FilePath` objects can be used with the `CreateFile` and 10 | `OpenFile` primitives and the `File` class to get a reference to a 11 | file that can be used to write to and/or read from the file. It can 12 | also be used with the `Directory` object to get a reference to a 13 | directory object that can be used for directory operations. 14 | 15 | The `FileLines` class allows a file to be accessed one line at a time. 16 | 17 | The `FileStream` actor provides the ability to asynchronously write to 18 | a file. 19 | 20 | The `Path` primitive can be used to do path-related operations on 21 | strings and characters. 22 | 23 | # Example program 24 | 25 | This program opens the files that are given as command line arguments 26 | and prints their contents. 27 | 28 | ```pony 29 | use "files" 30 | 31 | actor Main 32 | new create(env: Env) => 33 | for file_name in env.args.slice(1).values() do 34 | let path = FilePath(FileAuth(env.root), file_name) 35 | match OpenFile(path) 36 | | let file: File => 37 | while file.errno() is FileOK do 38 | env.out.write(file.read(1024)) 39 | end 40 | else 41 | env.err.print("Error opening file '" + file_name + "'") 42 | end 43 | end 44 | ``` 45 | """ 46 | -------------------------------------------------------------------------------- /client_vscode/packages/format/_format_float.pony: -------------------------------------------------------------------------------- 1 | use @snprintf[I32](str: Pointer[U8] tag, size: USize, fmt: Pointer[U8] tag, ...) 2 | if not windows 3 | use @_snprintf[I32](str: Pointer[U8] tag, count: USize, fmt: Pointer[U8] tag, ...) 4 | if windows 5 | 6 | primitive _FormatFloat 7 | """ 8 | Worker type providing to string conversions for floats. 9 | """ 10 | fun f64( 11 | x: F64, 12 | fmt: FormatFloat = FormatDefault, 13 | prefix: PrefixNumber = PrefixDefault, 14 | prec: USize = 6, 15 | width: USize = 0, 16 | align: Align = AlignRight, 17 | fill: U32 = ' ') 18 | : String iso^ 19 | => 20 | // TODO: prefix, align, fill 21 | var prec' = if prec == -1 then 6 else prec end 22 | 23 | recover 24 | var s = String((prec' + 8).max(width.max(31))) 25 | var f = String(31) .> append("%") 26 | 27 | if width > 0 then f.append(width.string()) end 28 | f .> append(".") .> append(prec'.string()) 29 | 30 | match fmt 31 | | FormatExp => f.append("e") 32 | | FormatExpLarge => f.append("E") 33 | | FormatFix => f.append("f") 34 | | FormatFixLarge => f.append("F") 35 | | FormatGeneral => f.append("g") 36 | | FormatGeneralLarge => f.append("G") 37 | else 38 | f.append("g") 39 | end 40 | 41 | ifdef windows then 42 | @_snprintf(s.cstring(), s.space(), f.cstring(), x) 43 | else 44 | @snprintf(s.cstring(), s.space(), f.cstring(), x) 45 | end 46 | 47 | s .> recalc() 48 | end 49 | -------------------------------------------------------------------------------- /client_vscode/packages/format/align.pony: -------------------------------------------------------------------------------- 1 | primitive AlignLeft 2 | primitive AlignRight 3 | primitive AlignCenter 4 | 5 | type Align is 6 | ( AlignLeft 7 | | AlignRight 8 | | AlignCenter ) 9 | -------------------------------------------------------------------------------- /client_vscode/packages/format/format_spec.pony: -------------------------------------------------------------------------------- 1 | trait val FormatSpec 2 | 3 | primitive FormatDefault is FormatSpec 4 | 5 | primitive FormatUTF32 is FormatSpec 6 | primitive FormatBinary is FormatSpec 7 | primitive FormatBinaryBare is FormatSpec 8 | primitive FormatOctal is FormatSpec 9 | primitive FormatOctalBare is FormatSpec 10 | primitive FormatHex is FormatSpec 11 | primitive FormatHexBare is FormatSpec 12 | primitive FormatHexSmall is FormatSpec 13 | primitive FormatHexSmallBare is FormatSpec 14 | 15 | type FormatInt is 16 | ( FormatDefault 17 | | FormatUTF32 18 | | FormatBinary 19 | | FormatBinaryBare 20 | | FormatOctal 21 | | FormatOctalBare 22 | | FormatHex 23 | | FormatHexBare 24 | | FormatHexSmall 25 | | FormatHexSmallBare ) 26 | 27 | primitive FormatExp is FormatSpec 28 | primitive FormatExpLarge is FormatSpec 29 | primitive FormatFix is FormatSpec 30 | primitive FormatFixLarge is FormatSpec 31 | primitive FormatGeneral is FormatSpec 32 | primitive FormatGeneralLarge is FormatSpec 33 | 34 | type FormatFloat is 35 | ( FormatDefault 36 | | FormatExp 37 | | FormatExpLarge 38 | | FormatFix 39 | | FormatFixLarge 40 | | FormatGeneral 41 | | FormatGeneralLarge ) 42 | -------------------------------------------------------------------------------- /client_vscode/packages/format/prefix_spec.pony: -------------------------------------------------------------------------------- 1 | trait val PrefixSpec 2 | 3 | primitive PrefixDefault is PrefixSpec 4 | 5 | primitive PrefixSpace is PrefixSpec 6 | primitive PrefixSign is PrefixSpec 7 | 8 | type PrefixNumber is 9 | ( PrefixDefault 10 | | PrefixSpace 11 | | PrefixSign ) 12 | -------------------------------------------------------------------------------- /client_vscode/packages/ini/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | // Tests below function across all systems and are listed alphabetically 9 | test(_TestIniParse) 10 | 11 | class \nodoc\ iso _TestIniParse is UnitTest 12 | fun name(): String => "ini/IniParse" 13 | 14 | fun apply(h: TestHelper) ? => 15 | let source = 16 | """ 17 | key 1 = value 1 ; Not in a section 18 | [Section 1] # First section 19 | 20 | key 2 = value 2 21 | 22 | [Section 2] 23 | 24 | [Section 3] 25 | key 2 = value 3 26 | key 1 = value 1;Not a comment 27 | """ 28 | 29 | let array: Array[String] = source.split("\r\n") 30 | let map = IniParse(array.values())? 31 | 32 | h.assert_eq[Bool](map.contains("Section 2"), true) 33 | 34 | h.assert_eq[String](map("")?("key 1")?, "value 1") 35 | h.assert_eq[String](map("Section 1")?("key 2")?, "value 2") 36 | h.assert_eq[String](map("Section 3")?("key 2")?, "value 3") 37 | h.assert_eq[String](map("Section 3")?("key 1")?, "value 1;Not a comment") 38 | -------------------------------------------------------------------------------- /client_vscode/packages/ini/ini_map.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | type IniMap is Map[String, Map[String, String]] 4 | 5 | primitive IniParse 6 | """ 7 | This is used to parse INI formatted text as a nested map of strings. 8 | """ 9 | fun apply(lines: Iterator[String]): IniMap ref^ ? => 10 | """ 11 | This accepts a string iterator and returns a nested map of strings. If 12 | parsing fails, an error is raised. 13 | """ 14 | let map = IniMap 15 | 16 | let f = object 17 | let map: IniMap = map 18 | 19 | fun ref apply(section: String, key: String, value: String): Bool => 20 | try 21 | if not map.contains(section) then 22 | map.insert(section, Map[String, String]) 23 | end 24 | map(section)?(key) = value 25 | end 26 | true 27 | 28 | fun ref add_section(section: String): Bool => 29 | if not map.contains(section) then 30 | map.insert(section, Map[String, String]) 31 | end 32 | true 33 | 34 | fun ref errors(line: USize, err: IniError): Bool => 35 | false 36 | end 37 | 38 | if not Ini(lines, f) then 39 | error 40 | end 41 | 42 | map 43 | -------------------------------------------------------------------------------- /client_vscode/packages/itertools/itertools.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Itertools Package 3 | 4 | The itertools package provides the `Iter` class for doing useful things with 5 | iterators. It is Inspired by Python's itertools library, Rust's Iterator, and 6 | Elixir's Enum and Stream. 7 | 8 | ## Iter 9 | 10 | The Iter class wraps iterators so that additional methods may be applied to it. 11 | Some methods, such as fold and collect, run through the underlying iterator in 12 | order to return a result. Others, such as map and filter, are lazy. This means 13 | that they return another Iter so that the resulting values are computed one by 14 | one as needed. Lazy methods return Iter types. 15 | 16 | For example, the following code creates an Iter from the values of an array 17 | containing the numbers 1 through 5, increments each number by one, filters out 18 | any odd numbers, and prints the rest. 19 | 20 | ```pony 21 | let xs = Iter[I64]([1; 2; 3; 4; 5].values()) 22 | .map[I64]({(x) => x + 1 }) 23 | .filter({(x) => (x % 2) == 0 }) 24 | .map[None]({(x) => env.out.print(x.string()) }) 25 | ``` 26 | 27 | This will result in an iterator that prints the numbers 2, 4, and 6. However, 28 | due to the lazy nature of the map and filter, no iteration has actually occurred 29 | and nothing will be printed. One solution to this would be to loop over the 30 | resulting Iter as so: 31 | 32 | ```pony 33 | for x in xs do 34 | None 35 | end 36 | ``` 37 | 38 | This will trigger the iteration and print out the values 2, 4, and 6. This is 39 | where the `run` method comes in handy by doing the iteration without the need 40 | for a loop. So the final code would be as follows: 41 | 42 | ```pony 43 | Iter[I64]([1; 2; 3; 4; 5].values()) 44 | .map[I64]({(x) => x + 1 }) 45 | .filter({(x) => (x % 2) == 0 }) 46 | .map[None]({(x) => env.out.print(x.string()) }) 47 | .run() 48 | ``` 49 | 50 | Output: 51 | 52 | ``` 53 | 2 54 | 4 55 | 6 56 | ``` 57 | """ 58 | -------------------------------------------------------------------------------- /client_vscode/packages/json/json.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # JSON Package 3 | 4 | The `json` package provides the [JsonDoc](json-JsonDoc.md) class both as a container for a JSON 5 | document and as means of parsing from and writing to [String](builtin-String.md). 6 | 7 | ## JSON Representation 8 | 9 | JSON is represented in Pony as the following types: 10 | 11 | * object - [JsonObject](json-JsonObject.md) 12 | * array - [JsonArray](json-JsonArray.md) 13 | * string - [String](builtin-String.md) 14 | * integer - [I64](builtin-I64.md) 15 | * float - [F64](builtin-F64.md) 16 | * boolean - [Bool](builtin-Bool.md) 17 | * null - [None](builtin-None.md) 18 | 19 | The collection types JsonObject and JsonArray can contain any other JSON 20 | structures arbitrarily nested. 21 | 22 | [JsonType](json-JsonType.md) is used to subsume all possible JSON types. It can 23 | also be used to describe everything that can be serialized using this package. 24 | 25 | ## Parsing JSON 26 | 27 | For getting JSON from a String into proper Pony data structures, 28 | [JsonDoc.parse](json-JsonDoc.md#parse) needs to be used. This will populate the 29 | public field `JsonDoc.data`, which is [None](builtin-None.md), if [parse](json-JsonDoc.md#parse) has 30 | not been called yet. 31 | 32 | Every call to [parse](json-JsonDoc.md#parse) overwrites the `data` field, so one 33 | JsonDoc instance can be used to parse multiple JSON Strings one by one. 34 | 35 | ```pony 36 | let doc = JsonDoc 37 | // parsing 38 | doc.parse("{\"key\":\"value\", \"property\": true, \"array\":[1, 2.5, false]}")? 39 | 40 | // extracting values from a JSON structure 41 | let json: JsonObject = doc.data as JsonObject 42 | let key: String = json.data("key")? as String 43 | let property: Bool = json.data("property")? as Bool 44 | let array: JsonArray = json.data("array")? as JsonArray 45 | let first: I64 = array.data(0)? as I64 46 | let second: F64 = array.data(1)? as F64 47 | let last: Bool = array.data(2)? as Bool 48 | ``` 49 | 50 | ### Sending JSON 51 | 52 | [JsonDoc](json-JsonDoc.md) has the `ref` reference capability, which means it is 53 | not sendable by default. If you need to send it to another actor you need to 54 | recover it to a sendable reference capability (either `val` or `iso`). For the 55 | sake of simplicity it is recommended to do the parsing already in the recover 56 | block: 57 | 58 | ```pony 59 | // sending an iso doc 60 | let json_string = "{\"array\":[1, true, null]}" 61 | let sendable_doc: JsonDoc iso = recover iso JsonDoc.>parse(json_string)? end 62 | some_actor.send(consume sendable_doc) 63 | 64 | // sending a val doc 65 | let val_doc: JsonDoc val = recover val JsonDoc.>parse(json_string)? end 66 | some_actor.send_val(val_doc) 67 | ``` 68 | 69 | When sending an `iso` JsonDoc it is important to recover it to a `ref` on the 70 | receiving side in order to be able to properly access the json structures in 71 | `data`. 72 | 73 | ## Writing JSON 74 | 75 | JSON is written using the [JsonDoc.string](json-JsonDoc.md#string) method. This 76 | will serialize the contents of the `data` field to [String](builtin-String.md). 77 | 78 | ```pony 79 | // building up the JSON data structure 80 | let doc = JsonDoc 81 | let obj = JsonObject 82 | obj.data("key") = "value" 83 | obj.data("property") = true 84 | obj.data("array") = JsonArray.from_array([ as JsonType: I64(1); F64(2.5); false]) 85 | doc.data = obj 86 | 87 | // writing to String 88 | env.out.print( 89 | doc.string(where indent=" ", pretty_print=true) 90 | ) 91 | 92 | ``` 93 | """ 94 | -------------------------------------------------------------------------------- /client_vscode/packages/math/fibonacci.pony: -------------------------------------------------------------------------------- 1 | class Fibonacci[A: (Integer[A] val & Unsigned) = U64] is Iterator[A] 2 | """ 3 | Useful for microbenchmarks to impress your friends. Look y'all, Pony goes 4 | fast! We suppose if you are into Agile planning poker that you could also 5 | use this in conjunction with `Random` to assign User Story Points. 6 | """ 7 | var _last: A = 0 8 | var _next: A = 0 9 | var _uber_next: A = 1 10 | 11 | fun apply(n: U8): A => 12 | if n == 0 then 0 13 | elseif n == 1 then 1 14 | else 15 | let j = n / 2 16 | let fib_j = apply(j) 17 | let fib_i = apply(j - 1) 18 | 19 | if (n % 2) == 0 then 20 | fib_j * (fib_j + (fib_i * 2)) 21 | elseif (n % 4) == 1 then 22 | (((fib_j * 2) + fib_i) * ((fib_j * 2) - fib_i)) + 2 23 | else 24 | (((fib_j * 2) + fib_i) * ((fib_j * 2) - fib_i)) - 2 25 | end 26 | end 27 | 28 | //The generator stops on overflow. 29 | fun has_next(): Bool => _last <= _next 30 | 31 | fun ref next(): A => 32 | _last = _next = _uber_next = _next + _uber_next 33 | _last 34 | -------------------------------------------------------------------------------- /client_vscode/packages/math/greatest_common_divisor.pony: -------------------------------------------------------------------------------- 1 | primitive GreatestCommonDivisor 2 | """ 3 | Get greatest common divisor of x and y. 4 | 5 | Providing 0 will result in an error. 6 | 7 | Example usage: 8 | 9 | ```pony 10 | use "math" 11 | 12 | actor Main 13 | new create(env: Env) => 14 | try 15 | let gcd = GreatestCommonDivisor[I64](10, 20)? 16 | env.out.print(gcd.string()) 17 | else 18 | env.out.print("No GCD") 19 | end 20 | ``` 21 | """ 22 | fun apply[A: Integer[A] val](x: A, y: A): A ? => 23 | let zero = A.from[U8](0) 24 | if (x == zero) or (y == zero) then 25 | error 26 | end 27 | 28 | var x': A = x 29 | var y': A = y 30 | 31 | while y' != zero do 32 | let z = y' 33 | y' = x' % y' 34 | x' = z 35 | end 36 | 37 | x' 38 | -------------------------------------------------------------------------------- /client_vscode/packages/math/least_common_multiple.pony: -------------------------------------------------------------------------------- 1 | primitive LeastCommonMultiple 2 | """ 3 | Get the least common multiple of x and y where both x and y >= 1. 4 | 5 | Providing 0 or numbers that overflow the integer width will result in an 6 | error. 7 | 8 | Example usage: 9 | 10 | ```pony 11 | use "math" 12 | 13 | actor Main 14 | new create(env: Env) => 15 | try 16 | let lcm = LeastCommonMultiple[U64](10, 20)? 17 | env.out.print(lcm.string()) 18 | else 19 | env.out.print("No LCM") 20 | end 21 | ``` 22 | """ 23 | fun apply[A: (Integer[A] val & Unsigned)](x: A, y: A): A ? => 24 | (x / GreatestCommonDivisor[A](x, y)?) *? y 25 | -------------------------------------------------------------------------------- /client_vscode/packages/math/math.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Math package 3 | 4 | Given the name `Math` for this package, you'd expect it have a broad and grand 5 | scope. Surprise! Not currently. However, we do have the most useful of all 6 | programming language math constructs: fibonacci! 7 | 8 | People like to make fun of fibonacci but let's face it, no fibonacci, no 9 | benchmarks. We hear from some of our engineer friends that math is very 10 | important to programming, we call upon that particular class of engineer friends 11 | to help us fill out this package with more maths than you can shake a stick at. 12 | Btw, in case you are wondering, yes we can shake a stick at a lot of maths. 13 | """ 14 | -------------------------------------------------------------------------------- /client_vscode/packages/net/auth.pony: -------------------------------------------------------------------------------- 1 | primitive NetAuth 2 | new create(from: AmbientAuth) => 3 | None 4 | 5 | primitive DNSAuth 6 | new create(from: (AmbientAuth | NetAuth)) => 7 | None 8 | 9 | primitive UDPAuth 10 | new create(from: (AmbientAuth | NetAuth)) => 11 | None 12 | 13 | primitive TCPAuth 14 | new create(from: (AmbientAuth | NetAuth)) => 15 | None 16 | 17 | primitive TCPListenAuth 18 | new create(from: (AmbientAuth | NetAuth | TCPAuth)) => 19 | None 20 | 21 | primitive TCPConnectAuth 22 | new create(from: (AmbientAuth | NetAuth | TCPAuth)) => 23 | None 24 | -------------------------------------------------------------------------------- /client_vscode/packages/net/dns.pony: -------------------------------------------------------------------------------- 1 | use @pony_os_addrinfo[Pointer[U8]](family: U32, host: Pointer[U8] tag, 2 | service: Pointer[U8] tag) 3 | use @pony_os_getaddr[None](addr: Pointer[None] tag, ipaddr: NetAddress tag) 4 | use @pony_os_nextaddr[Pointer[U8]](addr: Pointer[None] tag) 5 | use @freeaddrinfo[None](addr: Pointer[None] tag) 6 | use @pony_os_host_ip4[Bool](host: Pointer[U8] tag) 7 | use @pony_os_host_ip6[Bool](host: Pointer[U8] tag) 8 | 9 | primitive DNS 10 | """ 11 | Helper functions for resolving DNS queries. 12 | """ 13 | fun apply(auth: DNSAuth, host: String, service: String) 14 | : Array[NetAddress] iso^ 15 | => 16 | """ 17 | Gets all IPv4 and IPv6 addresses for a host and service. 18 | """ 19 | _resolve(auth, 0, host, service) 20 | 21 | fun ip4(auth: DNSAuth, host: String, service: String) 22 | : Array[NetAddress] iso^ 23 | => 24 | """ 25 | Gets all IPv4 addresses for a host and service. 26 | """ 27 | _resolve(auth, 1, host, service) 28 | 29 | fun ip6(auth: DNSAuth, host: String, service: String) 30 | : Array[NetAddress] iso^ 31 | => 32 | """ 33 | Gets all IPv6 addresses for a host and service. 34 | """ 35 | _resolve(auth, 2, host, service) 36 | 37 | fun broadcast_ip4(auth: DNSAuth, service: String) 38 | : Array[NetAddress] iso^ 39 | => 40 | """ 41 | Link-local IP4 broadcast address. 42 | """ 43 | ip4(auth, "255.255.255.255", service) 44 | 45 | fun broadcast_ip6(auth: DNSAuth, service: String) 46 | : Array[NetAddress] iso^ 47 | => 48 | """ 49 | Link-local IP6 broadcast address. 50 | """ 51 | ip6(auth, "FF02::1", service) 52 | 53 | fun is_ip4(host: String): Bool => 54 | """ 55 | Returns true if the host is a literal IPv4 address. 56 | """ 57 | @pony_os_host_ip4(host.cstring()) 58 | 59 | fun is_ip6(host: String): Bool => 60 | """ 61 | Returns true if the host is a literal IPv6 address. 62 | """ 63 | @pony_os_host_ip6(host.cstring()) 64 | 65 | fun _resolve( 66 | auth: DNSAuth, 67 | family: U32, 68 | host: String, 69 | service: String) 70 | : Array[NetAddress] iso^ 71 | => 72 | """ 73 | Turns an addrinfo pointer into an array of addresses. 74 | """ 75 | var list = recover Array[NetAddress] end 76 | var result = @pony_os_addrinfo(family, host.cstring(), service.cstring()) 77 | 78 | if not result.is_null() then 79 | var addr = result 80 | 81 | while not addr.is_null() do 82 | let ip = recover NetAddress end 83 | @pony_os_getaddr(addr, ip) 84 | list.push(consume ip) 85 | addr = @pony_os_nextaddr(addr) 86 | end 87 | 88 | @freeaddrinfo(result) 89 | end 90 | 91 | list 92 | -------------------------------------------------------------------------------- /client_vscode/packages/net/net.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Net package 3 | 4 | The Net package provides support for creating UDP and TCP clients and 5 | servers, reading and writing network data, and establishing UDP and 6 | TCP connections. 7 | """ 8 | 9 | use @pony_os_sockname[Bool](fd: U32, ip: NetAddress tag) 10 | -------------------------------------------------------------------------------- /client_vscode/packages/net/proxy.pony: -------------------------------------------------------------------------------- 1 | 2 | interface Proxy 3 | fun apply(wrap: TCPConnectionNotify iso): TCPConnectionNotify iso^ 4 | 5 | class val NoProxy is Proxy 6 | """ 7 | Default implementation of a proxy that does not alter the supplied `TCPConnectionNotify`. 8 | 9 | ```pony 10 | actor MyClient 11 | new create(host: String, service: String, proxy: Proxy = NoProxy) => 12 | let conn: TCPConnection = TCPConnection.create( 13 | TCPConnectAuth(env.root), 14 | proxy.apply(MyConnectionNotify.create()), 15 | "localhost", 16 | "80") 17 | ``` 18 | """ 19 | fun apply(wrap: TCPConnectionNotify iso): TCPConnectionNotify iso^ => wrap 20 | -------------------------------------------------------------------------------- /client_vscode/packages/net/tcp_listen_notify.pony: -------------------------------------------------------------------------------- 1 | interface TCPListenNotify 2 | """ 3 | Notifications for TCP listeners. 4 | 5 | For an example of using this class, please see the documentation for the 6 | `TCPListener` actor. 7 | """ 8 | fun ref listening(listen: TCPListener ref) => 9 | """ 10 | Called when the listener has been bound to an address. 11 | """ 12 | None 13 | 14 | fun ref not_listening(listen: TCPListener ref) 15 | """ 16 | Called if it wasn't possible to bind the listener to an address. 17 | 18 | It is expected to implement proper error handling. You need to opt in to 19 | ignoring errors, which can be implemented like this: 20 | 21 | ```pony 22 | fun ref not_listening(listen: TCPListener ref) => 23 | None 24 | ``` 25 | """ 26 | 27 | fun ref closed(listen: TCPListener ref) => 28 | """ 29 | Called when the listener is closed. 30 | """ 31 | None 32 | 33 | fun ref connected(listen: TCPListener ref): TCPConnectionNotify iso^ ? 34 | """ 35 | Create a new TCPConnectionNotify to attach to a new TCPConnection for a 36 | newly established connection to the server. 37 | """ 38 | -------------------------------------------------------------------------------- /client_vscode/packages/net/udp_notify.pony: -------------------------------------------------------------------------------- 1 | interface UDPNotify 2 | """ 3 | Notifications for UDP connections. 4 | 5 | For an example of using this class please see the documentatoin for the 6 | `UDPSocket` actor. 7 | """ 8 | fun ref listening(sock: UDPSocket ref) => 9 | """ 10 | Called when the socket has been bound to an address. 11 | """ 12 | None 13 | 14 | fun ref not_listening(sock: UDPSocket ref) 15 | """ 16 | Called if it wasn't possible to bind the socket to an address. 17 | 18 | It is expected to implement proper error handling. You need to opt in to 19 | ignoring errors, which can be implemented like this: 20 | 21 | ```pony 22 | fun ref not_listening(sock: UDPSocket ref) => 23 | None 24 | ``` 25 | """ 26 | 27 | fun ref received( 28 | sock: UDPSocket ref, 29 | data: Array[U8] iso, 30 | from: NetAddress) 31 | => 32 | """ 33 | Called when new data is received on the socket. 34 | """ 35 | None 36 | 37 | fun ref closed(sock: UDPSocket ref) => 38 | """ 39 | Called when the socket is closed. 40 | """ 41 | None 42 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_bench/_aggregator.pony: -------------------------------------------------------------------------------- 1 | 2 | class ref _Aggregator 3 | let _ponybench: PonyBench 4 | let _runner: _Runner 5 | let _overhead: Bool 6 | let _config: BenchConfig 7 | var _samples: Array[U64] iso 8 | var _warmup: Bool = true 9 | var iterations: U64 = 1 10 | 11 | new create( 12 | ponybench: PonyBench, 13 | runner: _Runner, 14 | config: BenchConfig, 15 | overhead: Bool) 16 | => 17 | _ponybench = ponybench 18 | _runner = runner 19 | _overhead = overhead 20 | _config = config 21 | _samples = recover Array[U64](_config.samples) end 22 | 23 | fun ref complete(name: String, t: U64) => 24 | if _warmup then 25 | match _calc_iterations(t) 26 | | let n: U64 => iterations = n 27 | | None => _warmup = false 28 | end 29 | _runner() 30 | else 31 | _samples.push(t) 32 | if _samples.size() < _config.samples then 33 | _runner() 34 | else 35 | _ponybench._complete(_Results( 36 | name, 37 | _samples = recover [] end, 38 | iterations, 39 | _overhead)) 40 | end 41 | end 42 | 43 | fun ref _calc_iterations(runtime: U64): (U64 | None) => 44 | let max_i = _config.max_iterations 45 | let max_t = _config.max_sample_time 46 | let nspi = runtime / iterations 47 | if (runtime < max_t) and (iterations < max_i) then 48 | var itrs' = 49 | if nspi == 0 then max_i 50 | else max_t / nspi 51 | end 52 | itrs' = (itrs' + (itrs' / 5)).min(iterations * 100).max(iterations + 1) 53 | _round_up(itrs') 54 | else 55 | iterations = iterations.min(max_i) 56 | None 57 | end 58 | 59 | fun _round_up(x: U64): U64 => 60 | """ 61 | Round x up to a number of the form [1^x, 2^x, 3^x, 5^x]. 62 | """ 63 | let base = _round_down_10(x) 64 | if x <= base then 65 | base 66 | elseif x <= (base * 2) then 67 | base * 2 68 | elseif x <= (base * 3) then 69 | base * 3 70 | elseif x <= (base * 5) then 71 | base * 5 72 | else 73 | base * 10 74 | end 75 | 76 | fun _round_down_10(x: U64): U64 => 77 | """ 78 | Round down to the nearest power of 10. 79 | """ 80 | let tens = x.f64().log10().floor() 81 | F64(10).pow(tens).u64() 82 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_bench/_output_manager.pony: -------------------------------------------------------------------------------- 1 | use "format" 2 | use "term" 3 | 4 | interface _OutputManager 5 | fun ref apply(results: _Results) 6 | 7 | class _TerminalOutput is _OutputManager 8 | let _env: Env 9 | let _noadjust: Bool 10 | var _overhead_mean: F64 = 0 11 | var _overhead_median: F64 = 0 12 | 13 | new create(env: Env) => 14 | _env = env 15 | _noadjust = _env.args.contains("--noadjust", {(a, b) => a == b }) 16 | if not _noadjust then 17 | _print("Benchmark results will have their mean and median adjusted for overhead.") 18 | _print("You may disable this with --noadjust.\n") 19 | end 20 | _print_heading() 21 | 22 | fun ref apply(results: _Results) => 23 | if results.overhead then 24 | if _noadjust then 25 | _print_benchmark(consume results, false) 26 | else 27 | _overhead_mean = results.mean() / results.iterations.f64() 28 | _overhead_median = results.median() / results.iterations.f64() 29 | end 30 | else 31 | _print_benchmark(consume results, not _noadjust) 32 | end 33 | 34 | fun ref _print_benchmark(results: _Results, adjust: Bool) => 35 | let iters = results.iterations.f64() 36 | let mean' = results.mean() 37 | var mean = mean' / iters 38 | var median = results.median() / iters 39 | if adjust then 40 | mean = mean - _overhead_mean 41 | median = median - _overhead_median 42 | end 43 | 44 | let std_dev = results.std_dev() 45 | let relative_std_dev = (std_dev * 100) / mean' 46 | 47 | _print_result( 48 | results.name, 49 | mean.round().i64().string(), 50 | median.round().i64().string(), 51 | Format.float[F64](relative_std_dev where prec = 2, fmt = FormatFix), 52 | iters.u64().string()) 53 | 54 | if (mean.round() < 0) or (median.round() < 0) then 55 | _warn("Adjustment for overhead has resulted in negative values.") 56 | end 57 | 58 | fun _print_heading() => 59 | _print("".join( 60 | [ ANSI.bold() 61 | Format("Benchmark" where width = 30) 62 | Format("mean" where width = 18, align = AlignRight) 63 | Format("median" where width = 18, align = AlignRight) 64 | Format("deviation" where width = 12, align = AlignRight) 65 | Format("iterations" where width = 12, align = AlignRight) 66 | ANSI.reset() 67 | ].values())) 68 | 69 | fun _print_result( 70 | name: String, 71 | mean: String, 72 | median: String, 73 | dev: String, 74 | iters: String) 75 | => 76 | _print("".join( 77 | [ Format(name where width = 30) 78 | Format(mean + " ns" where width = 18, align = AlignRight) 79 | Format(median + " ns" where width = 18, align = AlignRight) 80 | Format("±" + dev + "%" where width = 13, align = AlignRight) 81 | Format(iters where width = 12, align = AlignRight) 82 | ].values())) 83 | 84 | fun _print(msg: String) => 85 | _env.out.print(msg) 86 | 87 | fun _warn(msg: String) => 88 | _print(ANSI.yellow() + ANSI.bold() + "Warning: " + msg + ANSI.reset()) 89 | 90 | // TODO document 91 | // overhead, results... 92 | // name, results... 93 | class _CSVOutput 94 | let _env: Env 95 | 96 | new create(env: Env) => 97 | _env = env 98 | 99 | fun ref apply(results: _Results) => 100 | _print(results.raw_str()) 101 | 102 | fun _print(msg: String) => 103 | _env.out.print(msg) 104 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_bench/_results.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | class val _Results 4 | let name: String 5 | let samples: Array[U64] 6 | let iterations: U64 7 | let overhead: Bool 8 | 9 | new val create( 10 | name': String, 11 | samples': Array[U64] iso, 12 | iterations': U64, 13 | overhead': Bool) 14 | => 15 | name = name' 16 | samples = consume samples' 17 | iterations = iterations' 18 | overhead = overhead' 19 | Sort[Array[U64], U64](samples) 20 | 21 | fun raw_str(): String => 22 | let str = recover String end 23 | str .> append(name) .> append(",") 24 | for n in samples.values() do 25 | let nspi = n / iterations 26 | str .> append(nspi.string()) .> append(",") 27 | end 28 | if samples.size() > 0 then try str.pop()? end end 29 | str 30 | 31 | fun sum(): U64 => 32 | var sum': U64 = 0 33 | try 34 | for i in Range(0, samples.size()) do 35 | sum' = sum' + samples(i)? 36 | end 37 | end 38 | sum' 39 | 40 | fun mean(): F64 => 41 | sum().f64() / samples.size().f64() 42 | 43 | fun median(): F64 => 44 | try 45 | let len = samples.size() 46 | let i = len / 2 47 | if (len % 2) == 1 then 48 | samples(i)?.f64() 49 | else 50 | (let lo, let hi) = (samples(i)?, samples(i + 1)?) 51 | ((lo.f64() + hi.f64()) / 2).round() 52 | end 53 | else 54 | 0 55 | end 56 | 57 | fun std_dev(): F64 => 58 | // sample standard deviation 59 | if samples.size() < 2 then return 0 end 60 | try 61 | var sum_squares: F64 = 0 62 | for i in Range(0, samples.size()) do 63 | let n = samples(i)?.f64() 64 | sum_squares = sum_squares + (n * n) 65 | end 66 | let avg_squares = sum_squares / samples.size().f64() 67 | let mean' = mean() 68 | let mean_sq = mean' * mean' 69 | let len = samples.size().f64() 70 | ((len / (len - 1)) * (avg_squares - mean_sq)).sqrt() 71 | else 72 | 0 73 | end 74 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_check/ascii_range.pony: -------------------------------------------------------------------------------- 1 | 2 | primitive ASCIINUL 3 | fun apply(): String => "\x00" 4 | 5 | primitive ASCIIDigits 6 | fun apply(): String => "0123456789" 7 | 8 | primitive ASCIIWhiteSpace 9 | fun apply(): String => " \t\n\r\x0b\x0c" 10 | 11 | primitive ASCIIPunctuation 12 | fun apply(): String => "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" 13 | 14 | primitive ASCIILettersLower 15 | fun apply(): String => "abcdefghijklmnopqrstuvwxyz" 16 | 17 | primitive ASCIILettersUpper 18 | fun apply(): String => "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 19 | 20 | primitive ASCIILetters 21 | fun apply(): String => ASCIILettersLower() + ASCIILettersUpper() 22 | 23 | primitive ASCIIPrintable 24 | fun apply(): String => 25 | ASCIIDigits() 26 | + ASCIILetters() 27 | + ASCIIPunctuation() 28 | + ASCIIWhiteSpace() 29 | 30 | primitive ASCIINonPrintable 31 | fun apply(): String => 32 | "\x01\x02\x03\x04\x05\x06\x07\x08\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" 33 | 34 | primitive ASCIIAll 35 | """ 36 | Represents all ASCII characters, 37 | excluding the NUL (\x00) character for its special treatment in C strings. 38 | """ 39 | fun apply(): String => 40 | ASCIIPrintable() + ASCIINonPrintable() 41 | 42 | primitive ASCIIAllWithNUL 43 | """ 44 | Represents all ASCII characters, 45 | including the NUL (\x00) character for its special treatment in C strings. 46 | """ 47 | fun apply(): String => 48 | ASCIIAll() + ASCIINUL() 49 | 50 | type ASCIIRange is 51 | ( ASCIINUL 52 | | ASCIIDigits 53 | | ASCIIWhiteSpace 54 | | ASCIIPunctuation 55 | | ASCIILettersLower 56 | | ASCIILettersUpper 57 | | ASCIILetters 58 | | ASCIIPrintable 59 | | ASCIINonPrintable 60 | | ASCIIAll 61 | | ASCIIAllWithNUL) 62 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_check/for_all.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | class ForAll[T] 4 | let _gen: Generator[T] val 5 | let _helper: TestHelper 6 | 7 | new create(gen': Generator[T] val, testHelper: TestHelper) => 8 | _gen = gen' 9 | _helper = testHelper 10 | 11 | fun ref apply(prop: {(T, PropertyHelper) ?} val) ? => 12 | """execute""" 13 | Property1UnitTest[T]( 14 | object iso is Property1[T] 15 | fun name(): String => "" 16 | 17 | fun gen(): Generator[T] => _gen 18 | 19 | fun ref property(arg1: T, h: PropertyHelper) ? => 20 | prop(consume arg1, h)? 21 | end 22 | ).apply(_helper)? 23 | 24 | class ForAll2[T1, T2] 25 | let _gen1: Generator[T1] val 26 | let _gen2: Generator[T2] val 27 | let _helper: TestHelper 28 | 29 | new create( 30 | gen1': Generator[T1] val, 31 | gen2': Generator[T2] val, 32 | h: TestHelper) 33 | => 34 | _gen1 = gen1' 35 | _gen2 = gen2' 36 | _helper = h 37 | 38 | fun ref apply(prop: {(T1, T2, PropertyHelper) ?} val) ? => 39 | Property2UnitTest[T1, T2]( 40 | object iso is Property2[T1, T2] 41 | fun name(): String => "" 42 | fun gen1(): Generator[T1] => _gen1 43 | fun gen2(): Generator[T2] => _gen2 44 | fun ref property2(arg1: T1, arg2: T2, h: PropertyHelper) ? => 45 | prop(consume arg1, consume arg2, h)? 46 | end 47 | ).apply(_helper)? 48 | 49 | class ForAll3[T1, T2, T3] 50 | let _gen1: Generator[T1] val 51 | let _gen2: Generator[T2] val 52 | let _gen3: Generator[T3] val 53 | let _helper: TestHelper 54 | 55 | new create( 56 | gen1': Generator[T1] val, 57 | gen2': Generator[T2] val, 58 | gen3': Generator[T3] val, 59 | h: TestHelper) 60 | => 61 | _gen1 = gen1' 62 | _gen2 = gen2' 63 | _gen3 = gen3' 64 | _helper = h 65 | 66 | fun ref apply(prop: {(T1, T2, T3, PropertyHelper) ?} val) ? => 67 | Property3UnitTest[T1, T2, T3]( 68 | object iso is Property3[T1, T2, T3] 69 | fun name(): String => "" 70 | fun gen1(): Generator[T1] => _gen1 71 | fun gen2(): Generator[T2] => _gen2 72 | fun gen3(): Generator[T3] => _gen3 73 | fun ref property3(arg1: T1, arg2: T2, arg3: T3, h: PropertyHelper) ? => 74 | prop(consume arg1, consume arg2, consume arg3, h)? 75 | end 76 | ).apply(_helper)? 77 | 78 | class ForAll4[T1, T2, T3, T4] 79 | let _gen1: Generator[T1] val 80 | let _gen2: Generator[T2] val 81 | let _gen3: Generator[T3] val 82 | let _gen4: Generator[T4] val 83 | let _helper: TestHelper 84 | 85 | new create( 86 | gen1': Generator[T1] val, 87 | gen2': Generator[T2] val, 88 | gen3': Generator[T3] val, 89 | gen4': Generator[T4] val, 90 | h: TestHelper) 91 | => 92 | _gen1 = gen1' 93 | _gen2 = gen2' 94 | _gen3 = gen3' 95 | _gen4 = gen4' 96 | _helper = h 97 | 98 | fun ref apply(prop: {(T1, T2, T3, T4, PropertyHelper) ?} val) ? => 99 | Property4UnitTest[T1, T2, T3, T4]( 100 | object iso is Property4[T1, T2, T3, T4] 101 | fun name(): String => "" 102 | fun gen1(): Generator[T1] => _gen1 103 | fun gen2(): Generator[T2] => _gen2 104 | fun gen3(): Generator[T3] => _gen3 105 | fun gen4(): Generator[T4] => _gen4 106 | fun ref property4(arg1: T1, arg2: T2, arg3: T3, arg4: T4, h: PropertyHelper) ? => 107 | prop(consume arg1, consume arg2, consume arg3, consume arg4, h)? 108 | end 109 | ).apply(_helper)? 110 | 111 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_check/poperator.pony: -------------------------------------------------------------------------------- 1 | class ref Poperator[T] is Iterator[T^] 2 | """ 3 | Iterate over a [Seq](builtin-Seq.md) descructively by `pop`ing its elements. 4 | 5 | Once `has_next()` returns `false`, the [Seq](builtin-Seq.md) is empty. 6 | 7 | Nominee for the annual pony class-naming awards. 8 | """ 9 | 10 | let _seq: Seq[T] 11 | 12 | new create(seq: Seq[T]) => 13 | _seq = seq 14 | 15 | new empty() => 16 | _seq = Array[T](0) 17 | 18 | fun ref has_next(): Bool => 19 | _seq.size() > 0 20 | 21 | fun ref next(): T^ ? => 22 | _seq.pop()? 23 | 24 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_test/_color.pony: -------------------------------------------------------------------------------- 1 | primitive _Color 2 | """ 3 | Strings to embedded in text to specify colours. These are copies of the 4 | strings defined in packages/term. They are duplicated here to avoid a 5 | dependency. 6 | """ 7 | fun reset(): String => 8 | """ 9 | Resets all colours and text styles to the default. 10 | """ 11 | "\x1B[0m" 12 | 13 | fun red(): String => 14 | """ 15 | Bright red text. 16 | """ 17 | "\x1B[91m" 18 | 19 | fun green(): String => 20 | """ 21 | Bright green text. 22 | """ 23 | "\x1B[92m" 24 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_test/_group.pony: -------------------------------------------------------------------------------- 1 | trait tag _Group 2 | """ 3 | Test exclusion is achieved by organising tests into groups. Each group can be 4 | exclusive, ie only one test is run at a time, or simultaneous, ie all tests 5 | are run concurrently. 6 | """ 7 | 8 | be apply(runner: _TestRunner) 9 | """ 10 | Run the given test, or queue it and run later, as appropriate. 11 | """ 12 | 13 | be _test_complete(runner: _TestRunner) 14 | """ 15 | The specified test has completed. 16 | """ 17 | 18 | actor _ExclusiveGroup is _Group 19 | """ 20 | Test group in which we only ever have one test running at a time. 21 | """ 22 | 23 | embed _tests: Array[_TestRunner] = Array[_TestRunner] 24 | var _next: USize = 0 25 | var _in_test:Bool = false 26 | 27 | be apply(runner: _TestRunner) => 28 | if _in_test then 29 | // We're already running one test, save this one for later 30 | _tests.push(runner) 31 | else 32 | // Run test now 33 | _in_test = true 34 | runner.run() 35 | end 36 | 37 | be _test_complete(runner: _TestRunner) => 38 | _in_test = false 39 | 40 | if _next < _tests.size() then 41 | // We have queued tests, run the next one 42 | try 43 | let next_test = _tests(_next)? 44 | _next = _next + 1 45 | _in_test = true 46 | next_test.run() 47 | end 48 | end 49 | 50 | 51 | actor _SimultaneousGroup is _Group 52 | """ 53 | Test group in which all tests can run concurrently. 54 | """ 55 | 56 | be apply(runner: _TestRunner) => 57 | // Just run the test 58 | runner.run() 59 | 60 | be _test_complete(runner: _TestRunner) => 61 | // We don't care about tests finishing 62 | None 63 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_test/_test_record.pony: -------------------------------------------------------------------------------- 1 | class _TestRecord 2 | """ 3 | Store and report the result and log from a single test. 4 | """ 5 | 6 | let _env: Env 7 | let name: String 8 | var _pass: Bool = false 9 | var _log: (Array[String] val | None) = None 10 | 11 | new create(env: Env, name': String) => 12 | _env = env 13 | name = name' 14 | 15 | fun ref _result(pass: Bool, log: Array[String] val) => 16 | """ 17 | Our test has completed, store the result. 18 | """ 19 | _pass = pass 20 | _log = log 21 | 22 | fun _report(log_all: Bool): Bool => 23 | """ 24 | Print our test summary, including the log if appropriate. 25 | The log_all parameter indicates whether we've been told to print logs for 26 | all tests. The default is to only print logs for tests that fail. 27 | Returns our pass / fail status. 28 | """ 29 | var show_log = log_all 30 | 31 | if _pass then 32 | _env.out.print(_Color.green() + "---- Passed: " + name + _Color.reset()) 33 | else 34 | _env.out.print(_Color.red() + "**** FAILED: " + name + _Color.reset()) 35 | show_log = true 36 | end 37 | 38 | if show_log then 39 | match _log 40 | | let log: Array[String] val => 41 | // Print the log. Simply print each string in the array. 42 | for msg in log.values() do 43 | _env.out.print(msg) 44 | end 45 | end 46 | end 47 | 48 | _pass 49 | 50 | fun _list_failed() => 51 | """ 52 | Print our test name out in the list of failed test, if we failed. 53 | """ 54 | if not _pass then 55 | _env.out.print(_Color.red() + "**** FAILED: " + name + _Color.reset()) 56 | end 57 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_test/test_list.pony: -------------------------------------------------------------------------------- 1 | trait TestList 2 | """ 3 | Source of unit tests for a PonyTest object. 4 | See package doc string for further information and example use. 5 | """ 6 | 7 | fun tag tests(test: PonyTest) 8 | """ 9 | Add all the tests in this suite to the given test object. 10 | Typically the implementation of this function will be of the form: 11 | ```pony 12 | fun tests(test: PonyTest) => 13 | test(_TestClass1) 14 | test(_TestClass2) 15 | test(_TestClass3) 16 | ``` 17 | """ 18 | -------------------------------------------------------------------------------- /client_vscode/packages/pony_test/unit_test.pony: -------------------------------------------------------------------------------- 1 | trait UnitTest 2 | """ 3 | Each unit test class must provide this trait. Simple tests only need to 4 | define the name() and apply() functions. The remaining functions specify 5 | additional test options. 6 | """ 7 | 8 | fun name(): String 9 | """ 10 | Report the test name, which is used when printing test results and on the 11 | command line to select tests to run. 12 | """ 13 | 14 | fun exclusion_group(): String => 15 | """ 16 | Report the test exclusion group, returning an empty string for none. 17 | The default body returns an empty string. 18 | """ 19 | "" 20 | 21 | fun ref apply(h: TestHelper) ? 22 | """ 23 | Run the test. 24 | Raising an error is interpreted as a test failure. 25 | """ 26 | 27 | fun ref timed_out(h: TestHelper) => 28 | """ 29 | Tear down a possibly hanging test. 30 | Called when the timeout specified by to long_test() expires. 31 | There is no need for this function to call complete(false). 32 | tear_down() will still be called after this completes. 33 | The default is to do nothing. 34 | """ 35 | None 36 | 37 | fun ref set_up(h: TestHelper) ? => 38 | """ 39 | Set up the testing environment before a test method is called. 40 | Default is to do nothing. 41 | """ 42 | None 43 | 44 | fun ref tear_down(h: TestHelper) => 45 | """ 46 | Tidy up after the test has completed. 47 | Called for each run test, whether that test passed, succeeded or timed out. 48 | The default is to do nothing. 49 | """ 50 | None 51 | 52 | fun label(): String => 53 | """ 54 | Report the test label, returning an empty string for none. 55 | It can be later use to filter tests which we want to run, by labels. 56 | """ 57 | "" 58 | -------------------------------------------------------------------------------- /client_vscode/packages/process/auth.pony: -------------------------------------------------------------------------------- 1 | primitive StartProcessAuth 2 | new create(from: AmbientAuth) => 3 | None 4 | -------------------------------------------------------------------------------- /client_vscode/packages/process/process_error.pony: -------------------------------------------------------------------------------- 1 | class val ProcessError 2 | let error_type: ProcessErrorType 3 | let message: (String | None) 4 | 5 | new val create(error_type': ProcessErrorType, 6 | message': (String | None) = None) 7 | => 8 | error_type = error_type' 9 | message = message' 10 | 11 | fun string(): String iso^ => 12 | match message 13 | | let m: String => 14 | recover 15 | let etc = error_type.string() 16 | let err = String(etc.size() + 2 + m.size()) 17 | err.append(consume etc) 18 | err.append(": ") 19 | err.append(m) 20 | err 21 | end 22 | else 23 | error_type.string() 24 | end 25 | 26 | type ProcessErrorType is 27 | ( ExecveError 28 | | PipeError 29 | | ForkError 30 | | WaitpidError 31 | | WriteError 32 | | KillError 33 | | CapError 34 | | ChdirError 35 | | UnknownError 36 | ) 37 | 38 | primitive ExecveError 39 | fun string(): String iso^ => "ExecveError".clone() 40 | 41 | primitive PipeError 42 | fun string(): String iso^ => "PipeError".clone() 43 | 44 | primitive ForkError 45 | fun string(): String iso^ => "ForkError".clone() 46 | 47 | primitive WaitpidError 48 | fun string(): String iso^ => "WaitpidError".clone() 49 | 50 | primitive WriteError 51 | fun string(): String iso^ => "WriteError".clone() 52 | 53 | primitive KillError // Not thrown at this time 54 | fun string(): String iso^ => "KillError".clone() 55 | 56 | primitive CapError 57 | fun string(): String iso^ => "CapError".clone() 58 | 59 | primitive ChdirError 60 | fun string(): String iso^ => "ChdirError".clone() 61 | 62 | primitive UnknownError 63 | fun string(): String iso^ => "UnknownError".clone() 64 | -------------------------------------------------------------------------------- /client_vscode/packages/process/process_notify.pony: -------------------------------------------------------------------------------- 1 | interface ProcessNotify 2 | """ 3 | Notifications for Process connections. 4 | """ 5 | 6 | fun ref created(process: ProcessMonitor ref) => 7 | """ 8 | ProcessMonitor calls this when it is created. 9 | """ 10 | 11 | fun ref stdout(process: ProcessMonitor ref, data: Array[U8] iso) => 12 | """ 13 | ProcessMonitor calls this when new data is received on STDOUT of the 14 | forked process 15 | """ 16 | 17 | fun ref stderr(process: ProcessMonitor ref, data: Array[U8] iso) => 18 | """ 19 | ProcessMonitor calls this when new data is received on STDERR of the 20 | forked process 21 | """ 22 | 23 | fun ref failed(process: ProcessMonitor ref, err: ProcessError) => 24 | """ 25 | ProcessMonitor calls this if we run into errors communicating with the 26 | forked process. 27 | """ 28 | 29 | fun ref expect(process: ProcessMonitor ref, qty: USize): USize => 30 | """ 31 | Called when the process monitor has been told to expect a certain quantity 32 | of bytes. This allows nested notifiers to change the expected quantity, 33 | which allows a lower level protocol to handle any framing. 34 | """ 35 | qty 36 | 37 | fun ref dispose(process: ProcessMonitor ref, child_exit_status: ProcessExitStatus) => 38 | """ 39 | Called when ProcessMonitor terminates to cleanup ProcessNotify if a child 40 | process was in fact started. `dispose` will not be called if a child process 41 | was never started. The notify will know that a process was started and to 42 | expect a `dispose` call by having received a `created` call. 43 | 44 | `dispose` includes the exit status of the child process. If the process 45 | finished, then `child_exit_status` will be an instance of [Exited](process-Exited.md). 46 | 47 | The childs exit code can be retrieved from the `Exited` instance by using 48 | [Exited.exit_code()](process-Exited.md#exit_code). 49 | 50 | On Posix systems, if the process has been killed by a signal (e.g. through 51 | the `kill` command), `child_exit_status` will be an instance of 52 | [Signaled](process-Signaled.md) with the signal number that terminated the 53 | process available via [Signaled.signal()](process-Signaled.md#signal). 54 | """ 55 | -------------------------------------------------------------------------------- /client_vscode/packages/promises/_then.pony: -------------------------------------------------------------------------------- 1 | class _Then[A: Any #share, B: Any #share] 2 | """ 3 | A step in a promise pipeline. 4 | """ 5 | let _fulfill: Fulfill[A, B] 6 | let _rejected: Reject[B] 7 | let _promise: Promise[B] 8 | var _active: Bool = true 9 | 10 | new iso create(fulfill: Fulfill[A, B], rejected: Reject[B]) => 11 | """ 12 | A step is represented by a fulfill function and a reject function. 13 | """ 14 | _fulfill = consume fulfill 15 | _rejected = consume rejected 16 | _promise = Promise[B] 17 | 18 | fun promise(): Promise[B] => 19 | """ 20 | Returns the next promise in the chain. 21 | """ 22 | _promise 23 | 24 | fun ref apply(value: A) => 25 | """ 26 | Called with the result of the previous promise when it is fulfilled. 27 | """ 28 | if _active then 29 | _active = false 30 | 31 | try 32 | _promise(_fulfill(value)?) 33 | else 34 | _promise.reject() 35 | end 36 | end 37 | 38 | fun ref reject() => 39 | """ 40 | Called when the previous promise is rejected. 41 | """ 42 | if _active then 43 | _active = false 44 | 45 | try 46 | _promise(_rejected()?) 47 | else 48 | _promise.reject() 49 | end 50 | end 51 | 52 | interface _IThen[A: Any #share] 53 | """ 54 | An interface representing an abstract Then. This allows for any Then that 55 | accepts an input of type A, regardless of the output type. 56 | """ 57 | fun ref apply(value: A) 58 | fun ref reject() 59 | -------------------------------------------------------------------------------- /client_vscode/packages/promises/fulfill.pony: -------------------------------------------------------------------------------- 1 | primitive _Pending 2 | primitive _Reject 3 | 4 | interface iso Fulfill[A: Any #share, B: Any #share] 5 | """ 6 | A function from A to B that is called when a promise is fulfilled. 7 | """ 8 | fun ref apply(value: A): B ? 9 | 10 | interface iso Reject[A: Any #share] 11 | """ 12 | A function on A that is called when a promise is rejected. 13 | """ 14 | fun ref apply(): A ? 15 | 16 | class iso FulfillIdentity[A: Any #share] 17 | """ 18 | An identity function for fulfilling promises. 19 | """ 20 | fun ref apply(value: A): A => 21 | consume value 22 | 23 | class iso RejectAlways[A: Any #share] 24 | """ 25 | A reject that always raises an error. 26 | """ 27 | fun ref apply(): A ? => 28 | error 29 | -------------------------------------------------------------------------------- /client_vscode/packages/promises/promises.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Promises Package 3 | 4 | A `Promise` represents a value that will be available at a later 5 | time. `Promise`s can either be fulfilled with a value or rejected. Any 6 | number of function handlers can be added to the `Promise`, to be 7 | called when the `Promise` is fulfilled or rejected. These handlers 8 | themselves are also wrapped in `Promise`s so that they can be chained 9 | together in order for the fulfilled value of one `Promise` to be used 10 | to compute a value which will be used to fulfill the next `Promise` in 11 | the chain, or so that if the `Promise` is rejected then the subsequent 12 | reject functions will also be called. The input and output types of a 13 | fulfill handler do not have to be the same, so a chain of fulfill 14 | handlers can transform the original value into something new. 15 | 16 | Fulfill and reject handlers can either be specified as classes that 17 | implment the `Fulfill` and `Reject` interfaces, or as functions with 18 | the same signatures as the `apply` methods in `Fulfill` and `Reject`. 19 | 20 | In the following code, the fulfillment of the `Promise` causes the 21 | execution of several fulfillment functions. The output is: 22 | 23 | ``` 24 | fulfilled + foo 25 | fulfilled + bar 26 | fulfilled + baz 27 | ``` 28 | 29 | ```pony 30 | use "promises" 31 | 32 | class PrintFulfill is Fulfill[String, String] 33 | let _env: Env 34 | let _msg: String 35 | new create(env: Env, msg: String) => 36 | _env = env 37 | _msg = msg 38 | fun apply(s: String): String => 39 | _env.out.print(" + ".join([s; _msg].values())) 40 | s 41 | 42 | actor Main 43 | new create(env: Env) => 44 | let promise = Promise[String] 45 | promise.next[String](recover PrintFulfill(env, "foo") end) 46 | promise.next[String](recover PrintFulfill(env, "bar") end) 47 | promise.next[String](recover PrintFulfill(env, "baz") end) 48 | promise("fulfilled") 49 | ``` 50 | 51 | In the following code, the fulfill functions are chained together so 52 | that the fulfilled value of the first one is used to generate a value 53 | which fulfills the second one, which in turn is used to compute a 54 | value which fulfills the third one, which in turn is used to compute a 55 | value which fulfills the fourth one. The output is the average length 56 | of the words passed on the command line or `0` if there are no command 57 | line arguments. 58 | 59 | ```pony 60 | use "promises" 61 | 62 | primitive Computation 63 | fun tag string_to_strings(s: String): Array[String] val => 64 | recover s.split() end 65 | fun tag strings_to_sizes(sa: Array[String] val): Array[USize] val => 66 | recover 67 | let len = Array[USize] 68 | for s in sa.values() do 69 | len.push(s.size()) 70 | end 71 | len 72 | end 73 | fun tag sizes_to_avg(sza: Array[USize] val): USize => 74 | var acc = USize(0) 75 | for sz in sza.values() do 76 | acc = acc + sz 77 | end 78 | acc / sza.size() 79 | fun tag output(env: Env, sz: USize): None => 80 | env.out.print(sz.string()) 81 | 82 | actor Main 83 | new create(env: Env) => 84 | let promise = Promise[String] 85 | promise.next[Array[String] val](recover Computation~string_to_strings() end) 86 | .next[Array[USize] val](recover Computation~strings_to_sizes() end) 87 | .next[USize](recover Computation~sizes_to_avg() end) 88 | .next[None](recover Computation~output(env) end) 89 | promise(" ".join(env.args.slice(1).values())) 90 | ``` 91 | """ 92 | -------------------------------------------------------------------------------- /client_vscode/packages/random/benchmarks/main.pony: -------------------------------------------------------------------------------- 1 | use ".." 2 | use "pony_bench" 3 | 4 | actor Main is BenchmarkList 5 | new create(env: Env) => 6 | PonyBench(env, this) 7 | 8 | fun tag benchmarks(bench: PonyBench) => 9 | bench(RandIntBenchmark) 10 | bench(RandIntUnbiasedBenchmark) 11 | bench(RandIntFPMultBenchmark) 12 | bench(RandomBenchmark[MT]("mt")) 13 | bench(RandomBenchmark[XorShift128Plus]("xorshift128+")) 14 | bench(RandomBenchmark[XorOshiro128Plus]("xoroshiro128+")) 15 | bench(RandomBenchmark[XorOshiro128StarStar]("xoroshiro128**")) 16 | bench(RandomBenchmark[SplitMix64]("splitmix64")) 17 | 18 | class iso RandIntBenchmark is MicroBenchmark 19 | let _rand: Rand 20 | var _bound: U64 = 0 21 | 22 | new iso create() => 23 | _rand = Rand.create() 24 | 25 | fun name(): String => "random/int" 26 | 27 | fun ref before_iteration() => 28 | _bound = _rand.next() 29 | 30 | fun ref apply() => 31 | let x = _rand.int(_bound) 32 | DoNotOptimise[U64](x) 33 | DoNotOptimise.observe() 34 | 35 | class iso RandIntUnbiasedBenchmark is MicroBenchmark 36 | let _rand: Rand 37 | var _bound: U64 = 0 38 | 39 | new iso create() => 40 | _rand = Rand.create() 41 | 42 | fun name(): String => "random/int-unbiased" 43 | 44 | fun ref before_iteration() => 45 | _bound = _rand.next() 46 | 47 | fun ref apply() => 48 | let x = _rand.int_unbiased(_bound) 49 | DoNotOptimise[U64](x) 50 | DoNotOptimise.observe() 51 | 52 | class iso RandIntFPMultBenchmark is MicroBenchmark 53 | let _rand: Rand 54 | var _bound: U64 = 0 55 | 56 | new iso create() => 57 | _rand = Rand.create() 58 | 59 | fun name(): String => "random/int-fp-mult" 60 | 61 | fun ref before_iteration() => 62 | _bound = _rand.next() 63 | 64 | fun ref apply() => 65 | let x = _rand.int_fp_mult(_bound) 66 | DoNotOptimise[U64](x) 67 | DoNotOptimise.observe() 68 | 69 | class iso RandomBenchmark[T: Random ref] is MicroBenchmark 70 | let _rand: T 71 | let _name: String 72 | 73 | new iso create(name': String) => 74 | _name = name' 75 | _rand = T.create() 76 | 77 | fun name(): String => "random/next/" + _name 78 | 79 | fun ref apply() => 80 | let x: U64 = _rand.next() 81 | DoNotOptimise[U64](x) 82 | DoNotOptimise.observe() 83 | -------------------------------------------------------------------------------- /client_vscode/packages/random/dice.pony: -------------------------------------------------------------------------------- 1 | class Dice 2 | """ 3 | A simple dice roller. 4 | """ 5 | var r: Random 6 | 7 | new create(from: Random) => 8 | """ 9 | Initialise with a random number generator. 10 | """ 11 | r = from 12 | 13 | fun ref apply(count: U64, sides: U64): U64 => 14 | """ 15 | Return the sum of `count` rolls of a die with the given number of `sides`. 16 | The die is numbered from 1 to `sides`. For example, count = 2 and 17 | sides = 6 will return a value between 2 and 12. 18 | """ 19 | var sum = count 20 | var i: U64 = 0 21 | 22 | while i < count do 23 | sum = sum + r.int(sides) 24 | i = i + 1 25 | end 26 | sum 27 | -------------------------------------------------------------------------------- /client_vscode/packages/random/mt.pony: -------------------------------------------------------------------------------- 1 | class MT is Random 2 | """ 3 | A Mersenne Twister. This is a non-cryptographic random number generator. This 4 | should only be used for legacy applications that require a Mersenne Twister, 5 | otherwise use Rand. 6 | """ 7 | embed _state: Array[U64] 8 | var _index: USize 9 | 10 | new create(x: U64 = 5489, y: U64 = 0) => 11 | """ 12 | Create with the specified seed. Returned values are deterministic for a 13 | given seed. 14 | """ 15 | _state = Array[U64](_n()) 16 | _index = _n() 17 | 18 | var seed = x xor y 19 | 20 | _state.push(seed) 21 | var i: USize = 1 22 | 23 | while i < _n() do 24 | seed = ((seed xor (seed >> 62)) * 6364136223846793005) + i.u64() 25 | _state.push(seed) 26 | i = i + 1 27 | end 28 | 29 | fun ref next(): U64 => 30 | """ 31 | A random integer in [0, 2^64) 32 | """ 33 | if _index >= _n() then 34 | _populate() 35 | end 36 | 37 | try 38 | var x = _state(_index)? 39 | _index = _index + 1 40 | 41 | x = x xor ((x >> 29) and 0x5555555555555555) 42 | x = x xor ((x << 17) and 0x71d67fffeda60000) 43 | x = x xor ((x << 37) and 0xfff7eee000000000) 44 | x xor (x >> 43) 45 | else 46 | 0 47 | end 48 | 49 | fun ref _populate() => 50 | """ 51 | Repopulates the state array. 52 | """ 53 | try 54 | _index = 0 55 | var x = _state(0)? 56 | var i: USize = 0 57 | 58 | while i < _m() do 59 | x = _lower(i, x)? 60 | i = i + 1 61 | end 62 | 63 | x = _state(_m())? 64 | i = _m() 65 | 66 | while i < _n1() do 67 | x = _upper(i, x)? 68 | i = i + 1 69 | end 70 | 71 | _wrap()? 72 | end 73 | 74 | fun tag _n(): USize => 312 75 | fun tag _m(): USize => 156 76 | fun tag _n1(): USize => _n() - 1 77 | 78 | fun tag _mask(x: U64, y: U64): U64 => 79 | (x and 0xffffffff80000000) or (y and 0x000000007fffffff) 80 | 81 | fun tag _matrix(x: U64): U64 => (x and 1) * 0xb5026f5aa96619e9 82 | 83 | fun tag _mix(x: U64, y: U64): U64 => 84 | let z = _mask(x, y) 85 | (z >> 1) xor _matrix(z) 86 | 87 | fun ref _lower(i: USize, x: U64): U64 ? => 88 | let y = _state(i + 1)? 89 | _state(i)? = _state(i + _m())? xor _mix(x, y) 90 | y 91 | 92 | fun ref _upper(i: USize, x: U64): U64 ? => 93 | let y = _state(i + 1)? 94 | _state(i)? = _state(i - _m())? xor _mix(x, y) 95 | y 96 | 97 | fun ref _wrap(): U64 ? => 98 | let x = _state(_n1())? 99 | let y = _state(0)? 100 | _state(_n1())? = _state(_m() - 1)? xor _mix(x, y) 101 | y 102 | -------------------------------------------------------------------------------- /client_vscode/packages/random/splitmix64.pony: -------------------------------------------------------------------------------- 1 | class SplitMix64 is Random 2 | """ 3 | Very fast Pseudo-Random-Number-Generator 4 | using only 64 bit of state, as detailed at: 5 | 6 | http://xoshiro.di.unimi.it/ and http://gee.cs.oswego.edu/dl/papers/oopsla14.pdf 7 | 8 | Using [XorOshiro128StarStar](random-XorOshiro128StarStar.md) or [XorOshiro128Plus](random-XorOshiro128Plus.md) 9 | should be prefered unless using only 64 bit of state is a requirement. 10 | """ 11 | // state 12 | var _x: U64 13 | 14 | new from_u64(x: U64 = 5489) => 15 | _x = x 16 | 17 | new create(x: U64 = 5489, y: U64 = 0) => 18 | """ 19 | Only x is used, y is discarded. 20 | """ 21 | _x = x 22 | 23 | fun ref next(): U64 => 24 | _x = _x + U64(0x9e3779b97f4a7c15) 25 | var z: U64 = _x 26 | z = (z xor (z >> 30)) * U64(0xbf58476d1ce4e5b9) 27 | z = (z xor (z >> 27)) * U64(0x94d049bb133111eb) 28 | z xor (z >> 31) 29 | 30 | -------------------------------------------------------------------------------- /client_vscode/packages/random/xoroshiro.pony: -------------------------------------------------------------------------------- 1 | class XorOshiro128Plus is Random 2 | """ 3 | This is an implementation of xoroshiro128+, as detailed at: 4 | 5 | http://xoroshiro.di.unimi.it 6 | 7 | This is currently the default Rand implementation. 8 | """ 9 | // state 10 | var _x: U64 11 | var _y: U64 12 | 13 | new from_u64(x: U64 = 5489) => 14 | """ 15 | Use seed x to seed a [SplitMix64](random-SplitMix64.md) and use this to 16 | initialize the 128 bits of state. 17 | """ 18 | let sm = SplitMix64(x) 19 | _x = sm.next() 20 | _y = sm.next() 21 | 22 | new create(x: U64 = 5489, y: U64 = 0) => 23 | """ 24 | Create with the specified seed. Returned values are deterministic for a 25 | given seed. 26 | """ 27 | _x = x 28 | _y = y 29 | next() 30 | 31 | fun ref next(): U64 => 32 | """ 33 | A random integer in [0, 2^64) 34 | """ 35 | let x = _x 36 | var y = _y 37 | let r = x + y 38 | 39 | y = x xor y 40 | _x = x.rotl(24) xor y xor (y << 16) 41 | _y = y.rotl(37) 42 | r 43 | 44 | class XorOshiro128StarStar is Random 45 | """ 46 | This is an implementation of xoroshiro128**, as detailed at: 47 | 48 | http://xoshiro.di.unimi.it/ 49 | 50 | This Rand implementation is slightly slower than [XorOshiro128Plus](random-XorOshiro128Plus.md) 51 | but does not exhibit "mild dependencies in Hamming weights" (the lower four bits might fail linearity tests). 52 | """ 53 | 54 | var _x: U64 55 | var _y: U64 56 | 57 | new from_u64(x: U64 = 5489) => 58 | """ 59 | Use seed x to seed a [SplitMix64](random-SplitMix64.md) and use this to 60 | initialize the 128 bits of state. 61 | """ 62 | let sm = SplitMix64(x) 63 | _x = sm.next() 64 | _y = sm.next() 65 | 66 | new create(x: U64 = 5489, y: U64 = 0) => 67 | _x = x 68 | _y = y 69 | next() 70 | 71 | fun ref next(): U64 => 72 | let x = _x 73 | var y = _y 74 | let r = (x * 5).rotl(7) * 9 75 | y = x xor y 76 | 77 | _x = x.rotl(24) xor y xor (y << 16) 78 | _y = y.rotl(37) 79 | r 80 | -------------------------------------------------------------------------------- /client_vscode/packages/random/xorshift.pony: -------------------------------------------------------------------------------- 1 | class XorShift128Plus is Random 2 | """ 3 | This is an implementation of xorshift+, as detailed at: 4 | 5 | http://xoroshiro.di.unimi.it 6 | 7 | This should only be used for legacy applications that specifically require 8 | XorShift128Plus, otherwise use Rand. 9 | """ 10 | var _x: U64 11 | var _y: U64 12 | 13 | new from_u64(x: U64 = 5489) => 14 | """ 15 | Use seed x to seed a [SplitMix64](random-SplitMix64.md) and use this to 16 | initialize the 128 bits of state. 17 | """ 18 | let sm = SplitMix64(x) 19 | _x = sm.next() 20 | _y = sm.next() 21 | 22 | new create(x: U64 = 5489, y: U64 = 0) => 23 | """ 24 | Create with the specified seed. Returned values are deterministic for a 25 | given seed. 26 | """ 27 | _x = x 28 | _y = y 29 | next() 30 | 31 | fun ref next(): U64 => 32 | """ 33 | A random integer in [0, 2^64) 34 | """ 35 | var y = _x 36 | let x = _y 37 | let r = x + y 38 | _x = x 39 | y = y xor (y << 23) 40 | _y = y xor x xor (y >> 18) xor (x >> 5) 41 | r 42 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/_actor_stats.pony: -------------------------------------------------------------------------------- 1 | struct _ActorStats 2 | """ 3 | Pony struct for the Pony actor stats C struct that can be used to 4 | inspect statistics about an actor. 5 | """ 6 | 7 | var heap_mem_allocated: USize = -1 8 | """ 9 | Memory currently allocated by objects on the actor heap 10 | """ 11 | 12 | var heap_mem_used: USize = -1 13 | """ 14 | Memory currently used by objects on the actor heap 15 | """ 16 | 17 | var heap_num_allocated: USize = -1 18 | """ 19 | Number of objects currently on the actor heap 20 | """ 21 | 22 | var heap_realloc_counter: USize = -1 23 | """ 24 | Number of heap re-allocations made on the actor heap during the 25 | lifetime of the actor 26 | """ 27 | 28 | var heap_alloc_counter: USize = -1 29 | """ 30 | Number of heap allocations made on the actor heap during the 31 | lifetime of the actor 32 | """ 33 | 34 | var heap_free_counter: USize = -1 35 | """ 36 | Number of heap allocations freed on the actor heap during the 37 | lifetime of the actor 38 | """ 39 | 40 | var heap_gc_counter: USize = -1 41 | """ 42 | Number of times the heap has been garbage collected 43 | """ 44 | 45 | var system_cpu: USize = -1 46 | """ 47 | Amount of cpu used to process system messages 48 | """ 49 | 50 | var app_cpu: USize = -1 51 | """ 52 | Amount of cpu used to process app messages 53 | """ 54 | 55 | var gc_mark_cpu: USize = -1 56 | """ 57 | Amount of cpu used for mark phase to garbage collect actor heap 58 | """ 59 | 60 | var gc_sweep_cpu: USize = -1 61 | """ 62 | Amount of cpu used for sweep phase to garbage collect actor heap 63 | """ 64 | 65 | var messages_sent_counter: USize = -1 66 | """ 67 | Number of messages the actor has sent 68 | """ 69 | 70 | var system_messages_processed_counter: USize = -1 71 | """ 72 | Number of system messages the actor has processed 73 | """ 74 | 75 | var app_messages_processed_counter: USize = -1 76 | """ 77 | Number of app messages the actor has processed 78 | """ 79 | 80 | var foreign_actormap_objectmap_mem_used: USize = -1 81 | """ 82 | Memory in use by the objectmaps stored in the foreign actormap 83 | """ 84 | 85 | var foreign_actormap_objectmap_mem_allocated: USize = -1 86 | """ 87 | Memory allocated by the objectmaps stored in the foreign actormap 88 | """ 89 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/_scheduler_stats.pony: -------------------------------------------------------------------------------- 1 | struct _SchedulerStats 2 | """ 3 | Pony struct for the Pony scheduler stats C struct that can be used to 4 | inspect statistics about a scheduler thread. 5 | """ 6 | 7 | var mem_used: I64 = -1 8 | """ 9 | Memory used by mutemaps 10 | """ 11 | 12 | var mem_allocated: I64 = -1 13 | """ 14 | Memory allocated for mutemaps 15 | """ 16 | 17 | var mem_used_actors: I64 = -1 18 | """ 19 | Memory used for actors created and for GC acquire/release actormaps 20 | """ 21 | 22 | var mem_allocated_actors: I64 = -1 23 | """ 24 | Memory allocated for actors created and for GC acquire/release actormaps 25 | """ 26 | 27 | var created_actors_counter: USize = -1 28 | """ 29 | Count of actors created 30 | """ 31 | 32 | var destroyed_actors_counter: USize = -1 33 | """ 34 | Count of actors destroyed 35 | """ 36 | 37 | var actor_app_cpu: USize = -1 38 | """ 39 | Amount of cpu used to process actor app messages 40 | """ 41 | 42 | var actor_gc_mark_cpu: USize = -1 43 | """ 44 | Amount of cpu used for mark phase to garbage collect actor heaps 45 | """ 46 | 47 | var actor_gc_sweep_cpu: USize = -1 48 | """ 49 | Amount of cpu used sweep phase to garbage collect actor heaps 50 | """ 51 | 52 | var actor_system_cpu: USize = -1 53 | """ 54 | Amount of cpu used to process actor system messages 55 | """ 56 | 57 | var msg_cpu: USize = -1 58 | """ 59 | Amount of cpu used to process scheduler system messages 60 | """ 61 | 62 | var misc_cpu: USize = -1 63 | """ 64 | Amount of cpu used to by scheduler while waiting to do work 65 | """ 66 | 67 | var mem_used_inflight_messages: I64 = -1 68 | """ 69 | Memory used by inflight messages 70 | """ 71 | 72 | var mem_allocated_inflight_messages: I64 = -1 73 | """ 74 | Memory allocated for inflight messages 75 | """ 76 | 77 | var num_inflight_messages: I64 = -1 78 | """ 79 | Number of inflight messages 80 | """ 81 | 82 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | None 9 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/auth.pony: -------------------------------------------------------------------------------- 1 | primitive SchedulerInfoAuth 2 | new create(auth: AmbientAuth) => None 3 | 4 | primitive ActorStatsAuth 5 | new create(auth: AmbientAuth) => None 6 | 7 | primitive SchedulerStatsAuth 8 | new create(auth: AmbientAuth) => None 9 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/runtime_info.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Runtime Info package 3 | 4 | The runtime information package exposes information about the Pony runtime that 5 | can be queried at runtime. The most common usage at this time is limiting the 6 | number of work based on the number of available schedulers. 7 | 8 | For example, in an application that is doing parallel processing and wants to 9 | limit the number of processing actors to the maximum number that could be run 10 | at one time, you can use `Scheduler.schedulers` to get the scheduler 11 | information. 12 | 13 | ```pony 14 | use "collections" 15 | use "runtime_info" 16 | 17 | actor Processor 18 | 19 | actor Main 20 | new create(env: Env) => 21 | let s = Scheduler.schedulers(SchedulerInfoAuth(env.root)) 22 | for i in Range(0, s) do 23 | Processor 24 | end 25 | ``` 26 | """ 27 | -------------------------------------------------------------------------------- /client_vscode/packages/runtime_info/scheduler.pony: -------------------------------------------------------------------------------- 1 | use @pony_schedulers[U32]() 2 | use @pony_active_schedulers[U32]() 3 | use @pony_min_schedulers[U32]() 4 | use @pony_scheduler_yield[Bool]() 5 | use @pony_scheduler_index[I32]() 6 | 7 | primitive Scheduler 8 | """ 9 | Provides functions that expose information about runtime schedulers. 10 | """ 11 | 12 | fun schedulers(auth: SchedulerInfoAuth): U32 => 13 | """ 14 | Returns the maximum number of schedulers available to run actors. 15 | """ 16 | @pony_schedulers() 17 | 18 | fun active_schedulers(auth: SchedulerInfoAuth): U32 => 19 | """ 20 | Returns the number of schedulers currently available to run actors. 21 | """ 22 | @pony_active_schedulers() 23 | 24 | fun minimum_schedulers(auth: SchedulerInfoAuth): U32 => 25 | """ 26 | Returns the minimum number of schedulers. The active number of schedulers is 27 | guaranteed to never drop below this number. 28 | """ 29 | @pony_min_schedulers() 30 | 31 | fun sleeping_schedulers(auth: SchedulerInfoAuth): U32 => 32 | """ 33 | Returns the number of schedulers that are currently sleeping and not 34 | available run actors. Schedulers are put to sleep if there isn't enough 35 | work to keep all of the possible schedulers busy. 36 | """ 37 | @pony_schedulers() - @pony_active_schedulers() 38 | 39 | fun scaling_is_active(auth: SchedulerInfoAuth): Bool => 40 | """ 41 | Returns true is scheduler scaling is on and the number of active schedulers 42 | can change while the program is running based on load. 43 | """ 44 | schedulers(auth) > minimum_schedulers(auth) 45 | 46 | fun will_yield_cpu(auth: SchedulerInfoAuth): Bool => 47 | """ 48 | Returns true if schedulers without work will yield the CPU allowing other 49 | processes to have access. 50 | """ 51 | @pony_scheduler_yield() 52 | 53 | fun scheduler_index(auth: SchedulerInfoAuth): I32 => 54 | """ 55 | Returns the index of the current scheduler thread 56 | """ 57 | @pony_scheduler_index() 58 | -------------------------------------------------------------------------------- /client_vscode/packages/signals/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | test(_TestSignalINT) 9 | 10 | class \nodoc\ _TestSighupNotify is SignalNotify 11 | let _h: TestHelper 12 | 13 | new iso create(h: TestHelper) => 14 | _h = h 15 | 16 | fun ref apply(count: U32): Bool => 17 | _h.complete(true) 18 | false 19 | 20 | class \nodoc\ iso _TestSignalINT is UnitTest 21 | var _signal: (SignalHandler | None) = None 22 | 23 | fun name(): String => "signals/INT" 24 | 25 | fun ref apply(h: TestHelper) => 26 | let signal = SignalHandler(_TestSighupNotify(h), Sig.int()) 27 | signal.raise() 28 | _signal = signal 29 | h.long_test(2_000_000_000) // 2 second timeout 30 | 31 | fun timed_out(h: TestHelper) => 32 | try 33 | (_signal as SignalHandler).dispose() 34 | end 35 | 36 | h.fail("timeout") 37 | h.complete(false) 38 | -------------------------------------------------------------------------------- /client_vscode/packages/signals/signal_handler.pony: -------------------------------------------------------------------------------- 1 | use @pony_asio_event_create[AsioEventID]( 2 | owner: AsioEventNotify, 3 | fd: U32, 4 | flags: U32, 5 | nsec: U64, 6 | noisy: Bool) 7 | use @pony_asio_event_unsubscribe[None](event: AsioEventID) 8 | use @pony_asio_event_destroy[None](event: AsioEventID) 9 | 10 | actor SignalHandler is AsioEventNotify 11 | """ 12 | Listen for a specific signal. 13 | If the wait parameter is true, the program will not terminate until the SignalHandler's dispose method is called, or if the SignalNotify returns false, after handling the signal as this also disposes the SignalHandler and unsubscribes it. 14 | 15 | """ 16 | let _notify: SignalNotify 17 | let _sig: U32 18 | var _event: AsioEventID 19 | 20 | new create(notify: SignalNotify iso, sig: U32, wait: Bool = false) => 21 | """ 22 | Create a signal handler. 23 | """ 24 | _notify = consume notify 25 | _sig = sig 26 | _event = 27 | @pony_asio_event_create(this, 0, AsioEvent.signal(), sig.u64(), wait) 28 | 29 | be raise() => 30 | """ 31 | Raise the signal. 32 | """ 33 | SignalRaise(_sig) 34 | 35 | be dispose() => 36 | """ 37 | Dispose of the signal handler. 38 | """ 39 | _dispose() 40 | 41 | be _event_notify(event: AsioEventID, flags: U32, arg: U32) => 42 | """ 43 | Called when the signal is received, or when the AsioEventID can be 44 | destroyed. 45 | """ 46 | if AsioEvent.disposable(flags) then 47 | @pony_asio_event_destroy(event) 48 | elseif event is _event then 49 | if not _notify(arg) then 50 | _dispose() 51 | end 52 | end 53 | 54 | fun ref _dispose() => 55 | """ 56 | Dispose of the AsioEventID. 57 | """ 58 | if not _event.is_null() then 59 | @pony_asio_event_unsubscribe(_event) 60 | _event = AsioEvent.none() 61 | _notify.dispose() 62 | end 63 | -------------------------------------------------------------------------------- /client_vscode/packages/signals/signal_notify.pony: -------------------------------------------------------------------------------- 1 | use @getpid[I32]() 2 | use @kill[I32](pid_t: I32, sig: U32) 3 | use @raise[I32](sig: U32) 4 | 5 | interface SignalNotify 6 | """ 7 | Notifications for a signal. 8 | """ 9 | fun ref apply(count: U32): Bool => 10 | """ 11 | Called with the the number of times the signal has fired since this was 12 | last called. Return false to stop listening for the signal. 13 | """ 14 | true 15 | 16 | fun ref dispose() => 17 | """ 18 | Called if the signal is disposed. This is also called if the notifier 19 | returns false. 20 | """ 21 | None 22 | 23 | primitive SignalRaise 24 | """ 25 | Raise a signal. 26 | """ 27 | fun apply(sig: U32) => 28 | ifdef osx then 29 | // On Darwin, @raise delivers the signal to the current thread, not the 30 | // process, but kqueue EVFILT_SIGNAL will only see signals delivered to 31 | // the process. @kill delivers the signal to a specific process. 32 | @kill(@getpid(), sig) 33 | else 34 | @raise(sig) 35 | end 36 | -------------------------------------------------------------------------------- /client_vscode/packages/signals/signals.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Signals package 3 | 4 | The Signals package provides support for handling Unix style signals. 5 | For each signal that you want to handle, you need to create a `SignalHandler` 6 | and a corresponding `SignalNotify` object. Each SignalHandler runs as it own 7 | actor and upon receiving the signal will call its corresponding 8 | `SignalNotify`'s apply method. 9 | 10 | ## Example program 11 | 12 | The following program will listen for the TERM signal and output a message to 13 | standard out if it is received. 14 | 15 | ```pony 16 | use "signals" 17 | 18 | actor Main 19 | new create(env: Env) => 20 | // Create a TERM handler 21 | let signal = SignalHandler(TermHandler(env), Sig.term()) 22 | // Raise TERM signal 23 | signal.raise() 24 | 25 | class TermHandler is SignalNotify 26 | let _env: Env 27 | 28 | new iso create(env: Env) => 29 | _env = env 30 | 31 | fun ref apply(count: U32): Bool => 32 | _env.out.print("TERM signal received") 33 | true 34 | ``` 35 | 36 | ## Signal portability 37 | 38 | The `Sig` primitive provides support for portable signal handling across Linux, 39 | FreeBSD and OSX. Signals are not supported on Windows and attempting to use 40 | them will cause a compilation error. 41 | 42 | ## Shutting down handlers 43 | 44 | Unlike a `TCPConnection` and other forms of input receiving, creating a 45 | `SignalHandler` will not keep your program running. As such, you are not 46 | required to call `dispose` on your signal handlers in order to shutdown your 47 | program. 48 | 49 | """ 50 | -------------------------------------------------------------------------------- /client_vscode/packages/stdlib/_test.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Pony Standard Library 3 | 4 | This package represents the test suite for the Pony standard library. 5 | 6 | For every new package, please add a Main actor and tests to the package in a 7 | file called 'test.pony'. Then add a corresponding use directive and a line to 8 | the main actor constructor of this package to invoke those tests. 9 | 10 | All tests can be run by compiling and running packages/stdlib. 11 | """ 12 | 13 | // Include ALL standard library packages here, even if they don't have tests. 14 | // That way stdlib can be used to type check the whole standard library, 15 | // generate docs for it, etc. 16 | use "pony_test" 17 | use assert = "assert" 18 | use backpressure= "backpressure" 19 | use base64 = "encode/base64" 20 | use buffered = "buffered" 21 | use builtin_test = "builtin_test" 22 | use bureaucracy = "bureaucracy" 23 | use capsicum = "capsicum" 24 | use cli = "cli" 25 | use collections = "collections" 26 | use collections_persistent = "collections/persistent" 27 | use constrained_types = "constrained_types" 28 | use debug = "debug" 29 | use files = "files" 30 | use format = "format" 31 | use ini = "ini" 32 | use itertools = "itertools" 33 | use math = "math" 34 | use net = "net" 35 | use pony_bench = "pony_bench" 36 | use pony_check = "pony_check" 37 | use process = "process" 38 | use promises = "promises" 39 | use random = "random" 40 | use runtime_info = "runtime_info" 41 | use serialise = "serialise" 42 | use signals = "signals" 43 | use strings = "strings" 44 | use term = "term" 45 | use time = "time" 46 | 47 | 48 | actor \nodoc\ Main is TestList 49 | new create(env: Env) => PonyTest(env, this) 50 | new make() => None 51 | 52 | fun tag tests(test: PonyTest) => 53 | // Tests below function across all systems and are listed alphabetically 54 | base64.Main.make().tests(test) 55 | buffered.Main.make().tests(test) 56 | builtin_test.Main.make().tests(test) 57 | bureaucracy.Main.make().tests(test) 58 | cli.Main.make().tests(test) 59 | collections.Main.make().tests(test) 60 | collections_persistent.Main.make().tests(test) 61 | constrained_types.Main.make().tests(test) 62 | files.Main.make().tests(test) 63 | format.Main.make().tests(test) 64 | ini.Main.make().tests(test) 65 | itertools.Main.make().tests(test) 66 | math.Main.make().tests(test) 67 | net.Main.make().tests(test) 68 | pony_check.Main.make().tests(test) 69 | process.Main.make().tests(test) 70 | promises.Main.make().tests(test) 71 | random.Main.make().tests(test) 72 | runtime_info.Main.make().tests(test) 73 | serialise.Main.make().tests(test) 74 | strings.Main.make().tests(test) 75 | time.Main.make().tests(test) 76 | 77 | // Tests below function exclude windows and are listed alphabetically 78 | ifdef not windows then 79 | // The signals tests currently abort the process on Windows, so ignore 80 | // them. 81 | signals.Main.make().tests(test) 82 | end 83 | 84 | fun @runtime_override_defaults(rto: RuntimeOptions) => 85 | rto.ponynoblock = true 86 | -------------------------------------------------------------------------------- /client_vscode/packages/strings/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | // Tests below function across all systems and are listed alphabetically 9 | test(_TestStringsCommonPrefix) 10 | 11 | class \nodoc\ iso _TestStringsCommonPrefix is UnitTest 12 | """ 13 | Test strings/CommonPrefix 14 | """ 15 | fun name(): String => "strings/CommonPrefix" 16 | 17 | fun apply(h: TestHelper) => 18 | h.assert_eq[String]("", CommonPrefix(Array[String])) 19 | h.assert_eq[String]("", CommonPrefix([""])) 20 | h.assert_eq[String]("", CommonPrefix([""; "asdf"])) 21 | h.assert_eq[String]("", CommonPrefix(["qwer"; "asdf"])) 22 | h.assert_eq[String]("", CommonPrefix(["asdf"; "asdf"; "qwer"])) 23 | h.assert_eq[String]("asdf", CommonPrefix(["asdf"; "asdf"])) 24 | h.assert_eq[String]("as", CommonPrefix(["asdf"; "asdf"; "aser"])) 25 | h.assert_eq[String]("a", CommonPrefix(["a"; "asdf"; "asdf"; "aser"])) 26 | h.assert_eq[String]("12", CommonPrefix([U32(1234); U32(12)])) 27 | -------------------------------------------------------------------------------- /client_vscode/packages/strings/common_prefix.pony: -------------------------------------------------------------------------------- 1 | primitive CommonPrefix 2 | """ 3 | Creates a string that is the common prefix of the supplied strings, possibly 4 | empty. 5 | """ 6 | 7 | fun apply(data: ReadSeq[Stringable]): String iso^ => 8 | var res = "".clone() 9 | try 10 | let iter = data.values() 11 | if iter.has_next() then 12 | res = iter.next()?.string() 13 | for d in iter do 14 | var idx: USize = 0 15 | let s = d.string() 16 | while (idx < res.size()) and (idx < s.size()) do 17 | if res(idx)? != s(idx)? then 18 | break 19 | end 20 | idx = idx + 1 21 | end 22 | res = res.substring(0, idx.isize()) 23 | end 24 | end 25 | end 26 | res 27 | -------------------------------------------------------------------------------- /client_vscode/packages/strings/strings.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Strings package 3 | 4 | The Strings package provides utilities for working with sequences of strings. 5 | """ 6 | -------------------------------------------------------------------------------- /client_vscode/packages/term/ansi_notify.pony: -------------------------------------------------------------------------------- 1 | interface ANSINotify 2 | """ 3 | Receive input from an ANSITerm. 4 | """ 5 | fun ref apply(term: ANSITerm ref, input: U8) => 6 | None 7 | 8 | fun ref up(ctrl: Bool, alt: Bool, shift: Bool) => 9 | None 10 | 11 | fun ref down(ctrl: Bool, alt: Bool, shift: Bool) => 12 | None 13 | 14 | fun ref left(ctrl: Bool, alt: Bool, shift: Bool) => 15 | None 16 | 17 | fun ref right(ctrl: Bool, alt: Bool, shift: Bool) => 18 | None 19 | 20 | fun ref delete(ctrl: Bool, alt: Bool, shift: Bool) => 21 | None 22 | 23 | fun ref insert(ctrl: Bool, alt: Bool, shift: Bool) => 24 | None 25 | 26 | fun ref home(ctrl: Bool, alt: Bool, shift: Bool) => 27 | None 28 | 29 | fun ref end_key(ctrl: Bool, alt: Bool, shift: Bool) => 30 | None 31 | 32 | fun ref page_up(ctrl: Bool, alt: Bool, shift: Bool) => 33 | None 34 | 35 | fun ref page_down(ctrl: Bool, alt: Bool, shift: Bool) => 36 | None 37 | 38 | fun ref fn_key(i: U8, ctrl: Bool, alt: Bool, shift: Bool) => 39 | None 40 | 41 | fun ref prompt(term: ANSITerm ref, value: String) => 42 | None 43 | 44 | fun ref size(rows: U16, cols: U16) => 45 | None 46 | 47 | fun ref closed() => 48 | None 49 | -------------------------------------------------------------------------------- /client_vscode/packages/term/readline_notify.pony: -------------------------------------------------------------------------------- 1 | use "promises" 2 | 3 | interface ReadlineNotify 4 | """ 5 | Notifier for readline. 6 | """ 7 | fun ref apply(line: String, prompt: Promise[String]) => 8 | """ 9 | Receives finished lines. The next prompt is set by fulfilling the promise. 10 | If the promise is rejected, readline will stop handling input. 11 | """ 12 | None 13 | 14 | fun ref tab(line: String): Seq[String] box => 15 | """ 16 | Return tab completion possibilities. 17 | """ 18 | Array[String] 19 | -------------------------------------------------------------------------------- /client_vscode/packages/term/term.pony: -------------------------------------------------------------------------------- 1 | """ 2 | # Term package 3 | 4 | The Term package provides support for building text-based user interfaces in ANSI terminals. 5 | """ 6 | -------------------------------------------------------------------------------- /client_vscode/packages/time/_test.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | 3 | actor \nodoc\ Main is TestList 4 | new create(env: Env) => PonyTest(env, this) 5 | new make() => None 6 | 7 | fun tag tests(test: PonyTest) => 8 | // Tests below function across all systems and are listed alphabetically 9 | test(_TestNanos) 10 | test(_TestPosixDate) 11 | 12 | class \nodoc\ iso _TestNanos is UnitTest 13 | fun name(): String => "time/Nanos" 14 | 15 | fun apply(h: TestHelper) => 16 | h.assert_eq[U64](5_000_000_000, Nanos.from_seconds(5)) 17 | h.assert_eq[U64](5_000_000, Nanos.from_millis(5)) 18 | h.assert_eq[U64](5_000, Nanos.from_micros(5)) 19 | 20 | h.assert_eq[U64](1_230_000_000, Nanos.from_seconds_f(1.23)) 21 | h.assert_eq[U64](1_230_000, Nanos.from_millis_f(1.23)) 22 | h.assert_eq[U64](1_230, Nanos.from_micros_f(1.23)) 23 | 24 | class \nodoc\ iso _TestPosixDate is UnitTest 25 | fun name(): String => "time/PosixDate" 26 | 27 | fun apply(h: TestHelper) => 28 | // time is in seconds 29 | h.assert_eq[I64](0, PosixDate(0, 0).time()) 30 | h.assert_eq[I64](1, PosixDate(1, 0).time()) 31 | // small nanoseconds can not affect time 32 | h.assert_eq[I64](0, PosixDate(0, 900_000_000).time()) 33 | // big nanoseconds can affect time 34 | h.assert_eq[I64](1, PosixDate(0, 1_000_000_000).time()) 35 | h.assert_eq[I64](2, PosixDate(1, 1_000_000_000).time()) 36 | // negaive seconds should be changed to zero 37 | h.assert_eq[I64](0, PosixDate(-1, 0).time()) 38 | h.assert_eq[I64](1, PosixDate(-1, 1_000_000_000).time()) 39 | // negative nanoseconds cannot not affect time 40 | h.assert_eq[I64](1, PosixDate(1, -1_000_000_000).time()) 41 | 42 | // Windows should throw error when %L is in format string 43 | ifdef windows then 44 | h.assert_error({() ? => 45 | (let seconds, let nanos) = Time.now() 46 | let d = PosixDate(seconds, nanos) 47 | d.format("%Y-%m-%d %H:%M:%S.%L")? 48 | }) 49 | end 50 | -------------------------------------------------------------------------------- /client_vscode/packages/time/_timing_wheel.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | class _TimingWheel 4 | """ 5 | A timing wheel in a hierarchical set of timing wheels. Each wheel covers 6 6 | bits of precision. 7 | """ 8 | let _shift: U64 9 | let _adjust: U64 10 | var _pending: U64 = 0 11 | embed _list: Array[List[Timer]] 12 | 13 | new create(index: USize) => 14 | """ 15 | Create a timing wheel at the given hierarchical level. 16 | """ 17 | _shift = (index * _bits()).u64() 18 | _adjust = if index > 0 then 1 else 0 end 19 | _list = Array[List[Timer]](_max()) 20 | 21 | for i in Range(0, _max()) do 22 | _list.push(List[Timer]) 23 | end 24 | 25 | fun ref schedule(timer: Timer) => 26 | """ 27 | Schedule a timer on this wheel. Mark the bit indicating that the given slot 28 | has timers in its list. 29 | """ 30 | let slot = ((timer._next() >> _shift) - _adjust) and _mask() 31 | 32 | try 33 | let list = _list(slot.usize())? 34 | _list(slot.usize())?.append_node(timer._get_node()) 35 | _pending = _pending or (1 << slot) 36 | end 37 | 38 | fun ref advance(list: List[Timer], current: U64, elapsed: U64): Bool => 39 | """ 40 | Remove pending timers from this timing wheel and put them on the pending 41 | list supplied. Needs the current time and the elapsed time since the 42 | previous advance. Returns true if the next timing wheel in the hierarchy 43 | should be advanced. 44 | """ 45 | let time = (elapsed >> _shift).max(1) 46 | let pending = 47 | if time <= _mask() then 48 | let slot = time and _mask() 49 | let slots = (1 << slot) - 1 50 | let old_slot = _slot(current - elapsed) 51 | let new_slot = _slot(current) 52 | 53 | slots.rotl(old_slot) or 54 | slots.rotl(new_slot).rotr(slot) or 55 | (1 << new_slot) 56 | else 57 | -1 58 | end 59 | 60 | while (pending and _pending) != 0 do 61 | let slot = (pending and _pending).ctz() 62 | try list.append_list(_list(slot.usize())?) end 63 | _pending = _pending and not (1 << slot) 64 | end 65 | 66 | (pending and 1) != 0 67 | 68 | fun next(current: U64): U64 => 69 | """ 70 | Given a current time, return the next time at which this timing wheel 71 | should be advanced. Returns -1 if no timers are on this timing wheel. 72 | """ 73 | if _pending != 0 then 74 | let slot = _slot(current) 75 | let mask = (1 << _shift) - 1 76 | ((_pending.rotr(slot).ctz() + _adjust).u64() << _shift.u64()) - 77 | (current and mask) 78 | else 79 | -1 80 | end 81 | 82 | fun ref clear() => 83 | """ 84 | Cancels all pending timers. 85 | """ 86 | for list in _list.values() do 87 | for timer in list.values() do 88 | timer._cancel() 89 | end 90 | end 91 | 92 | fun _slot(time: U64): U64 => 93 | """ 94 | Return the slot for a given time. 95 | """ 96 | (time >> _shift) and _mask() 97 | 98 | fun tag _bits(): USize => 6 99 | fun tag _max(): USize => 1 << _bits() 100 | fun tag _mask(): U64 => (_max() - 1).u64() 101 | -------------------------------------------------------------------------------- /client_vscode/packages/time/nanos.pony: -------------------------------------------------------------------------------- 1 | 2 | primitive Nanos 3 | """ 4 | Collection of utility functions for converting various durations of time 5 | to nanoseconds, for passing to other functions in the time package. 6 | """ 7 | fun from_seconds(t: U64): U64 => 8 | t * 1_000_000_000 9 | 10 | fun from_millis(t: U64): U64 => 11 | t * 1_000_000 12 | 13 | fun from_micros(t: U64): U64 => 14 | t * 1_000 15 | 16 | fun from_seconds_f(t: F64): U64 => 17 | (t * 1_000_000_000).trunc().u64() 18 | 19 | fun from_millis_f(t: F64): U64 => 20 | (t * 1_000_000).trunc().u64() 21 | 22 | fun from_micros_f(t: F64): U64 => 23 | (t * 1_000).trunc().u64() 24 | 25 | fun from_wall_clock(wall: (I64, I64)): U64 => 26 | ((wall._1 * 1000000000) + wall._2).u64() 27 | -------------------------------------------------------------------------------- /client_vscode/packages/time/posix_date.pony: -------------------------------------------------------------------------------- 1 | use @ponyint_gmtime[None](date: PosixDate, sec: I64, nsec: I64) 2 | use @ponyint_timegm[I64](date: PosixDate tag) 3 | use @ponyint_formattime[Pointer[U8]](date: PosixDate tag, fmt: Pointer[U8] tag) ? 4 | 5 | class PosixDate 6 | """ 7 | Represents a proleptic Gregorian date and time, without specifying a 8 | time zone. The day of month, month, day of week, and day of year are all 9 | indexed from 1, i.e. January is 1, Monday is 1. 10 | """ 11 | var nsec: I32 = 0 12 | var sec: I32 = 0 13 | var min: I32 = 0 14 | var hour: I32 = 0 15 | var day_of_month: I32 = 1 16 | var month: I32 = 1 17 | var year: I32 = 1970 18 | var day_of_week: I32 = 4 19 | var day_of_year: I32 = 1 20 | 21 | new create(seconds: I64 = 0, nanoseconds: I64 = 0) => 22 | """ 23 | Create a date from a POSIX time. Negative arguments will be changed to zero. 24 | """ 25 | @ponyint_gmtime(this, 26 | _negative_to_zero(seconds), 27 | _negative_to_zero(nanoseconds)) 28 | 29 | fun time(): I64 => 30 | """ 31 | Return a POSIX time. Treats the date as UTC. 32 | """ 33 | @ponyint_timegm(this) 34 | 35 | fun ref normal() => 36 | """ 37 | Normalise all the fields of the date. For example, if the hour is 24, it is 38 | set to 0 and the day is advanced. This allows fields to be changed naively, 39 | eg. adding 1000 to hours to advance the time by 1000 hours, and then 40 | normalising the date. 41 | """ 42 | @ponyint_gmtime(this, time(), nsec.i64()) 43 | 44 | fun format(fmt: String): String ? => 45 | """ 46 | Format the time as for strftime. 47 | 48 | Will return an empty string if the format string is "%p" or "%P". 49 | """ 50 | recover 51 | String.from_cstring(@ponyint_formattime(this, fmt.cstring())?) 52 | end 53 | 54 | fun _negative_to_zero(value: I64): I64 => 55 | if value > 0 then 56 | value 57 | else 58 | 0 59 | end 60 | -------------------------------------------------------------------------------- /client_vscode/packages/time/timer_notify.pony: -------------------------------------------------------------------------------- 1 | interface TimerNotify 2 | """ 3 | Notifications for timer. 4 | """ 5 | fun ref apply(timer: Timer, count: U64): Bool => 6 | """ 7 | Called with the the number of times the timer has fired since this was last 8 | called. Usually, the value of `count` will be 1. If it is not 1, it means 9 | that the timer isn't firing on schedule. 10 | 11 | For example, if your timer is set to fire every 10 milliseconds, and 12 | `count` is 2, that means it has been between 20-29 milliseconds since the 13 | last time your timer fired. Non 1 values for a timer are rare and indicate 14 | a system under heavy load. 15 | 16 | Return true to reschedule the timer (if it has an interval), or 17 | false to cancel the timer (even if it has an interval). 18 | """ 19 | true 20 | 21 | fun ref cancel(timer: Timer) => 22 | """ 23 | Called if the timer is cancelled. This is also called if the notifier 24 | returns false from its `apply` method. 25 | """ 26 | None 27 | -------------------------------------------------------------------------------- /client_vscode/src/extension.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/zigtools/zls-vscode/blob/master/src/extension.ts 2 | 3 | // git tags by date 4 | // git tag --sort=-creatordate 5 | 6 | import { ExtensionContext, window, StatusBarAlignment, StatusBarItem, workspace, OutputChannel } from 'vscode'; 7 | 8 | import { 9 | ExecutableOptions, 10 | LanguageClient, 11 | LanguageClientOptions, 12 | ServerOptions, 13 | TransportKind, 14 | } from 'vscode-languageclient/node'; 15 | 16 | let client: LanguageClient; 17 | let outputChannel: OutputChannel; 18 | 19 | export async function activate(context: ExtensionContext) { 20 | outputChannel = window.createOutputChannel("Pony Language Server"); 21 | 22 | let exe = context.asAbsolutePath("pony-lsp"); 23 | showPony(true); 24 | // If the extension is launched in debug mode then the debug server options are used 25 | // Otherwise the run options are used 26 | let serverOptions: ServerOptions = { 27 | command: exe, 28 | args: ["stdio"], 29 | transport: TransportKind.stdio, 30 | options: { 31 | env: { 32 | "PONYPATH": context.asAbsolutePath("packages"), 33 | } 34 | } 35 | }; 36 | 37 | // Options to control the language client 38 | let clientOptions: LanguageClientOptions = { 39 | documentSelector: [{ scheme: "file", language: "pony" }], 40 | diagnosticCollectionName: "Pony", 41 | stdioEncoding: "utf-8", 42 | traceOutputChannel: outputChannel, 43 | outputChannel: outputChannel, 44 | }; 45 | 46 | // Create the language client and start the client. 47 | client = new LanguageClient( 48 | 'pony', 49 | 'Pony Language Server', 50 | serverOptions, 51 | clientOptions 52 | ); 53 | 54 | outputChannel.appendLine("PonyLSP client ready"); 55 | // Start the client. This will also launch the server 56 | return client.start().catch(reason => { 57 | window.showWarningMessage(`Failed to run Pony Language Server (PLS): ${reason}`); 58 | showPony(false); 59 | client = null; 60 | }); 61 | } 62 | 63 | export function deactivate(): Thenable | undefined { 64 | if (!client) { 65 | return undefined; 66 | } 67 | return client.stop(); 68 | } 69 | 70 | export var ponyVerEntry: StatusBarItem; 71 | 72 | export function showPony(good: boolean) { 73 | ponyVerEntry = window.createStatusBarItem(StatusBarAlignment.Left); 74 | if (good) ponyVerEntry.text = `Pony LSP ✓`; 75 | else ponyVerEntry.text = `Pony LSP ✗`; 76 | ponyVerEntry.show(); 77 | } 78 | -------------------------------------------------------------------------------- /client_vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2020", 5 | "lib": ["es2020"], 6 | "outDir": "out", 7 | "rootDir": "src", 8 | "sourceMap": true 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules", ".vscode-test"] 12 | } -------------------------------------------------------------------------------- /client_vscode/webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | 11 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 12 | output: { // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 13 | path: path.resolve(__dirname, 'dist'), 14 | filename: 'extension.js', 15 | libraryTarget: "commonjs2", 16 | devtoolModuleFilenameTemplate: "../[resource-path]", 17 | }, 18 | devtool: 'source-map', 19 | externals: { 20 | vscode: "commonjs vscode" // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 21 | }, 22 | resolve: { // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 23 | extensions: ['.ts', '.js'] 24 | }, 25 | module: { 26 | rules: [{ 27 | test: /\.ts$/, 28 | exclude: /node_modules/, 29 | use: [{ 30 | loader: 'ts-loader', 31 | }] 32 | }] 33 | }, 34 | stats: { 35 | errorDetails: true 36 | } 37 | } 38 | 39 | module.exports = config; 40 | -------------------------------------------------------------------------------- /corral.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "lsp", 4 | "lsp/workspace", 5 | "lsp/test" 6 | ], 7 | "deps": [ 8 | { 9 | "locator": "github.com/mfelsche/pony-immutable-json.git", 10 | "version": "0.3.1" 11 | }, 12 | { 13 | "locator": "github.com/mfelsche/pony-ast.git", 14 | "version": "v0.2.1" 15 | } 16 | ], 17 | "info": { 18 | "description": "The Pony Language Server", 19 | "homepage": "", 20 | "license": "", 21 | "documentation_url": "", 22 | "version": "0.2.2", 23 | "name": "lsp" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "locks": [ 3 | { 4 | "locator": "github.com/ponylang/peg.git", 5 | "revision": "0.1.5" 6 | }, 7 | { 8 | "locator": "github.com/mfelsche/pony-immutable-json.git", 9 | "revision": "0.3.1" 10 | }, 11 | { 12 | "locator": "github.com/mfelsche/pony-ast.git", 13 | "revision": "v0.2.1" 14 | }, 15 | { 16 | "locator": "github.com/mfelsche/pony-binarysearch.git", 17 | "revision": "v0.1.1" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /lsp/channel_stdio.pony: -------------------------------------------------------------------------------- 1 | use "immutable-json" 2 | 3 | 4 | class InputNotifier is InputNotify 5 | let handler: BaseProtocol 6 | 7 | new iso create(notifier: Notifier tag) => 8 | handler = BaseProtocol(notifier) 9 | 10 | fun ref apply(data': Array[U8 val] iso): None val => 11 | handler(consume data') 12 | 13 | fun ref dispose(): None val => 14 | None 15 | 16 | trait tag Channel 17 | be send(msg: Message val) 18 | be log(data: String val, message_type: MessageType = Debug) 19 | be set_notifier(notifier: Notifier tag) 20 | be dispose() 21 | 22 | actor Stdio is Channel 23 | let out: OutStream 24 | let stdin: InputStream 25 | 26 | new create( 27 | out': OutStream tag, 28 | stdin': InputStream tag) => 29 | out = out' 30 | stdin = stdin' 31 | 32 | be set_notifier(notifier: Notifier tag) => 33 | // clear out any old handler 34 | this.stdin.dispose() 35 | 36 | // start receiving input 37 | // we do expect some bigger json messages, so allocate 256 bytes by default 38 | this.stdin.apply(InputNotifier(notifier) where chunk_size = 256) 39 | 40 | be send(msg: Message val) => 41 | let output: String val = msg.string() 42 | out.write(output) 43 | out.flush() 44 | 45 | be log(data: String val, message_type: MessageType = Debug) => 46 | """ 47 | Log data to the editor via window/logMessage 48 | """ 49 | send( 50 | Notification( 51 | "window/logMessage", 52 | Obj("type", message_type.apply())("message", data).build() 53 | ) 54 | ) 55 | be dispose() => 56 | this.stdin.dispose() 57 | -------------------------------------------------------------------------------- /lsp/corral.pony: -------------------------------------------------------------------------------- 1 | use "files" 2 | use "collections" 3 | 4 | class val Locator is (Hashable & Stringable) 5 | """ 6 | Encapsulation of the bundle dependency's locator string, parsed into distinct 7 | fields. 8 | locator := repo_path[.vcs_suffix][/bundle_path] 9 | """ 10 | let repo_path: String 11 | let vcs_suffix: String 12 | let bundle_path: String 13 | 14 | new val create(loc: String) => 15 | let suffixes = [".git"; ".hg"; ".bzr"; ".svn"] 16 | var rp = "" 17 | var vs = "" 18 | var bp = "" 19 | for s in suffixes.values() do 20 | let parts = loc.split_by(s) 21 | if parts.size() == 2 then try 22 | rp = parts(0)? 23 | vs = s 24 | let p = parts(1)? 25 | bp = if p.at("/") then p.trim(1) else p end 26 | break 27 | end end 28 | end 29 | if vs == "" then 30 | bp = loc // With no vcs, the locator is the local bundle path 31 | end 32 | repo_path = rp 33 | vcs_suffix = vs 34 | bundle_path = bp 35 | 36 | fun path(): String => 37 | """Returns a unique name for this locator without the vcs suffix.""" 38 | Path.to_slash(Path.join(repo_path, bundle_path)) 39 | 40 | fun flat_name(): String => 41 | _Flattened(path()) 42 | 43 | fun string(): String iso^ => 44 | """Returns the full string for of this locator.""" 45 | Path.to_slash(Path.join(repo_path + vcs_suffix, bundle_path)).clone() 46 | 47 | fun compare(that: Locator box): Compare => 48 | if (repo_path != that.repo_path) then return repo_path.compare(that.repo_path) end 49 | if (vcs_suffix != that.vcs_suffix) then return vcs_suffix.compare(that.vcs_suffix) end 50 | bundle_path.compare(that.bundle_path) 51 | 52 | fun hash(): USize => 53 | repo_path.hash() xor vcs_suffix.hash() xor bundle_path.hash() 54 | 55 | fun is_vcs(): Bool => vcs_suffix != "" 56 | 57 | fun is_local(): Bool => (repo_path == "") or repo_path.at(".") or repo_path.at("/") 58 | 59 | fun is_remote_vcs(): Bool => is_vcs() and not is_local() 60 | 61 | fun is_local_vcs(): Bool => is_vcs() and is_local() 62 | 63 | fun is_local_direct(): Bool => not is_vcs() and is_local() 64 | 65 | primitive _Flattened 66 | fun apply(path: String): String val => 67 | let dash_code: U8 = '_' 68 | let path_name_arr = recover val 69 | var acc: Array[U8] = Array[U8] 70 | for char in path.array().values() do 71 | if _is_alphanum(char) then 72 | acc.push(char) 73 | else 74 | try // we know we don't index out of bounds 75 | if acc.size() == 0 then 76 | acc.push(dash_code) 77 | elseif acc(acc.size() - 1)? != dash_code then 78 | acc.push(dash_code) 79 | end 80 | end 81 | end 82 | end 83 | consume acc 84 | end 85 | String.from_array(consume path_name_arr) 86 | 87 | fun _is_alphanum(c: U8): Bool => 88 | (('0' <= c) and (c <= '9')) 89 | or 90 | (('A' <= c) and (c <= 'Z')) 91 | or 92 | (('a' <= c) and (c <= 'z')) 93 | or 94 | (c == '_') 95 | -------------------------------------------------------------------------------- /lsp/diagnostics.pony: -------------------------------------------------------------------------------- 1 | use "immutable-json" 2 | use "ast" 3 | 4 | class ref Diagnostic 5 | """ 6 | See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic 7 | """ 8 | let range: LspPositionRange 9 | let severity: I64 10 | // left out intentionally 11 | // let code: (I64 | String | None) 12 | // let code_description: (CodeDescription | None) 13 | let message: String 14 | let related_information: Array[DiagnosticRelatedInformation] 15 | 16 | new ref create(range': LspPositionRange, severity': I64, message': String) => 17 | range = range' 18 | severity = severity' 19 | message = message' 20 | related_information = Array[DiagnosticRelatedInformation].create(0) 21 | 22 | new val from_error(err: Error) => 23 | this.range = LspPositionRange.from_single_pos(LspPosition.from_ast_pos(err.position)) 24 | this.severity = DiagnosticSeverities.err() 25 | this.message = err.msg 26 | this.related_information = Array[DiagnosticRelatedInformation].create(err.infos.size()) 27 | for info in err.infos.values() do 28 | let file_path = 29 | try 30 | info.file as String 31 | else 32 | try 33 | err.file as String 34 | else 35 | continue 36 | end 37 | end 38 | let file = Uris.from_path(file_path) 39 | let location = LspLocation.create( 40 | file, 41 | LspPositionRange.from_single_pos( 42 | LspPosition.from_ast_pos(info.position) 43 | ) 44 | ) 45 | this.related_information.push( 46 | DiagnosticRelatedInformation.create(location, info.msg) 47 | ) 48 | end 49 | 50 | fun to_json(): JsonType => 51 | var builder = Obj("range", this.range.to_json())( 52 | "severity", this.severity)( 53 | "source", "pony-lsp")( 54 | "message", this.message) 55 | if this.related_information.size() > 0 then 56 | var arr = Arr 57 | for rel_info in this.related_information.values() do 58 | arr = arr(rel_info.to_json()) 59 | end 60 | builder = builder("relatedInformation", arr) 61 | end 62 | builder.build() 63 | 64 | 65 | 66 | primitive DiagnosticSeverities 67 | fun tag err(): I64 => 1 68 | fun tag warning(): I64 => 2 69 | fun tag information(): I64 => 2 70 | fun tag hint(): I64 => 2 71 | 72 | class val DiagnosticRelatedInformation 73 | let location: LspLocation 74 | let message: String 75 | 76 | new create(location': LspLocation, message': String) => 77 | location = location' 78 | message = message' 79 | 80 | fun to_json(): JsonType => 81 | Obj("location", this.location.to_json())( 82 | "message", this.message).build() -------------------------------------------------------------------------------- /lsp/lsp_language.pony: -------------------------------------------------------------------------------- 1 | /* 2 | use "immutable-json" 3 | use "collections" 4 | use "files" 5 | use "backpressure" 6 | use "process" 7 | use "debug" 8 | use "ast" 9 | 10 | 11 | actor LanguageProtocol 12 | var initialized: Bool = false 13 | let channel: Stdio 14 | let document: DocumentProtocol 15 | let compiler: PonyCompiler 16 | 17 | 18 | new create(compiler': PonyCompiler, channel': Stdio, document': DocumentProtocol) => 19 | compiler = compiler' 20 | channel = channel' 21 | document = document' 22 | 23 | be handle_goto_definition(msg: RequestMessage val) => 24 | // TODO 25 | Log(channel, "GOTO Definition") 26 | None 27 | 28 | be handle_hover(msg: RequestMessage val) => 29 | match msg.params 30 | | let p: JsonObject => 31 | try 32 | let uri = JsonPath("$.textDocument.uri", p)?(0)? as String 33 | let line = JsonPath("$.position.line", p)?(0)? as I64 34 | let character = JsonPath("$.position.character", p)?(0)? as I64 35 | let filepath = uri.clone() 36 | filepath.replace("file://", "") 37 | let notifier = HoverNotifier(msg.id, compiler, channel) 38 | compiler.get_type_at(filepath.clone(), line.usize()+1, character.usize()+1, notifier) 39 | else 40 | Log(channel, "ERROR retrieving textDocument uri: " + msg.json().string()) 41 | channel.send_message(ResponseMessage(msg.id, None, ResponseError(-32700, "parse error"))) 42 | end 43 | else 44 | channel.send_message(ResponseMessage(msg.id, None, ResponseError(-32700, "parse error"))) 45 | end 46 | 47 | 48 | actor HoverNotifier 49 | let id: (I64 val | String val | None val) 50 | let compiler: PonyCompiler 51 | let channel: Stdio 52 | 53 | new create( 54 | id': (I64 val | String val | None val), 55 | compiler': PonyCompiler, 56 | channel': Stdio 57 | ) => 58 | id = id' 59 | compiler = compiler' 60 | channel = channel' 61 | 62 | be type_notified(t: (String | None)) => 63 | match t 64 | | let s: String => 65 | Log(channel, "type_notified " + s) 66 | channel.send_message(ResponseMessage(id, JsonObject( 67 | recover val 68 | Map[String, JsonType](1) 69 | .>update("contents", JsonObject( 70 | recover val 71 | Map[String, JsonType](2) 72 | .>update("kind", "markdown") 73 | .>update("value", s) 74 | end 75 | )) 76 | end 77 | ))) 78 | | None => 79 | Log(channel, "type_notified is None") 80 | channel.send_message(ResponseMessage(id, JsonObject( 81 | recover val 82 | Map[String, JsonType](1) 83 | .>update("contents", JsonObject( 84 | recover val 85 | Map[String, JsonType](2) 86 | .>update("kind", "markdown") 87 | .>update("value", "❌") 88 | end 89 | )) 90 | end 91 | ))) 92 | end 93 | */ 94 | -------------------------------------------------------------------------------- /lsp/main.pony: -------------------------------------------------------------------------------- 1 | """ 2 | ## The Pony Language Server 3 | 4 | This package implements the (Language Server Protocol Spec 5 | v3.17](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/) 6 | for Pony. 7 | 8 | It is using the `ast` library to parse and type-check pony projects opened in 9 | the editor, using the same code as the official compiler `ponyc`, so the 10 | diagnostics and code analysis provided will always be in sync with what the 11 | `ponyc` compiler provides. 12 | 13 | ## Package Contents 14 | 15 | ### `lsp` 16 | 17 | This package contains all the code supporting the protocol, data structures and types from the spec, the communication 18 | with a language client. The [`LanguageServer`](lsp-LanguageServer.md) is 19 | controlling which requests and notifications are supported and dispatches to the 20 | actor handling the workspace for the given request. 21 | 22 | - [`Channel`](lsp-Channel.md) defining the necessary channel behaviours and [`Stdio`](lsp-Stdio.md) being the implementation for Standard-IO based communication. 23 | - [`PonyCompiler`](lsp-PonyCompiler.md) as an actor whose main job is to expose 24 | the `ast` lib functionality of parsing and typechecking a pony project and to 25 | linearize all requests as the underlying libponyc is not 100% thread-safe. 26 | 27 | ### `lsp/workspace` 28 | 29 | This package contains the actual logic applied to handling a single pony 30 | project. The [`WorkspaceManager`](lsp-workspace-WorkspaceManager.md) actor handles 31 | requests and notifications, starts the parsing and typechecking process and 32 | receives its results. It builds up the necessary state needed for answering LSP 33 | client requests in the [`PackageState`](lsp-workspace-PackageState.md) and 34 | [`DocumentState`](lsp-workspace-DocumentState.md) classes. 35 | 36 | """ 37 | use "files" 38 | use "ast" 39 | 40 | actor Main 41 | new create(env: Env) => 42 | let channel = Stdio(env.out, env.input) 43 | let pony_path = 44 | match PonyPath(env) 45 | | let p: String => p 46 | | None => "" 47 | end 48 | let language_server = LanguageServer(channel, env, pony_path) 49 | // at this point the server should listen to incoming messages via stdin 50 | -------------------------------------------------------------------------------- /lsp/options.pony: -------------------------------------------------------------------------------- 1 | use "immutable-json" 2 | use "files" 3 | 4 | class val ServerOptions 5 | """ 6 | server options provided via Initialize request 7 | """ 8 | let pony_path: (Array[String] val | None) 9 | 10 | new val from_json(json: JsonObject) => 11 | pony_path = 12 | try 13 | recover val 14 | Path.split_list(json.data("PONYPATH")? as String val) 15 | end 16 | end 17 | 18 | new val default() => 19 | pony_path = None 20 | -------------------------------------------------------------------------------- /lsp/position.pony: -------------------------------------------------------------------------------- 1 | use "immutable-json" 2 | use "ast" 3 | 4 | class val LspPositionRange 5 | """ 6 | See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range 7 | """ 8 | let _start: LspPosition 9 | """ 10 | Inclusive start position 11 | """ 12 | let _end: LspPosition 13 | """ 14 | Exclusive end position 15 | """ 16 | 17 | new val from_single_pos(pos: LspPosition) => 18 | _start = pos 19 | _end = pos 20 | 21 | new val create(start_pos: LspPosition, end_pos: LspPosition) => 22 | _start = start_pos 23 | _end = end_pos 24 | 25 | fun to_json(): JsonType => 26 | Obj("start", this._start.to_json())( 27 | "end", this._start.to_json() 28 | ).build() 29 | 30 | class val LspPosition 31 | """ 32 | See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position 33 | """ 34 | let _line: USize 35 | """ 36 | Line position in a document (zero-based). 37 | """ 38 | let _character: USize 39 | 40 | new val create(line': USize, character': USize) => 41 | _line = line' 42 | _character = character' 43 | 44 | new val from_ast_pos(position: Position) => 45 | _line = (position.line() - 1).max(0) 46 | _character = (position.column() - 1).max(0) 47 | 48 | fun to_json(): JsonType => 49 | Obj("line", this._line.i64())( 50 | "character", this._character.i64()).build() 51 | 52 | class val LspLocation 53 | """ 54 | See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location 55 | """ 56 | let uri: String 57 | let range: LspPositionRange 58 | 59 | new val create(uri': String, range': LspPositionRange) => 60 | uri = uri' 61 | range = range' 62 | 63 | fun to_json(): JsonType => 64 | Obj("uri", uri)("range", this.range.to_json()).build() 65 | -------------------------------------------------------------------------------- /lsp/test/_workspace_tests.pony: -------------------------------------------------------------------------------- 1 | use "pony_test" 2 | use "files" 3 | use ".." 4 | use "../workspace" 5 | 6 | primitive _WorkspaceTests is TestList 7 | new make() => 8 | None 9 | 10 | fun tag tests(test: PonyTest) => 11 | test(_RouterFindTest) 12 | 13 | class \nodoc\ iso _RouterFindTest is UnitTest 14 | fun name(): String => "router/find" 15 | 16 | fun apply(h: TestHelper) ? => 17 | let file_auth = FileAuth(h.env.root) 18 | let this_dir_path = Path.dir(__loc.file()) 19 | let folder = FilePath(file_auth, this_dir_path) 20 | let channel = TestChannel(h, 21 | {(h: TestHelper, channel: TestChannel ref): Bool => 22 | true 23 | }) 24 | let scanner = WorkspaceScanner.create(channel) 25 | let workspaces = scanner.scan(file_auth, this_dir_path) 26 | h.assert_eq[USize](2, workspaces.size()) 27 | // main.pony workspace has been found first 28 | var workspace = workspaces(0)? 29 | h.assert_eq[String](folder.path, workspace.folder.path) 30 | 31 | // corral workspace 32 | workspace = workspaces(1)? 33 | h.assert_eq[String](folder.join("workspace")?.path, workspace.folder.path) 34 | 35 | let router = WorkspaceRouter.create() 36 | let compiler = PonyCompiler("") // dummy, not actually in use 37 | 38 | let mgr = WorkspaceManager(workspace, file_auth, channel, compiler) 39 | router.add_workspace(folder, mgr)? 40 | 41 | let file_path = folder.join("main.pony")? 42 | let found = router.find_workspace(file_path.path) 43 | h.assert_isnt[(WorkspaceManager | None)](None, found) 44 | 45 | -------------------------------------------------------------------------------- /lsp/test/workspace/corral.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [], 3 | "deps": [], 4 | "info": { 5 | "description": "The Pony Language Server Test Workspace", 6 | "homepage": "", 7 | "license": "", 8 | "documentation_url": "", 9 | "version": "0.2.0", 10 | "name": "lsp-test" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lsp/test/workspace/main.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | 3 | actor Main 4 | new create(env: Env) => 5 | None 6 | -------------------------------------------------------------------------------- /lsp/uri.pony: -------------------------------------------------------------------------------- 1 | use "files" 2 | 3 | primitive Uris 4 | fun to_path(uri: String): String => 5 | """ 6 | Ensure an LSP uri (https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri) 7 | is converted to a path, so the `schema://` needs to be dropped, if present. 8 | """ 9 | let result = uri.split_by("://", 2) 10 | try 11 | result(result.size() - 1)? 12 | else 13 | // shouldn't happen, given that split_by never returns an empty array 14 | uri 15 | end 16 | 17 | fun from_path(path: String): String => 18 | """ 19 | Convert a local path to an LSP uri 20 | """ 21 | if path.contains("://") then 22 | path 23 | else 24 | // TODO: lets do something more sophisticated here 25 | "file://" + path 26 | end 27 | -------------------------------------------------------------------------------- /lsp/workspace/data.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "files" 3 | use "itertools" 4 | use "immutable-json" 5 | 6 | class val WorkspaceData 7 | """ 8 | Data extracted from corral.json 9 | """ 10 | let name: String 11 | let folder: FilePath 12 | // dependency names, relative to /_corral/ 13 | let dependencies: Array[String] val 14 | // absolute paths (derived from folder and dependencies) 15 | let dependency_paths: Array[String] val 16 | // absolute paths of packages listed in all corral.json files (including dependencies) 17 | let package_paths: Set[String] val 18 | let _min_package_paths_len: USize 19 | // TODO: further structure a workspace into different packages, separately 20 | // compiled 21 | 22 | new val create( 23 | name': String, 24 | folder': FilePath, 25 | dependencies': Set[String] val, 26 | package_paths': Set[String] val) 27 | => 28 | name = name' 29 | folder = folder' 30 | dependencies = 31 | recover val 32 | Iter[String](dependencies'.values()) 33 | .collect(Array[String].create(dependencies'.size())) 34 | end 35 | dependency_paths = 36 | recover val 37 | Iter[String](dependencies.values()) 38 | .map[String]({(dep): String? => folder.join("_corral")?.join(dep)?.path}) 39 | .collect(Array[String].create(dependencies.size())) 40 | end 41 | package_paths = package_paths' 42 | var min: USize = USize.max_value() 43 | for package_path in package_paths.values() do 44 | min = min.min(package_path.size()) 45 | end 46 | _min_package_paths_len = min 47 | 48 | fun debug(): String => 49 | var dp_arr = Arr.create() 50 | for dp in dependencies.values() do 51 | dp_arr = dp_arr(dp) 52 | end 53 | var pp_arr = Arr.create() 54 | for pp in package_paths.values() do 55 | pp_arr = pp_arr(pp) 56 | end 57 | Obj("name", name)( 58 | "folder", folder.path 59 | )( 60 | "dependencies", dp_arr 61 | )( 62 | "packages", pp_arr 63 | ).build().string() 64 | 65 | fun find_package(document_path: String): (FilePath | None) => 66 | var doc_path: String val = document_path 67 | while (doc_path != ".") and (doc_path.size() >= _min_package_paths_len) do 68 | try 69 | let package_path = this.package_paths(doc_path)? 70 | return this.folder.join( 71 | package_path.substring(this.folder.path.size().isize() + 1) 72 | )? 73 | end 74 | doc_path = Path.dir(doc_path) 75 | end 76 | None 77 | 78 | fun workspace_path(path: String): FilePath ? => 79 | // check if path is within the workspace folder 80 | let found_idx = 81 | try 82 | path.find(this.folder.path)? 83 | else 84 | -1 85 | end 86 | if found_idx == 0 then 87 | this.folder.join(path.substring(this.folder.path.size().isize() + 1))? 88 | else 89 | error 90 | end 91 | 92 | 93 | -------------------------------------------------------------------------------- /lsp/workspace/router.pony: -------------------------------------------------------------------------------- 1 | use "collections" 2 | use "files" 3 | use ".." 4 | 5 | class WorkspaceRouter 6 | let workspaces: Map[String, WorkspaceManager] 7 | var min_workspace_path_len: USize 8 | 9 | new ref create() => 10 | workspaces = Map[String, WorkspaceManager].create() 11 | min_workspace_path_len = USize.max_value() 12 | 13 | fun find_workspace(file_uri: String): (WorkspaceManager | None) => 14 | var file_path = Uris.to_path(file_uri) 15 | // check the parent directories upwards if any of them is part of a workspace 16 | while (file_path != ".") and (file_path.size() >= this.min_workspace_path_len) do 17 | try 18 | let workspace = this.workspaces(file_path)? 19 | return workspace 20 | end 21 | file_path = Path.dir(file_path) 22 | end 23 | None 24 | 25 | fun ref add_workspace(folder: FilePath, mgr: WorkspaceManager) ? => 26 | let abs_folder = folder.canonical()?.path 27 | let old_mgr = workspaces(abs_folder) = mgr 28 | match old_mgr 29 | | let old: WorkspaceManager => old.dispose() 30 | end 31 | this.min_workspace_path_len = this.min_workspace_path_len.min(abs_folder.size()) 32 | 33 | fun ref dispose() => 34 | for mgr in this.workspaces.values() do 35 | mgr.dispose() 36 | end 37 | this.workspaces.clear() 38 | 39 | 40 | --------------------------------------------------------------------------------