@greenpandastudios/aug-cli 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +13 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/aug.mjs +3 -0
- package/docs/api/crypto.md +351 -0
- package/docs/api/io.md +207 -0
- package/docs/api/json.md +21 -0
- package/docs/api/memory.md +109 -0
- package/docs/api/time.md +54 -0
- package/docs/api/web.md +184 -0
- package/docs/assets/benchmarks/execution.svg +2978 -0
- package/docs/assets/benchmarks/http.svg +1674 -0
- package/docs/assets/benchmarks/improvements.svg +2315 -0
- package/docs/assets/benchmarks/memory.svg +1891 -0
- package/docs/benchmark-baseline.json +1087 -0
- package/docs/benchmark-results.json +91123 -0
- package/docs/benchmarks.json +38 -0
- package/docs/compatibility.md +42 -0
- package/docs/concurrency-implementation.md +18 -0
- package/docs/diagnostics.md +97 -0
- package/docs/docker.md +35 -0
- package/docs/example-projects.json +26 -0
- package/docs/examples/approved-design/counters.md +253 -0
- package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/approved-design/domain/app.md +165 -0
- package/docs/examples/approved-design/domain/export.md +83 -0
- package/docs/examples/approved-design/domain/models.md +80 -0
- package/docs/examples/approved-design/domain/numbers.md +248 -0
- package/docs/examples/approved-design/index.md +39 -0
- package/docs/examples/approved-design/main-yaml.md +24 -0
- package/docs/examples/approved-design/main.md +215 -0
- package/docs/examples/benchmark/index.md +33 -0
- package/docs/examples/benchmark/main-yaml.md +17 -0
- package/docs/examples/benchmark/main.md +117 -0
- package/docs/examples/cli-args/index.md +32 -0
- package/docs/examples/cli-args/main.md +107 -0
- package/docs/examples/collections/index.md +32 -0
- package/docs/examples/collections/main.md +118 -0
- package/docs/examples/collections-benchmark/index.md +34 -0
- package/docs/examples/collections-benchmark/main.md +115 -0
- package/docs/examples/cpu-benchmark/index.md +34 -0
- package/docs/examples/cpu-benchmark/main.md +90 -0
- package/docs/examples/developer-workflow/calculator.md +357 -0
- package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/developer-workflow/index.md +37 -0
- package/docs/examples/developer-workflow/logging/console.md +124 -0
- package/docs/examples/developer-workflow/logging/export.md +70 -0
- package/docs/examples/developer-workflow/logging/logger.md +111 -0
- package/docs/examples/developer-workflow/main.md +172 -0
- package/docs/examples/drop/index.md +33 -0
- package/docs/examples/drop/main.md +85 -0
- package/docs/examples/drop/resource.md +95 -0
- package/docs/examples/errors/errors.md +85 -0
- package/docs/examples/errors/index.md +33 -0
- package/docs/examples/errors/main.md +92 -0
- package/docs/examples/ffi/index.md +33 -0
- package/docs/examples/ffi/main.md +75 -0
- package/docs/examples/ffi/native.md +93 -0
- package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/generic-di/index.md +33 -0
- package/docs/examples/generic-di/main.md +111 -0
- package/docs/examples/generic-di/types.md +180 -0
- package/docs/examples/generics/index.md +33 -0
- package/docs/examples/generics/main.md +120 -0
- package/docs/examples/generics/types.md +189 -0
- package/docs/examples/hello/app/export.md +67 -0
- package/docs/examples/hello/app/greeter.md +190 -0
- package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/hello/index.md +37 -0
- package/docs/examples/hello/logging/console.md +121 -0
- package/docs/examples/hello/logging/export.md +71 -0
- package/docs/examples/hello/logging/logger.md +120 -0
- package/docs/examples/hello/main.md +115 -0
- package/docs/examples/http-benchmark/index.md +35 -0
- package/docs/examples/http-benchmark/main.md +79 -0
- package/docs/examples/http-benchmark/routes.md +88 -0
- package/docs/examples/index.md +60 -0
- package/docs/examples/interceptors/app.md +250 -0
- package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/interceptors/index.md +35 -0
- package/docs/examples/interceptors/interceptors.md +284 -0
- package/docs/examples/interceptors/logging.md +155 -0
- package/docs/examples/interceptors/main.md +162 -0
- package/docs/examples/json-benchmark/data.md +71 -0
- package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/json-benchmark/index.md +35 -0
- package/docs/examples/json-benchmark/main.md +131 -0
- package/docs/examples/new-syntax/console.md +118 -0
- package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/new-syntax/greeter.md +145 -0
- package/docs/examples/new-syntax/index.md +36 -0
- package/docs/examples/new-syntax/logger.md +111 -0
- package/docs/examples/new-syntax/main.md +135 -0
- package/docs/examples/new-syntax/math.md +79 -0
- package/docs/examples/oidc-login/client/contracts.md +151 -0
- package/docs/examples/oidc-login/client/endpoints.md +263 -0
- package/docs/examples/oidc-login/client/export.md +107 -0
- package/docs/examples/oidc-login/client/login.md +515 -0
- package/docs/examples/oidc-login/client/logout.md +249 -0
- package/docs/examples/oidc-login/client/protocol.md +595 -0
- package/docs/examples/oidc-login/client/session.md +297 -0
- package/docs/examples/oidc-login/client/views.md +144 -0
- package/docs/examples/oidc-login/common/export.md +115 -0
- package/docs/examples/oidc-login/common/headers.md +162 -0
- package/docs/examples/oidc-login/common/keys.md +336 -0
- package/docs/examples/oidc-login/common/settings.md +116 -0
- package/docs/examples/oidc-login/common/views.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +925 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +434 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +374 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +150 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +532 -0
- package/docs/examples/oidc-login/index.md +57 -0
- package/docs/examples/oidc-login/main-yaml.md +28 -0
- package/docs/examples/oidc-login/main.md +283 -0
- package/docs/examples/oidc-login/provider/authorization.md +457 -0
- package/docs/examples/oidc-login/provider/contracts.md +267 -0
- package/docs/examples/oidc-login/provider/credentials.md +148 -0
- package/docs/examples/oidc-login/provider/discovery.md +215 -0
- package/docs/examples/oidc-login/provider/export.md +131 -0
- package/docs/examples/oidc-login/provider/token.md +364 -0
- package/docs/examples/oidc-login/provider/userinfo.md +228 -0
- package/docs/examples/oidc-login/provider/views.md +137 -0
- package/docs/examples/ownership/counter.md +140 -0
- package/docs/examples/ownership/index.md +33 -0
- package/docs/examples/ownership/main.md +90 -0
- package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/ownership-transfer/index.md +33 -0
- package/docs/examples/ownership-transfer/main.md +125 -0
- package/docs/examples/ownership-transfer/resource.md +150 -0
- package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +117 -0
- package/docs/examples/packages-app/index.md +34 -0
- package/docs/examples/packages-app/main-yaml.md +18 -0
- package/docs/examples/packages-app/main.md +80 -0
- package/docs/examples/packages-math/aug-package-json.md +24 -0
- package/docs/examples/packages-math/index.md +36 -0
- package/docs/examples/packages-math/package-json.md +25 -0
- package/docs/examples/packages-math/src/arithmetic.md +121 -0
- package/docs/examples/packages-math/src/export.md +63 -0
- package/docs/examples/startup-benchmark/index.md +34 -0
- package/docs/examples/startup-benchmark/main.md +68 -0
- package/docs/examples/visibility/counter.md +142 -0
- package/docs/examples/visibility/index.md +33 -0
- package/docs/examples/visibility/main.md +96 -0
- package/docs/examples.json +47 -0
- package/docs/getting-started.md +5 -0
- package/docs/grammar.md +136 -0
- package/docs/implementation-map.md +106 -0
- package/docs/index.md +46 -0
- package/docs/language-conformance.md +30 -0
- package/docs/language-constructs.md +1461 -0
- package/docs/language-design-audit.md +147 -0
- package/docs/maintaining-docs.md +43 -0
- package/docs/packages.md +184 -0
- package/docs/performance.md +535 -0
- package/docs/production-readiness.md +39 -0
- package/docs/reference.md +361 -0
- package/docs/release-review.md +23 -0
- package/docs/releasing.md +79 -0
- package/docs/roadmap.md +13 -0
- package/docs/specifications.md +86 -0
- package/docs/testing.md +120 -0
- package/docs/tooling.md +197 -0
- package/docs/web-implementation-plan.md +39 -0
- package/docs/web-library-gaps.md +27 -0
- package/docs/web.md +197 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/approved-design/.aug-spec/manifest.json +14 -0
- package/examples/approved-design/counters.aug +22 -0
- package/examples/approved-design/counters.aug.md +177 -0
- package/examples/approved-design/domain/app.aug +12 -0
- package/examples/approved-design/domain/app.aug.md +97 -0
- package/examples/approved-design/domain/export.aug +5 -0
- package/examples/approved-design/domain/export.aug.md +25 -0
- package/examples/approved-design/domain/models.aug +2 -0
- package/examples/approved-design/domain/models.aug.md +30 -0
- package/examples/approved-design/domain/numbers.aug +29 -0
- package/examples/approved-design/domain/numbers.aug.md +141 -0
- package/examples/approved-design/main.aug +26 -0
- package/examples/approved-design/main.aug.md +108 -0
- package/examples/approved-design/main.yaml +8 -0
- package/examples/benchmark/.aug-spec/manifest.json +7 -0
- package/examples/benchmark/main.aug +17 -0
- package/examples/benchmark/main.aug.md +43 -0
- package/examples/benchmark/main.yaml +1 -0
- package/examples/cli-args/.aug-spec/manifest.json +7 -0
- package/examples/cli-args/main.aug +15 -0
- package/examples/cli-args/main.aug.md +38 -0
- package/examples/collections/.aug-spec/manifest.json +7 -0
- package/examples/collections/main.aug +18 -0
- package/examples/collections/main.aug.md +43 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/developer-workflow/.aug-spec/manifest.json +13 -0
- package/examples/developer-workflow/calculator.aug +55 -0
- package/examples/developer-workflow/calculator.aug.md +228 -0
- package/examples/developer-workflow/logging/console.aug +8 -0
- package/examples/developer-workflow/logging/console.aug.md +67 -0
- package/examples/developer-workflow/logging/export.aug +2 -0
- package/examples/developer-workflow/logging/export.aug.md +19 -0
- package/examples/developer-workflow/logging/logger.aug +6 -0
- package/examples/developer-workflow/logging/logger.aug.md +57 -0
- package/examples/developer-workflow/main.aug +25 -0
- package/examples/developer-workflow/main.aug.md +79 -0
- package/examples/drop/.aug-spec/manifest.json +8 -0
- package/examples/drop/main.aug +3 -0
- package/examples/drop/main.aug.md +35 -0
- package/examples/drop/resource.aug +8 -0
- package/examples/drop/resource.aug.md +44 -0
- package/examples/errors/.aug-spec/manifest.json +8 -0
- package/examples/errors/errors.aug +6 -0
- package/examples/errors/errors.aug.md +33 -0
- package/examples/errors/main.aug +7 -0
- package/examples/errors/main.aug.md +36 -0
- package/examples/ffi/.aug-spec/manifest.json +8 -0
- package/examples/ffi/main.aug +2 -0
- package/examples/ffi/main.aug.md +27 -0
- package/examples/ffi/native.aug +6 -0
- package/examples/ffi/native.aug.md +43 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/generic-di/.aug-spec/manifest.json +10 -0
- package/examples/generic-di/main.aug +9 -0
- package/examples/generic-di/main.aug.md +49 -0
- package/examples/generic-di/types.aug +17 -0
- package/examples/generic-di/types.aug.md +124 -0
- package/examples/generics/.aug-spec/manifest.json +8 -0
- package/examples/generics/main.aug +9 -0
- package/examples/generics/main.aug.md +58 -0
- package/examples/generics/types.aug +19 -0
- package/examples/generics/types.aug.md +132 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/hello/.aug-spec/manifest.json +14 -0
- package/examples/hello/app/export.aug +1 -0
- package/examples/hello/app/export.aug.md +17 -0
- package/examples/hello/app/greeter.aug +22 -0
- package/examples/hello/app/greeter.aug.md +109 -0
- package/examples/hello/logging/console.aug +7 -0
- package/examples/hello/logging/console.aug.md +65 -0
- package/examples/hello/logging/export.aug +2 -0
- package/examples/hello/logging/export.aug.md +19 -0
- package/examples/hello/logging/logger.aug +9 -0
- package/examples/hello/logging/logger.aug.md +59 -0
- package/examples/hello/main.aug +9 -0
- package/examples/hello/main.aug.md +49 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/interceptors/.aug-spec/manifest.json +12 -0
- package/examples/interceptors/app.aug +28 -0
- package/examples/interceptors/app.aug.md +162 -0
- package/examples/interceptors/interceptors.aug +40 -0
- package/examples/interceptors/interceptors.aug.md +180 -0
- package/examples/interceptors/logging.aug +12 -0
- package/examples/interceptors/logging.aug.md +96 -0
- package/examples/interceptors/main.aug +22 -0
- package/examples/interceptors/main.aug.md +76 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/new-syntax/.aug-spec/manifest.json +13 -0
- package/examples/new-syntax/console.aug +7 -0
- package/examples/new-syntax/console.aug.md +63 -0
- package/examples/new-syntax/greeter.aug +10 -0
- package/examples/new-syntax/greeter.aug.md +89 -0
- package/examples/new-syntax/logger.aug +6 -0
- package/examples/new-syntax/logger.aug.md +57 -0
- package/examples/new-syntax/main.aug +12 -0
- package/examples/new-syntax/main.aug.md +64 -0
- package/examples/new-syntax/math.aug +3 -0
- package/examples/new-syntax/math.aug.md +29 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug +73 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +791 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug +68 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +266 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug +6 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +55 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug +45 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +250 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug +11 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +96 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug +58 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +420 -0
- package/examples/oidc-login/.aug-spec/manifest.json +40 -0
- package/examples/oidc-login/README.md +29 -0
- package/examples/oidc-login/client/contracts.aug +7 -0
- package/examples/oidc-login/client/contracts.aug.md +80 -0
- package/examples/oidc-login/client/endpoints.aug +21 -0
- package/examples/oidc-login/client/endpoints.aug.md +161 -0
- package/examples/oidc-login/client/export.aug +7 -0
- package/examples/oidc-login/client/export.aug.md +29 -0
- package/examples/oidc-login/client/login.aug +58 -0
- package/examples/oidc-login/client/login.aug.md +331 -0
- package/examples/oidc-login/client/logout.aug +18 -0
- package/examples/oidc-login/client/logout.aug.md +150 -0
- package/examples/oidc-login/client/protocol.aug +106 -0
- package/examples/oidc-login/client/protocol.aug.md +326 -0
- package/examples/oidc-login/client/session.aug +34 -0
- package/examples/oidc-login/client/session.aug.md +155 -0
- package/examples/oidc-login/client/views.aug +21 -0
- package/examples/oidc-login/client/views.aug.md +68 -0
- package/examples/oidc-login/common/export.aug +9 -0
- package/examples/oidc-login/common/export.aug.md +33 -0
- package/examples/oidc-login/common/headers.aug +11 -0
- package/examples/oidc-login/common/headers.aug.md +79 -0
- package/examples/oidc-login/common/keys.aug +37 -0
- package/examples/oidc-login/common/keys.aug.md +207 -0
- package/examples/oidc-login/common/settings.aug +4 -0
- package/examples/oidc-login/common/settings.aug.md +47 -0
- package/examples/oidc-login/common/views.aug +16 -0
- package/examples/oidc-login/common/views.aug.md +34 -0
- package/examples/oidc-login/main.aug +39 -0
- package/examples/oidc-login/main.aug.md +166 -0
- package/examples/oidc-login/main.yaml +12 -0
- package/examples/oidc-login/provider/authorization.aug +59 -0
- package/examples/oidc-login/provider/authorization.aug.md +264 -0
- package/examples/oidc-login/provider/contracts.aug +15 -0
- package/examples/oidc-login/provider/contracts.aug.md +193 -0
- package/examples/oidc-login/provider/credentials.aug +10 -0
- package/examples/oidc-login/provider/credentials.aug.md +64 -0
- package/examples/oidc-login/provider/discovery.aug +13 -0
- package/examples/oidc-login/provider/discovery.aug.md +133 -0
- package/examples/oidc-login/provider/export.aug +13 -0
- package/examples/oidc-login/provider/export.aug.md +41 -0
- package/examples/oidc-login/provider/token.aug +37 -0
- package/examples/oidc-login/provider/token.aug.md +223 -0
- package/examples/oidc-login/provider/userinfo.aug +26 -0
- package/examples/oidc-login/provider/userinfo.aug.md +104 -0
- package/examples/oidc-login/provider/views.aug +18 -0
- package/examples/oidc-login/provider/views.aug.md +63 -0
- package/examples/ownership/.aug-spec/manifest.json +8 -0
- package/examples/ownership/counter.aug +14 -0
- package/examples/ownership/counter.aug.md +85 -0
- package/examples/ownership/main.aug +4 -0
- package/examples/ownership/main.aug.md +38 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/ownership-transfer/.aug-spec/manifest.json +10 -0
- package/examples/ownership-transfer/main.aug +9 -0
- package/examples/ownership-transfer/main.aug.md +63 -0
- package/examples/ownership-transfer/resource.aug +16 -0
- package/examples/ownership-transfer/resource.aug.md +89 -0
- package/examples/packages/README.md +15 -0
- package/examples/packages/app/.aug-spec/manifest.json +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +63 -0
- package/examples/packages/app/main.aug +2 -0
- package/examples/packages/app/main.aug.md +33 -0
- package/examples/packages/app/main.yaml +2 -0
- package/examples/packages/math/.aug-spec/manifest.json +8 -0
- package/examples/packages/math/README.md +3 -0
- package/examples/packages/math/aug-package.json +8 -0
- package/examples/packages/math/package.json +9 -0
- package/examples/packages/math/src/arithmetic.aug +8 -0
- package/examples/packages/math/src/arithmetic.aug.md +63 -0
- package/examples/packages/math/src/export.aug +1 -0
- package/examples/packages/math/src/export.aug.md +17 -0
- package/examples/visibility/.aug-spec/manifest.json +8 -0
- package/examples/visibility/counter.aug +14 -0
- package/examples/visibility/counter.aug.md +87 -0
- package/examples/visibility/main.aug +7 -0
- package/examples/visibility/main.aug.md +39 -0
- package/package.json +50 -0
- package/runtime/aug_crypto.c +121 -0
- package/runtime/aug_html.c +93 -0
- package/runtime/aug_http.c +829 -0
- package/runtime/aug_json.c +165 -0
- package/runtime/aug_runtime.c +792 -0
- package/runtime/aug_runtime.h +245 -0
- package/runtime/aug_tasks.c +172 -0
- package/runtime/aug_time.c +5 -0
- package/runtime/aug_values.c +80 -0
- package/scripts/bootstrap-native.mjs +121 -0
- package/scripts/native-dependencies.lock.json +65 -0
- package/scripts/native-home.mjs +11 -0
- package/src/actions.js +109 -0
- package/src/ast.js +19 -0
- package/src/builtins.js +93 -0
- package/src/checker.js +2896 -0
- package/src/cli.js +344 -0
- package/src/codegen.js +1159 -0
- package/src/config.js +149 -0
- package/src/continuation.js +110 -0
- package/src/di.js +24 -0
- package/src/documentation.js +27 -0
- package/src/editor.js +782 -0
- package/src/effects.js +29 -0
- package/src/fixes.js +222 -0
- package/src/formatter.js +296 -0
- package/src/freshness.js +154 -0
- package/src/help.js +212 -0
- package/src/html.js +27 -0
- package/src/http-policies.js +90 -0
- package/src/inference.js +16 -0
- package/src/interceptors.js +70 -0
- package/src/javadoc.js +67 -0
- package/src/lexer.js +199 -0
- package/src/libraries.js +31 -0
- package/src/lsp.js +180 -0
- package/src/native.js +144 -0
- package/src/navigation.js +162 -0
- package/src/openapi.js +220 -0
- package/src/ownership.js +232 -0
- package/src/package-manager.js +299 -0
- package/src/parser.js +1155 -0
- package/src/policies.js +130 -0
- package/src/project-init.js +19 -0
- package/src/project.js +292 -0
- package/src/schemas.js +62 -0
- package/src/semantic.js +255 -0
- package/src/spec.js +738 -0
- package/src/testing.js +186 -0
- package/src/types.js +10 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
#include "aug_runtime.h"
|
|
2
|
+
#include <pthread.h>
|
|
3
|
+
#include <errno.h>
|
|
4
|
+
|
|
5
|
+
#include <stdio.h>
|
|
6
|
+
#include <limits.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
static AugObject *heap = NULL;
|
|
11
|
+
static AugExecution default_execution;
|
|
12
|
+
static AugExecution *executions = &default_execution;
|
|
13
|
+
static AugExecution *current_execution = &default_execution;
|
|
14
|
+
#define frames (current_execution->root_frames)
|
|
15
|
+
#define scopes (current_execution->scope_stack)
|
|
16
|
+
#define scope_count (current_execution->scope_depth)
|
|
17
|
+
AugScopeJoin aug_scope_join_hook = NULL;
|
|
18
|
+
void (*aug_task_checkpoint_hook)(void);
|
|
19
|
+
AugExecution *aug_execution_current(void) { return current_execution; }
|
|
20
|
+
AugExecution *aug_execution_switch(AugExecution *execution) { AugExecution *previous = current_execution; current_execution = execution; return previous; }
|
|
21
|
+
void aug_execution_init(AugExecution *execution) { memset(execution, 0, sizeof(*execution)); execution->next = executions; executions = execution; }
|
|
22
|
+
void aug_execution_dispose(AugExecution *execution) { AugExecution **cursor = &executions; while (*cursor && *cursor != execution) cursor = &(*cursor)->next; if (*cursor) *cursor = execution->next; }
|
|
23
|
+
static AugRetained *retained = NULL;
|
|
24
|
+
static AugValue *globals = NULL;
|
|
25
|
+
static size_t global_count = 0;
|
|
26
|
+
static size_t object_count = 0;
|
|
27
|
+
static size_t next_collection = 1024;
|
|
28
|
+
static bool collecting = false;
|
|
29
|
+
static AugValue cli_args = {0};
|
|
30
|
+
static bool equal(AugValue left, AugValue right);
|
|
31
|
+
bool aug_test_failed = false;
|
|
32
|
+
size_t aug_test_assertions = 0;
|
|
33
|
+
|
|
34
|
+
static void fail(const char *message) {
|
|
35
|
+
fprintf(stderr, "AugScript runtime error: %s\n", message);
|
|
36
|
+
exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
AugValue aug_null(void) { return (AugValue){ .tag = AUG_NULL }; }
|
|
40
|
+
AugValue aug_int(int64_t value) { return (AugValue){ .tag = AUG_INT, .as.integer = value }; }
|
|
41
|
+
AugValue aug_float(double value) { return (AugValue){ .tag = AUG_FLOAT, .as.floating = value }; }
|
|
42
|
+
AugValue aug_bool(bool value) { return (AugValue){ .tag = AUG_BOOL, .as.boolean = value }; }
|
|
43
|
+
|
|
44
|
+
static AugValue checked_error(const char *name) {
|
|
45
|
+
aug_throw(aug_new_object(name, 0, NULL, NULL, 0));
|
|
46
|
+
return aug_null();
|
|
47
|
+
}
|
|
48
|
+
AugValue aug_error_named(const char *name) { return checked_error(name); }
|
|
49
|
+
|
|
50
|
+
/* Arithmetic is defined modulo 2^64, including negation and MIN / -1. */
|
|
51
|
+
static int64_t signed_bits(uint64_t bits) { int64_t result; memcpy(&result, &bits, sizeof(result)); return result; }
|
|
52
|
+
|
|
53
|
+
static AugObject *allocate(int kind, const char *type_name, size_t field_count,
|
|
54
|
+
const unsigned char *owned_fields,
|
|
55
|
+
const AugMethodEntry *methods, size_t method_count) {
|
|
56
|
+
if (!collecting && object_count >= next_collection) aug_collect();
|
|
57
|
+
AugObject *object = calloc(1, sizeof(AugObject));
|
|
58
|
+
if (!object) fail("out of memory");
|
|
59
|
+
object->kind = kind;
|
|
60
|
+
object->type_name = type_name;
|
|
61
|
+
object->field_count = field_count;
|
|
62
|
+
object->capacity = field_count;
|
|
63
|
+
object->owned_fields = owned_fields;
|
|
64
|
+
object->fields = field_count ? calloc(field_count, sizeof(AugValue)) : NULL;
|
|
65
|
+
if (field_count && !object->fields) fail("out of memory");
|
|
66
|
+
object->methods = methods;
|
|
67
|
+
object->method_count = method_count;
|
|
68
|
+
object->next = heap;
|
|
69
|
+
heap = object;
|
|
70
|
+
object_count++;
|
|
71
|
+
return object;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
AugValue aug_string(const char *value) {
|
|
75
|
+
return aug_string_n(value, strlen(value));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
AugValue aug_string_n(const void *value, size_t length) {
|
|
79
|
+
AugObject *object = allocate(AUG_STRING, "string", 0, NULL, NULL, 0);
|
|
80
|
+
object->text = malloc(length + 1);
|
|
81
|
+
if (!object->text) fail("out of memory");
|
|
82
|
+
memcpy(object->text, value, length);
|
|
83
|
+
object->text[length] = 0;
|
|
84
|
+
object->text_length = length;
|
|
85
|
+
return (AugValue){ .tag = AUG_STRING, .as.object = object };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
AugValue aug_bytes(const void *value, size_t length, int kind) {
|
|
89
|
+
AugObject *object = allocate(kind, kind == AUG_PRIVATE_KEY_KIND ? "RsaPrivateKey" : kind == AUG_PUBLIC_KEY_KIND ? "RsaPublicKey" : "Bytes", 0, NULL, NULL, 0);
|
|
90
|
+
object->text = malloc(length + 1);
|
|
91
|
+
if (!object->text) fail("out of memory");
|
|
92
|
+
if (length) memcpy(object->text, value, length);
|
|
93
|
+
object->text[length] = 0;
|
|
94
|
+
object->text_length = length;
|
|
95
|
+
return (AugValue){ .tag = AUG_OBJECT, .as.object = object };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
AugValue aug_new_object(const char *name, size_t field_count,
|
|
99
|
+
const unsigned char *owned_fields,
|
|
100
|
+
const AugMethodEntry *methods, size_t method_count) {
|
|
101
|
+
AugObject *object = allocate(AUG_OBJECT, name, field_count, owned_fields, methods, method_count);
|
|
102
|
+
return (AugValue){ .tag = AUG_OBJECT, .as.object = object };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
AugValue aug_list_new(AugValue *items, size_t count) {
|
|
106
|
+
AugObject *object = allocate(AUG_LIST_KIND, "List", count, NULL, NULL, 0);
|
|
107
|
+
for (size_t i = 0; i < count; i++) object->fields[i] = items[i];
|
|
108
|
+
return (AugValue){ .tag = AUG_OBJECT, .as.object = object };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static AugObject *expect_list(AugValue value) {
|
|
112
|
+
if (value.tag != AUG_OBJECT || !value.as.object || value.as.object->kind != AUG_LIST_KIND ||
|
|
113
|
+
value.as.object->dropped) fail("expected live List");
|
|
114
|
+
return value.as.object;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void aug_list_append(AugValue list, AugValue item) {
|
|
118
|
+
AugObject *object = expect_list(list);
|
|
119
|
+
if (object->frozen) fail("cannot mutate a frozen List");
|
|
120
|
+
if (object->field_count == object->capacity) {
|
|
121
|
+
size_t capacity = object->capacity ? object->capacity * 2 : 4;
|
|
122
|
+
AugValue *fields = realloc(object->fields, capacity * sizeof(AugValue));
|
|
123
|
+
if (!fields) fail("out of memory");
|
|
124
|
+
object->fields = fields;
|
|
125
|
+
object->capacity = capacity;
|
|
126
|
+
}
|
|
127
|
+
object->fields[object->field_count++] = item;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
AugValue aug_list_get(AugValue list, int64_t index) {
|
|
131
|
+
AugObject *object = expect_list(list);
|
|
132
|
+
if (index < 0 || (uint64_t)index >= object->field_count) return checked_error("IndexError");
|
|
133
|
+
return object->fields[index];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
AugValue aug_list_at(AugValue list, int64_t index) {
|
|
137
|
+
AugObject *object = expect_list(list);
|
|
138
|
+
return index < 0 || (uint64_t)index >= object->field_count ? aug_null() : object->fields[index];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
int64_t aug_list_length(AugValue list) {
|
|
142
|
+
return (int64_t)expect_list(list)->field_count;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
AugValue aug_tuple_new(AugValue *items, size_t count) {
|
|
146
|
+
AugObject *object = allocate(AUG_TUPLE_KIND, "Tuple", count, NULL, NULL, 0);
|
|
147
|
+
for (size_t i = 0; i < count; i++) object->fields[i] = items[i];
|
|
148
|
+
return (AugValue){ .tag = AUG_OBJECT, .as.object = object };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static AugObject *expect_tuple(AugValue value) {
|
|
152
|
+
if (value.tag != AUG_OBJECT || !value.as.object || value.as.object->kind != AUG_TUPLE_KIND ||
|
|
153
|
+
value.as.object->dropped) fail("expected live Tuple");
|
|
154
|
+
return value.as.object;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
AugValue aug_tuple_get(AugValue tuple, int64_t index) {
|
|
158
|
+
AugObject *object = expect_tuple(tuple);
|
|
159
|
+
if (index < 0 || (uint64_t)index >= object->field_count) fail("Tuple index out of range");
|
|
160
|
+
return object->fields[index];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
int64_t aug_tuple_length(AugValue tuple) { return (int64_t)expect_tuple(tuple)->field_count; }
|
|
164
|
+
|
|
165
|
+
static uint64_t hash_value(AugValue value) {
|
|
166
|
+
switch (value.tag) {
|
|
167
|
+
case AUG_NULL: return 0;
|
|
168
|
+
case AUG_BOOL: return value.as.boolean ? 1231 : 1237;
|
|
169
|
+
case AUG_INT:
|
|
170
|
+
case AUG_FLOAT: {
|
|
171
|
+
double number = value.tag == AUG_INT ? (double)value.as.integer : value.as.floating;
|
|
172
|
+
if (number == 0) number = 0; /* normalize negative zero */
|
|
173
|
+
uint64_t bits;
|
|
174
|
+
memcpy(&bits, &number, sizeof(bits));
|
|
175
|
+
bits ^= bits >> 33; bits *= UINT64_C(0xff51afd7ed558ccd);
|
|
176
|
+
bits ^= bits >> 33; bits *= UINT64_C(0xc4ceb9fe1a85ec53);
|
|
177
|
+
return bits ^ (bits >> 33);
|
|
178
|
+
}
|
|
179
|
+
case AUG_STRING: {
|
|
180
|
+
uint64_t hash = UINT64_C(14695981039346656037);
|
|
181
|
+
for (size_t i = 0; i < value.as.object->text_length; i++)
|
|
182
|
+
hash = (hash ^ (unsigned char)value.as.object->text[i]) * UINT64_C(1099511628211);
|
|
183
|
+
return hash;
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
if (value.as.object->kind == AUG_TUPLE_KIND || value.as.object->kind == AUG_RECORD_KIND) {
|
|
187
|
+
uint64_t hash = UINT64_C(14695981039346656037);
|
|
188
|
+
for (size_t i = 0; i < value.as.object->field_count; i++)
|
|
189
|
+
hash = (hash ^ hash_value(value.as.object->fields[i])) * UINT64_C(1099511628211);
|
|
190
|
+
return hash;
|
|
191
|
+
}
|
|
192
|
+
return (uint64_t)(uintptr_t)value.as.object;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Buckets store field offsets + 1; zero is an empty bucket. Fields also keep
|
|
197
|
+
entries in insertion order and remain visible to the garbage collector. */
|
|
198
|
+
static bool key_equal(AugValue left, AugValue right) {
|
|
199
|
+
if (left.tag == AUG_INT && right.tag == AUG_INT) return left.as.integer == right.as.integer;
|
|
200
|
+
return equal(left, right);
|
|
201
|
+
}
|
|
202
|
+
static size_t bucket_for_hash(AugObject *object, AugValue key, uint64_t hash) {
|
|
203
|
+
size_t bucket = (size_t)hash & (object->bucket_count - 1);
|
|
204
|
+
while (object->buckets[bucket] && !key_equal(object->fields[object->buckets[bucket] - 1], key))
|
|
205
|
+
bucket = (bucket + 1) & (object->bucket_count - 1);
|
|
206
|
+
return bucket;
|
|
207
|
+
}
|
|
208
|
+
static size_t bucket_for(AugObject *object, AugValue key) { return bucket_for_hash(object, key, hash_value(key)); }
|
|
209
|
+
|
|
210
|
+
static bool grow_table(AugObject *object, size_t stride) {
|
|
211
|
+
size_t entries = object->field_count / stride;
|
|
212
|
+
bool rehashed = !object->bucket_count || (entries + 1) * 10 > object->bucket_count * 7;
|
|
213
|
+
if (rehashed) {
|
|
214
|
+
size_t count = object->bucket_count ? object->bucket_count * 2 : 8;
|
|
215
|
+
size_t *buckets = calloc(count, sizeof(size_t));
|
|
216
|
+
if (!buckets) fail("out of memory");
|
|
217
|
+
free(object->buckets);
|
|
218
|
+
object->buckets = buckets;
|
|
219
|
+
object->bucket_count = count;
|
|
220
|
+
for (size_t i = 0; i < object->field_count; i += stride)
|
|
221
|
+
object->buckets[bucket_for(object, object->fields[i])] = i + 1;
|
|
222
|
+
}
|
|
223
|
+
if (object->field_count + stride > object->capacity) {
|
|
224
|
+
size_t capacity = object->capacity ? object->capacity * 2 : 8;
|
|
225
|
+
AugValue *fields = realloc(object->fields, capacity * sizeof(AugValue));
|
|
226
|
+
if (!fields) fail("out of memory");
|
|
227
|
+
object->fields = fields;
|
|
228
|
+
object->capacity = capacity;
|
|
229
|
+
}
|
|
230
|
+
return rehashed;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
AugValue aug_map_new(void) {
|
|
234
|
+
AugObject *object = allocate(AUG_MAP_KIND, "Map", 0, NULL, NULL, 0);
|
|
235
|
+
return (AugValue){ .tag = AUG_OBJECT, .as.object = object };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static AugObject *expect_map(AugValue value) {
|
|
239
|
+
if (value.tag != AUG_OBJECT || !value.as.object || value.as.object->kind != AUG_MAP_KIND ||
|
|
240
|
+
value.as.object->dropped) fail("expected live Map");
|
|
241
|
+
return value.as.object;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
void aug_map_set(AugValue map, AugValue key, AugValue value) {
|
|
245
|
+
AugObject *object = expect_map(map);
|
|
246
|
+
if (object->frozen) fail("cannot mutate a frozen Map");
|
|
247
|
+
uint64_t hash = hash_value(key); size_t bucket = 0;
|
|
248
|
+
if (object->bucket_count) {
|
|
249
|
+
bucket = bucket_for_hash(object, key, hash);
|
|
250
|
+
size_t field = object->buckets[bucket];
|
|
251
|
+
if (field) { object->fields[field] = value; return; }
|
|
252
|
+
}
|
|
253
|
+
if (grow_table(object, 2)) bucket = bucket_for_hash(object, key, hash);
|
|
254
|
+
object->buckets[bucket] = object->field_count + 1;
|
|
255
|
+
object->fields[object->field_count++] = key;
|
|
256
|
+
object->fields[object->field_count++] = value;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
AugValue aug_map_get(AugValue map, AugValue key) {
|
|
260
|
+
AugObject *object = expect_map(map);
|
|
261
|
+
if (!object->bucket_count) return aug_null();
|
|
262
|
+
size_t field = object->buckets[bucket_for(object, key)];
|
|
263
|
+
return field ? object->fields[field] : aug_null();
|
|
264
|
+
}
|
|
265
|
+
AugValue aug_map_take(AugValue map, AugValue key) {
|
|
266
|
+
AugObject *object = expect_map(map); if (object->frozen) fail("cannot mutate a frozen Map");
|
|
267
|
+
if (!object->bucket_count) return aug_null(); size_t field = object->buckets[bucket_for(object, key)];
|
|
268
|
+
if (!field) return aug_null(); AugValue result = object->fields[field]; size_t first = field - 1;
|
|
269
|
+
memmove(object->fields + first, object->fields + first + 2, (object->field_count - first - 2) * sizeof(AugValue));
|
|
270
|
+
object->field_count -= 2; object->fields[object->field_count] = aug_null(); object->fields[object->field_count + 1] = aug_null();
|
|
271
|
+
memset(object->buckets, 0, object->bucket_count * sizeof(size_t));
|
|
272
|
+
for (size_t i = 0; i < object->field_count; i += 2) object->buckets[bucket_for(object, object->fields[i])] = i + 1;
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
bool aug_map_contains(AugValue map, AugValue key) {
|
|
277
|
+
AugObject *object = expect_map(map);
|
|
278
|
+
return object->bucket_count && object->buckets[bucket_for(object, key)] != 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
int64_t aug_map_length(AugValue map) {
|
|
282
|
+
return (int64_t)(expect_map(map)->field_count / 2);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static AugObject *expect_set(AugValue value) {
|
|
286
|
+
if (value.tag != AUG_OBJECT || !value.as.object || value.as.object->kind != AUG_SET_KIND ||
|
|
287
|
+
value.as.object->dropped) fail("expected live Set");
|
|
288
|
+
return value.as.object;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
AugValue aug_set_new(AugValue *items, size_t count) {
|
|
292
|
+
AugObject *object = allocate(AUG_SET_KIND, "Set", 0, NULL, NULL, 0);
|
|
293
|
+
AugValue result = { .tag = AUG_OBJECT, .as.object = object };
|
|
294
|
+
for (size_t i = 0; i < count; i++) aug_set_add(result, items[i]);
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
void aug_set_add(AugValue set, AugValue item) {
|
|
299
|
+
AugObject *object = expect_set(set);
|
|
300
|
+
if (object->frozen) fail("cannot mutate a frozen Set");
|
|
301
|
+
uint64_t hash = hash_value(item); size_t bucket = 0;
|
|
302
|
+
if (object->bucket_count) {
|
|
303
|
+
bucket = bucket_for_hash(object, item, hash);
|
|
304
|
+
if (object->buckets[bucket]) return;
|
|
305
|
+
}
|
|
306
|
+
if (grow_table(object, 1)) bucket = bucket_for_hash(object, item, hash);
|
|
307
|
+
object->buckets[bucket] = object->field_count + 1;
|
|
308
|
+
object->fields[object->field_count++] = item;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
bool aug_set_contains(AugValue set, AugValue item) {
|
|
312
|
+
AugObject *object = expect_set(set);
|
|
313
|
+
return object->bucket_count && object->buckets[bucket_for(object, item)] != 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
int64_t aug_set_length(AugValue set) { return (int64_t)expect_set(set)->field_count; }
|
|
317
|
+
|
|
318
|
+
AugValue aug_iter_snapshot(AugValue collection) {
|
|
319
|
+
AugObject *object = collection.as.object;
|
|
320
|
+
bool map = object->kind == AUG_MAP_KIND;
|
|
321
|
+
size_t count = map ? object->field_count / 2 : object->field_count;
|
|
322
|
+
AugValue result = aug_list_new(NULL, 0);
|
|
323
|
+
AugFrame frame; aug_frame_enter(&frame, &result, 1);
|
|
324
|
+
for (size_t index = 0; index < count; index++) {
|
|
325
|
+
AugValue item = map ? aug_tuple_new(&object->fields[index * 2], 2) : object->fields[index];
|
|
326
|
+
aug_list_append(result, item);
|
|
327
|
+
}
|
|
328
|
+
aug_frame_leave(&frame);
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Destructured Map loops need a snapshot of fields, not one heap Tuple per
|
|
333
|
+
entry. The copy preserves insertion order and isolates subsequent writes. */
|
|
334
|
+
AugValue aug_map_entries_snapshot(AugValue map) {
|
|
335
|
+
AugObject *object = expect_map(map);
|
|
336
|
+
AugFrame frame; aug_frame_enter(&frame, &map, 1);
|
|
337
|
+
AugValue result = aug_list_new(object->fields, object->field_count);
|
|
338
|
+
aug_frame_leave(&frame); return result;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
void aug_set_cli_args(int argc, char **argv) {
|
|
342
|
+
AugValue values[1] = { aug_null() };
|
|
343
|
+
cli_args = aug_list_new(values, 0);
|
|
344
|
+
for (int i = 1; i < argc; i++) {
|
|
345
|
+
AugValue arg = aug_string(argv[i]);
|
|
346
|
+
aug_list_append(cli_args, arg);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
AugValue aug_arguments(void) { return cli_args; }
|
|
351
|
+
|
|
352
|
+
static AugValue file_error(void) {
|
|
353
|
+
AugValue error = aug_new_object("FileError", 0, NULL, NULL, 0);
|
|
354
|
+
aug_throw(error);
|
|
355
|
+
return aug_null();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
static bool valid_text(const unsigned char *text, size_t size) {
|
|
359
|
+
for (size_t i = 0; i < size;) {
|
|
360
|
+
unsigned char first = text[i++];
|
|
361
|
+
if (!first) return false;
|
|
362
|
+
if (first < 0x80) continue;
|
|
363
|
+
int extra = first >= 0xc2 && first <= 0xdf ? 1 : first >= 0xe0 && first <= 0xef ? 2 : first >= 0xf0 && first <= 0xf4 ? 3 : -1;
|
|
364
|
+
if (extra < 0 || i + (size_t)extra > size) return false;
|
|
365
|
+
uint32_t code = first & (extra == 1 ? 0x1f : extra == 2 ? 0x0f : 0x07);
|
|
366
|
+
for (int j = 0; j < extra; j++) { unsigned char next = text[i++]; if ((next & 0xc0) != 0x80) return false; code = (code << 6) | (next & 0x3f); }
|
|
367
|
+
if (code < (extra == 1 ? 0x80u : extra == 2 ? 0x800u : 0x10000u) || code > 0x10ffff || (code >= 0xd800 && code <= 0xdfff)) return false;
|
|
368
|
+
}
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
AugValue aug_read_file(AugValue path) {
|
|
373
|
+
FILE *file = fopen(aug_cstring(path), "rb");
|
|
374
|
+
if (!file) return file_error();
|
|
375
|
+
if (fseek(file, 0, SEEK_END) != 0) { fclose(file); return file_error(); }
|
|
376
|
+
long length = ftell(file);
|
|
377
|
+
if (length < 0 || fseek(file, 0, SEEK_SET) != 0) { fclose(file); return file_error(); }
|
|
378
|
+
char *contents = malloc((size_t)length + 1);
|
|
379
|
+
if (!contents) fail("out of memory");
|
|
380
|
+
size_t count = fread(contents, 1, (size_t)length, file);
|
|
381
|
+
bool failed = ferror(file) || count != (size_t)length;
|
|
382
|
+
if (fclose(file) != 0) failed = true;
|
|
383
|
+
if (failed || !valid_text((const unsigned char *)contents, count)) { free(contents); return file_error(); }
|
|
384
|
+
contents[count] = '\0';
|
|
385
|
+
AugValue value = aug_string(contents);
|
|
386
|
+
free(contents);
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
AugValue aug_write_file(AugValue path, AugValue content) {
|
|
391
|
+
FILE *file = fopen(aug_cstring(path), "wb");
|
|
392
|
+
if (!file) return file_error();
|
|
393
|
+
const char *text = aug_cstring(content);
|
|
394
|
+
size_t length = strlen(text);
|
|
395
|
+
bool failed = fwrite(text, 1, length, file) != length;
|
|
396
|
+
if (fclose(file) != 0) failed = true;
|
|
397
|
+
return failed ? file_error() : aug_null();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
AugValue aug_field(AugValue object, size_t index) {
|
|
401
|
+
if (object.tag != AUG_OBJECT || !object.as.object || index >= object.as.object->field_count)
|
|
402
|
+
fail("invalid field access");
|
|
403
|
+
if (object.as.object->dropped) fail("use of dropped object");
|
|
404
|
+
return object.as.object->fields[index];
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
void aug_set_field(AugValue object, size_t index, AugValue value) {
|
|
408
|
+
if (object.tag != AUG_OBJECT || !object.as.object || index >= object.as.object->field_count)
|
|
409
|
+
fail("invalid field assignment");
|
|
410
|
+
if (object.as.object->dropped) fail("use of dropped object");
|
|
411
|
+
if (object.as.object->frozen) fail("cannot assign a frozen field");
|
|
412
|
+
object.as.object->fields[index] = value;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
AugValue aug_call_method(AugValue object, const char *name, AugValue *args, int count) {
|
|
416
|
+
if (object.tag != AUG_OBJECT || !object.as.object) fail("method call on non-object");
|
|
417
|
+
if (object.as.object->dropped) fail("use of dropped object");
|
|
418
|
+
for (size_t i = 0; i < object.as.object->method_count; i++) {
|
|
419
|
+
const AugMethodEntry *entry = &object.as.object->methods[i];
|
|
420
|
+
if (strcmp(entry->name, name) == 0) return entry->function(object, args, count);
|
|
421
|
+
}
|
|
422
|
+
fprintf(stderr, "AugScript runtime error: %s has no method %s\n",
|
|
423
|
+
object.as.object->type_name, name);
|
|
424
|
+
exit(1);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const char *aug_cstring(AugValue value) {
|
|
428
|
+
if (value.tag != AUG_STRING || !value.as.object) fail("expected string");
|
|
429
|
+
return value.as.object->text;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
int64_t aug_cint(AugValue value) {
|
|
433
|
+
if (value.tag != AUG_INT) fail("expected int");
|
|
434
|
+
return value.as.integer;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
AugValue aug_to_c_int(AugValue value) {
|
|
438
|
+
_Static_assert(sizeof(int) == 4 && INT_MAX == INT32_MAX, "AugScript c_int requires a signed 32-bit C int");
|
|
439
|
+
int64_t number = aug_cint(value);
|
|
440
|
+
if (number < INT32_MIN || number > INT32_MAX) {
|
|
441
|
+
return checked_error("ConversionError");
|
|
442
|
+
}
|
|
443
|
+
return value;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
typedef struct AugCoverage { const char *file; size_t line, count; struct AugCoverage *next; } AugCoverage;
|
|
447
|
+
static AugCoverage *coverage = NULL;
|
|
448
|
+
void aug_coverage_register(const char *file, size_t line) {
|
|
449
|
+
for (AugCoverage *point = coverage; point; point = point->next)
|
|
450
|
+
if (point->line == line && !strcmp(point->file, file)) return;
|
|
451
|
+
AugCoverage *point = malloc(sizeof(*point));
|
|
452
|
+
if (!point) fail("out of memory");
|
|
453
|
+
*point = (AugCoverage){ file, line, 0, coverage }; coverage = point;
|
|
454
|
+
}
|
|
455
|
+
void aug_cover(const char *file, size_t line) {
|
|
456
|
+
for (AugCoverage *point = coverage; point; point = point->next)
|
|
457
|
+
if (point->line == line && !strcmp(point->file, file)) { point->count++; return; }
|
|
458
|
+
}
|
|
459
|
+
static void write_coverage(void) {
|
|
460
|
+
const char *path = getenv("AUG_COVERAGE_FILE");
|
|
461
|
+
FILE *output = path && coverage ? fopen(path, "w") : NULL;
|
|
462
|
+
while (coverage) {
|
|
463
|
+
AugCoverage *point = coverage; coverage = point->next;
|
|
464
|
+
if (output) fprintf(output, "%s\t%zu\t%zu\n", point->file, point->line, point->count);
|
|
465
|
+
free(point);
|
|
466
|
+
}
|
|
467
|
+
if (output) fclose(output);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
double aug_cfloat(AugValue value) {
|
|
471
|
+
if (value.tag == AUG_FLOAT) return value.as.floating;
|
|
472
|
+
if (value.tag == AUG_INT) return (double)value.as.integer;
|
|
473
|
+
fail("expected number");
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
bool aug_truthy(AugValue value) {
|
|
478
|
+
if (value.tag != AUG_BOOL) fail("expected bool");
|
|
479
|
+
return value.as.boolean;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
static bool equal(AugValue left, AugValue right) {
|
|
483
|
+
if ((left.tag == AUG_INT && right.tag == AUG_FLOAT) || (left.tag == AUG_FLOAT && right.tag == AUG_INT))
|
|
484
|
+
return aug_cfloat(left) == aug_cfloat(right);
|
|
485
|
+
if (left.tag != right.tag) return false;
|
|
486
|
+
switch (left.tag) {
|
|
487
|
+
case AUG_NULL: return true;
|
|
488
|
+
case AUG_INT: return left.as.integer == right.as.integer;
|
|
489
|
+
case AUG_FLOAT: return left.as.floating == right.as.floating;
|
|
490
|
+
case AUG_BOOL: return left.as.boolean == right.as.boolean;
|
|
491
|
+
case AUG_STRING: return left.as.object->text_length == right.as.object->text_length &&
|
|
492
|
+
memcmp(left.as.object->text, right.as.object->text, left.as.object->text_length) == 0;
|
|
493
|
+
default:
|
|
494
|
+
if ((left.as.object->kind == AUG_TUPLE_KIND && right.as.object->kind == AUG_TUPLE_KIND) ||
|
|
495
|
+
(left.as.object->kind == AUG_RECORD_KIND && right.as.object->kind == AUG_RECORD_KIND && !strcmp(left.as.object->type_name, right.as.object->type_name))) {
|
|
496
|
+
if (left.as.object->field_count != right.as.object->field_count) return false;
|
|
497
|
+
for (size_t i = 0; i < left.as.object->field_count; i++)
|
|
498
|
+
if (!equal(left.as.object->fields[i], right.as.object->fields[i])) return false;
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
return left.as.object == right.as.object;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
AugValue aug_binary(const char *op, AugValue left, AugValue right) {
|
|
506
|
+
if (!strcmp(op, "==")) return aug_bool(equal(left, right));
|
|
507
|
+
if (!strcmp(op, "!=")) return aug_bool(!equal(left, right));
|
|
508
|
+
if (!strcmp(op, "&&")) return aug_bool(aug_truthy(left) && aug_truthy(right));
|
|
509
|
+
if (!strcmp(op, "||")) return aug_bool(aug_truthy(left) || aug_truthy(right));
|
|
510
|
+
if (!strcmp(op, "+") && left.tag == AUG_STRING && right.tag == AUG_STRING) {
|
|
511
|
+
const char *a = aug_cstring(left), *b = aug_cstring(right);
|
|
512
|
+
size_t first_length = left.as.object->text_length, length = first_length + right.as.object->text_length;
|
|
513
|
+
char *joined = malloc(length + 1);
|
|
514
|
+
if (!joined) fail("out of memory");
|
|
515
|
+
memcpy(joined, a, first_length);
|
|
516
|
+
memcpy(joined + first_length, b, right.as.object->text_length);
|
|
517
|
+
AugValue result = aug_string_n(joined, length);
|
|
518
|
+
free(joined);
|
|
519
|
+
return result;
|
|
520
|
+
}
|
|
521
|
+
if ((left.tag != AUG_INT && left.tag != AUG_FLOAT) ||
|
|
522
|
+
(right.tag != AUG_INT && right.tag != AUG_FLOAT)) fail("invalid binary operands");
|
|
523
|
+
double a = aug_cfloat(left), b = aug_cfloat(right);
|
|
524
|
+
if (left.tag == AUG_INT && right.tag == AUG_INT) {
|
|
525
|
+
int64_t x = left.as.integer, y = right.as.integer;
|
|
526
|
+
if (!strcmp(op, "<")) return aug_bool(x < y);
|
|
527
|
+
if (!strcmp(op, ">")) return aug_bool(x > y);
|
|
528
|
+
if (!strcmp(op, "<=")) return aug_bool(x <= y);
|
|
529
|
+
if (!strcmp(op, ">=")) return aug_bool(x >= y);
|
|
530
|
+
}
|
|
531
|
+
if (!strcmp(op, "<")) return aug_bool(a < b);
|
|
532
|
+
if (!strcmp(op, ">")) return aug_bool(a > b);
|
|
533
|
+
if (!strcmp(op, "<=")) return aug_bool(a <= b);
|
|
534
|
+
if (!strcmp(op, ">=")) return aug_bool(a >= b);
|
|
535
|
+
if (!strcmp(op, "/") && b == 0) return checked_error("ArithmeticError");
|
|
536
|
+
if (left.tag == AUG_INT && right.tag == AUG_INT) {
|
|
537
|
+
int64_t x = left.as.integer, y = right.as.integer;
|
|
538
|
+
if (!strcmp(op, "<")) return aug_bool(x < y);
|
|
539
|
+
if (!strcmp(op, ">")) return aug_bool(x > y);
|
|
540
|
+
if (!strcmp(op, "<=")) return aug_bool(x <= y);
|
|
541
|
+
if (!strcmp(op, ">=")) return aug_bool(x >= y);
|
|
542
|
+
if (!strcmp(op, "+")) return aug_int(signed_bits((uint64_t)x + (uint64_t)y));
|
|
543
|
+
if (!strcmp(op, "-")) return aug_int(signed_bits((uint64_t)x - (uint64_t)y));
|
|
544
|
+
if (!strcmp(op, "*")) return aug_int(signed_bits((uint64_t)x * (uint64_t)y));
|
|
545
|
+
if (!strcmp(op, "/")) return aug_int(x == INT64_MIN && y == -1 ? INT64_MIN : x / y);
|
|
546
|
+
}
|
|
547
|
+
if (!strcmp(op, "+")) return aug_float(a + b);
|
|
548
|
+
if (!strcmp(op, "-")) return aug_float(a - b);
|
|
549
|
+
if (!strcmp(op, "*")) return aug_float(a * b);
|
|
550
|
+
if (!strcmp(op, "/")) return aug_float(a / b);
|
|
551
|
+
fail("unknown binary operator");
|
|
552
|
+
return aug_null();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
AugValue aug_unary(const char *op, AugValue value) {
|
|
556
|
+
if (!strcmp(op, "!")) return aug_bool(!aug_truthy(value));
|
|
557
|
+
if (!strcmp(op, "-") && value.tag == AUG_INT) return aug_int(signed_bits(UINT64_C(0) - (uint64_t)value.as.integer));
|
|
558
|
+
if (!strcmp(op, "-") && value.tag == AUG_FLOAT) return aug_float(-value.as.floating);
|
|
559
|
+
fail("invalid unary operand");
|
|
560
|
+
return aug_null();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
void aug_print(AugValue value) {
|
|
564
|
+
switch (value.tag) {
|
|
565
|
+
case AUG_NULL: puts("null"); break;
|
|
566
|
+
case AUG_INT: printf("%lld\n", (long long)value.as.integer); break;
|
|
567
|
+
case AUG_FLOAT: printf("%g\n", value.as.floating); break;
|
|
568
|
+
case AUG_BOOL: puts(value.as.boolean ? "true" : "false"); break;
|
|
569
|
+
case AUG_STRING: fwrite(value.as.object->text, 1, value.as.object->text_length, stdout); putchar('\n'); break;
|
|
570
|
+
case AUG_OBJECT:
|
|
571
|
+
if (value.as.object->kind == AUG_HTML_KIND) {fwrite(value.as.object->text, 1, value.as.object->text_length, stdout); putchar('\n');}
|
|
572
|
+
else printf("<%s>\n", value.as.object->type_name); break;
|
|
573
|
+
default: fail("invalid value");
|
|
574
|
+
}
|
|
575
|
+
fflush(stdout);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
void aug_assert(AugValue condition, const char *expression, const char *file, int line) {
|
|
579
|
+
aug_test_assertions++;
|
|
580
|
+
if (aug_truthy(condition)) return;
|
|
581
|
+
aug_test_failed = true;
|
|
582
|
+
fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, expression);
|
|
583
|
+
aug_throw(aug_new_object("AssertionError", 0, NULL, NULL, 0));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
void aug_frame_enter(AugFrame *frame, AugValue *slots, size_t count) {
|
|
587
|
+
frame->slots = slots;
|
|
588
|
+
frame->count = count;
|
|
589
|
+
frame->previous = frames;
|
|
590
|
+
frames = frame;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
void aug_frame_leave(AugFrame *frame) {
|
|
594
|
+
if (frames != frame) fail("invalid root frame");
|
|
595
|
+
frames = frame->previous;
|
|
596
|
+
}
|
|
597
|
+
void aug_retain(AugRetained *root, AugValue *values, size_t count) {
|
|
598
|
+
root->values = values; root->count = count; root->next = retained; retained = root;
|
|
599
|
+
}
|
|
600
|
+
void aug_release(AugRetained *root) {
|
|
601
|
+
AugRetained **cursor = &retained; while (*cursor && *cursor != root) cursor = &(*cursor)->next;
|
|
602
|
+
if (*cursor) *cursor = root->next;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
void aug_register_globals(AugValue *values, size_t count) {
|
|
606
|
+
globals = values;
|
|
607
|
+
global_count = count;
|
|
608
|
+
}
|
|
609
|
+
AugValue aug_binding_get(size_t index) {
|
|
610
|
+
return scopes && scopes->mask[index] ? scopes->values[index] : globals[index];
|
|
611
|
+
}
|
|
612
|
+
void aug_binding_set(size_t index, AugValue value) {
|
|
613
|
+
if (scopes && scopes->mask[index]) scopes->values[index] = value; else globals[index] = value;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
size_t aug_scope_depth(void) { return scope_count; }
|
|
617
|
+
typedef struct AugHeldLock {struct AugHeldLock *previous; pthread_mutex_t *mutex; AugValue value;} AugHeldLock;
|
|
618
|
+
void (*aug_mutex_wait_hook)(void);
|
|
619
|
+
static void destroy_mutex(void *native) {pthread_mutex_destroy(native); free(native);}
|
|
620
|
+
static const unsigned char shared_owned_field[] = {1};
|
|
621
|
+
AugValue aug_shared_new(AugValue value) {
|
|
622
|
+
AugFrame frame; aug_frame_enter(&frame, &value, 1);
|
|
623
|
+
AugValue result = aug_new_object("Shared", 1, shared_owned_field, NULL, 0);
|
|
624
|
+
pthread_mutex_t *mutex = malloc(sizeof(*mutex)); if (!mutex || pthread_mutex_init(mutex, NULL)) fail("cannot initialize shared state");
|
|
625
|
+
result.as.object->native = mutex; result.as.object->finalize = destroy_mutex; aug_set_field(result, 0, value);
|
|
626
|
+
aug_frame_leave(&frame); return result;
|
|
627
|
+
}
|
|
628
|
+
size_t aug_lock_depth(void) {return current_execution->lock_depth;}
|
|
629
|
+
AugValue aug_shared_lock(AugValue value) {
|
|
630
|
+
pthread_mutex_t *mutex = value.as.object->native; int status;
|
|
631
|
+
while ((status = pthread_mutex_trylock(mutex)) == EBUSY && !aug_cancelled) {
|
|
632
|
+
if (aug_mutex_wait_hook) aug_mutex_wait_hook(); else {status = pthread_mutex_lock(mutex); break;}
|
|
633
|
+
}
|
|
634
|
+
if (aug_cancelled) return aug_null(); if (status) fail("cannot lock shared state");
|
|
635
|
+
AugHeldLock *lock = malloc(sizeof(*lock)); if (!lock) fail("out of memory");
|
|
636
|
+
*lock = (AugHeldLock){current_execution->held_locks, mutex, value};
|
|
637
|
+
current_execution->held_locks = lock; current_execution->lock_depth++; return aug_field(value, 0);
|
|
638
|
+
}
|
|
639
|
+
void aug_lock_leave(void) {
|
|
640
|
+
AugHeldLock *lock = current_execution->held_locks; if (!lock) fail("invalid lock release");
|
|
641
|
+
current_execution->held_locks = lock->previous; current_execution->lock_depth--; pthread_mutex_unlock(lock->mutex); free(lock);
|
|
642
|
+
}
|
|
643
|
+
void aug_lock_restore(size_t depth) {while (aug_lock_depth() > depth) aug_lock_leave();}
|
|
644
|
+
void aug_scope_enter(const unsigned char *mask) {
|
|
645
|
+
AugScope *scope = calloc(1, sizeof(AugScope));
|
|
646
|
+
if (!scope) fail("out of memory");
|
|
647
|
+
scope->values = calloc(global_count ? global_count : 1, sizeof(AugValue));
|
|
648
|
+
if (!scope->values) fail("out of memory");
|
|
649
|
+
scope->mask = mask; scope->previous = scopes;
|
|
650
|
+
scopes = scope; scope_count++;
|
|
651
|
+
}
|
|
652
|
+
void aug_scope_leave(void) {
|
|
653
|
+
if (!scopes) fail("invalid composition scope");
|
|
654
|
+
AugScope *scope = scopes;
|
|
655
|
+
if (aug_scope_join_hook) aug_scope_join_hook(scope);
|
|
656
|
+
scopes = scope->previous; scope_count--;
|
|
657
|
+
free(scope->values); free(scope);
|
|
658
|
+
}
|
|
659
|
+
/* Join borrowers while the scope's injected resources are still available. */
|
|
660
|
+
void aug_scope_join_to(size_t depth) {
|
|
661
|
+
AugScope *scope = scopes;
|
|
662
|
+
for (size_t count = scope_count; count > depth && scope; count--, scope = scope->previous)
|
|
663
|
+
if (aug_scope_join_hook) aug_scope_join_hook(scope);
|
|
664
|
+
}
|
|
665
|
+
void aug_scope_restore(size_t depth) { while (scope_count > depth) aug_scope_leave(); }
|
|
666
|
+
|
|
667
|
+
static void mark(AugValue value) {
|
|
668
|
+
if (value.tag != AUG_STRING && value.tag != AUG_OBJECT) return;
|
|
669
|
+
AugObject *object = value.as.object;
|
|
670
|
+
if (!object || object->marked) return;
|
|
671
|
+
object->marked = true;
|
|
672
|
+
for (size_t i = 0; i < object->field_count; i++) mark(object->fields[i]);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
void aug_freeze(AugValue value) {
|
|
676
|
+
if ((value.tag != AUG_OBJECT && value.tag != AUG_STRING) || value.as.object->frozen) return;
|
|
677
|
+
size_t count = 0, capacity = 16;
|
|
678
|
+
AugObject **pending = malloc(capacity * sizeof(*pending)); if (!pending) fail("out of memory");
|
|
679
|
+
value.as.object->frozen = true; pending[count++] = value.as.object;
|
|
680
|
+
while (count) {
|
|
681
|
+
AugObject *object = pending[--count];
|
|
682
|
+
for (size_t i = 0; i < object->field_count; i++) {
|
|
683
|
+
AugValue field = object->fields[i];
|
|
684
|
+
if ((field.tag != AUG_OBJECT && field.tag != AUG_STRING) || field.as.object->frozen) continue;
|
|
685
|
+
field.as.object->frozen = true;
|
|
686
|
+
if (count == capacity) { capacity *= 2; pending = realloc(pending, capacity * sizeof(*pending)); if (!pending) fail("out of memory"); }
|
|
687
|
+
pending[count++] = field.as.object;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
free(pending);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
static void mark_execution_roots(void) {
|
|
694
|
+
for (AugRetained *root = retained; root; root = root->next) for (size_t i = 0; i < root->count; i++) mark(root->values[i]);
|
|
695
|
+
for (size_t i = 0; i < global_count; i++) mark(globals[i]);
|
|
696
|
+
for (AugExecution *execution = executions; execution; execution = execution->next) {
|
|
697
|
+
for (AugHeldLock *lock = execution->held_locks; lock; lock = lock->previous) mark(lock->value);
|
|
698
|
+
for (AugScope *scope = execution->scope_stack; scope; scope = scope->previous)
|
|
699
|
+
for (size_t i = 0; i < global_count; i++) mark(scope->values[i]);
|
|
700
|
+
if (execution->has_error) mark(execution->error);
|
|
701
|
+
for (AugFrame *frame = execution->root_frames; frame; frame = frame->previous)
|
|
702
|
+
for (size_t i = 0; i < frame->count; i++) mark(frame->slots[i]);
|
|
703
|
+
}
|
|
704
|
+
mark(cli_args);
|
|
705
|
+
if (aug_has_error) mark(aug_error);
|
|
706
|
+
for (AugFrame *frame = frames; frame; frame = frame->previous)
|
|
707
|
+
for (size_t i = 0; i < frame->count; i++) mark(frame->slots[i]);
|
|
708
|
+
}
|
|
709
|
+
void aug_collect(void) {
|
|
710
|
+
if (collecting) return;
|
|
711
|
+
collecting = true;
|
|
712
|
+
mark_execution_roots();
|
|
713
|
+
for (AugObject *object = heap; object; object = object->next) {
|
|
714
|
+
if (!object->marked && object->kind == AUG_OBJECT && !object->dropped)
|
|
715
|
+
aug_drop((AugValue){ .tag = AUG_OBJECT, .as.object = object });
|
|
716
|
+
}
|
|
717
|
+
// Cleanup may change an existing root or allocate values. Trace every suspended
|
|
718
|
+
// execution again, including fields of objects marked by the first pass.
|
|
719
|
+
for (AugObject *object = heap; object; object = object->next) object->marked = false;
|
|
720
|
+
mark_execution_roots();
|
|
721
|
+
// Objects created by cleanup receive their own cleanup opportunity next cycle.
|
|
722
|
+
for (AugObject *object = heap; object; object = object->next)
|
|
723
|
+
if (!object->marked && object->kind == AUG_OBJECT && !object->dropped)
|
|
724
|
+
mark((AugValue){.tag=AUG_OBJECT, .as.object=object});
|
|
725
|
+
AugObject **cursor = &heap;
|
|
726
|
+
while (*cursor) {
|
|
727
|
+
AugObject *object = *cursor;
|
|
728
|
+
if (object->marked) { object->marked = false; cursor = &object->next; }
|
|
729
|
+
else {
|
|
730
|
+
*cursor = object->next;
|
|
731
|
+
if (object->kind == AUG_PRIVATE_KEY_KIND && object->text) {
|
|
732
|
+
volatile unsigned char *secret = (volatile unsigned char *)object->text;
|
|
733
|
+
for (size_t i = 0; i < object->text_length; i++) secret[i] = 0;
|
|
734
|
+
}
|
|
735
|
+
if (object->finalize) object->finalize(object->native);
|
|
736
|
+
free(object->text);
|
|
737
|
+
free(object->fields);
|
|
738
|
+
free(object->buckets);
|
|
739
|
+
free(object);
|
|
740
|
+
object_count--;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
next_collection = object_count * 2 + 1024;
|
|
744
|
+
collecting = false;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
void aug_drop(AugValue value) {
|
|
748
|
+
if (value.tag != AUG_OBJECT && value.tag != AUG_STRING) return;
|
|
749
|
+
AugObject *object = value.as.object;
|
|
750
|
+
if (!object || object->dropped) return;
|
|
751
|
+
if (object->kind == AUG_OBJECT) {
|
|
752
|
+
if (getenv("AUG_TRACE_DROPS")) fprintf(stderr, "drop: %s\n", object->type_name);
|
|
753
|
+
for (size_t i = 0; i < object->method_count; i++)
|
|
754
|
+
if (strcmp(object->methods[i].name, "drop") == 0) {
|
|
755
|
+
object->methods[i].function(value, NULL, 0);
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
object->dropped = true;
|
|
760
|
+
for (size_t i = 0; i < object->field_count; i++)
|
|
761
|
+
if (object->owned_fields && object->owned_fields[i]) aug_drop(object->fields[i]);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
void aug_throw(AugValue value) { aug_error = value; aug_has_error = true; }
|
|
765
|
+
AugValue aug_take_error(void) {
|
|
766
|
+
AugValue value = aug_error;
|
|
767
|
+
aug_error = aug_null();
|
|
768
|
+
aug_has_error = false;
|
|
769
|
+
return value;
|
|
770
|
+
}
|
|
771
|
+
bool aug_error_is(const char *name) {
|
|
772
|
+
if (!aug_has_error) return false;
|
|
773
|
+
if (!strcmp(name, "Error")) return true;
|
|
774
|
+
return aug_error.tag == AUG_OBJECT &&
|
|
775
|
+
!strcmp(aug_error.as.object->type_name, name);
|
|
776
|
+
}
|
|
777
|
+
void aug_report_error(void) {
|
|
778
|
+
if (!aug_has_error) return;
|
|
779
|
+
if (aug_error.tag == AUG_OBJECT) fprintf(stderr, "Uncaught %s\n", aug_error.as.object->type_name);
|
|
780
|
+
else fprintf(stderr, "Uncaught error\n");
|
|
781
|
+
}
|
|
782
|
+
void aug_shutdown(void) {
|
|
783
|
+
write_coverage();
|
|
784
|
+
aug_scope_restore(0);
|
|
785
|
+
globals = NULL;
|
|
786
|
+
global_count = 0;
|
|
787
|
+
cli_args = aug_null();
|
|
788
|
+
frames = NULL;
|
|
789
|
+
aug_error = aug_null();
|
|
790
|
+
aug_has_error = false;
|
|
791
|
+
aug_collect();
|
|
792
|
+
}
|