Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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