Skip to content

Replace nwnsc subprocess with WASM compiler for diagnostics#81

Closed
PhilippeChab wants to merge 2 commits into
mainfrom
compiler-wasm
Closed

Replace nwnsc subprocess with WASM compiler for diagnostics#81
PhilippeChab wants to merge 2 commits into
mainfrom
compiler-wasm

Conversation

@PhilippeChab
Copy link
Copy Markdown
Owner

Summary

PR #62's intent was to migrate from spawning the native nwnsc binary
to the in-process Beamdog nwn_script_comp. This PR accomplishes that
goal but uses a WebAssembly build of the compiler instead, removing
the need for any native subprocess at all.

The WASM build comes from a fork of neverwinter.nim extended with
multi-error recovery, no-entry-point validation, and a clean C API
suitable for Emscripten.

Why WASM over the native binary

  • Multi-error per pass. Reports every diagnostic in the file plus
    its #include'd helpers in a single compile, instead of stopping at
    the first error.
  • Include validation works without a void main. Helper / include
    scripts can be edited and validated as the user types.
  • One artifact, every platform. ~210KB WASM works anywhere Node
    runs. No separate Linux/Mac/Windows binaries to ship, no platform
    detection, no shell: true / powershell.exe quirks.
  • In-process. No spawn / stdout parsing, no per-keystroke
    process startup overhead.

What changed

  • server/wasm/nwscript_compiler.{js,wasm} — replaced with the new
    WASM build (~210KB, was ~308KB).
  • server/src/Providers/DiagnosticsProvider.ts — rewritten:
    • Loads the WASM once on first publish.
    • Per publish, creates a compiler instance, sets
      collect-all-errors and require-entry-point=false, runs compile,
      drains the captured-error vector.
    • Resolver callback consults a per-call cache then asks the
      workspace file system for any name the compiler requests, so
      nwscript.nss and #included files are picked up automatically.
    • Errors that fire inside an include get routed to that include's
      own URI when we can resolve it, so the squiggle lands on the file
      that actually contains the bug.
    • Pre-seeds empty diagnostic lists for the target plus all
      transitive includes, so fixing an error clears the squiggle
      immediately.
  • Removed: spawn(child_process) machinery,
    getExecutablePath / hasSupportedOS, nwnsc flag construction
    (-y -c -l -r -h -n -i), the line-by-line stdout parser.
  • Kept (no-op for backwards compat with existing settings.json):
    compiler.os, compiler.nwnHome, compiler.nwnInstallation,
    compiler.reportWarnings.

What's left in place for safety

  • server/resources/compiler/{linux,mac,windows}/nwnsc* — the native
    binaries are no longer referenced but kept on the branch so this
    PR can be reverted cleanly if the WASM approach hits a snag.

Once the WASM approach is verified in the wild, those ~13MB of
binaries can be deleted in a follow-up.

Test plan

  • yarn compile:server passes (verified locally).
  • yarn buildServer produces a working bundle (verified locally).
  • Open a workspace with a broken .nss, confirm squiggles appear.
  • Verify multi-error diagnostics: a file with three type errors
    on three separate lines should show three squiggles in one pass.
  • Verify include validation: editing a helper file (no void main)
    produces diagnostics directly, no longer requires the file to be
    imported by a main script.
  • Verify per-include error routing: an error in lib.nss reached
    via #include "lib" from main.nss shows on lib.nss.
  • Verify clean state: fixing an error clears the squiggle.

🤖 Generated with Claude Code

PR #62's intent was to migrate from spawning the native nwnsc binary
to the in-process Beamdog nwn_script_comp; this commit accomplishes
that goal but uses our WebAssembly build instead, which:

  - has multi-error recovery (one compile pass, every diagnostic in
    the file plus its #include'd helpers)
  - has no entry-point requirement (helper / include scripts can be
    edited and validated without a void main)
  - is ~210KB (vs 4-5MB native binary per platform)
  - works on every platform that runs Node, no separate Linux/Mac/
    Windows binaries to ship

DiagnosticsProvider rewritten:

  - Loads server/wasm/nwscript_compiler.{js,wasm} once on first use.
  - Per publish, creates a fresh compiler instance, sets
    collect-all-errors and require-entry-point=false, runs compile,
    drains the captured-error vector.
  - Resolver callback consults a per-call cache first then asks the
    workspace file system for any name the compiler requests, so
    nwscript.nss and #include'd files are picked up automatically.
  - Errors that fire inside an include are routed to the include's
    own URI (when we can resolve it via the workspace) rather than
    being attached to the file we were asked to check; the user
    sees the squiggle on the file that actually contains the bug.
  - Pre-seeds an empty diagnostic list for the target plus all
    transitive includes, so fixing an error clears the squiggle
    immediately.

Removed:

  - spawn(child_process) machinery
  - getExecutablePath / hasSupportedOS - the WASM is platform-neutral
  - nwnsc command-line flag construction (-y -c -l -r -h -n -i)
  - stdout/stderr line-by-line parser (replaced by the
    collected-errors API)

The compiler config keeps `enabled` and `verbose`; `os`, `nwnHome`,
`nwnInstallation`, `reportWarnings` are now no-ops (kept in
Config.ts for backwards-compat with any user settings.json that
sets them).

server/resources/compiler/{linux,mac,windows}/ binaries are no
longer referenced; left in place so this commit can be reverted
cleanly if the WASM approach hits a snag.
@PhilippeChab
Copy link
Copy Markdown
Owner Author

Replaced by a clean PR from a branch off main. The original branch was based on top of an unrelated AST-tokenization commit, dragging that whole change into the diff.

@PhilippeChab PhilippeChab deleted the compiler-wasm branch May 2, 2026 19:44
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