diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 0000000..fc4b057 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: MPL-2.0 +# ClusterFuzzLite build image for betlang. +# +# ClusterFuzzLite invokes `docker build -f .clusterfuzzlite/Dockerfile`, +# so this file must be named `Dockerfile`. It mirrors the OCI-neutral +# Containerfile in this directory (kept for podman-first local builds per +# the authority stack); keep the two in sync. +FROM gcr.io/oss-fuzz-base/base-builder-rust +RUN apt-get update && apt-get install -y make autoconf automake libtool +COPY . $SRC/betlang +WORKDIR $SRC/betlang +COPY .clusterfuzzlite/build.sh $SRC/ diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index ca42f96..d6dd9d9 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -20,6 +20,7 @@ permissions: read-all jobs: audit: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 @@ -35,6 +36,7 @@ jobs: # Optional: Create issues for vulnerabilities create-issue: runs-on: ubuntu-latest + timeout-minutes: 30 needs: audit if: failure() permissions: diff --git a/.github/workflows/casket-pages.yml b/.github/workflows/casket-pages.yml index 5f185d3..facf911 100644 --- a/.github/workflows/casket-pages.yml +++ b/.github/workflows/casket-pages.yml @@ -18,6 +18,7 @@ concurrency: jobs: build: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 @@ -91,6 +92,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest + timeout-minutes: 30 needs: build steps: - name: Deploy to GitHub Pages diff --git a/.github/workflows/cflite_batch.yml b/.github/workflows/cflite_batch.yml index 607ab6f..a48f4df 100644 --- a/.github/workflows/cflite_batch.yml +++ b/.github/workflows/cflite_batch.yml @@ -7,6 +7,7 @@ permissions: read-all jobs: fuzz: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1 diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml index f35994e..33002dd 100644 --- a/.github/workflows/cflite_pr.yml +++ b/.github/workflows/cflite_pr.yml @@ -10,6 +10,7 @@ permissions: read-all jobs: fuzz: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8f37f26..3ea2c75 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -22,6 +22,7 @@ permissions: read-all jobs: analyze: runs-on: ubuntu-latest + timeout-minutes: 30 permissions: contents: read security-events: write diff --git a/.github/workflows/comprehensive-quality.yml b/.github/workflows/comprehensive-quality.yml index 7ac536b..7804b45 100644 --- a/.github/workflows/comprehensive-quality.yml +++ b/.github/workflows/comprehensive-quality.yml @@ -15,6 +15,7 @@ jobs: # DEPENDABILITY - Stability and reliability dependability: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check test coverage @@ -34,6 +35,7 @@ jobs: # SECURITY - Multi-layer security scanning security: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Secret scanning @@ -54,6 +56,7 @@ jobs: # INTEROPERABILITY - API and format compatibility interoperability: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check API specs @@ -71,6 +74,7 @@ jobs: # VALIDATION - Input/output validation validation: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check for validation patterns @@ -81,6 +85,7 @@ jobs: # ATTESTATION - Supply chain integrity (SLSA) attestation: runs-on: ubuntu-latest + timeout-minutes: 30 permissions: id-token: write contents: read @@ -101,6 +106,7 @@ jobs: # VERIFICATION - Formal methods where applicable verification: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check SPARK proofs @@ -117,6 +123,7 @@ jobs: # FUNCTIONALITY - Feature completeness functionality: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check TODOs and FIXMEs @@ -130,6 +137,7 @@ jobs: # PERFORMANCE - Benchmarks and profiling performance: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check for benchmarks @@ -146,6 +154,7 @@ jobs: # ACCESSIBILITY - A11y compliance accessibility: runs-on: ubuntu-latest + timeout-minutes: 30 if: hashFiles('**/*.html') != '' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 @@ -161,6 +170,7 @@ jobs: # LICENSE COMPLIANCE license: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check license files @@ -179,6 +189,7 @@ jobs: # DOCUMENTATION QUALITY documentation: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - name: Check docs completeness diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index f59a9ca..a9a0c18 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -26,6 +26,7 @@ jobs: # Build job build: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -45,6 +46,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest + timeout-minutes: 30 needs: build steps: - name: Deploy to GitHub Pages diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aef5cd5..3723a71 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,7 @@ env: jobs: build-linux: runs-on: ubuntu-latest + timeout-minutes: 30 strategy: matrix: target: @@ -57,6 +58,7 @@ jobs: build-macos: runs-on: macos-latest + timeout-minutes: 30 strategy: matrix: target: @@ -88,6 +90,7 @@ jobs: build-windows: runs-on: windows-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 @@ -113,6 +116,7 @@ jobs: build-lsp: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 @@ -138,6 +142,7 @@ jobs: release: needs: [build-linux, build-macos, build-windows, build-lsp] runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 diff --git a/.github/workflows/scorecard-enforcer.yml b/.github/workflows/scorecard-enforcer.yml index 5519b4d..cbae4a8 100644 --- a/.github/workflows/scorecard-enforcer.yml +++ b/.github/workflows/scorecard-enforcer.yml @@ -22,6 +22,7 @@ permissions: read-all jobs: scorecard: runs-on: ubuntu-latest + timeout-minutes: 30 permissions: security-events: write id-token: write # For OIDC @@ -60,6 +61,7 @@ jobs: # Check specific high-priority items check-critical: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd0afdd..c0800c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,6 +13,7 @@ jobs: test: name: Test on Racket ${{ matrix.racket-version }} runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: fail-fast: false @@ -28,7 +29,9 @@ jobs: uses: Bogdanp/setup-racket@2466913449df77df2bad149d1f2fc4e1ea4795dd # v1.15 with: version: ${{ matrix.racket-version }} - packages: 'rackunit' + # rackunit ships with the full Racket distribution (already present + # at installation scope); re-requesting it at user scope errors with + # "package is currently installed in a wider scope". - name: Run core tests run: racket tests/basics.rkt @@ -69,6 +72,7 @@ jobs: lint: name: Code Quality runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout code @@ -98,6 +102,7 @@ jobs: docs: name: Documentation Check runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout code @@ -125,6 +130,7 @@ jobs: rsr-compliance: name: RSR Framework Compliance runs-on: ubuntu-latest + timeout-minutes: 30 steps: - name: Checkout code diff --git a/.github/workflows/workflow-linter.yml b/.github/workflows/workflow-linter.yml index 02b2e76..a8bf960 100644 --- a/.github/workflows/workflow-linter.yml +++ b/.github/workflows/workflow-linter.yml @@ -15,6 +15,7 @@ permissions: read-all jobs: lint-workflows: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 diff --git a/.governance-allowlist b/.governance-allowlist new file mode 100644 index 0000000..1a2f60d --- /dev/null +++ b/.governance-allowlist @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: MPL-2.0 +# +# .governance-allowlist — Layer 2.5 typed-infrastructure file enumerating +# per-repo TypeScript exemptions for the standards-repo governance scanner +# (check-ts-allowlist.deno.js). Sibling to the Layer 2 prose table in +# .claude/CLAUDE.md (TypeScript Exemptions section), which already approves +# the `playground/**` sandbox (see playground/README.adoc). +# +# Why this file exists *in addition to* the CLAUDE.md table: +# the upstream scanner's `globToRegex` keeps the glob's relative form +# (no `./` prefix) while its recursive walk of "." yields paths *with* the +# `./` prefix (e.g. `./playground/src/ternary.ts`). A glob like +# `playground/**` therefore compiles to a regex that fails to anchor +# against `./playground/...`, so the CLAUDE.md row exempts zero files in +# practice and the scanner reports "1 exemption parsed" yet still flags the +# files. The lead-`*` wildcard below sidesteps that (it matches any run, +# including `/` and the `./` prefix) until the scanner itself is fixed +# upstream. +# +# Each non-blank, non-`#` line is a glob; `*` matches any run including `/`. +# This single pattern covers all six approved playground .ts files: +# playground/src/{probability,ternary,main}.ts +# playground/test/{ternary_test,probability_test}.ts +# playground/examples/uncertainty.ts +*playground/*.ts diff --git a/.hypatia-ignore b/.hypatia-ignore new file mode 100644 index 0000000..f16828e --- /dev/null +++ b/.hypatia-ignore @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: MPL-2.0 +# +# .hypatia-ignore — repo-scoped exemptions for the estate governance +# bundle's anti-pattern / Hypatia scanner. Format (per the bundle's +# `is_exempt`): each non-comment line is `${rule}:${path}`, matched as a +# fixed-string whole-line equality. Comment (`#`) and blank lines are +# tolerated. +# +# ─── Playground TypeScript sandbox ────────────────────────────────── +# +# The `playground/` directory is an intentional experimental sandbox, +# decoupled from the Racket core, in which TypeScript is one of several +# languages explored (see playground/README.adoc). This is an APPROVED +# carve-out, already documented in the TypeScript Exemptions table in +# .claude/CLAUDE.md, with the same unblock condition: migrate the sample +# to AffineScript or delete it once the experiment is settled. These +# entries implement that approved exemption for the Hypatia scanner. +cicd_rules/banned_language_file:playground/src/ternary.ts +cicd_rules/banned_language_file:playground/src/probability.ts +cicd_rules/banned_language_file:playground/src/main.ts +cicd_rules/banned_language_file:playground/test/ternary_test.ts +cicd_rules/banned_language_file:playground/test/probability_test.ts +cicd_rules/banned_language_file:playground/examples/uncertainty.ts diff --git a/Cargo.toml b/Cargo.toml index 3aeec5a..0755725 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ members = [ [workspace.package] version = "0.1.0" edition = "2021" -license = "MIT OR Apache-2.0" +license = "MPL-2.0" repository = "https://github.com/hyperpolymath/betlang" rust-version = "1.75" diff --git a/SPEC.core.scm.orig b/SPEC.core.scm.orig deleted file mode 100644 index 342cc35..0000000 --- a/SPEC.core.scm.orig +++ /dev/null @@ -1,151 +0,0 @@ -;; SPDX-FileCopyrightText: 2025 hyperpolymath -;; SPDX-License-Identifier: MPL-2.0 -;; -;; SPEC.core.scm - Formal Semantics Specification for betlang -;; -;; This file defines the authoritative semantics for the core betlang primitives. -;; The Racket interpreter in core/betlang.rkt is the reference implementation. -;; All implementations and backends MUST conform to these semantics. - -(define betlang-spec - '((version . "1.0.0") - (schema . "hyperpolymath.betlang.spec/1") - (status . "authoritative") - (reference-implementation . "core/betlang.rkt") - - ;;========================================================================= - ;; CORE PRIMITIVE: bet - ;;========================================================================= - (bet - . ((signature . "(bet A B C) -> A | B | C") - (description . "Randomly select one of three values with uniform probability") - - (formal-semantics - . ((denotation . "[[bet A B C]] : Value x Value x Value -> Dist(Value)") - (probability-model - . ((P-A . "1/3") - (P-B . "1/3") - (P-C . "1/3"))) - (entropy . "log2(3) = 1.585 bits"))) - - (evaluation-order . "strict") - (note . "All three arguments are evaluated before selection occurs") - - (algebraic-properties - . ((symmetry . "bet A B C ~ bet B C A ~ bet C A B (distributionally)") - (idempotence . "bet X X X = X (deterministic)") - (independence . "Successive bet calls are independent"))) - - (edge-cases - . ((identical-values . "bet X X X always returns X") - (thunk-arguments . "Thunks are NOT called; use bet/lazy for lazy evaluation"))))) - - ;;========================================================================= - ;; WEIGHTED VARIANT: bet/weighted - ;;========================================================================= - (bet/weighted - . ((signature . "(bet/weighted '(A w1) '(B w2) '(C w3)) -> A | B | C") - (description . "Randomly select one of three values with weights proportional to probabilities") - - (formal-semantics - . ((denotation . "[[bet/weighted (A w1) (B w2) (C w3)]] : (Value x Weight)^3 -> Dist(Value)") - (probability-model - . ((total-weight . "W = w1 + w2 + w3") - (P-A . "w1 / W") - (P-B . "w2 / W") - (P-C . "w3 / W"))) - (entropy . "H = -sum(pi * log2(pi)) where pi = wi/W"))) - - (constraints - . ((arity . "Exactly 3 weighted pairs required") - (weights . "Must be non-negative numbers; total > 0") - (format . "Each argument is a quoted pair '(value weight)"))) - - (error-conditions - . ((wrong-arity . "exn:fail if not exactly 3 arguments") - (zero-total . "undefined behavior if w1+w2+w3 = 0") - (negative-weight . "undefined behavior for negative weights"))) - - (examples - . (("(bet/weighted '(A 1) '(B 1) '(C 1))" . "Equivalent to (bet A B C)") - ("(bet/weighted '(rare 1) '(uncommon 3) '(common 6))" . "P(rare)=0.1, P(uncommon)=0.3, P(common)=0.6"))))) - - ;;========================================================================= - ;; CONDITIONAL VARIANT: bet/conditional - ;;========================================================================= - (bet/conditional - . ((signature . "(bet/conditional pred A B C) -> A | B | C | A") - (description . "Conditional bet: if pred is true return A, else bet between B C A") - - (formal-semantics - . ((denotation . "[[bet/conditional pred A B C]] : Bool x Value^3 -> Dist(Value)") - (semantics - . ((when-true . "pred = #t => return A deterministically") - (when-false . "pred = #f => return [[bet B C A]]"))) - (probability-model-when-false - . ((P-B . "1/3") - (P-C . "1/3") - (P-A . "1/3"))))) - - (evaluation-order . "pred evaluated first; then A B C if needed") - - (note . "The false-branch includes A in the bet, giving A a 'second chance'"))) - - ;;========================================================================= - ;; LAZY VARIANT: bet/lazy - ;;========================================================================= - (bet/lazy - . ((signature . "(bet/lazy thunk-a thunk-b thunk-c) -> (thunk-a) | (thunk-b) | (thunk-c)") - (description . "Lazy bet: only the selected thunk is evaluated") - - (formal-semantics - . ((denotation . "[[bet/lazy ta tb tc]] : Thunk^3 -> Dist(Value)") - (semantics . "Select index i in {0,1,2} uniformly; return (ti)") - (probability-model - . ((P-a . "1/3") - (P-b . "1/3") - (P-c . "1/3"))))) - - (evaluation-order . "lazy - only selected thunk invoked") - (constraints . "Arguments must be zero-arity procedures (thunks)"))) - - ;;========================================================================= - ;; SEEDED EXECUTION: bet-with-seed - ;;========================================================================= - (bet-with-seed - . ((signature . "(bet-with-seed seed thunk) -> Value") - (description . "Execute bet with deterministic random seed for reproducibility") - - (formal-semantics - . ((denotation . "[[bet-with-seed s t]] : Int x Thunk -> Value") - (semantics . "Parameterize PRNG with seed s, then invoke thunk") - (determinism . "Same seed always produces same sequence of random choices"))) - - (constraints - . ((seed-type . "Non-negative integer") - (scope . "Seed affects only bets within the thunk's dynamic extent"))) - - (use-cases - . ("Reproducible tests" - "Debugging stochastic behavior" - "Conformance testing")))) - - ;;========================================================================= - ;; TESTING REQUIREMENTS - ;;========================================================================= - (testing-requirements - . ((seedability . "All stochastic tests MUST use bet-with-seed for reproducibility") - (statistical-tolerance . "Probability estimates should use sufficient sample size (n >= 1000)") - (deterministic-tests . "Include tests for deterministic edge cases (bet X X X)") - (conformance-corpus . "See conformance/ directory for canonical test cases"))) - - ;;========================================================================= - ;; IMPLEMENTATION NOTES - ;;========================================================================= - (implementation-notes - . ((prng . "Uses Racket's (random) with (random 3) for uniform ternary selection") - (thread-safety . "Not thread-safe by default; use Racket synchronization") - (memory-model . "Eager evaluation except for bet/lazy") - (error-propagation . "Racket exceptions propagate through bet forms"))))) - -;; End of SPEC.core.scm diff --git a/bindings/chapel/Cargo.toml b/bindings/chapel/Cargo.toml index 533b6e3..156b375 100644 --- a/bindings/chapel/Cargo.toml +++ b/bindings/chapel/Cargo.toml @@ -20,4 +20,4 @@ rand.workspace = true rand_distr.workspace = true [build-dependencies] -cbindgen = "0.26" +cbindgen = "0.28" diff --git a/bindings/julia/Cargo.toml b/bindings/julia/Cargo.toml index 7f287ac..5895740 100644 --- a/bindings/julia/Cargo.toml +++ b/bindings/julia/Cargo.toml @@ -20,4 +20,4 @@ rand.workspace = true rand_distr.workspace = true [build-dependencies] -cbindgen = "0.26" +cbindgen = "0.28" diff --git a/editors/jetbrains/build.gradle b/editors/jetbrains/build.gradle deleted file mode 100644 index eb29836..0000000 --- a/editors/jetbrains/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// Betlang IntelliJ Plugin - Gradle Build - -plugins { - id 'java' - id 'org.jetbrains.intellij' version '1.17.0' -} - -group = 'com.hyperpolymath' -version = '0.1.0' - -repositories { - mavenCentral() -} - -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 -} - -dependencies { - // LSP4J for Language Server Protocol support - implementation 'org.eclipse.lsp4j:org.eclipse.lsp4j:0.21.1' - implementation 'org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.21.1' -} - -intellij { - version = '2023.3' - type = 'IC' // IntelliJ IDEA Community Edition - - plugins = [ - 'com.intellij.java' - ] -} - -tasks { - patchPluginXml { - sinceBuild = '233' - untilBuild = '243.*' - } - - signPlugin { - certificateChain = System.getenv("CERTIFICATE_CHAIN") - privateKey = System.getenv("PRIVATE_KEY") - password = System.getenv("PRIVATE_KEY_PASSWORD") - } - - publishPlugin { - token = System.getenv("PUBLISH_TOKEN") - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangColorSettingsPage.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangColorSettingsPage.java deleted file mode 100644 index 7739ff2..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangColorSettingsPage.java +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.fileTypes.SyntaxHighlighter; -import com.intellij.openapi.options.colors.AttributesDescriptor; -import com.intellij.openapi.options.colors.ColorDescriptor; -import com.intellij.openapi.options.colors.ColorSettingsPage; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.util.Map; - -/** - * Color settings page for Betlang syntax highlighting customization - */ -public class BetlangColorSettingsPage implements ColorSettingsPage { - - private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[]{ - new AttributesDescriptor("Keyword", BetlangSyntaxHighlighter.KEYWORD), - new AttributesDescriptor("String", BetlangSyntaxHighlighter.STRING), - new AttributesDescriptor("Number", BetlangSyntaxHighlighter.NUMBER), - new AttributesDescriptor("Comment", BetlangSyntaxHighlighter.COMMENT), - new AttributesDescriptor("Identifier", BetlangSyntaxHighlighter.IDENTIFIER), - new AttributesDescriptor("Operator", BetlangSyntaxHighlighter.OPERATOR), - new AttributesDescriptor("Braces", BetlangSyntaxHighlighter.BRACES), - new AttributesDescriptor("Parentheses", BetlangSyntaxHighlighter.PARENTHESES), - new AttributesDescriptor("Brackets", BetlangSyntaxHighlighter.BRACKETS), - new AttributesDescriptor("Comma", BetlangSyntaxHighlighter.COMMA), - new AttributesDescriptor("Bad character", BetlangSyntaxHighlighter.BAD_CHARACTER), - }; - - @Nullable - @Override - public Icon getIcon() { - return BetlangIcons.FILE; - } - - @NotNull - @Override - public SyntaxHighlighter getHighlighter() { - return new BetlangSyntaxHighlighter(); - } - - @NotNull - @Override - public String getDemoText() { - return """ - // Betlang - Ternary probabilistic programming - - // Basic bet expression - let outcome = bet { "heads", "tails", "edge" } - - // Function definition - fn roll_dice(sides) { - let first = bet { 1, 2, 3 } - let second = bet { 4, 5, 6 } - bet { first, second, sides } - } - - // Weighted bet - let weighted = bet[0.5, 0.3, 0.2] { "likely", "medium", "rare" } - - // Nested bets - let complex = bet { - bet { 1, 2, 3 }, - bet { "a", "b", "c" }, - 42 - } - - // Using results - let result = roll_dice(6) - print("Rolled: " + result) - """; - } - - @Nullable - @Override - public Map getAdditionalHighlightingTagToDescriptorMap() { - return null; - } - - @Override - public AttributesDescriptor @NotNull [] getAttributeDescriptors() { - return DESCRIPTORS; - } - - @Override - public ColorDescriptor @NotNull [] getColorDescriptors() { - return ColorDescriptor.EMPTY_ARRAY; - } - - @NotNull - @Override - public String getDisplayName() { - return "Betlang"; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangDocumentationProvider.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangDocumentationProvider.java deleted file mode 100644 index 5e0a2fa..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangDocumentationProvider.java +++ /dev/null @@ -1,299 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lang.documentation.AbstractDocumentationProvider; -import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.Nullable; - -/** - * Documentation provider for Betlang elements. - * Provides hover documentation for keywords and built-in functions. - */ -public class BetlangDocumentationProvider extends AbstractDocumentationProvider { - - @Override - public @Nullable @Nls String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { - if (element == null) { - return null; - } - - String text = element.getText(); - - return switch (text) { - case "bet" -> generateBetDoc(); - case "let" -> generateLetDoc(); - case "fn" -> generateFnDoc(); - case "if" -> generateIfDoc(); - case "else" -> generateElseDoc(); - case "match" -> generateMatchDoc(); - case "true", "false" -> generateBoolDoc(text); - case "nil" -> generateNilDoc(); - case "print" -> generatePrintDoc(); - case "sample" -> generateSampleDoc(); - case "observe" -> generateObserveDoc(); - default -> null; - }; - } - - @Override - public @Nullable @Nls String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { - if (element == null) { - return null; - } - - String text = element.getText(); - - return switch (text) { - case "bet" -> "bet { A, B, C } - Ternary probabilistic choice"; - case "let" -> "let name = value - Variable binding"; - case "fn" -> "fn name(params) { body } - Function definition"; - default -> null; - }; - } - - private String generateBetDoc() { - return """ - - -

bet

-

Syntax: bet { A, B, C }

-

Description: The core Betlang primitive. Randomly selects one of three values - with equal probability (1/3 each).

- -

Weighted Variant

-

Syntax: bet[w1, w2, w3] { A, B, C }

-

Selects with custom probabilities. Weights are normalized automatically.

- -

Examples

-
-                // Equal probability
-                let coin = bet { "heads", "tails", "edge" }
-
-                // Weighted (50%, 30%, 20%)
-                let weighted = bet[0.5, 0.3, 0.2] { "common", "uncommon", "rare" }
-
-                // Nested bets
-                let nested = bet {
-                    bet { 1, 2, 3 },
-                    bet { 4, 5, 6 },
-                    7
-                }
-                
- -

Musical Inspiration

-

The ternary form (A-B-A) is inspired by musical ternary form, - where a piece has three sections with the first and third being similar.

- - - """; - } - - private String generateLetDoc() { - return """ - - -

let

-

Syntax: let name = expression

-

Description: Binds a value to a name in the current scope.

- -

Examples

-
-                let x = 42
-                let result = bet { 1, 2, 3 }
-                let greeting = "Hello, World!"
-                
- -

Shadowing

-

Variables can be shadowed in inner scopes:

-
-                let x = 1
-                fn example() {
-                    let x = 2  // shadows outer x
-                    x          // returns 2
-                }
-                
- - - """; - } - - private String generateFnDoc() { - return """ - - -

fn

-

Syntax: fn name(param1, param2, ...) { body }

-

Description: Defines a function with the given parameters.

- -

Examples

-
-                fn add(a, b) {
-                    a + b
-                }
-
-                fn roll_dice() {
-                    bet { 1, 2, 3 } + bet { 0, 3, 3 }
-                }
-
-                fn factorial(n) {
-                    if n <= 1 {
-                        1
-                    } else {
-                        n * factorial(n - 1)
-                    }
-                }
-                
- - - """; - } - - private String generateIfDoc() { - return """ - - -

if

-

Syntax: if condition { then_branch } else { else_branch }

-

Description: Conditional expression. Returns the value of the executed branch.

- -

Examples

-
-                if x > 0 {
-                    "positive"
-                } else {
-                    "non-positive"
-                }
-                
- - - """; - } - - private String generateElseDoc() { - return """ - - -

else

-

Description: The alternative branch in an if expression.

-

See if for full documentation.

- - - """; - } - - private String generateMatchDoc() { - return """ - - -

match

-

Syntax:

-
-                match value {
-                    pattern1 => result1,
-                    pattern2 => result2,
-                    _ => default
-                }
-                
-

Description: Pattern matching expression.

- -

Examples

-
-                let result = bet { 1, 2, 3 }
-                match result {
-                    1 => "first",
-                    2 => "second",
-                    3 => "third"
-                }
-                
- - - """; - } - - private String generateBoolDoc(String value) { - return String.format(""" - - -

%s

-

Type: Boolean

-

Description: Boolean literal value.

- - - """, value); - } - - private String generateNilDoc() { - return """ - - -

nil

-

Type: Nil

-

Description: The absence of a value. Similar to null in other languages.

- - - """; - } - - private String generatePrintDoc() { - return """ - - -

print

-

Syntax: print(value)

-

Description: Outputs the value to the console.

-

Returns: nil

- -

Examples

-
-                print("Hello, World!")
-                print(42)
-                print(bet { "a", "b", "c" })
-                
- - - """; - } - - private String generateSampleDoc() { - return """ - - -

sample

-

Syntax: sample(n, expression)

-

Description: Runs the expression n times and collects the results.

-

Returns: List of sampled values

- -

Examples

-
-                // Sample 100 coin flips
-                let flips = sample(100, bet { "H", "T", "E" })
-
-                // Sample dice rolls
-                let rolls = sample(1000, bet { 1, 2, 3 } + bet { 0, 3, 3 })
-                
- - - """; - } - - private String generateObserveDoc() { - return """ - - -

observe

-

Syntax: observe(condition)

-

Description: Conditions the probabilistic execution on the given condition being true. - Used for Bayesian inference and conditioning.

- -

Examples

-
-                // Condition on outcome
-                let die = bet { 1, 2, 3 } + bet { 0, 3, 3 }
-                observe(die >= 4)  // Only consider cases where die >= 4
-                
- - - """; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementType.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementType.java deleted file mode 100644 index 38a0397..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementType.java +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; - -/** - * Element type for Betlang PSI elements - */ -public class BetlangElementType extends IElementType { - public BetlangElementType(@NotNull String debugName) { - super(debugName, BetlangLanguage.INSTANCE); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementTypes.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementTypes.java deleted file mode 100644 index 611eb0d..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangElementTypes.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.IElementType; - -/** - * Element types and factory for Betlang PSI - */ -public interface BetlangElementTypes { - IElementType BET_EXPR = new BetlangElementType("BET_EXPR"); - IElementType LET_EXPR = new BetlangElementType("LET_EXPR"); - IElementType FUN_EXPR = new BetlangElementType("FUN_EXPR"); - IElementType IF_EXPR = new BetlangElementType("IF_EXPR"); - - class Factory { - public static PsiElement createElement(ASTNode node) { - return new BetlangPsiElement(node); - } - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFile.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFile.java deleted file mode 100644 index ccf83e8..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFile.java +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.extapi.psi.PsiFileBase; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.psi.FileViewProvider; -import org.jetbrains.annotations.NotNull; - -/** - * PSI file for Betlang source files - */ -public class BetlangFile extends PsiFileBase { - public BetlangFile(@NotNull FileViewProvider viewProvider) { - super(viewProvider, BetlangLanguage.INSTANCE); - } - - @NotNull - @Override - public FileType getFileType() { - return BetlangFileType.INSTANCE; - } - - @Override - public String toString() { - return "Betlang File"; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFileType.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFileType.java deleted file mode 100644 index f434f42..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangFileType.java +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.openapi.fileTypes.LanguageFileType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * File type for Betlang source files (.bet, .betlang) - */ -public class BetlangFileType extends LanguageFileType { - public static final BetlangFileType INSTANCE = new BetlangFileType(); - - private BetlangFileType() { - super(BetlangLanguage.INSTANCE); - } - - @NotNull - @Override - public String getName() { - return "Betlang"; - } - - @NotNull - @Override - public String getDescription() { - return "Betlang source file"; - } - - @NotNull - @Override - public String getDefaultExtension() { - return "bet"; - } - - @Nullable - @Override - public Icon getIcon() { - return BetlangIcons.FILE; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangIcons.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangIcons.java deleted file mode 100644 index 2e79cae..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangIcons.java +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.openapi.util.IconLoader; - -import javax.swing.*; - -/** - * Icons for Betlang plugin - */ -public class BetlangIcons { - public static final Icon FILE = IconLoader.getIcon("/icons/betlang.svg", BetlangIcons.class); - public static final Icon REPL = IconLoader.getIcon("/icons/repl.svg", BetlangIcons.class); -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLanguage.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLanguage.java deleted file mode 100644 index 4c00744..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLanguage.java +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lang.Language; - -/** - * Betlang language definition - */ -public class BetlangLanguage extends Language { - public static final BetlangLanguage INSTANCE = new BetlangLanguage(); - - private BetlangLanguage() { - super("Betlang"); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLexer.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLexer.java deleted file mode 100644 index 750f3f2..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLexer.java +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lexer.LexerBase; -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Simple lexer for Betlang syntax highlighting. - * Full parsing is handled by the LSP server. - */ -public class BetlangLexer extends LexerBase { - private CharSequence buffer; - private int bufferEnd; - private int tokenStart; - private int tokenEnd; - private IElementType tokenType; - - @Override - public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) { - this.buffer = buffer; - this.bufferEnd = endOffset; - this.tokenStart = startOffset; - this.tokenEnd = startOffset; - advance(); - } - - @Override - public int getState() { - return 0; - } - - @Nullable - @Override - public IElementType getTokenType() { - return tokenType; - } - - @Override - public int getTokenStart() { - return tokenStart; - } - - @Override - public int getTokenEnd() { - return tokenEnd; - } - - @Override - public void advance() { - tokenStart = tokenEnd; - if (tokenStart >= bufferEnd) { - tokenType = null; - return; - } - - char c = buffer.charAt(tokenStart); - - // Comments - if (c == '/' && tokenStart + 1 < bufferEnd) { - char next = buffer.charAt(tokenStart + 1); - if (next == '/') { - tokenEnd = findLineEnd(); - tokenType = BetlangTokenTypes.LINE_COMMENT; - return; - } else if (next == '*') { - tokenEnd = findBlockCommentEnd(); - tokenType = BetlangTokenTypes.BLOCK_COMMENT; - return; - } - } - - // Strings - if (c == '"') { - tokenEnd = findStringEnd('"'); - tokenType = BetlangTokenTypes.STRING; - return; - } - - // Numbers - if (Character.isDigit(c)) { - tokenEnd = findNumberEnd(); - tokenType = BetlangTokenTypes.NUMBER; - return; - } - - // Identifiers and keywords - if (Character.isLetter(c) || c == '_') { - tokenEnd = findIdentifierEnd(); - String text = buffer.subSequence(tokenStart, tokenEnd).toString(); - tokenType = getKeywordType(text); - return; - } - - // Operators and punctuation - tokenEnd = tokenStart + 1; - tokenType = getOperatorType(c); - } - - private int findLineEnd() { - int pos = tokenStart + 2; - while (pos < bufferEnd && buffer.charAt(pos) != '\n') { - pos++; - } - return pos; - } - - private int findBlockCommentEnd() { - int pos = tokenStart + 2; - while (pos + 1 < bufferEnd) { - if (buffer.charAt(pos) == '*' && buffer.charAt(pos + 1) == '/') { - return pos + 2; - } - pos++; - } - return bufferEnd; - } - - private int findStringEnd(char quote) { - int pos = tokenStart + 1; - while (pos < bufferEnd) { - char c = buffer.charAt(pos); - if (c == quote) { - return pos + 1; - } - if (c == '\\' && pos + 1 < bufferEnd) { - pos++; // Skip escaped character - } - pos++; - } - return bufferEnd; - } - - private int findNumberEnd() { - int pos = tokenStart; - boolean hasDot = false; - while (pos < bufferEnd) { - char c = buffer.charAt(pos); - if (Character.isDigit(c)) { - pos++; - } else if (c == '.' && !hasDot) { - hasDot = true; - pos++; - } else if ((c == 'e' || c == 'E') && pos > tokenStart) { - pos++; - if (pos < bufferEnd && (buffer.charAt(pos) == '+' || buffer.charAt(pos) == '-')) { - pos++; - } - } else { - break; - } - } - return pos; - } - - private int findIdentifierEnd() { - int pos = tokenStart; - while (pos < bufferEnd) { - char c = buffer.charAt(pos); - if (Character.isLetterOrDigit(c) || c == '_') { - pos++; - } else { - break; - } - } - return pos; - } - - private IElementType getKeywordType(String text) { - switch (text) { - case "let": - case "in": - case "fun": - case "if": - case "then": - case "else": - case "match": - case "with": - case "type": - case "module": - case "bet": - return BetlangTokenTypes.KEYWORD; - case "true": - case "false": - case "unknown": - return BetlangTokenTypes.CONSTANT; - default: - return BetlangTokenTypes.IDENTIFIER; - } - } - - private IElementType getOperatorType(char c) { - switch (c) { - case '{': - case '}': - case '(': - case ')': - case '[': - case ']': - return BetlangTokenTypes.BRACE; - case ',': - case ';': - return BetlangTokenTypes.PUNCTUATION; - case '+': - case '-': - case '*': - case '/': - case '=': - case '<': - case '>': - case '!': - case '&': - case '|': - case '@': - return BetlangTokenTypes.OPERATOR; - default: - if (Character.isWhitespace(c)) { - return BetlangTokenTypes.WHITESPACE; - } - return BetlangTokenTypes.OTHER; - } - } - - @NotNull - @Override - public CharSequence getBufferSequence() { - return buffer; - } - - @Override - public int getBufferEnd() { - return bufferEnd; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLspServerSupportProvider.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLspServerSupportProvider.java deleted file mode 100644 index 9d9ed0c..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangLspServerSupportProvider.java +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.execution.ExecutionException; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.platform.lsp.api.LspServerSupportProvider; -import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * LSP server support provider for Betlang. - * Connects to the bet-lsp server (Gleam/BEAM based). - */ -public class BetlangLspServerSupportProvider implements LspServerSupportProvider { - private static final Logger LOG = Logger.getInstance(BetlangLspServerSupportProvider.class); - - @Override - public void fileOpened(@NotNull Project project, @NotNull VirtualFile file, @NotNull LspServerStarter serverStarter) { - if (file.getExtension() != null && file.getExtension().equals("bet")) { - serverStarter.ensureServerStarted(new BetlangLspServerDescriptor(project)); - } - } - - private static class BetlangLspServerDescriptor extends ProjectWideLspServerDescriptor { - - BetlangLspServerDescriptor(@NotNull Project project) { - super(project, "Betlang"); - } - - @NotNull - @Override - public GeneralCommandLine createCommandLine() throws ExecutionException { - // Try to find bet-lsp in various locations - String lspPath = findLspServer(); - - if (lspPath == null) { - throw new ExecutionException("Could not find bet-lsp server. Please ensure it is installed."); - } - - GeneralCommandLine commandLine = new GeneralCommandLine(); - - // Check if it's an escript or native binary - if (lspPath.endsWith(".escript") || lspPath.contains("gleam")) { - commandLine.setExePath("escript"); - commandLine.addParameter(lspPath); - } else { - commandLine.setExePath(lspPath); - } - - commandLine.addParameter("--stdio"); - commandLine.setWorkDirectory(getProject().getBasePath()); - - LOG.info("Starting Betlang LSP server: " + commandLine.getCommandLineString()); - - return commandLine; - } - - @Override - public boolean isSupportedFile(@NotNull VirtualFile file) { - String extension = file.getExtension(); - return extension != null && extension.equals("bet"); - } - - private String findLspServer() { - // Check various possible locations - String[] searchPaths = { - // Project-local - getProject().getBasePath() + "/lsp/bet-lsp/build/erlang-shipment/entrypoint.sh", - getProject().getBasePath() + "/.bet/bin/bet-lsp", - - // User home - System.getProperty("user.home") + "/.bet/bin/bet-lsp", - System.getProperty("user.home") + "/.local/bin/bet-lsp", - - // System paths - "/usr/local/bin/bet-lsp", - "/usr/bin/bet-lsp", - "/opt/bet/bin/bet-lsp", - - // Guix/Nix - System.getProperty("user.home") + "/.guix-profile/bin/bet-lsp", - "/run/current-system/sw/bin/bet-lsp", - }; - - // Check PATH environment variable - String pathEnv = System.getenv("PATH"); - if (pathEnv != null) { - for (String dir : pathEnv.split(File.pathSeparator)) { - Path lspPath = Paths.get(dir, "bet-lsp"); - if (lspPath.toFile().exists() && lspPath.toFile().canExecute()) { - return lspPath.toString(); - } - } - } - - // Check predefined paths - for (String path : searchPaths) { - File file = new File(path); - if (file.exists() && file.canExecute()) { - return path; - } - } - - // Check for Gleam build output - String gleamBuild = getProject().getBasePath() + "/lsp/bet-lsp/build/dev/erlang/bet_lsp/ebin"; - File gleamDir = new File(gleamBuild); - if (gleamDir.exists()) { - // Use erl to run the BEAM module directly - return gleamBuild; - } - - return null; - } - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParser.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParser.java deleted file mode 100644 index 278afc3..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParser.java +++ /dev/null @@ -1,249 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.PsiBuilder; -import com.intellij.lang.PsiParser; -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; - -/** - * Parser for Betlang source files. - * Creates a basic AST structure from tokens. - */ -public class BetlangParser implements PsiParser { - @NotNull - @Override - public ASTNode parse(@NotNull IElementType root, @NotNull PsiBuilder builder) { - PsiBuilder.Marker rootMarker = builder.mark(); - - while (!builder.eof()) { - parseStatement(builder); - } - - rootMarker.done(root); - return builder.getTreeBuilt(); - } - - private void parseStatement(@NotNull PsiBuilder builder) { - IElementType tokenType = builder.getTokenType(); - - if (tokenType == null) { - builder.advanceLexer(); - return; - } - - if (tokenType == BetlangTokenTypes.KEYWORD && "bet".equals(builder.getTokenText())) { - parseBetExpression(builder); - } else if (tokenType == BetlangTokenTypes.KEYWORD && "let".equals(builder.getTokenText())) { - parseLetBinding(builder); - } else if (tokenType == BetlangTokenTypes.KEYWORD && "fn".equals(builder.getTokenText())) { - parseFunctionDef(builder); - } else if (tokenType == BetlangTokenTypes.COMMENT || - tokenType == BetlangTokenTypes.WHITESPACE || - tokenType == BetlangTokenTypes.NEWLINE) { - builder.advanceLexer(); - } else { - parseExpression(builder); - } - } - - private void parseBetExpression(@NotNull PsiBuilder builder) { - PsiBuilder.Marker marker = builder.mark(); - - // Consume 'bet' - builder.advanceLexer(); - skipWhitespace(builder); - - // Expect '{' - if (builder.getTokenType() == BetlangTokenTypes.LBRACE) { - builder.advanceLexer(); - skipWhitespace(builder); - - // Parse three branches - for (int i = 0; i < 3 && !builder.eof(); i++) { - parseExpression(builder); - skipWhitespace(builder); - - if (builder.getTokenType() == BetlangTokenTypes.COMMA) { - builder.advanceLexer(); - skipWhitespace(builder); - } - } - - // Expect '}' - if (builder.getTokenType() == BetlangTokenTypes.RBRACE) { - builder.advanceLexer(); - } - } - - marker.done(BetlangElementTypes.BET_EXPR); - } - - private void parseLetBinding(@NotNull PsiBuilder builder) { - PsiBuilder.Marker marker = builder.mark(); - - // Consume 'let' - builder.advanceLexer(); - skipWhitespace(builder); - - // Expect identifier - if (builder.getTokenType() == BetlangTokenTypes.IDENTIFIER) { - builder.advanceLexer(); - skipWhitespace(builder); - } - - // Expect '=' - if (builder.getTokenType() == BetlangTokenTypes.OPERATOR && "=".equals(builder.getTokenText())) { - builder.advanceLexer(); - skipWhitespace(builder); - } - - // Parse value expression - parseExpression(builder); - - marker.done(BetlangElementTypes.LET_BINDING); - } - - private void parseFunctionDef(@NotNull PsiBuilder builder) { - PsiBuilder.Marker marker = builder.mark(); - - // Consume 'fn' - builder.advanceLexer(); - skipWhitespace(builder); - - // Expect function name - if (builder.getTokenType() == BetlangTokenTypes.IDENTIFIER) { - builder.advanceLexer(); - skipWhitespace(builder); - } - - // Expect '(' - if (builder.getTokenType() == BetlangTokenTypes.LPAREN) { - builder.advanceLexer(); - skipWhitespace(builder); - - // Parse parameters - while (builder.getTokenType() == BetlangTokenTypes.IDENTIFIER) { - builder.advanceLexer(); - skipWhitespace(builder); - - if (builder.getTokenType() == BetlangTokenTypes.COMMA) { - builder.advanceLexer(); - skipWhitespace(builder); - } - } - - // Expect ')' - if (builder.getTokenType() == BetlangTokenTypes.RPAREN) { - builder.advanceLexer(); - skipWhitespace(builder); - } - } - - // Parse body - if (builder.getTokenType() == BetlangTokenTypes.LBRACE) { - parseBlock(builder); - } - - marker.done(BetlangElementTypes.FN_DEF); - } - - private void parseBlock(@NotNull PsiBuilder builder) { - PsiBuilder.Marker marker = builder.mark(); - - // Consume '{' - builder.advanceLexer(); - skipWhitespace(builder); - - // Parse statements until '}' - while (!builder.eof() && builder.getTokenType() != BetlangTokenTypes.RBRACE) { - parseStatement(builder); - skipWhitespace(builder); - } - - // Consume '}' - if (builder.getTokenType() == BetlangTokenTypes.RBRACE) { - builder.advanceLexer(); - } - - marker.done(BetlangElementTypes.BLOCK); - } - - private void parseExpression(@NotNull PsiBuilder builder) { - PsiBuilder.Marker marker = builder.mark(); - - parsePrimaryExpression(builder); - skipWhitespace(builder); - - // Handle binary operators - while (builder.getTokenType() == BetlangTokenTypes.OPERATOR) { - builder.advanceLexer(); - skipWhitespace(builder); - parsePrimaryExpression(builder); - skipWhitespace(builder); - } - - marker.done(BetlangElementTypes.EXPRESSION); - } - - private void parsePrimaryExpression(@NotNull PsiBuilder builder) { - IElementType tokenType = builder.getTokenType(); - - if (tokenType == BetlangTokenTypes.NUMBER) { - builder.advanceLexer(); - } else if (tokenType == BetlangTokenTypes.STRING) { - builder.advanceLexer(); - } else if (tokenType == BetlangTokenTypes.IDENTIFIER) { - builder.advanceLexer(); - skipWhitespace(builder); - - // Check for function call - if (builder.getTokenType() == BetlangTokenTypes.LPAREN) { - parseCallArgs(builder); - } - } else if (tokenType == BetlangTokenTypes.LPAREN) { - builder.advanceLexer(); - skipWhitespace(builder); - parseExpression(builder); - skipWhitespace(builder); - if (builder.getTokenType() == BetlangTokenTypes.RPAREN) { - builder.advanceLexer(); - } - } else if (tokenType == BetlangTokenTypes.KEYWORD && "bet".equals(builder.getTokenText())) { - parseBetExpression(builder); - } else if (tokenType != null) { - builder.advanceLexer(); - } - } - - private void parseCallArgs(@NotNull PsiBuilder builder) { - // Consume '(' - builder.advanceLexer(); - skipWhitespace(builder); - - // Parse arguments - while (!builder.eof() && builder.getTokenType() != BetlangTokenTypes.RPAREN) { - parseExpression(builder); - skipWhitespace(builder); - - if (builder.getTokenType() == BetlangTokenTypes.COMMA) { - builder.advanceLexer(); - skipWhitespace(builder); - } - } - - // Consume ')' - if (builder.getTokenType() == BetlangTokenTypes.RPAREN) { - builder.advanceLexer(); - } - } - - private void skipWhitespace(@NotNull PsiBuilder builder) { - while (builder.getTokenType() == BetlangTokenTypes.WHITESPACE || - builder.getTokenType() == BetlangTokenTypes.NEWLINE || - builder.getTokenType() == BetlangTokenTypes.COMMENT) { - builder.advanceLexer(); - } - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParserDefinition.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParserDefinition.java deleted file mode 100644 index 43c00c2..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangParserDefinition.java +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lang.ASTNode; -import com.intellij.lang.ParserDefinition; -import com.intellij.lang.PsiParser; -import com.intellij.lexer.Lexer; -import com.intellij.openapi.project.Project; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.tree.IFileElementType; -import com.intellij.psi.tree.TokenSet; -import org.jetbrains.annotations.NotNull; - -/** - * Parser definition for Betlang. - * Note: Full parsing is delegated to the LSP server. - * This provides minimal structure for IDE integration. - */ -public class BetlangParserDefinition implements ParserDefinition { - public static final IFileElementType FILE = new IFileElementType(BetlangLanguage.INSTANCE); - - @NotNull - @Override - public Lexer createLexer(Project project) { - return new BetlangLexer(); - } - - @NotNull - @Override - public PsiParser createParser(Project project) { - return new BetlangParser(); - } - - @NotNull - @Override - public IFileElementType getFileNodeType() { - return FILE; - } - - @NotNull - @Override - public TokenSet getCommentTokens() { - return BetlangTokenSets.COMMENTS; - } - - @NotNull - @Override - public TokenSet getStringLiteralElements() { - return BetlangTokenSets.STRINGS; - } - - @NotNull - @Override - public PsiElement createElement(ASTNode node) { - return BetlangElementTypes.Factory.createElement(node); - } - - @NotNull - @Override - public PsiFile createFile(@NotNull FileViewProvider viewProvider) { - return new BetlangFile(viewProvider); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangPsiElement.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangPsiElement.java deleted file mode 100644 index 7fc408a..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangPsiElement.java +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.extapi.psi.ASTWrapperPsiElement; -import com.intellij.lang.ASTNode; -import org.jetbrains.annotations.NotNull; - -/** - * Base PSI element for Betlang - */ -public class BetlangPsiElement extends ASTWrapperPsiElement { - public BetlangPsiElement(@NotNull ASTNode node) { - super(node); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighter.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighter.java deleted file mode 100644 index 98696a5..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighter.java +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.lexer.Lexer; -import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; -import com.intellij.openapi.editor.HighlighterColors; -import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; - -import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey; - -/** - * Syntax highlighter for Betlang source files - */ -public class BetlangSyntaxHighlighter extends SyntaxHighlighterBase { - - public static final TextAttributesKey KEYWORD = - createTextAttributesKey("BETLANG_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD); - - public static final TextAttributesKey STRING = - createTextAttributesKey("BETLANG_STRING", DefaultLanguageHighlighterColors.STRING); - - public static final TextAttributesKey NUMBER = - createTextAttributesKey("BETLANG_NUMBER", DefaultLanguageHighlighterColors.NUMBER); - - public static final TextAttributesKey COMMENT = - createTextAttributesKey("BETLANG_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT); - - public static final TextAttributesKey IDENTIFIER = - createTextAttributesKey("BETLANG_IDENTIFIER", DefaultLanguageHighlighterColors.IDENTIFIER); - - public static final TextAttributesKey OPERATOR = - createTextAttributesKey("BETLANG_OPERATOR", DefaultLanguageHighlighterColors.OPERATION_SIGN); - - public static final TextAttributesKey BRACES = - createTextAttributesKey("BETLANG_BRACES", DefaultLanguageHighlighterColors.BRACES); - - public static final TextAttributesKey PARENTHESES = - createTextAttributesKey("BETLANG_PARENTHESES", DefaultLanguageHighlighterColors.PARENTHESES); - - public static final TextAttributesKey BRACKETS = - createTextAttributesKey("BETLANG_BRACKETS", DefaultLanguageHighlighterColors.BRACKETS); - - public static final TextAttributesKey COMMA = - createTextAttributesKey("BETLANG_COMMA", DefaultLanguageHighlighterColors.COMMA); - - public static final TextAttributesKey BAD_CHARACTER = - createTextAttributesKey("BETLANG_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER); - - private static final TextAttributesKey[] KEYWORD_KEYS = new TextAttributesKey[]{KEYWORD}; - private static final TextAttributesKey[] STRING_KEYS = new TextAttributesKey[]{STRING}; - private static final TextAttributesKey[] NUMBER_KEYS = new TextAttributesKey[]{NUMBER}; - private static final TextAttributesKey[] COMMENT_KEYS = new TextAttributesKey[]{COMMENT}; - private static final TextAttributesKey[] IDENTIFIER_KEYS = new TextAttributesKey[]{IDENTIFIER}; - private static final TextAttributesKey[] OPERATOR_KEYS = new TextAttributesKey[]{OPERATOR}; - private static final TextAttributesKey[] BRACES_KEYS = new TextAttributesKey[]{BRACES}; - private static final TextAttributesKey[] PARENTHESES_KEYS = new TextAttributesKey[]{PARENTHESES}; - private static final TextAttributesKey[] BRACKETS_KEYS = new TextAttributesKey[]{BRACKETS}; - private static final TextAttributesKey[] COMMA_KEYS = new TextAttributesKey[]{COMMA}; - private static final TextAttributesKey[] BAD_CHARACTER_KEYS = new TextAttributesKey[]{BAD_CHARACTER}; - private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0]; - - @NotNull - @Override - public Lexer getHighlightingLexer() { - return new BetlangLexer(); - } - - @Override - public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) { - if (tokenType.equals(BetlangTokenTypes.KEYWORD)) { - return KEYWORD_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.STRING)) { - return STRING_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.NUMBER)) { - return NUMBER_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.COMMENT)) { - return COMMENT_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.IDENTIFIER)) { - return IDENTIFIER_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.OPERATOR)) { - return OPERATOR_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.LBRACE) || tokenType.equals(BetlangTokenTypes.RBRACE)) { - return BRACES_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.LPAREN) || tokenType.equals(BetlangTokenTypes.RPAREN)) { - return PARENTHESES_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.LBRACKET) || tokenType.equals(BetlangTokenTypes.RBRACKET)) { - return BRACKETS_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.COMMA)) { - return COMMA_KEYS; - } - if (tokenType.equals(BetlangTokenTypes.BAD_CHARACTER)) { - return BAD_CHARACTER_KEYS; - } - return EMPTY_KEYS; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighterFactory.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighterFactory.java deleted file mode 100644 index 1ad3232..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangSyntaxHighlighterFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.openapi.fileTypes.SyntaxHighlighter; -import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Factory for creating Betlang syntax highlighters - */ -public class BetlangSyntaxHighlighterFactory extends SyntaxHighlighterFactory { - @NotNull - @Override - public SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) { - return new BetlangSyntaxHighlighter(); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenSets.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenSets.java deleted file mode 100644 index edc5043..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenSets.java +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.psi.tree.TokenSet; - -/** - * Token sets for Betlang - */ -public interface BetlangTokenSets { - TokenSet COMMENTS = TokenSet.create( - BetlangTokenTypes.LINE_COMMENT, - BetlangTokenTypes.BLOCK_COMMENT - ); - - TokenSet STRINGS = TokenSet.create(BetlangTokenTypes.STRING); - - TokenSet KEYWORDS = TokenSet.create(BetlangTokenTypes.KEYWORD); - - TokenSet OPERATORS = TokenSet.create(BetlangTokenTypes.OPERATOR); -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenTypes.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenTypes.java deleted file mode 100644 index be0163b..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/BetlangTokenTypes.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang; - -import com.intellij.psi.tree.IElementType; - -/** - * Token types for Betlang lexer - */ -public interface BetlangTokenTypes { - IElementType LINE_COMMENT = new BetlangElementType("LINE_COMMENT"); - IElementType BLOCK_COMMENT = new BetlangElementType("BLOCK_COMMENT"); - IElementType STRING = new BetlangElementType("STRING"); - IElementType NUMBER = new BetlangElementType("NUMBER"); - IElementType KEYWORD = new BetlangElementType("KEYWORD"); - IElementType CONSTANT = new BetlangElementType("CONSTANT"); - IElementType IDENTIFIER = new BetlangElementType("IDENTIFIER"); - IElementType OPERATOR = new BetlangElementType("OPERATOR"); - IElementType BRACE = new BetlangElementType("BRACE"); - IElementType PUNCTUATION = new BetlangElementType("PUNCTUATION"); - IElementType WHITESPACE = new BetlangElementType("WHITESPACE"); - IElementType OTHER = new BetlangElementType("OTHER"); -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/EvalSelectionAction.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/EvalSelectionAction.java deleted file mode 100644 index cf9da3f..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/EvalSelectionAction.java +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.actions; - -import com.hyperpolymath.betlang.BetlangFileType; -import com.hyperpolymath.betlang.BetlangIcons; -import com.hyperpolymath.betlang.repl.BetlangReplToolWindowFactory; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowManager; -import org.jetbrains.annotations.NotNull; - -/** - * Action to evaluate selected Betlang code in the REPL - */ -public class EvalSelectionAction extends AnAction { - - public EvalSelectionAction() { - super("Evaluate Selection in REPL", "Evaluate selected Betlang code in the REPL", BetlangIcons.FILE); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - Project project = e.getProject(); - Editor editor = e.getData(CommonDataKeys.EDITOR); - - if (project == null || editor == null) { - return; - } - - SelectionModel selectionModel = editor.getSelectionModel(); - String selectedText = selectionModel.getSelectedText(); - - if (selectedText == null || selectedText.isEmpty()) { - // If no selection, evaluate the current line - int caretLine = editor.getCaretModel().getLogicalPosition().line; - selectedText = editor.getDocument().getText().split("\n")[caretLine]; - } - - if (selectedText.isEmpty()) { - return; - } - - // Open REPL and send the code - ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); - ToolWindow toolWindow = toolWindowManager.getToolWindow(BetlangReplToolWindowFactory.TOOL_WINDOW_ID); - - if (toolWindow != null) { - final String code = selectedText; - toolWindow.show(() -> { - BetlangReplToolWindowFactory.sendToRepl(project, code); - }); - } - } - - @Override - public void update(@NotNull AnActionEvent e) { - Project project = e.getProject(); - Editor editor = e.getData(CommonDataKeys.EDITOR); - VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE); - - boolean enabled = project != null && editor != null && file != null && - BetlangFileType.INSTANCE.getDefaultExtension().equals(file.getExtension()); - - e.getPresentation().setEnabledAndVisible(enabled); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/RestartLspAction.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/RestartLspAction.java deleted file mode 100644 index 35f3e67..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/RestartLspAction.java +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.actions; - -import com.hyperpolymath.betlang.BetlangIcons; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.platform.lsp.api.LspServerManager; -import org.jetbrains.annotations.NotNull; - -/** - * Action to restart the Betlang LSP server - */ -public class RestartLspAction extends AnAction { - private static final Logger LOG = Logger.getInstance(RestartLspAction.class); - - public RestartLspAction() { - super("Restart Betlang LSP", "Restart the Betlang language server", BetlangIcons.FILE); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - Project project = e.getProject(); - if (project == null) { - return; - } - - LOG.info("Restarting Betlang LSP server"); - - // The LSP server will be automatically restarted when files are opened - // We just need to stop the current instance - try { - LspServerManager lspServerManager = LspServerManager.getInstance(project); - lspServerManager.stopServers(descriptor -> - descriptor.getDisplayName().equals("Betlang")); - - // Notify user - com.intellij.notification.NotificationGroupManager.getInstance() - .getNotificationGroup("Betlang Notifications") - .createNotification( - "Betlang LSP", - "Language server restarted. Open a .bet file to reconnect.", - com.intellij.notification.NotificationType.INFORMATION - ) - .notify(project); - - } catch (Exception ex) { - LOG.error("Failed to restart LSP server", ex); - } - } - - @Override - public void update(@NotNull AnActionEvent e) { - Project project = e.getProject(); - e.getPresentation().setEnabledAndVisible(project != null); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/StartReplAction.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/StartReplAction.java deleted file mode 100644 index 096ea5a..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/actions/StartReplAction.java +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.actions; - -import com.hyperpolymath.betlang.BetlangIcons; -import com.hyperpolymath.betlang.repl.BetlangReplToolWindowFactory; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowManager; -import org.jetbrains.annotations.NotNull; - -/** - * Action to start the Betlang REPL - */ -public class StartReplAction extends AnAction { - - public StartReplAction() { - super("Start Betlang REPL", "Open the Betlang interactive REPL", BetlangIcons.FILE); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - Project project = e.getProject(); - if (project == null) { - return; - } - - ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); - ToolWindow toolWindow = toolWindowManager.getToolWindow(BetlangReplToolWindowFactory.TOOL_WINDOW_ID); - - if (toolWindow != null) { - toolWindow.show(() -> { - // REPL content is created by the factory - }); - } - } - - @Override - public void update(@NotNull AnActionEvent e) { - Project project = e.getProject(); - e.getPresentation().setEnabledAndVisible(project != null); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/repl/BetlangReplToolWindowFactory.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/repl/BetlangReplToolWindowFactory.java deleted file mode 100644 index d947e9c..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/repl/BetlangReplToolWindowFactory.java +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.repl; - -import com.hyperpolymath.betlang.BetlangIcons; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.process.*; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.terminal.JBTerminalWidget; -import com.intellij.ui.content.Content; -import com.intellij.ui.content.ContentFactory; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import javax.swing.text.*; -import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.io.File; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Tool window factory for the Betlang REPL - */ -public class BetlangReplToolWindowFactory implements ToolWindowFactory, DumbAware { - - public static final String TOOL_WINDOW_ID = "Betlang REPL"; - private static final Logger LOG = Logger.getInstance(BetlangReplToolWindowFactory.class); - - private static final Map replInstances = new ConcurrentHashMap<>(); - - @Override - public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { - ReplInstance instance = new ReplInstance(project); - replInstances.put(project, instance); - - Content content = ContentFactory.getInstance().createContent( - instance.getPanel(), - "REPL", - false - ); - content.setIcon(BetlangIcons.FILE); - content.setDisposer(instance); - - toolWindow.getContentManager().addContent(content); - } - - public static void sendToRepl(@NotNull Project project, @NotNull String code) { - ReplInstance instance = replInstances.get(project); - if (instance != null) { - instance.sendCode(code); - } - } - - /** - * Instance of a REPL session - */ - private static class ReplInstance implements Disposable { - private final Project project; - private final JPanel panel; - private final JTextPane outputPane; - private final JTextField inputField; - private final StyledDocument outputDoc; - private ProcessHandler processHandler; - private OutputStream processInput; - - private final Style normalStyle; - private final Style promptStyle; - private final Style errorStyle; - private final Style resultStyle; - - ReplInstance(@NotNull Project project) { - this.project = project; - - // Create output pane - outputPane = new JTextPane(); - outputPane.setEditable(false); - outputPane.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 13)); - outputDoc = outputPane.getStyledDocument(); - - // Create styles - normalStyle = outputPane.addStyle("normal", null); - StyleConstants.setForeground(normalStyle, Color.WHITE); - - promptStyle = outputPane.addStyle("prompt", null); - StyleConstants.setForeground(promptStyle, new Color(100, 200, 100)); - StyleConstants.setBold(promptStyle, true); - - errorStyle = outputPane.addStyle("error", null); - StyleConstants.setForeground(errorStyle, new Color(255, 100, 100)); - - resultStyle = outputPane.addStyle("result", null); - StyleConstants.setForeground(resultStyle, new Color(150, 200, 255)); - - // Create input field - inputField = new JTextField(); - inputField.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 13)); - inputField.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER) { - String code = inputField.getText(); - if (!code.isEmpty()) { - sendCode(code); - inputField.setText(""); - } - } - } - }); - - // Create panel - panel = new JPanel(new BorderLayout()); - panel.setBackground(new Color(30, 30, 30)); - outputPane.setBackground(new Color(30, 30, 30)); - inputField.setBackground(new Color(45, 45, 45)); - inputField.setForeground(Color.WHITE); - inputField.setCaretColor(Color.WHITE); - - JScrollPane scrollPane = new JScrollPane(outputPane); - scrollPane.setBorder(BorderFactory.createEmptyBorder()); - - JPanel inputPanel = new JPanel(new BorderLayout()); - inputPanel.setBackground(new Color(30, 30, 30)); - JLabel promptLabel = new JLabel("bet> "); - promptLabel.setForeground(new Color(100, 200, 100)); - promptLabel.setFont(new Font(Font.MONOSPACED, Font.BOLD, 13)); - inputPanel.add(promptLabel, BorderLayout.WEST); - inputPanel.add(inputField, BorderLayout.CENTER); - - panel.add(scrollPane, BorderLayout.CENTER); - panel.add(inputPanel, BorderLayout.SOUTH); - - // Start the REPL process - startProcess(); - } - - JPanel getPanel() { - return panel; - } - - void sendCode(@NotNull String code) { - if (processInput != null) { - try { - appendText("bet> " + code + "\n", promptStyle); - processInput.write((code + "\n").getBytes(StandardCharsets.UTF_8)); - processInput.flush(); - } catch (Exception e) { - appendText("Error sending to REPL: " + e.getMessage() + "\n", errorStyle); - } - } else { - appendText("REPL not running. Attempting to restart...\n", errorStyle); - startProcess(); - } - } - - private void startProcess() { - String replPath = findRepl(); - if (replPath == null) { - appendText("Could not find bet-cli or Racket REPL.\n", errorStyle); - appendText("Please ensure Betlang is installed.\n", errorStyle); - return; - } - - try { - GeneralCommandLine commandLine = new GeneralCommandLine(); - - if (replPath.endsWith(".rkt")) { - commandLine.setExePath("racket"); - commandLine.addParameter(replPath); - } else { - commandLine.setExePath(replPath); - commandLine.addParameter("repl"); - } - - commandLine.setWorkDirectory(project.getBasePath()); - - processHandler = ProcessHandlerFactory.getInstance() - .createColoredProcessHandler(commandLine); - - processInput = processHandler.getProcessInput(); - - processHandler.addProcessListener(new ProcessAdapter() { - @Override - public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { - String text = event.getText(); - if (outputType == ProcessOutputTypes.STDOUT) { - appendText(text, resultStyle); - } else if (outputType == ProcessOutputTypes.STDERR) { - appendText(text, errorStyle); - } - } - - @Override - public void processTerminated(@NotNull ProcessEvent event) { - appendText("\n[REPL terminated with exit code " + - event.getExitCode() + "]\n", errorStyle); - processInput = null; - } - }); - - processHandler.startNotify(); - appendText("Betlang REPL started\n", normalStyle); - appendText("Type expressions to evaluate, or 'exit' to quit\n\n", normalStyle); - - } catch (ExecutionException e) { - appendText("Failed to start REPL: " + e.getMessage() + "\n", errorStyle); - LOG.error("Failed to start REPL", e); - } - } - - private void appendText(String text, Style style) { - SwingUtilities.invokeLater(() -> { - try { - outputDoc.insertString(outputDoc.getLength(), text, style); - outputPane.setCaretPosition(outputDoc.getLength()); - } catch (BadLocationException e) { - LOG.error("Error appending to output", e); - } - }); - } - - private String findRepl() { - // Check for bet-cli first - String[] cliPaths = { - project.getBasePath() + "/target/release/bet-cli", - project.getBasePath() + "/target/debug/bet-cli", - System.getProperty("user.home") + "/.cargo/bin/bet-cli", - System.getProperty("user.home") + "/.bet/bin/bet-cli", - "/usr/local/bin/bet-cli", - "/usr/bin/bet-cli", - }; - - // Check PATH - String pathEnv = System.getenv("PATH"); - if (pathEnv != null) { - for (String dir : pathEnv.split(File.pathSeparator)) { - File file = new File(dir, "bet-cli"); - if (file.exists() && file.canExecute()) { - return file.getAbsolutePath(); - } - } - } - - for (String path : cliPaths) { - File file = new File(path); - if (file.exists() && file.canExecute()) { - return path; - } - } - - // Fall back to Racket REPL - String[] rktPaths = { - project.getBasePath() + "/repl/shell.rkt", - }; - - for (String path : rktPaths) { - File file = new File(path); - if (file.exists()) { - return path; - } - } - - return null; - } - - @Override - public void dispose() { - replInstances.remove(project); - if (processHandler != null && !processHandler.isProcessTerminated()) { - processHandler.destroyProcess(); - } - } - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationFactory.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationFactory.java deleted file mode 100644 index 3e3c821..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.run; - -import com.intellij.execution.configurations.ConfigurationFactory; -import com.intellij.execution.configurations.ConfigurationType; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.openapi.components.BaseState; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Factory for creating Betlang run configurations - */ -public class BetlangConfigurationFactory extends ConfigurationFactory { - - public BetlangConfigurationFactory(@NotNull ConfigurationType type) { - super(type); - } - - @Override - public @NotNull @NonNls String getId() { - return BetlangConfigurationType.ID; - } - - @Override - public @NotNull RunConfiguration createTemplateConfiguration(@NotNull Project project) { - return new BetlangRunConfiguration(project, this, "Betlang"); - } - - @Override - public @Nullable Class getOptionsClass() { - return BetlangRunConfigurationOptions.class; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationType.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationType.java deleted file mode 100644 index 0814fb5..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangConfigurationType.java +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.run; - -import com.hyperpolymath.betlang.BetlangIcons; -import com.intellij.execution.configurations.ConfigurationFactory; -import com.intellij.execution.configurations.ConfigurationType; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -/** - * Run configuration type for Betlang programs - */ -public class BetlangConfigurationType implements ConfigurationType { - - public static final String ID = "BetlangRunConfiguration"; - - @Override - public @NotNull @Nls(capitalization = Nls.Capitalization.Title) String getDisplayName() { - return "Betlang"; - } - - @Override - public @Nls(capitalization = Nls.Capitalization.Sentence) String getConfigurationTypeDescription() { - return "Run Betlang programs"; - } - - @Override - public Icon getIcon() { - return BetlangIcons.FILE; - } - - @Override - public @NotNull @NonNls String getId() { - return ID; - } - - @Override - public ConfigurationFactory[] getConfigurationFactories() { - return new ConfigurationFactory[]{new BetlangConfigurationFactory(this)}; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfiguration.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfiguration.java deleted file mode 100644 index e8594f6..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfiguration.java +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.run; - -import com.intellij.execution.ExecutionException; -import com.intellij.execution.Executor; -import com.intellij.execution.configurations.*; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.process.ProcessHandlerFactory; -import com.intellij.execution.process.ProcessTerminatedListener; -import com.intellij.execution.runners.ExecutionEnvironment; -import com.intellij.openapi.options.SettingsEditor; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -/** - * Run configuration for Betlang programs - */ -public class BetlangRunConfiguration extends RunConfigurationBase { - - protected BetlangRunConfiguration(@NotNull Project project, - @NotNull ConfigurationFactory factory, - @Nullable String name) { - super(project, factory, name); - } - - @Override - protected @NotNull BetlangRunConfigurationOptions getOptions() { - return (BetlangRunConfigurationOptions) super.getOptions(); - } - - public String getScriptPath() { - return getOptions().getScriptPath(); - } - - public void setScriptPath(String path) { - getOptions().setScriptPath(path); - } - - public String getArguments() { - return getOptions().getArguments(); - } - - public void setArguments(String args) { - getOptions().setArguments(args); - } - - public String getWorkingDirectory() { - return getOptions().getWorkingDirectory(); - } - - public void setWorkingDirectory(String dir) { - getOptions().setWorkingDirectory(dir); - } - - public int getSampleCount() { - return getOptions().getSampleCount(); - } - - public void setSampleCount(int count) { - getOptions().setSampleCount(count); - } - - public long getRandomSeed() { - return getOptions().getRandomSeed(); - } - - public void setRandomSeed(long seed) { - getOptions().setRandomSeed(seed); - } - - public boolean getUseSeed() { - return getOptions().getUseSeed(); - } - - public void setUseSeed(boolean use) { - getOptions().setUseSeed(use); - } - - @Override - public @NotNull SettingsEditor getConfigurationEditor() { - return new BetlangSettingsEditor(getProject()); - } - - @Override - public @Nullable RunProfileState getState(@NotNull Executor executor, - @NotNull ExecutionEnvironment environment) - throws ExecutionException { - - return new CommandLineState(environment) { - @Override - protected @NotNull ProcessHandler startProcess() throws ExecutionException { - String scriptPath = getScriptPath(); - if (scriptPath == null || scriptPath.isEmpty()) { - throw new ExecutionException("No script file specified"); - } - - String betCli = findBetCli(); - if (betCli == null) { - throw new ExecutionException("Could not find bet-cli. Please ensure it is installed."); - } - - List command = new ArrayList<>(); - command.add(betCli); - command.add("run"); - command.add(scriptPath); - - // Add sample count if > 1 - int samples = getSampleCount(); - if (samples > 1) { - command.add("--samples"); - command.add(String.valueOf(samples)); - } - - // Add seed if specified - if (getUseSeed()) { - command.add("--seed"); - command.add(String.valueOf(getRandomSeed())); - } - - // Add user arguments - String args = getArguments(); - if (args != null && !args.isEmpty()) { - command.add("--"); - for (String arg : args.split("\\s+")) { - if (!arg.isEmpty()) { - command.add(arg); - } - } - } - - GeneralCommandLine commandLine = new GeneralCommandLine(command); - - String workDir = getWorkingDirectory(); - if (workDir != null && !workDir.isEmpty()) { - commandLine.setWorkDirectory(workDir); - } else { - commandLine.setWorkDirectory(getProject().getBasePath()); - } - - ProcessHandler processHandler = ProcessHandlerFactory.getInstance() - .createColoredProcessHandler(commandLine); - ProcessTerminatedListener.attach(processHandler); - - return processHandler; - } - }; - } - - private String findBetCli() { - // Check various possible locations - String[] searchPaths = { - getProject().getBasePath() + "/target/release/bet-cli", - getProject().getBasePath() + "/target/debug/bet-cli", - System.getProperty("user.home") + "/.cargo/bin/bet-cli", - System.getProperty("user.home") + "/.bet/bin/bet-cli", - System.getProperty("user.home") + "/.local/bin/bet-cli", - "/usr/local/bin/bet-cli", - "/usr/bin/bet-cli", - }; - - // Check PATH - String pathEnv = System.getenv("PATH"); - if (pathEnv != null) { - for (String dir : pathEnv.split(File.pathSeparator)) { - File file = new File(dir, "bet-cli"); - if (file.exists() && file.canExecute()) { - return file.getAbsolutePath(); - } - } - } - - // Check predefined paths - for (String path : searchPaths) { - File file = new File(path); - if (file.exists() && file.canExecute()) { - return path; - } - } - - return null; - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfigurationOptions.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfigurationOptions.java deleted file mode 100644 index 7e321de..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangRunConfigurationOptions.java +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.run; - -import com.intellij.execution.configurations.RunConfigurationOptions; -import com.intellij.openapi.components.StoredProperty; - -/** - * Options for Betlang run configurations - */ -public class BetlangRunConfigurationOptions extends RunConfigurationOptions { - - private final StoredProperty scriptPath = - string("").provideDelegate(this, "scriptPath"); - - private final StoredProperty arguments = - string("").provideDelegate(this, "arguments"); - - private final StoredProperty workingDirectory = - string("").provideDelegate(this, "workingDirectory"); - - private final StoredProperty sampleCount = - property(1).provideDelegate(this, "sampleCount"); - - private final StoredProperty randomSeed = - property(0L).provideDelegate(this, "randomSeed"); - - private final StoredProperty useSeed = - property(false).provideDelegate(this, "useSeed"); - - public String getScriptPath() { - return scriptPath.getValue(this); - } - - public void setScriptPath(String path) { - scriptPath.setValue(this, path); - } - - public String getArguments() { - return arguments.getValue(this); - } - - public void setArguments(String args) { - arguments.setValue(this, args); - } - - public String getWorkingDirectory() { - return workingDirectory.getValue(this); - } - - public void setWorkingDirectory(String dir) { - workingDirectory.setValue(this, dir); - } - - public int getSampleCount() { - return sampleCount.getValue(this); - } - - public void setSampleCount(int count) { - sampleCount.setValue(this, count); - } - - public long getRandomSeed() { - return randomSeed.getValue(this); - } - - public void setRandomSeed(long seed) { - randomSeed.setValue(this, seed); - } - - public boolean getUseSeed() { - return useSeed.getValue(this); - } - - public void setUseSeed(boolean use) { - useSeed.setValue(this, use); - } -} diff --git a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangSettingsEditor.java b/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangSettingsEditor.java deleted file mode 100644 index fca59a4..0000000 --- a/editors/jetbrains/src/main/java/com/hyperpolymath/betlang/run/BetlangSettingsEditor.java +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -package com.hyperpolymath.betlang.run; - -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; -import com.intellij.openapi.options.SettingsEditor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; -import com.intellij.ui.components.JBCheckBox; -import com.intellij.ui.components.JBLabel; -import com.intellij.ui.components.JBTextField; -import com.intellij.util.ui.FormBuilder; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -/** - * Settings editor for Betlang run configurations - */ -public class BetlangSettingsEditor extends SettingsEditor { - - private final JPanel panel; - private final TextFieldWithBrowseButton scriptPathField; - private final JBTextField argumentsField; - private final TextFieldWithBrowseButton workingDirectoryField; - private final JSpinner sampleCountSpinner; - private final JBCheckBox useSeedCheckbox; - private final JSpinner seedSpinner; - - public BetlangSettingsEditor(Project project) { - scriptPathField = new TextFieldWithBrowseButton(); - scriptPathField.addBrowseFolderListener( - "Select Betlang Script", - "Select the Betlang script to run", - project, - FileChooserDescriptorFactory.createSingleFileDescriptor("bet") - ); - - argumentsField = new JBTextField(); - - workingDirectoryField = new TextFieldWithBrowseButton(); - workingDirectoryField.addBrowseFolderListener( - "Select Working Directory", - "Select the working directory for the script", - project, - FileChooserDescriptorFactory.createSingleFolderDescriptor() - ); - - sampleCountSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 1000000, 1)); - - useSeedCheckbox = new JBCheckBox("Use fixed seed for reproducibility"); - - seedSpinner = new JSpinner(new SpinnerNumberModel(0L, Long.MIN_VALUE, Long.MAX_VALUE, 1L)); - seedSpinner.setEnabled(false); - - useSeedCheckbox.addActionListener(e -> seedSpinner.setEnabled(useSeedCheckbox.isSelected())); - - panel = FormBuilder.createFormBuilder() - .addLabeledComponent(new JBLabel("Script:"), scriptPathField, 1, false) - .addLabeledComponent(new JBLabel("Arguments:"), argumentsField, 1, false) - .addLabeledComponent(new JBLabel("Working directory:"), workingDirectoryField, 1, false) - .addSeparator() - .addLabeledComponent(new JBLabel("Sample count:"), sampleCountSpinner, 1, false) - .addComponent(useSeedCheckbox, 1) - .addLabeledComponent(new JBLabel("Random seed:"), seedSpinner, 1, false) - .addComponentFillVertically(new JPanel(), 0) - .getPanel(); - } - - @Override - protected void resetEditorFrom(@NotNull BetlangRunConfiguration config) { - scriptPathField.setText(config.getScriptPath()); - argumentsField.setText(config.getArguments()); - workingDirectoryField.setText(config.getWorkingDirectory()); - sampleCountSpinner.setValue(config.getSampleCount()); - useSeedCheckbox.setSelected(config.getUseSeed()); - seedSpinner.setValue(config.getRandomSeed()); - seedSpinner.setEnabled(config.getUseSeed()); - } - - @Override - protected void applyEditorTo(@NotNull BetlangRunConfiguration config) { - config.setScriptPath(scriptPathField.getText()); - config.setArguments(argumentsField.getText()); - config.setWorkingDirectory(workingDirectoryField.getText()); - config.setSampleCount((Integer) sampleCountSpinner.getValue()); - config.setUseSeed(useSeedCheckbox.isSelected()); - config.setRandomSeed((Long) seedSpinner.getValue()); - } - - @Override - protected @NotNull JComponent createEditor() { - return panel; - } -} diff --git a/editors/jetbrains/src/main/resources/META-INF/plugin.xml b/editors/jetbrains/src/main/resources/META-INF/plugin.xml deleted file mode 100644 index 8ae4dfb..0000000 --- a/editors/jetbrains/src/main/resources/META-INF/plugin.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - com.hyperpolymath.betlang - Betlang - - Hyperpolymath - - - Betlang Language Support -

Language support for Betlang - a ternary probabilistic programming language.

- -

Features

-
    -
  • Syntax highlighting
  • -
  • Error checking and diagnostics
  • -
  • Code completion
  • -
  • Hover documentation
  • -
  • Go to definition
  • -
  • Find references
  • -
  • Code formatting
  • -
  • Integrated REPL
  • -
- -

Quick Start

-

Create a file with .bet or .betlang extension and start coding!

- -
-let choice = bet { "heads", "tails", "edge" }
-println(choice)
-        
- ]]>
- - 0.1.0 -
    -
  • Initial release
  • -
  • LSP-based language support
  • -
  • Syntax highlighting
  • -
  • Basic error checking
  • -
- ]]>
- - com.intellij.modules.platform - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/editors/jetbrains/src/main/resources/icons/betlang.svg b/editors/jetbrains/src/main/resources/icons/betlang.svg deleted file mode 100644 index 1b66a6e..0000000 --- a/editors/jetbrains/src/main/resources/icons/betlang.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/editors/jetbrains/src/main/resources/icons/repl.svg b/editors/jetbrains/src/main/resources/icons/repl.svg deleted file mode 100644 index 4ae1431..0000000 --- a/editors/jetbrains/src/main/resources/icons/repl.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/editors/jetbrains/src/main/resources/messages/BetlangBundle.properties b/editors/jetbrains/src/main/resources/messages/BetlangBundle.properties deleted file mode 100644 index 0296472..0000000 --- a/editors/jetbrains/src/main/resources/messages/BetlangBundle.properties +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: MIT OR Apache-2.0 -# Betlang plugin message bundle - -notification.group.betlang=Betlang Notifications diff --git a/editors/vscode/README.md b/editors/vscode/README.md new file mode 100644 index 0000000..96667a1 --- /dev/null +++ b/editors/vscode/README.md @@ -0,0 +1,36 @@ + + +# Betlang for Visual Studio Code + +Language support for [Betlang](https://github.com/hyperpolymath/betlang) — a +ternary probabilistic programming language. + +## Features + +- Syntax highlighting (TextMate grammar, `syntaxes/betlang.tmLanguage.json`) +- Language Server Protocol client — spawns `bet-lsp` for diagnostics, + completion, and hover +- Commands: Start/Stop REPL, Evaluate Selection, Restart Language Server + +## Implementation + +The extension is written in **AffineScript** (`src/extension.affine`), per the +hyperpolymath language policy under which AffineScript replaces +ReScript/TypeScript for editor tooling. It compiles to `out/extension.cjs`, +which `package.json`'s `main` field points to: + +```bash +affinescript compile src/extension.affine -o out/extension.cjs --vscode-extension +# or +npm run compile +``` + +Requires the [AffineScript compiler](https://github.com/hyperpolymath/affinescript). + +> History: the previous ReScript implementation (`Extension.res` / `VSCode.res`) +> was removed 2026-06-02 when the extension was migrated to AffineScript. + +## Settings + +- `betlang.lspPath` — path to the `bet-lsp` executable (default: `bet-lsp`) +- `betlang.enableDiagnostics`, `betlang.enableCompletion`, `betlang.enableHover` diff --git a/editors/vscode/deno.json b/editors/vscode/deno.json index 27fbfdb..15a605e 100644 --- a/editors/vscode/deno.json +++ b/editors/vscode/deno.json @@ -2,14 +2,11 @@ "name": "betlang", "version": "0.1.0", "tasks": { - "vscode:prepublish": "rescript build", - "compile": "rescript build", - "watch": "rescript build -w", - "clean": "rescript clean" + "vscode:prepublish": "affinescript compile src/extension.affine -o out/extension.cjs --vscode-extension", + "compile": "affinescript compile src/extension.affine -o out/extension.cjs --vscode-extension", + "clean": "rm -rf out" }, "imports": { - "vscode-languageclient": "npm:vscode-languageclient@^9.0.0", - "@rescript/core": "npm:@rescript/core@^1.5.0", - "rescript": "^12.0.0" + "vscode-languageclient": "npm:vscode-languageclient@^9.0.0" } } \ No newline at end of file diff --git a/editors/vscode/lib/bs/.bsbuild b/editors/vscode/lib/bs/.bsbuild deleted file mode 100644 index deec221..0000000 --- a/editors/vscode/lib/bs/.bsbuild +++ /dev/null @@ -1,6 +0,0 @@ -2 -VSCode -Extension -src -1 -0 diff --git a/editors/vscode/lib/bs/.bsdeps b/editors/vscode/lib/bs/.bsdeps deleted file mode 100644 index b868eb6..0000000 --- a/editors/vscode/lib/bs/.bsdeps +++ /dev/null @@ -1,8 +0,0 @@ -11.1.4 -/var$REPOS_DIR/betlang/editors/vscode -0 -0 -rescript.json 0x1.a5fb25b059f1fp+30 -src 0x1.a5fb263114802p+30 -=== -/var$REPOS_DIR/betlang/editors/vscode/node_modules/rescript/linux/rescript.exe 0x1.a5fb24e7d80eep+30 diff --git a/editors/vscode/lib/bs/.ninja_log b/editors/vscode/lib/bs/.ninja_log deleted file mode 100644 index 4af46d8..0000000 --- a/editors/vscode/lib/bs/.ninja_log +++ /dev/null @@ -1,17 +0,0 @@ -# ninja log v6 -0 11 1769916729972994723 src/Extension.ast 1af734de227b8cd3 -11 13 1769916729975994833 src/Extension.d d0f74cf13a79f8ea -0 9 1769916773855607876 src/VSCode.ast d32b497bd7dcc62c -9 12 1769916773858607986 src/VSCode.d c8f900368ee47a85 -0 10 1769916785210025271 src/VSCode.ast e73f23a16009449a -0 11 1769916785211025308 src/Extension.ast b99667c40dc47c55 -10 13 1769916785210025271 src/VSCode.d c8f900368ee47a85 -11 13 1769916785211025308 src/Extension.d d0f74cf13a79f8ea -13 25 1769916785225025822 src/VSCode.cmj 20220ad1f8003a50 -13 25 1769916785225025822 src/VSCode.cmi 20220ad1f8003a50 -13 25 1769916785225025822 ../../src/VSCode.res.js 20220ad1f8003a50 -0 9 1769916822444394030 src/Extension.ast b99667c40dc47c55 -9 11 1769916822444394030 src/Extension.d d0f74cf13a79f8ea -11 26 1769916822461394655 src/Extension.cmj 5f3dff5f5ff6033 -11 26 1769916822461394655 src/Extension.cmi 5f3dff5f5ff6033 -11 26 1769916822461394655 ../../src/Extension.res.js 5f3dff5f5ff6033 diff --git a/editors/vscode/lib/bs/.sourcedirs.json b/editors/vscode/lib/bs/.sourcedirs.json deleted file mode 100644 index acda895..0000000 --- a/editors/vscode/lib/bs/.sourcedirs.json +++ /dev/null @@ -1 +0,0 @@ -{ "dirs" : [ "src" ] , "pkgs" : [] , "generated" : [] } \ No newline at end of file diff --git a/editors/vscode/lib/bs/build.ninja b/editors/vscode/lib/bs/build.ninja deleted file mode 100644 index 0c8e828..0000000 --- a/editors/vscode/lib/bs/build.ninja +++ /dev/null @@ -1,16 +0,0 @@ -rescript = 1 -rule astj - command = /var$REPOS_DIR/betlang/editors/vscode/node_modules/rescript/linux/bsc.exe -warn-error +101 -bs-v 11.1.4 -uncurried -absname -bs-ast -o $out $i -o src/VSCode.ast : astj ../../src/VSCode.res -rule deps - command = /var$REPOS_DIR/betlang/editors/vscode/node_modules/rescript/linux/bsb_helper.exe -hash 01f137aa28e8f6a8e6efabc3fd6f6c1c $in - restat = 1 -o src/VSCode.d : deps src/VSCode.ast -rule mij - command = /var$REPOS_DIR/betlang/editors/vscode/node_modules/rescript/linux/bsc.exe -I src -warn-error +101 -uncurried -bs-package-name betlang-vscode -bs-package-output esmodule:$in_d:.res.js $i - dyndep = 1 - restat = 1 -o src/VSCode.cmj src/VSCode.cmi ../../src/VSCode.res.js : mij src/VSCode.ast -o src/Extension.ast : astj ../../src/Extension.res -o src/Extension.d : deps src/Extension.ast -o src/Extension.cmj src/Extension.cmi ../../src/Extension.res.js : mij src/Extension.ast diff --git a/editors/vscode/lib/bs/install.ninja b/editors/vscode/lib/bs/install.ninja deleted file mode 100644 index b09f15e..0000000 --- a/editors/vscode/lib/bs/install.ninja +++ /dev/null @@ -1,14 +0,0 @@ -rescript = 1 -rule cp - command = cp $i $out -rule touch - command = touch $out -o VSCode.cmi : cp ../bs/src/VSCode.cmi -o VSCode.cmj : cp ../bs/src/VSCode.cmj -o VSCode.cmt : cp ../bs/src/VSCode.cmt -o VSCode.res : cp ../../src/VSCode.res -o Extension.cmi : cp ../bs/src/Extension.cmi -o Extension.cmj : cp ../bs/src/Extension.cmj -o Extension.cmt : cp ../bs/src/Extension.cmt -o Extension.res : cp ../../src/Extension.res -build install.stamp : touch VSCode.cmi VSCode.cmj Extension.cmi Extension.cmj diff --git a/editors/vscode/lib/bs/src/Extension.ast b/editors/vscode/lib/bs/src/Extension.ast deleted file mode 100644 index 0d67267..0000000 Binary files a/editors/vscode/lib/bs/src/Extension.ast and /dev/null differ diff --git a/editors/vscode/lib/bs/src/Extension.cmi b/editors/vscode/lib/bs/src/Extension.cmi deleted file mode 100644 index c0878d2..0000000 Binary files a/editors/vscode/lib/bs/src/Extension.cmi and /dev/null differ diff --git a/editors/vscode/lib/bs/src/Extension.cmj b/editors/vscode/lib/bs/src/Extension.cmj deleted file mode 100644 index 3b7c5bf..0000000 Binary files a/editors/vscode/lib/bs/src/Extension.cmj and /dev/null differ diff --git a/editors/vscode/lib/bs/src/Extension.cmt b/editors/vscode/lib/bs/src/Extension.cmt deleted file mode 100644 index 314fc9a..0000000 Binary files a/editors/vscode/lib/bs/src/Extension.cmt and /dev/null differ diff --git a/editors/vscode/lib/bs/src/Extension.d b/editors/vscode/lib/bs/src/Extension.d deleted file mode 100644 index 47e8f2d..0000000 --- a/editors/vscode/lib/bs/src/Extension.d +++ /dev/null @@ -1 +0,0 @@ -src/Extension.cmj : src/VSCode.cmj src/VSCode.cmi diff --git a/editors/vscode/lib/bs/src/VSCode.ast b/editors/vscode/lib/bs/src/VSCode.ast deleted file mode 100644 index 1df9d29..0000000 Binary files a/editors/vscode/lib/bs/src/VSCode.ast and /dev/null differ diff --git a/editors/vscode/lib/bs/src/VSCode.cmi b/editors/vscode/lib/bs/src/VSCode.cmi deleted file mode 100644 index c5e7093..0000000 Binary files a/editors/vscode/lib/bs/src/VSCode.cmi and /dev/null differ diff --git a/editors/vscode/lib/bs/src/VSCode.cmj b/editors/vscode/lib/bs/src/VSCode.cmj deleted file mode 100644 index 0be2959..0000000 Binary files a/editors/vscode/lib/bs/src/VSCode.cmj and /dev/null differ diff --git a/editors/vscode/lib/bs/src/VSCode.cmt b/editors/vscode/lib/bs/src/VSCode.cmt deleted file mode 100644 index fc8cd31..0000000 Binary files a/editors/vscode/lib/bs/src/VSCode.cmt and /dev/null differ diff --git a/editors/vscode/lib/bs/src/VSCode.d b/editors/vscode/lib/bs/src/VSCode.d deleted file mode 100644 index e69de29..0000000 diff --git a/editors/vscode/out/extension.js b/editors/vscode/out/extension.js deleted file mode 100644 index a358378..0000000 --- a/editors/vscode/out/extension.js +++ /dev/null @@ -1,159 +0,0 @@ -"use strict"; -// SPDX-License-Identifier: MIT OR Apache-2.0 -// Betlang VSCode Extension -// Thin wrapper that spawns the bet-lsp language server -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -exports.activate = activate; -exports.deactivate = deactivate; -const vscode = __importStar(require("vscode")); -const node_1 = require("vscode-languageclient/node"); -let client; -let outputChannel; -function activate(context) { - outputChannel = vscode.window.createOutputChannel('Betlang'); - outputChannel.appendLine('Betlang extension activating...'); - // Start the language client - startLanguageClient(context); - // Register commands - context.subscriptions.push(vscode.commands.registerCommand('betlang.startRepl', startRepl), vscode.commands.registerCommand('betlang.stopRepl', stopRepl), vscode.commands.registerCommand('betlang.evalSelection', evalSelection), vscode.commands.registerCommand('betlang.restartServer', () => restartServer(context))); - outputChannel.appendLine('Betlang extension activated'); -} -function startLanguageClient(context) { - const config = vscode.workspace.getConfiguration('betlang'); - const lspPath = config.get('lspPath', 'bet-lsp'); - // Server options - spawn the LSP server - const serverOptions = { - run: { - command: lspPath, - transport: node_1.TransportKind.stdio - }, - debug: { - command: lspPath, - transport: node_1.TransportKind.stdio, - options: { - env: { ...process.env, RUST_BACKTRACE: '1' } - } - } - }; - // Client options - const clientOptions = { - documentSelector: [ - { scheme: 'file', language: 'betlang' } - ], - synchronize: { - fileEvents: vscode.workspace.createFileSystemWatcher('**/*.{bet,betlang}') - }, - outputChannel: outputChannel, - initializationOptions: { - enableDiagnostics: config.get('enableDiagnostics', true), - enableCompletion: config.get('enableCompletion', true), - enableHover: config.get('enableHover', true) - } - }; - // Create and start the client - client = new node_1.LanguageClient('betlang', 'Betlang Language Server', serverOptions, clientOptions); - client.start().then(() => { - outputChannel.appendLine('Language server started'); - }).catch((error) => { - outputChannel.appendLine(`Failed to start language server: ${error}`); - vscode.window.showErrorMessage(`Failed to start Betlang language server. Make sure 'bet-lsp' is installed and in your PATH.`); - }); - context.subscriptions.push(client); -} -async function restartServer(context) { - outputChannel.appendLine('Restarting language server...'); - if (client) { - await client.stop(); - } - startLanguageClient(context); -} -async function startRepl() { - if (!client) { - vscode.window.showErrorMessage('Language server not running'); - return; - } - try { - const result = await client.sendRequest('betlang/repl/start', {}); - outputChannel.appendLine(`REPL started: ${JSON.stringify(result)}`); - vscode.window.showInformationMessage('Betlang REPL started'); - } - catch (error) { - vscode.window.showErrorMessage(`Failed to start REPL: ${error}`); - } -} -async function stopRepl() { - if (!client) { - return; - } - try { - await client.sendRequest('betlang/repl/stop', {}); - outputChannel.appendLine('REPL stopped'); - vscode.window.showInformationMessage('Betlang REPL stopped'); - } - catch (error) { - vscode.window.showErrorMessage(`Failed to stop REPL: ${error}`); - } -} -async function evalSelection() { - const editor = vscode.window.activeTextEditor; - if (!editor || !client) { - return; - } - const selection = editor.selection; - const code = selection.isEmpty - ? editor.document.lineAt(selection.start.line).text - : editor.document.getText(selection); - if (!code.trim()) { - return; - } - try { - const result = await client.sendRequest('betlang/eval', { code }); - outputChannel.appendLine(`> ${code}`); - outputChannel.appendLine(result.result || ''); - outputChannel.show(true); - } - catch (error) { - outputChannel.appendLine(`Error: ${error}`); - outputChannel.show(true); - } -} -function deactivate() { - if (!client) { - return undefined; - } - return client.stop(); -} -//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/editors/vscode/out/extension.js.map b/editors/vscode/out/extension.js.map deleted file mode 100644 index 58be70c..0000000 --- a/editors/vscode/out/extension.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";AAAA,6CAA6C;AAC7C,2BAA2B;AAC3B,uDAAuD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAavD,4BAgBC;AA0HD,gCAKC;AA1JD,+CAAiC;AACjC,qDAKoC;AAEpC,IAAI,MAAkC,CAAC;AACvC,IAAI,aAAmC,CAAC;AAExC,SAAgB,QAAQ,CAAC,OAAgC;IACrD,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAC7D,aAAa,CAAC,UAAU,CAAC,iCAAiC,CAAC,CAAC;IAE5D,4BAA4B;IAC5B,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAE7B,oBAAoB;IACpB,OAAO,CAAC,aAAa,CAAC,IAAI,CACtB,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,mBAAmB,EAAE,SAAS,CAAC,EAC/D,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,kBAAkB,EAAE,QAAQ,CAAC,EAC7D,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,uBAAuB,EAAE,aAAa,CAAC,EACvE,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CACzF,CAAC;IAEF,aAAa,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAgC;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAS,SAAS,EAAE,SAAS,CAAC,CAAC;IAEzD,wCAAwC;IACxC,MAAM,aAAa,GAAkB;QACjC,GAAG,EAAE;YACD,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,oBAAa,CAAC,KAAK;SACjC;QACD,KAAK,EAAE;YACH,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,oBAAa,CAAC,KAAK;YAC9B,OAAO,EAAE;gBACL,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE;aAC/C;SACJ;KACJ,CAAC;IAEF,iBAAiB;IACjB,MAAM,aAAa,GAA0B;QACzC,gBAAgB,EAAE;YACd,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;SAC1C;QACD,WAAW,EAAE;YACT,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,uBAAuB,CAAC,oBAAoB,CAAC;SAC7E;QACD,aAAa,EAAE,aAAa;QAC5B,qBAAqB,EAAE;YACnB,iBAAiB,EAAE,MAAM,CAAC,GAAG,CAAU,mBAAmB,EAAE,IAAI,CAAC;YACjE,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAU,kBAAkB,EAAE,IAAI,CAAC;YAC/D,WAAW,EAAE,MAAM,CAAC,GAAG,CAAU,aAAa,EAAE,IAAI,CAAC;SACxD;KACJ,CAAC;IAEF,8BAA8B;IAC9B,MAAM,GAAG,IAAI,qBAAc,CACvB,SAAS,EACT,yBAAyB,EACzB,aAAa,EACb,aAAa,CAChB,CAAC;IAEF,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACrB,aAAa,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,aAAa,CAAC,UAAU,CAAC,oCAAoC,KAAK,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAC1B,6FAA6F,CAChG,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,OAAgC;IACzD,aAAa,CAAC,UAAU,CAAC,+BAA+B,CAAC,CAAC;IAE1D,IAAI,MAAM,EAAE,CAAC;QACT,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,SAAS;IACpB,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,6BAA6B,CAAC,CAAC;QAC9D,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;QAClE,aAAa,CAAC,UAAU,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;AACL,CAAC;AAED,KAAK,UAAU,QAAQ;IACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAClD,aAAa,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa;IACxB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;IAC9C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACrB,OAAO;IACX,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACnC,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO;QAC1B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI;QACnD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACf,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,aAAa,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACtC,aAAa,CAAC,UAAU,CAAE,MAAc,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC;QAClE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,aAAa,CAAC,UAAU,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;QAC5C,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACL,CAAC;AAED,SAAgB,UAAU;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"} \ No newline at end of file diff --git a/editors/vscode/package.json b/editors/vscode/package.json index f9d2f35..0e59c52 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -26,7 +26,7 @@ "activationEvents": [ "onLanguage:betlang" ], - "main": "./src/Extension.res.js", + "main": "./out/extension.cjs", "contributes": { "languages": [ { @@ -110,16 +110,13 @@ ] }, "scripts": { - "vscode:prepublish": "rescript build", - "compile": "rescript build", - "watch": "rescript build -w", - "clean": "rescript clean" - }, - "devDependencies": { - "rescript": "^12.0.0" + "vscode:prepublish": "npm run compile", + "compile": "affinescript compile src/extension.affine -o out/extension.cjs --vscode-extension", + "watch": "echo 'watch mode not implemented for AffineScript source — re-run npm run compile'", + "clean": "rm -rf out" }, + "devDependencies": {}, "dependencies": { - "vscode-languageclient": "^9.0.0", - "@rescript/core": "^1.5.0" + "vscode-languageclient": "^9.0.0" } } diff --git a/editors/vscode/rescript.json b/editors/vscode/rescript.json deleted file mode 100644 index 32710a2..0000000 --- a/editors/vscode/rescript.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "betlang-vscode", - "version": "0.1.0", - "sources": [ - { - "dir": "src", - "subdirs": true - } - ], - "package-specs": [ - { - "module": "esmodule", - "in-source": true - } - ], - "suffix": ".res.js", - "bs-dependencies": [], - "warnings": { - "error": "+101" - } -} diff --git a/editors/vscode/src/Extension.res b/editors/vscode/src/Extension.res deleted file mode 100644 index d87e7b4..0000000 --- a/editors/vscode/src/Extension.res +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// Betlang VSCode Extension - ReScript Implementation -// Thin wrapper that spawns the bet-lsp language server - -open VSCode - -let client: ref> = ref(None) - -let startLanguageClient = (context: extensionContext) => { - let config = Workspace.getConfiguration("betlang") - let serverPath = switch Workspace.get(config, "lspPath") { - | Some(path) => path - | None => "bet-lsp" - } - - let serverOptions: LanguageClient.serverOptions = { - run: { - command: serverPath, - transport: Stdio, - }, - debug: { - command: serverPath, - transport: Stdio, - options: {env: Js.Dict.fromArray([("RUST_BACKTRACE", "1")])}, - }, - } - - let clientOptions: LanguageClient.clientOptions = { - documentSelector: [{scheme: "file", language: "betlang"}], - synchronize: { - fileEvents: Workspace.createFileSystemWatcher("**/*.{bet,betlang}"), - }, - } - - let languageClient = LanguageClient.make( - "betlang", - "Betlang Language Server", - serverOptions, - clientOptions, - ) - - client := Some(languageClient) - let _ = LanguageClient.start(languageClient) - () -} - -let restartServer = (context: extensionContext) => { - switch client.contents { - | Some(c) => - let _ = LanguageClient.stop(c) - startLanguageClient(context) - | None => startLanguageClient(context) - } -} - -let activate = (context: extensionContext) => { - startLanguageClient(context) - - // Register commands - let restartCmd = Commands.registerCommand("betlang.restartServer", () => - Js.Promise.make((~resolve, ~reject as _) => { - restartServer(context) - resolve(.) - }) - ) - let replStartCmd = Commands.registerCommand("betlang.startRepl", () => - Js.Promise.make((~resolve, ~reject as _) => { - let _ = Window.showInformationMessage("REPL not yet implemented") - resolve(.) - }) - ) - let replStopCmd = Commands.registerCommand("betlang.stopRepl", () => - Js.Promise.make((~resolve, ~reject as _) => { - let _ = Window.showInformationMessage("REPL not yet implemented") - resolve(.) - }) - ) - let evalCmd = Commands.registerCommand("betlang.evalSelection", () => - Js.Promise.make((~resolve, ~reject as _) => { - let _ = Window.showInformationMessage("Eval not yet implemented") - resolve(.) - }) - ) - - let _ = Js.Array2.push(context.subscriptions, restartCmd) - let _ = Js.Array2.push(context.subscriptions, replStartCmd) - let _ = Js.Array2.push(context.subscriptions, replStopCmd) - let _ = Js.Array2.push(context.subscriptions, evalCmd) - () -} - -let deactivate = () => { - switch client.contents { - | Some(c) => Some(LanguageClient.stop(c)) - | None => None - } -} diff --git a/editors/vscode/src/Extension.res.js b/editors/vscode/src/Extension.res.js deleted file mode 100644 index b784308..0000000 --- a/editors/vscode/src/Extension.res.js +++ /dev/null @@ -1,107 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as Vscode from "vscode"; -import * as Js_dict from "rescript/lib/es6/js_dict.js"; -import * as Caml_option from "rescript/lib/es6/caml_option.js"; -import * as $$Node from "vscode-languageclient/node"; - -var client = { - contents: undefined -}; - -function startLanguageClient(context) { - var config = Vscode.workspace.getConfiguration("betlang"); - var path = config.get("lspPath"); - var serverPath = path !== undefined ? path : "bet-lsp"; - var serverOptions_run = { - command: serverPath, - transport: 0 - }; - var serverOptions_debug = { - command: serverPath, - transport: 0, - options: { - env: Js_dict.fromArray([[ - "RUST_BACKTRACE", - "1" - ]]) - } - }; - var serverOptions = { - run: serverOptions_run, - debug: serverOptions_debug - }; - var clientOptions_documentSelector = [{ - scheme: "file", - language: "betlang" - }]; - var clientOptions_synchronize = { - fileEvents: Vscode.workspace.createFileSystemWatcher("**/*.{bet,betlang}") - }; - var clientOptions = { - documentSelector: clientOptions_documentSelector, - synchronize: clientOptions_synchronize - }; - var languageClient = new $$Node.LanguageClient("betlang", "Betlang Language Server", serverOptions, clientOptions); - client.contents = Caml_option.some(languageClient); - languageClient.start(); -} - -function restartServer(context) { - var c = client.contents; - if (c !== undefined) { - Caml_option.valFromOption(c).stop(); - return startLanguageClient(context); - } else { - return startLanguageClient(context); - } -} - -function activate(context) { - startLanguageClient(context); - var restartCmd = Vscode.commands.registerCommand("betlang.restartServer", (function () { - return new Promise((function (resolve, param) { - restartServer(context); - resolve(); - })); - })); - var replStartCmd = Vscode.commands.registerCommand("betlang.startRepl", (function () { - return new Promise((function (resolve, param) { - Vscode.window.showInformationMessage("REPL not yet implemented"); - resolve(); - })); - })); - var replStopCmd = Vscode.commands.registerCommand("betlang.stopRepl", (function () { - return new Promise((function (resolve, param) { - Vscode.window.showInformationMessage("REPL not yet implemented"); - resolve(); - })); - })); - var evalCmd = Vscode.commands.registerCommand("betlang.evalSelection", (function () { - return new Promise((function (resolve, param) { - Vscode.window.showInformationMessage("Eval not yet implemented"); - resolve(); - })); - })); - context.subscriptions.push(restartCmd); - context.subscriptions.push(replStartCmd); - context.subscriptions.push(replStopCmd); - context.subscriptions.push(evalCmd); -} - -function deactivate() { - var c = client.contents; - if (c !== undefined) { - return Caml_option.some(Caml_option.valFromOption(c).stop()); - } - -} - -export { - client , - startLanguageClient , - restartServer , - activate , - deactivate , -} -/* vscode Not a pure module */ diff --git a/editors/vscode/src/VSCode.res b/editors/vscode/src/VSCode.res deleted file mode 100644 index 7ee3614..0000000 --- a/editors/vscode/src/VSCode.res +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -// VSCode API bindings for ReScript - -type disposable -type fileSystemWatcher - -type extensionContext = { - subscriptions: array, -} - -module Workspace = { - type configuration - - @module("vscode") @scope("workspace") - external getConfiguration: string => configuration = "getConfiguration" - - @send external get: (configuration, string) => option = "get" - - @module("vscode") @scope("workspace") - external createFileSystemWatcher: string => fileSystemWatcher = "createFileSystemWatcher" -} - -module Window = { - @module("vscode") @scope("window") - external showInformationMessage: string => promise> = "showInformationMessage" - - @module("vscode") @scope("window") - external showErrorMessage: string => promise> = "showErrorMessage" -} - -module Commands = { - @module("vscode") @scope("commands") - external registerCommand: (string, unit => promise) => disposable = "registerCommand" -} - -module LanguageClient = { - type transportKind = | @as(0) Stdio - - type optionsType = {env?: Js.Dict.t} - - type runOptions = { - command: string, - transport: transportKind, - options?: optionsType, - } - - type serverOptions = { - run: runOptions, - debug: runOptions, - } - - type documentFilter = { - scheme: string, - language: string, - } - - type synchronizeOptions = {fileEvents: fileSystemWatcher} - - type clientOptions = { - documentSelector: array, - synchronize: synchronizeOptions, - } - - type t - - @module("vscode-languageclient/node") @new - external make: (string, string, serverOptions, clientOptions) => t = "LanguageClient" - - @send external start: t => promise = "start" - @send external stop: t => promise = "stop" -} diff --git a/editors/vscode/src/VSCode.res.js b/editors/vscode/src/VSCode.res.js deleted file mode 100644 index 4ff6a20..0000000 --- a/editors/vscode/src/VSCode.res.js +++ /dev/null @@ -1,18 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - - -var Workspace = {}; - -var $$Window = {}; - -var Commands = {}; - -var LanguageClient = {}; - -export { - Workspace , - $$Window , - Commands , - LanguageClient , -} -/* No side effect */ diff --git a/editors/vscode/src/extension.affine b/editors/vscode/src/extension.affine new file mode 100644 index 0000000..c69429e --- /dev/null +++ b/editors/vscode/src/extension.affine @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +// +// Betlang VS Code extension — AffineScript source of truth. +// +// Compiles to editors/vscode/out/extension.cjs via: +// affinescript compile editors/vscode/src/extension.affine \ +// -o editors/vscode/out/extension.cjs --vscode-extension +// The .cjs is what package.json's `main` field points to. +// +// Replaces the previous ReScript implementation (Extension.res / VSCode.res, +// removed 2026-06-02) per the hyperpolymath language policy, under which +// AffineScript replaces ReScript/TypeScript for editor tooling. The +// extension is a thin wrapper that spawns the `bet-lsp` language server and +// registers the Betlang editor commands. + +use Vscode::{ + registerCommand, + getConfiguration, + workspaceConfigGetString, + showInformationMessage, + showWarningMessage, + pushSubscription, + consoleLog, + execSync, + stringConcat +}; +use VscodeLanguageClient::{ + newLanguageClient, + languageClientStart +}; + +// ── Command handlers ─────────────────────────────────────────────────── +// +// The REPL / eval commands are stubs today (behavioural parity with the +// previous ReScript implementation); they surface an informational message +// until the REPL bridge lands. + +pub fn handler_start_repl() -> Int { + let _ = showInformationMessage("REPL not yet implemented"); + return 0; +} + +pub fn handler_stop_repl() -> Int { + let _ = showInformationMessage("REPL not yet implemented"); + return 0; +} + +pub fn handler_eval_selection() -> Int { + let _ = showInformationMessage("Eval not yet implemented"); + return 0; +} + +pub fn handler_restart_server() -> Int { + // Best-effort: a full restart needs the ExtensionContext we no longer + // hold here. Reloading the window re-fires `activate`, which restarts + // the language client. + let _ = showInformationMessage("Betlang LSP stopped (reload window to restart)"); + return 0; +} + +// ── LSP startup ───────────────────────────────────────────────────────── + +fn start_lsp() -> Int { + let cfg = getConfiguration("betlang"); + let server_path = workspaceConfigGetString(cfg, "lspPath", "bet-lsp"); + let probe_cmd = stringConcat("which ", server_path); + let which_rc = execSync(probe_cmd); + if which_rc != 0 { + let _ = showWarningMessage("Betlang LSP server (bet-lsp) not found. Language features disabled."); + return 1; + } + let client = newLanguageClient( + "betlang", + "Betlang Language Server", + server_path, + "", // no extra args (newline-separated list) + 0 // 0 = stdio transport + ); + let _ = languageClientStart(client); + let _ = showInformationMessage("Betlang Language Server started"); + return 0; +} + +// ── Lifecycle ──────────────────────────────────────────────────────────── + +pub fn activate(ctx: ExtensionContext) -> Int { + let _ = consoleLog("Betlang extension activated"); + + // Register commands. Each handler is a function value (no brittle + // wasm-table indices); the lambda takes the explicit `Unit` param and + // delegates to the named handler. + let _ = pushSubscription(ctx, registerCommand("betlang.startRepl", fn(u: Unit) => handler_start_repl())); + let _ = pushSubscription(ctx, registerCommand("betlang.stopRepl", fn(u: Unit) => handler_stop_repl())); + let _ = pushSubscription(ctx, registerCommand("betlang.evalSelection", fn(u: Unit) => handler_eval_selection())); + let _ = pushSubscription(ctx, registerCommand("betlang.restartServer", fn(u: Unit) => handler_restart_server())); + + let _ = start_lsp(); + return 0; +} + +pub fn deactivate() -> Int { + return 0; +} diff --git a/examples/probabilistic-structures.rkt b/examples/probabilistic-structures.rkt index 0e272e1..a38eb0e 100644 --- a/examples/probabilistic-structures.rkt +++ b/examples/probabilistic-structures.rkt @@ -233,7 +233,7 @@ (treap-insert t x))) (displayln (format " Inserted keys: 5 3 7 2 4 6 8 1 9")) -(displayln (format " Treap height: ~a (expected ~log₂(9) ≈ 3-4)" +(displayln (format " Treap height: ~a (expected ~~log₂(9) ≈ 3-4)" (treap-height my-treap))) (displayln "\n=== Probabilistic Data Structures Complete ===") diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index dfb05c6..49a086c 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -10,11 +10,14 @@ cargo-fuzz = true [dependencies] libfuzzer-sys = "0.4" -[dependencies.betlang] -path = ".." - [[bin]] name = "fuzz_main" path = "fuzz_targets/fuzz_main.rs" test = false doc = false + +# Keep the fuzz crate out of the root workspace (cargo-fuzz convention). +# An empty [workspace] table makes this its own workspace root so that +# `cargo fuzz build` (run from .clusterfuzzlite/build.sh) does not error +# "current package believes it's in a workspace when it's not". +[workspace] diff --git a/lib/optimization.rkt b/lib/optimization.rkt index e1738c5..f0cf4c9 100644 --- a/lib/optimization.rkt +++ b/lib/optimization.rkt @@ -4,6 +4,10 @@ ;; Optimization Algorithms with Probabilistic Elements +;; Only export algorithms that are actually implemented below. The +;; following were declared but never defined and have been removed from +;; the provide list: gradient-descent-stochastic, differential-evolution, +;; tabu-search, ant-colony, firefly-algorithm, golden-section-search. (provide simulated-annealing genetic-algorithm particle-swarm @@ -11,19 +15,13 @@ random-search evolutionary-strategy cross-entropy-method - gradient-descent-stochastic - differential-evolution - tabu-search - ant-colony - firefly-algorithm - ternary-search - golden-section-search) + ternary-search) ;; Simulated Annealing (define (simulated-annealing objective initial temp-schedule max-iter neighbor-fn) (let loop ([current initial] [current-score (objective initial)] - [best current] + [best initial] [best-score (objective initial)] [iter 0]) (if (>= iter max-iter) @@ -88,8 +86,8 @@ [gen 0]) (if (>= gen generations) (let* ([fitnesses (map fitness population)] - [best-idx (argmax identity (range (length fitnesses)) - #:key (lambda (i) (list-ref fitnesses i)))]) + [best-idx (argmax (lambda (i) (list-ref fitnesses i)) + (range (length fitnesses)))]) (list (list-ref population best-idx) (list-ref fitnesses best-idx))) (let* ([fitnesses (map fitness population)] @@ -179,11 +177,11 @@ (for/list ([i (in-range n-samples)]) (sample-fn))) (define scores (map objective samples)) - (define best-idx (argmax identity (range n-samples) #:key (lambda (i) (list-ref scores i)))) + (define best-idx (argmax (lambda (i) (list-ref scores i)) (range n-samples))) (list (list-ref samples best-idx) (list-ref scores best-idx))) ;; Evolutionary Strategy (ES) -(define (evolutionary-strategy objective dim mu lambda sigma max-gen bounds) +(define (evolutionary-strategy objective dim mu lambda-size sigma max-gen bounds) (define (random-individual) (for/list ([i (in-range dim)]) (+ (first bounds) (* (random) (- (second bounds) (first bounds)))))) @@ -193,17 +191,17 @@ [gen 0]) (if (>= gen max-gen) (let* ([scores (map objective population)] - [best-idx (argmax identity (range mu) #:key (lambda (i) (list-ref scores i)))]) + [best-idx (argmax (lambda (i) (list-ref scores i)) (range mu))]) (list (list-ref population best-idx) (list-ref scores best-idx))) (let* ([offspring - (for/list ([i (in-range lambda)]) + (for/list ([i (in-range lambda-size)]) (define parent (list-ref population (random mu))) (for/list ([gene parent]) (+ gene (* sigma (- (random) 0.5)))))] [all-individuals (append population offspring)] [all-scores (map objective all-individuals)] [sorted-indices - (sort (range (+ mu lambda)) + (sort (range (+ mu lambda-size)) > #:key (lambda (i) (list-ref all-scores i)))] [new-pop (for/list ([i (in-range mu)]) (list-ref all-individuals (list-ref sorted-indices i)))]) diff --git a/lib/sampling.rkt b/lib/sampling.rkt index bd3ed75..29030d8 100644 --- a/lib/sampling.rkt +++ b/lib/sampling.rkt @@ -14,8 +14,6 @@ adaptive-rejection-sampling slice-sampling hamiltonian-monte-carlo - parallel-tempering - nested-sampling ternary-sampling antithetic-variates control-variates diff --git a/repl/shell.rkt b/repl/shell.rkt index 253b962..3c11c12 100644 --- a/repl/shell.rkt +++ b/repl/shell.rkt @@ -1,5 +1,9 @@ #lang racket -(require racket/readline racket/format racket/pretty) +;; Note: racket/readline (interactive line-editing) lives in the separate +;; readline-lib package, which is absent from minimal Racket installs (e.g. +;; CI). It was imported but never used here — input is read via plain +;; `(read)` — so it is dropped to keep the REPL loadable everywhere. +(require racket/format racket/pretty) (require "../core/betlang.rkt") (require "../lib/statistics.rkt") (require "../lib/combinators.rkt")