Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ jobs:
- name: Run codegen WASM tests
run: opam exec -- ./tools/run_codegen_wasm_tests.sh

- name: Run codegen Deno-ESM tests (issue #122)
# Compiles tests/codegen-deno/*.affine with the --deno-esm backend
# and runs the *.harness.mjs under Node (CI has Node 20, not Deno;
# the Phase 1 fixtures are pure logic so Node ESM exercises them).
run: opam exec -- ./tools/run_codegen_deno_tests.sh

- name: Run face-transformer regression tests
run: opam exec -- ./tools/run_face_transformer_tests.sh

Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ htmlcov/
*.bak
*.wasm
/a.out

# issue #122: generated Deno-ESM regression outputs (compiled from the
# committed *.affine fixtures by tools/run_codegen_deno_tests.sh).
/tests/codegen-deno/*.deno.js
# Local-only build workaround (see file header); never committed.
/dune-workspace
49 changes: 43 additions & 6 deletions bin/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@
compilation errors. With [--wasm-gc], targets the WebAssembly GC
proposal instead of WASM 1.0 linear memory. *)
let compile_file face json wasm_gc vscode_ext vscode_adapter vscode_no_lc
path output =
deno_esm path output =
let face = resolve_face ~quiet:json face path in
if json then begin
let diags = ref [] in
Expand Down Expand Up @@ -512,8 +512,9 @@
use the original [prog] because they handle imports natively
via Codegen.gen_imports / the import section. *)
let flat_prog = Affinescript.Module_loader.flatten_imports loader prog in
let is_deno = deno_esm || Filename.check_suffix output ".deno.js" in
let is_julia = Filename.check_suffix output ".jl" in
let is_js = Filename.check_suffix output ".js" in
let is_js = (not is_deno) && Filename.check_suffix output ".js" in
let is_c = Filename.check_suffix output ".c" in
let is_wgsl = Filename.check_suffix output ".wgsl" in
let is_faust = Filename.check_suffix output ".dsp" in
Expand All @@ -534,7 +535,17 @@
let is_why3 = Filename.check_suffix output ".mlw" in
let is_lean = Filename.check_suffix output ".lean" in
let is_spirv = Filename.check_suffix output ".spv" in
if is_julia then begin
if is_deno then begin
match Affinescript.Codegen_deno.codegen_deno flat_prog resolve_ctx.symbols with
| Error msg ->
add { severity = Error; code = "E0824";
message = Printf.sprintf "Deno-ESM codegen error: %s" msg;
span = Affinescript.Span.dummy; help = None; labels = [] }
| Ok esm_code ->
let oc = open_out output in

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: ocaml.lang.portability.crlf-support.prefer-write-in-binary-mode Warning

'open_out' behaves differently on Windows and on Unix-like systems with respect to line endings. To get the same behavior everywhere, use 'open_out_bin' or 'open_out_gen [Open_binary]'. If you really want LF-to-CRLF translations to take place when running on Windows, use 'open_out_gen [Open_text]'.
output_string oc esm_code;
close_out oc
end else if is_julia then begin
match Affinescript.Julia_codegen.codegen_julia flat_prog resolve_ctx.symbols with
| Error msg ->
add { severity = Error; code = "E0800";
Expand Down Expand Up @@ -725,8 +736,9 @@
cross-module imports for backends that don't have native
module-system support. Wasm/Wasm-GC keep the original [prog]. *)
let flat_prog = Affinescript.Module_loader.flatten_imports loader prog in
let is_deno = deno_esm || Filename.check_suffix output ".deno.js" in
let is_julia = Filename.check_suffix output ".jl" in
let is_js = Filename.check_suffix output ".js" in
let is_js = (not is_deno) && Filename.check_suffix output ".js" in
let is_c = Filename.check_suffix output ".c" in
let is_wgsl = Filename.check_suffix output ".wgsl" in
let is_faust = Filename.check_suffix output ".dsp" in
Expand All @@ -747,7 +759,18 @@
let is_why3 = Filename.check_suffix output ".mlw" in
let is_lean = Filename.check_suffix output ".lean" in
let is_spirv = Filename.check_suffix output ".spv" in
if is_julia then
if is_deno then
(match Affinescript.Codegen_deno.codegen_deno flat_prog resolve_ctx.symbols with
| Error e ->
Format.eprintf "@[<v>Deno-ESM codegen error: %s@]@." e;
`Error (false, "Deno-ESM codegen error")
| Ok esm_code ->
let oc = open_out output in

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: ocaml.lang.portability.crlf-support.prefer-write-in-binary-mode Warning

'open_out' behaves differently on Windows and on Unix-like systems with respect to line endings. To get the same behavior everywhere, use 'open_out_bin' or 'open_out_gen [Open_binary]'. If you really want LF-to-CRLF translations to take place when running on Windows, use 'open_out_gen [Open_text]'.
output_string oc esm_code;
close_out oc;
Format.printf "Compiled %s -> %s (Deno-ESM)@." path output;
`Ok ())
else if is_julia then
(match Affinescript.Julia_codegen.codegen_julia flat_prog resolve_ctx.symbols with
| Error e ->
Format.eprintf "@[<v>Julia codegen error: %s@]@." e;
Expand Down Expand Up @@ -1178,6 +1201,20 @@
dependency for extensions that ship no language client; the \
wiring passes null in its place.")

(* Issue #122: --deno-esm. Selects the direct AST -> ES-module backend
({!Affinescript.Codegen_deno}) regardless of output extension, so a
drop-in `.js` ES module can be produced (e.g. `-o src/storage.js
--deno-esm`). A `.deno.js` output extension also routes here without
the flag, as a convenience for the test corpus / ad-hoc use. *)
let deno_esm_arg =
Arg.(value & flag & info ["deno-esm"]
~doc:"Emit a standalone Deno/Node ES module directly from the AST \
(issue #122): `export class` for struct+impl, `export` for \
public fns/consts, and `extern fn` lowered to direct host \
calls (Deno.*Sync / JSON / WebAssembly). No wasm, no require, \
no handle table — the output is a drop-in importable ESM. A \
`.deno.js` output extension selects this backend implicitly.")

(** Shared --face flag: select the parser surface-syntax face. *)
let face_arg =
let faces = Arg.enum [
Expand Down Expand Up @@ -1524,7 +1561,7 @@
let doc = "Compile a file to WebAssembly (1.0 or GC proposal), Julia (.jl), JavaScript (.js), C (.c), a WGSL compute kernel (.wgsl), a Faust DSP program (.dsp), or an ONNX model (.onnx)" in
let info = Cmd.info "compile" ~doc in
Cmd.v info Term.(ret (const compile_file $ face_arg $ json_arg $ wasm_gc_arg
$ vscode_ext_arg $ vscode_adapter_arg $ vscode_no_lc_arg
$ vscode_ext_arg $ vscode_adapter_arg $ vscode_no_lc_arg $ deno_esm_arg
$ path_arg $ output_arg))

let fmt_cmd =
Expand Down
Loading
Loading