Skip to content

feat(vscode): function-value callback ABI — registerCommand/onDidSave/withProgress (Refs #199)#201

Merged
hyperpolymath merged 1 commit into
mainfrom
stage-b/fn-value-callback-abi
May 18, 2026
Merged

feat(vscode): function-value callback ABI — registerCommand/onDidSave/withProgress (Refs #199)#201
hyperpolymath merged 1 commit into
mainfrom
stage-b/fn-value-callback-abi

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

#199 PR-5a — function-value callback ABI

Owner chose the function-value ABI. Replaces the brittle wasm-table-index handler: Int convention with real function values.

ABI shape decision (no compiler change)

handler: fn(Unit) -> R, not fn() -> R. AffineScript deliberately types a zero-param function as its bare return type (typecheck.ml:752), so fn() -> Int collapses to Int and won't unify. The explicit Unit param is the honest realisation and needs zero compiler change (verified). Full rationale in #199.

Change

  • stdlib/Vscode.affine: registerCommand / onDidSaveTextDocument / withProgressNotification handler params Int → fn(Unit) -> R. Also removes the duplicate extern type Thenable; introduced in feat(stdlib): async-extern binding surface — Thenable + withProgress/sendRequest (Refs #103) #198 (line 43 already declares it) — resolved at source.
  • examples/vscode_extension_minimal.affine + editors/vscode/src/extension.affine: call sites migrated from numbered table indices to fn(u: Unit) => handler_x() lambdas. Behaviour-preserving — the named handler functions are unchanged.

Verification

  • stdlib / example / editors extension all typecheck.
  • dune test --force 253/253. (A transient Examples-parse failure was my own _u typo — leading-underscore identifiers parse-error as params; a separate minor lexer observation, used u.)
  • Deno-ESM emits registerCommand("…", ((u) => handler_0())) — a real JS arrow passed directly. So the Deno fn-value extern path (PR-5b) needs no codegen change and is proven here.

Follow-ups

  • PR-5c: wasm mod.js marshalling (wrapHandler currently expects an Int table index; now receives a function value).
  • PR-5d: rsr-certifier pilot restore (now unblocked — withProgress takes a function).

Refs #199

…/withProgress (Refs #199)

#199 PR-5a (owner chose the function-value ABI). Replaces the brittle
wasm-table-index `handler: Int` convention with real function values.

ABI shape: `handler: fn(Unit) -> R` (not `fn() -> R`). AffineScript
types a zero-param function as its bare return type (typecheck.ml:752),
so `fn() -> Int` collapses to `Int`; the explicit `Unit` param is the
honest callback shape and needs zero compiler change (verified).

- stdlib/Vscode.affine: registerCommand / onDidSaveTextDocument /
  withProgressNotification handler params Int -> fn(Unit) -> R. Also
  removes the duplicate `extern type Thenable;` introduced in #198
  (line 43 already declares it) — resolved at source.
- examples/vscode_extension_minimal.affine + editors/vscode/src/
  extension.affine: call sites migrated from numbered indices to
  `fn(u: Unit) => handler_x()` lambdas (behaviour-preserving; named
  handlers unchanged).

Verified: stdlib/example/editors all typecheck; dune test 253/253
(the prior Examples-parse regression was my own `_u` typo — leading-
underscore idents parse-error in params, a separate minor lexer
observation; used `u`). Deno-ESM emits
`registerCommand("…", ((u) => handler_0()))` — a real JS arrow passed
directly, so the Deno fn-value extern path (PR-5b) needs no codegen
change. Wasm/mod.js marshalling (PR-5c) and the rsr-certifier pilot
(PR-5d) follow.

Refs #199

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 18, 2026 07:45
@hyperpolymath hyperpolymath merged commit 1e7dfc7 into main May 18, 2026
11 of 12 checks passed
@hyperpolymath hyperpolymath deleted the stage-b/fn-value-callback-abi branch May 18, 2026 07:45
hyperpolymath added a commit that referenced this pull request May 18, 2026
…es (Refs #199) (#202)

PR-5c. After PR-5a (#201) the function-value callback ABI passes a
handler as a closure pointer, not a bare __indirect_function_table
index. wrapHandler still did tbl.get(idx)() — wrong on the wasm path
(it would index the table with a heap pointer).

wrapHandler now reads the 8-byte closure pair from exported memory
([i32 function_id @ +0][i32 env_ptr @ +4], per codegen.ml), looks the
compiled lambda up by function_id in __indirect_function_table, and
invokes it with env_ptr as the first argument (the closure calling
convention, codegen.ml:794), zero-filling any further declared params
(the `Unit` handler arg) via fn.length. Returns the handler's result.

registerCommand / onDidSaveTextDocument call sites unchanged; the
now-misnamed `handlerIdx` params renamed to `handlerPtr`.

JS-only (mod.js is not dune-built — no 253 impact). node --check clean.
Correctness is by construction against the documented closure layout +
calling convention. Unblocks the rsr-certifier pilot (PR-5d).

Refs #199

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
    "type": "banned",
    "file": "AI.a2ml",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Superseded by 0-AI-MANIFEST.a2ml",
    "type": "banned",
    "file": "AI.djot",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant