Compare commits
19
Commits
2dffdf112c
...
idk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80164acb96 | ||
|
|
1c7322614c | ||
|
|
81a136fcf2 | ||
|
|
be1d7566f4 | ||
|
|
fab29f6fce | ||
|
|
7ab98341b9 | ||
|
|
2f471ae4b1 | ||
|
|
57defed077 | ||
|
|
0ba49ed85c | ||
|
|
33fb0f831c | ||
|
|
8120e21eae | ||
|
|
6774c08efb | ||
|
|
530a6934ba | ||
|
|
e2e287079c | ||
|
|
a97a0ad7bb | ||
|
|
9334373f96 | ||
|
|
aa5b45ec76 | ||
|
|
85d34883a6 | ||
|
|
f09a63f11c |
+3
-1
@@ -2,4 +2,6 @@
|
|||||||
. ((eval
|
. ((eval
|
||||||
. (progn (defun apply-cabal-fmt-h ()
|
. (progn (defun apply-cabal-fmt-h ()
|
||||||
(haskell-mode-buffer-apply-command "cabal-fmt"))
|
(haskell-mode-buffer-apply-command "cabal-fmt"))
|
||||||
(add-hook 'before-save-hook #'apply-cabal-fmt-h nil t))))))
|
(add-hook 'before-save-hook #'apply-cabal-fmt-h nil t)
|
||||||
|
(add-to-list 'haskell-font-lock-quasi-quote-modes
|
||||||
|
'("cps" . scheme-mode)))))))
|
||||||
|
|||||||
@@ -15,3 +15,9 @@ XXXX XXXX XXXX XXXX XXXX XXXX XXXX XX00
|
|||||||
zero indicates a 30-bit fixnum /
|
zero indicates a 30-bit fixnum /
|
||||||
in the upper bits
|
in the upper bits
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
|
| type/value | low bits |
|
||||||
|
|------------+----------|
|
||||||
|
| small int | 0 |
|
||||||
|
| ~false~ | 01 |
|
||||||
|
| ~true~ | 11 |
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#+title: Gyehoek Scheme
|
||||||
|
|
||||||
|
#+begin_center
|
||||||
|
(this document is written in present tense as if the project is complete, but Gyehoek is a work-in-progress.)
|
||||||
|
#+end_center
|
||||||
|
|
||||||
|
Gyehoek is an R⁷RS-compliant Scheme compiler targeting WebAssembly 3.0, relying principally on the recently standardised garbage collector and tail call proposals. the Gyehoek compiler is implemented in Haskell, and the Gyehoek runtime is a Rust program providing primitive routines and WebAssembly execution via the Wasmtime library.
|
||||||
|
|
||||||
|
primitives are implemented as native Rust functions made available to the guest by Wasmtime. in the future, it would be ideal to provide the primitives as a WASI interface to help decouple ourselves from a specific Wasm runtime, but it is not a priority.
|
||||||
|
|
||||||
|
Gyehoek allows separate compilation, ~eval~, first-class continuations, and so on.
|
||||||
|
|
||||||
|
* pipeline
|
||||||
|
|
||||||
|
a Scheme program's journey through Gyehoek is as follows:
|
||||||
|
1. read (source code → Scheme data)
|
||||||
|
2. parse (Scheme data → AST)
|
||||||
|
3. expand(?) (AST → AST)
|
||||||
|
4. contify (AST → CPS)
|
||||||
|
5. close (CPS → CPS)
|
||||||
|
6. lower (CPS → Wasm)
|
||||||
|
|
||||||
|
** read
|
||||||
|
|
||||||
|
in the read phase, Gyehoek's reader serialises textual source code into a sequence of tokens, which are then parsed into S-expressions. this phase is completely agnostic towards any interpretation of the data — it's just data, not code (yet). this distinction between reading and parsing is made so that the reader can easily be shared amongst many parsers, allowing convenient definition of human-readable representations for all sorts of compiler internals. Gyehoek's intermediate languages and WebAssembly text format are of particular interest.
|
||||||
|
|
||||||
|
the reader may be configured to extend R⁷RS's syntax with a special "antiquotation" notation, used internally in the compiler to elegantly interpolate and splice S-expression literals via Haskell's quasiquotation.
|
||||||
|
#+begin_src haskell
|
||||||
|
let meta = 123 :: Int
|
||||||
|
in [sx|(a b c #{meta} d)|] -- ⇒ (a b c 123 d)
|
||||||
|
|
||||||
|
let metas = ["c","d"] :: List Text
|
||||||
|
in [sx|(a b ##{metas} e f)|] -- ⇒ (a b "c" "d" e f)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Gyehoek's lexer and parser are generated by Alex and Happy, respectively.
|
||||||
|
|
||||||
|
unless otherwise noted, the term "parse" will be used in reference to the phase taking S-expressions to ASTs, while "read" refers to the combined Alex/Happy process. if the tokenisation process (Alex) must be distinguished from the "parse" process (Happy), the former is called "lexical analysis" and the latter "syntactic analysis."
|
||||||
|
|
||||||
|
** parse
|
||||||
|
|
||||||
|
- use invertible-grammar library
|
||||||
|
|
||||||
|
** expand
|
||||||
|
|
||||||
|
** contify
|
||||||
|
|
||||||
|
- procedures are distinguished from continuations, and procedure applications are distinguished from continuation jumps.
|
||||||
|
- all continuations and lambda will be named i think. the exception is continuations for primitive calls.
|
||||||
|
|
||||||
|
** close
|
||||||
|
|
||||||
|
** lower
|
||||||
Generated
+16
@@ -66,6 +66,21 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"crane": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1784248371,
|
||||||
|
"narHash": "sha256-0l0Y4D4wbZhp1Oi6h8OpbLtIm/4FN88oCf54MK2ZgiM=",
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"rev": "f7d151ec0bf52cf9662e2f59d7bea28588c2f070",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ipetkov",
|
||||||
|
"repo": "crane",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -587,6 +602,7 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"crane": "crane",
|
||||||
"haskellNix": "haskellNix",
|
"haskellNix": "haskellNix",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"haskellNix",
|
"haskellNix",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
url = "git+https://git.deertopia.net/msyds/sydpkgs";
|
url = "git+https://git.deertopia.net/msyds/sydpkgs";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
crane.url = "github:ipetkov/crane";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, sydpkgs, haskellNix, ... }@inputs:
|
outputs = { self, nixpkgs, sydpkgs, haskellNix, ... }@inputs:
|
||||||
@@ -16,13 +17,13 @@
|
|||||||
"x86_64-darwin" "x86_64-linux"
|
"x86_64-darwin" "x86_64-linux"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
overlays = [
|
overlays = [
|
||||||
haskellNix.overlay
|
haskellNix.overlay
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
gyehoek-wasmtime-wrapper = final.callPackage ./wasmtime.nix {};
|
shake-wrapper = final.callPackage ./shake-wrapper.nix {};
|
||||||
})
|
gyehoek-runtime = final.callPackage ./runtime {
|
||||||
(final: prev: {
|
crane-lib = inputs.crane.mkLib final;
|
||||||
|
};
|
||||||
gyehoek = final.haskell-nix.project' {
|
gyehoek = final.haskell-nix.project' {
|
||||||
src = ./.;
|
src = ./.;
|
||||||
compiler-nix-name = "ghc912";
|
compiler-nix-name = "ghc912";
|
||||||
@@ -30,32 +31,32 @@
|
|||||||
packages.gyehoek.components.tests.test.preCheck =
|
packages.gyehoek.components.tests.test.preCheck =
|
||||||
let
|
let
|
||||||
bin = [
|
bin = [
|
||||||
pkgs.gyehoek-wasmtime-wrapper
|
pkgs.git # tasty uses git diff
|
||||||
pkgs.git
|
|
||||||
];
|
];
|
||||||
in ''
|
in ''
|
||||||
# Wasmtime requires a cache in $HOME. This is less
|
export GYEHOEK_RUNTIME=${lib.getExe final.gyehoek-runtime}
|
||||||
# painful than reconfiguring the cache location.
|
|
||||||
export HOME=$(mktemp -d)
|
|
||||||
export PATH=${lib.makeBinPath bin}:$PATH
|
export PATH=${lib.makeBinPath bin}:$PATH
|
||||||
'';
|
'';
|
||||||
})];
|
})];
|
||||||
shell = {
|
shell = {
|
||||||
withHoogle = true;
|
withHoogle = true;
|
||||||
inputsFrom = [];
|
inputsFrom = [
|
||||||
|
final.gyehoek-runtime
|
||||||
|
];
|
||||||
tools = {
|
tools = {
|
||||||
cabal = {};
|
cabal = {};
|
||||||
haskell-language-server = {};
|
haskell-language-server = {};
|
||||||
};
|
};
|
||||||
buildInputs = with final; [
|
buildInputs = with final; [
|
||||||
haskellPackages.cabal-fmt
|
haskellPackages.cabal-fmt
|
||||||
self.packages.${final.stdenv.hostPlatform.system}.shake
|
shake-wrapper
|
||||||
final.wabt
|
wabt
|
||||||
final.nodejs
|
nodejs
|
||||||
final.wasm-tools
|
wasm-tools
|
||||||
final.wac-cli
|
wac-cli
|
||||||
final.guile
|
guile
|
||||||
final.gyehoek-wasmtime-wrapper
|
rust-analyzer
|
||||||
|
wasmtime
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -87,7 +88,7 @@
|
|||||||
hf.packages.${system} // lib.fix (packages: {
|
hf.packages.${system} // lib.fix (packages: {
|
||||||
gyehoek = hf.packages.${system}."gyehoek:exe:gyehoek";
|
gyehoek = hf.packages.${system}."gyehoek:exe:gyehoek";
|
||||||
default = packages.gyehoek;
|
default = packages.gyehoek;
|
||||||
shake = pkgs.callPackage ./shake-wrapper.nix {};
|
inherit (pkgs) gyehoek-runtime shake-wrapper;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
devShells = each-system
|
devShells = each-system
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
;; apply `f' to `x' twice.
|
||||||
|
((λ (f x)
|
||||||
|
(f (f x)))
|
||||||
|
(λ (x) (+ x 4))
|
||||||
|
9)
|
||||||
@@ -1,5 +1,2 @@
|
|||||||
ret > ExitSuccess
|
ret > ExitSuccess
|
||||||
out > 22
|
out > 22
|
||||||
out >
|
|
||||||
err > warning: using `--invoke` with a function that returns values is experimental and may break in the future
|
|
||||||
err >
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
(module
|
|
||||||
(type $heap-object (sub (struct (field (mut i32)))))
|
|
||||||
(func
|
|
||||||
(param)
|
|
||||||
(result (ref eq))
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(i32.const 3)
|
|
||||||
(i32.const 2)
|
|
||||||
i32.shl
|
|
||||||
ref.i31
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
(i32.const 4)
|
|
||||||
(i32.const 2)
|
|
||||||
i32.shl
|
|
||||||
ref.i31
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
i32.mul
|
|
||||||
ref.i31
|
|
||||||
(local.set 0)
|
|
||||||
(i32.const 2)
|
|
||||||
(i32.const 2)
|
|
||||||
i32.shl
|
|
||||||
ref.i31
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
(i32.const 5)
|
|
||||||
(i32.const 2)
|
|
||||||
i32.shl
|
|
||||||
ref.i31
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
i32.mul
|
|
||||||
ref.i31
|
|
||||||
(local.set 1)
|
|
||||||
(local.get 0)
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
(local.get 1)
|
|
||||||
(ref.cast (ref i31))
|
|
||||||
i31.get_s
|
|
||||||
i32.add
|
|
||||||
ref.i31
|
|
||||||
(local.set 2)
|
|
||||||
(local.get 2))
|
|
||||||
(export "main" (func 0)))
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > #f
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#f
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > 128
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
(((λ (f) f) (λ (x) (* x 4))) 32)
|
||||||
@@ -1,5 +1,2 @@
|
|||||||
ret > ExitSuccess
|
ret > ExitSuccess
|
||||||
out > 555
|
out > 555
|
||||||
out >
|
|
||||||
err > warning: using `--invoke` with a function that returns values is experimental and may break in the future
|
|
||||||
err >
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
(module
|
|
||||||
(type (sub (struct (field (mut i32)))))
|
|
||||||
(func
|
|
||||||
(param)
|
|
||||||
(result (ref eq))
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(i32.const 0)
|
|
||||||
ref.i31
|
|
||||||
(if
|
|
||||||
(result i32)
|
|
||||||
(then (i32.const 777) ref.i31)
|
|
||||||
(else (i32.const 555) ref.i31)))
|
|
||||||
(export "main" (func 0)))
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > 777
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
(if 123 777 555)
|
||||||
@@ -1,5 +1,2 @@
|
|||||||
ret > ExitSuccess
|
ret > ExitSuccess
|
||||||
out > 777
|
out > 777
|
||||||
out >
|
|
||||||
err > warning: using `--invoke` with a function that returns values is experimental and may break in the future
|
|
||||||
err >
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
(module
|
|
||||||
(type (sub (struct (field (mut i32)))))
|
|
||||||
(func
|
|
||||||
(param)
|
|
||||||
(result (ref eq))
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(i32.const 1)
|
|
||||||
ref.i31
|
|
||||||
(if
|
|
||||||
(result i32)
|
|
||||||
(then (i32.const 777) ref.i31)
|
|
||||||
(else (i32.const 555) ref.i31)))
|
|
||||||
(export "main" (func 0)))
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > #<procedure>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > 25
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ret > ExitSuccess
|
||||||
|
out > #t
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#t
|
||||||
+33
-18
@@ -25,6 +25,11 @@ common ghcstuffs
|
|||||||
default-extensions:
|
default-extensions:
|
||||||
BlockArguments
|
BlockArguments
|
||||||
DeriveGeneric
|
DeriveGeneric
|
||||||
|
DerivingVia
|
||||||
|
DuplicateRecordFields
|
||||||
|
NoFieldSelectors
|
||||||
|
OrPatterns
|
||||||
|
OverloadedLabels
|
||||||
OverloadedRecordDot
|
OverloadedRecordDot
|
||||||
OverloadedStrings
|
OverloadedStrings
|
||||||
PartialTypeSignatures
|
PartialTypeSignatures
|
||||||
@@ -34,9 +39,8 @@ common ghcstuffs
|
|||||||
executable gyehoek
|
executable gyehoek
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, base ^>=4.21.2.0
|
, base ^>=4.21.2.0
|
||||||
, gyehoek
|
, gyehoek
|
||||||
|
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
@@ -44,25 +48,25 @@ executable gyehoek
|
|||||||
|
|
||||||
library
|
library
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
ghc-options: -fplugin=Effectful.Plugin
|
ghc-options: -fplugin=Effectful.Plugin
|
||||||
|
|
||||||
-- cabal-fmt: expand src
|
-- cabal-fmt: expand src
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Gyehoek.CPS.Convert
|
Gyehoek.CPS.Convert
|
||||||
Gyehoek.CPS.Lower
|
Gyehoek.CPS.Lower
|
||||||
Gyehoek.CPS.Syntax
|
Gyehoek.CPS.Syntax
|
||||||
|
Gyehoek.Driver
|
||||||
Gyehoek.GenSym
|
Gyehoek.GenSym
|
||||||
Gyehoek.Options
|
Gyehoek.Options
|
||||||
Gyehoek.Scheme.Syntax
|
Gyehoek.Scheme.Syntax
|
||||||
Gyehoek.Sexp
|
Gyehoek.Sexp
|
||||||
Gyehoek.Wasm
|
Gyehoek.Wasm
|
||||||
Gyehoek.Driver
|
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, base ^>=4.21.2.0
|
, base ^>=4.21.2.0
|
||||||
, binary
|
, binary
|
||||||
, containers
|
, containers
|
||||||
, cradle
|
, typed-process
|
||||||
, effectful
|
, effectful
|
||||||
, effectful-core
|
, effectful-core
|
||||||
, effectful-plugin
|
, effectful-plugin
|
||||||
@@ -74,30 +78,41 @@ library
|
|||||||
, megaparsec
|
, megaparsec
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
|
, pretty-simple
|
||||||
, prettyprinter
|
, prettyprinter
|
||||||
, process
|
, process
|
||||||
, recursion-schemes
|
, recursion-schemes
|
||||||
, sexp-grammar
|
, sexp-grammar
|
||||||
|
, string-interpolate
|
||||||
, template-haskell
|
, template-haskell
|
||||||
, text
|
, text
|
||||||
, text-short
|
, text-short
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, vector
|
, vector
|
||||||
, string-interpolate
|
, bytestring
|
||||||
, pretty-simple
|
|
||||||
|
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: GHC2024
|
default-language: GHC2024
|
||||||
|
|
||||||
test-suite test
|
test-suite test
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
build-depends: base
|
other-modules:
|
||||||
, gyehoek
|
Gyehoek.Test.CPS.Syntax
|
||||||
, filepath
|
Gyehoek.Test.Golden
|
||||||
, tasty
|
Gyehoek.Test.Sexp
|
||||||
, tasty-silver
|
|
||||||
, directory
|
build-depends:
|
||||||
default-language: GHC2024
|
, base
|
||||||
|
, directory
|
||||||
|
, filepath
|
||||||
|
, gyehoek
|
||||||
|
, process-extras
|
||||||
|
, sexp-grammar
|
||||||
|
, tasty
|
||||||
|
, tasty-hunit
|
||||||
|
, tasty-silver
|
||||||
|
|
||||||
|
default-language: GHC2024
|
||||||
|
|||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script>
|
|
||||||
const imports = {
|
|
||||||
guppy: {
|
|
||||||
print: (arg) => console.log (arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch("u.wasm")
|
|
||||||
.then((response) => response.arrayBuffer())
|
|
||||||
.then((bytes) => WebAssembly.instantiate(bytes, imports))
|
|
||||||
.then((results) => {
|
|
||||||
results.instance.exports.main ();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
target/
|
||||||
Generated
+1935
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "gyehoek-runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.6.1", features = ["derive"] }
|
||||||
|
clio = { version = "0.3.5", features = ["clap-parse"] }
|
||||||
|
memoize = "0.6.0"
|
||||||
|
wasmtime = "46.0.1"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{ rustPlatform
|
||||||
|
, lib
|
||||||
|
, crane-lib
|
||||||
|
}:
|
||||||
|
|
||||||
|
crane-lib.buildPackage (lib.fix (finalAttrs: {
|
||||||
|
pname = "gyehoek-runtime";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./.;
|
||||||
|
# cargoLock = ./Cargo.lock;
|
||||||
|
doCheck = true;
|
||||||
|
meta.mainProgram = "gyehoek-runtime";
|
||||||
|
}))
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
use wasmtime::*;
|
||||||
|
use crate::internal as scm;
|
||||||
|
use crate::internal::{Scm,Immediate,HeapObject};
|
||||||
|
|
||||||
|
// pub fn small_fixnum_p (_)
|
||||||
|
|
||||||
|
// pub fn immediate_p (caller : Caller<'_, u32>, x : EqRef) -> EqRef {
|
||||||
|
// x.is_i31 ()
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn write_immediate (_caller : Caller<'_, u32>, imm : Immediate) {
|
||||||
|
match imm {
|
||||||
|
Immediate::SmallFixnum (n) => print! ("{}", n),
|
||||||
|
Immediate::Bool (b) => print! ("{}", if b { "#t" } else { "#f" }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write (caller : Caller<'_, u32>, x : Rooted<EqRef>) {
|
||||||
|
match scm::interpret (&caller, x).unwrap ().unwrap () {
|
||||||
|
Scm::Immediate (x) => write_immediate (caller, x),
|
||||||
|
Scm::HeapObject (x) => write_heap_object (caller, x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_heap_object (_caller : Caller<'_, u32>, x : HeapObject) {
|
||||||
|
match x {
|
||||||
|
HeapObject::Procedure => print! ("#<procedure>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truthy_p (caller : Caller<'_, u32>, x : Rooted<EqRef>,) -> u32 {
|
||||||
|
let r = scm::interpret (&caller, x).unwrap ().unwrap ();
|
||||||
|
if let Scm::Immediate (Immediate::Bool (false)) = r {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
use wasmtime::*;
|
||||||
|
use crate::types;
|
||||||
|
|
||||||
|
pub fn immediate_p (store : impl AsContext, x : Rooted<EqRef>) -> bool {
|
||||||
|
x.is_i31 (store).unwrap ()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Immediate {
|
||||||
|
SmallFixnum (i32),
|
||||||
|
Bool (bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum HeapObject {
|
||||||
|
Procedure
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Scm {
|
||||||
|
Immediate (Immediate),
|
||||||
|
HeapObject (HeapObject),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(nonstandard_style)]
|
||||||
|
pub type scm_bits = u32;
|
||||||
|
|
||||||
|
#[allow(nonstandard_style)]
|
||||||
|
pub const scm_false : scm_bits = 0b01;
|
||||||
|
#[allow(nonstandard_style)]
|
||||||
|
pub const scm_true : scm_bits = 0b11;
|
||||||
|
|
||||||
|
pub fn interpret_immediate (x : scm_bits) -> Option<Immediate> {
|
||||||
|
if x & 1 == 0 {
|
||||||
|
Some (Immediate::SmallFixnum ((x >> 1).try_into ().unwrap ()))
|
||||||
|
} else if x == scm_true {
|
||||||
|
Some (Immediate::Bool (true))
|
||||||
|
} else if x == scm_false {
|
||||||
|
Some (Immediate::Bool (false))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interpret_heap_object (
|
||||||
|
store : impl AsContext,
|
||||||
|
x : Rooted<EqRef>
|
||||||
|
) -> Result<Option<HeapObject>> {
|
||||||
|
if x.matches_ty (&store, &types::closure (&store)?)? {
|
||||||
|
Ok (Some (HeapObject::Procedure))
|
||||||
|
} else {
|
||||||
|
todo! ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interpret (
|
||||||
|
store : impl AsContext,
|
||||||
|
x : Rooted<EqRef>
|
||||||
|
) -> Result<Option<Scm>> {
|
||||||
|
if let Some (imm) = x.as_i31 (&store)? {
|
||||||
|
Ok (
|
||||||
|
interpret_immediate (imm.get_u32 ())
|
||||||
|
.map (Scm::Immediate)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Ok (
|
||||||
|
interpret_heap_object (&store, x)?
|
||||||
|
.map (Scm::HeapObject)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_immediate (
|
||||||
|
store : impl AsContext,
|
||||||
|
imm : Immediate
|
||||||
|
) -> scm_bits {
|
||||||
|
use Immediate::*;
|
||||||
|
match imm {
|
||||||
|
SmallFixnum (n) => (n << 1).try_into ().unwrap (),
|
||||||
|
Bool (false) => scm_false,
|
||||||
|
Bool (true) => scm_true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode (store : impl AsContextMut, x : Scm) -> Rooted<EqRef> {
|
||||||
|
match x {
|
||||||
|
Scm::Immediate (imm) => {
|
||||||
|
let i31 = I31::new_u32 (encode_immediate (&store, imm))
|
||||||
|
.unwrap ();
|
||||||
|
EqRef::from_i31 (store, i31)
|
||||||
|
}
|
||||||
|
Scm::HeapObject (ho) => {
|
||||||
|
todo! ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_bool (store : impl AsContextMut, b : bool) -> Rooted<EqRef> {
|
||||||
|
let x = if b { scm_true } else { scm_false };
|
||||||
|
let i31 = I31::new_u32 (x).unwrap ();
|
||||||
|
EqRef::from_i31 (store, i31)
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
mod gyehoek;
|
||||||
|
mod internal;
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::io::Read;
|
||||||
|
use clio::*;
|
||||||
|
use clap::Parser;
|
||||||
|
use wasmtime::*;
|
||||||
|
|
||||||
|
/// A runtime for Gyehoek scheme.
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(name = "gyehoek", version, about, long_about = None)]
|
||||||
|
struct Args {
|
||||||
|
/// Path to Wasm binary or textual source
|
||||||
|
#[clap(value_parser)]
|
||||||
|
wasm: Input,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<R : Read> (mut rdr : R) -> io::Result<Vec<u8>> {
|
||||||
|
let mut buf = vec! [];
|
||||||
|
rdr.read_to_end (&mut buf)?;
|
||||||
|
Ok (buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config () -> Config {
|
||||||
|
let mut cfg = Config::new ();
|
||||||
|
cfg.wasm_reference_types (true);
|
||||||
|
cfg.wasm_function_references (true);
|
||||||
|
cfg.wasm_tail_call (true);
|
||||||
|
cfg.wasm_gc (true);
|
||||||
|
cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link_primitives (linker : &mut Linker<u32>) -> wasmtime::Result<()> {
|
||||||
|
linker.func_wrap ("gyehoek", "write", gyehoek::write)?;
|
||||||
|
linker.func_wrap ("gyehoek", "truthy?", gyehoek::truthy_p)?;
|
||||||
|
Ok (())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main () -> wasmtime::Result<()> {
|
||||||
|
let args = Args::parse ();
|
||||||
|
let wasm_config = get_config ();
|
||||||
|
let engine = Engine::new (&wasm_config)?;
|
||||||
|
let module = Module::new (&engine, read (args.wasm)?)?;
|
||||||
|
let mut linker = Linker::new (&engine);
|
||||||
|
link_primitives (&mut linker)?;
|
||||||
|
let mut store : Store<u32> = Store::new (&engine, 4);
|
||||||
|
let instance = linker.instantiate (&mut store, &module)?;
|
||||||
|
let main = instance.get_typed_func::<(),()> (&mut store, "main")?;
|
||||||
|
main.call (&mut store, ())?;
|
||||||
|
Ok (())
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use wasmtime::*;
|
||||||
|
use memoize::memoize;
|
||||||
|
|
||||||
|
pub fn heap_object_struct (store : impl AsContext) -> Result<StructType> {
|
||||||
|
let ctx = store.as_context ();
|
||||||
|
let engine = ctx.engine ();
|
||||||
|
Ok (
|
||||||
|
StructType::with_finality_and_supertype (
|
||||||
|
engine,
|
||||||
|
Finality::NonFinal,
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
hash_field ()
|
||||||
|
]
|
||||||
|
)?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn heap_object (_store : impl AsContext) -> Result<HeapType> {
|
||||||
|
todo! ()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[memoize]
|
||||||
|
pub fn hash_field () -> FieldType {
|
||||||
|
FieldType::new (
|
||||||
|
Mutability::Var,
|
||||||
|
StorageType::ValType (ValType::I32)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn closure (store : impl AsContext) -> Result<HeapType> {
|
||||||
|
let ctx = store.as_context ();
|
||||||
|
let engine = ctx.engine ();
|
||||||
|
Ok (
|
||||||
|
HeapType::ConcreteStruct (
|
||||||
|
StructType::with_finality_and_supertype (
|
||||||
|
engine,
|
||||||
|
Finality::NonFinal,
|
||||||
|
Some (&heap_object_struct (&store)?),
|
||||||
|
vec![
|
||||||
|
hash_field (),
|
||||||
|
FieldType::new (
|
||||||
|
Mutability::Const,
|
||||||
|
StorageType::ValType (ValType::Ref (
|
||||||
|
RefType::new (
|
||||||
|
false,
|
||||||
|
HeapType::ConcreteFunc (
|
||||||
|
FuncType::new (
|
||||||
|
engine,
|
||||||
|
vec![ValType::I32],
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)?
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
|
{- HLINT ignore "Use camelCase" -}
|
||||||
module Gyehoek.CPS.Convert
|
module Gyehoek.CPS.Convert
|
||||||
( convert
|
( convertProgram
|
||||||
, convertProgram
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Gyehoek.CPS.Syntax
|
import Gyehoek.CPS.Syntax
|
||||||
@@ -12,6 +12,7 @@ import Effectful
|
|||||||
import Control.Monad.Cont qualified as Cont
|
import Control.Monad.Cont qualified as Cont
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import qualified Data.List.NonEmpty as NE
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
import qualified Gyehoek.Sexp
|
||||||
|
|
||||||
|
|
||||||
-- 뻘짓이어라
|
-- 뻘짓이어라
|
||||||
@@ -21,6 +22,14 @@ telescope
|
|||||||
-> t a -> (t b -> r) -> r
|
-> t a -> (t b -> r) -> r
|
||||||
telescope f = Cont.runCont . traverse (Cont.cont . f)
|
telescope f = Cont.runCont . traverse (Cont.cont . f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pattern Atomic e <-
|
||||||
|
e@( Scm.ExpLambda _ _
|
||||||
|
; Scm.ExpVar _
|
||||||
|
; Scm.ExpLit _ )
|
||||||
|
|
||||||
|
-- | Transform an expression with a meta-continuation.
|
||||||
convert
|
convert
|
||||||
:: forall es. (GenSym :> es)
|
:: forall es. (GenSym :> es)
|
||||||
=> Scm.Exp -> (Val -> Eff es Exp) -> Eff es Exp
|
=> Scm.Exp -> (Val -> Eff es Exp) -> Eff es Exp
|
||||||
@@ -31,21 +40,24 @@ convert (Scm.ExpLit l) k = k $ ValLit l
|
|||||||
convert (Scm.ExpPrim p) k =
|
convert (Scm.ExpPrim p) k =
|
||||||
telescope (convert @es) p \p' -> do
|
telescope (convert @es) p \p' -> do
|
||||||
r <- gensym' "r"
|
r <- gensym' "r"
|
||||||
ExpPrim p' [r] <$> k (ValVar r)
|
ExpPrim p' . MkKappa [r] <$> k (ValVar r)
|
||||||
|
|
||||||
convert (Scm.ExpLambda xs e) k = do
|
convert (Scm.ExpLambda xs e) k = do
|
||||||
f <- gensym' "λ-body"
|
f <- gensym' "λ-body"
|
||||||
ktail <- gensym' "λ-tail"
|
ktail <- gensym' "λ-tail"
|
||||||
m <- convert e $ \e' ->
|
m <- convert e $ \e' -> pure $ ExpContinue ktail [e']
|
||||||
pure $ ExpContinue ktail [e']
|
ke <- k $ ValVar f
|
||||||
ExpLet [(f, MkLambda xs ktail m)] <$> k (ValVar f)
|
pure [cps|
|
||||||
|
(letrec ((#{f} (λ (##{xs} #{ktail}) #{m})))
|
||||||
|
#{ke})
|
||||||
|
|]
|
||||||
|
|
||||||
convert (Scm.ExpApply f xs) k =
|
convert (Scm.ExpApply f xs) k =
|
||||||
telescope (convert @es) (f:|xs) \(f':|xs') -> do
|
telescope (convert @es) (f:|xs) \(f':|xs') -> do
|
||||||
r <- gensym' "r"
|
r <- gensym' "r"
|
||||||
x <- gensym' "x"
|
x <- gensym' "x"
|
||||||
m <- k (ValVar x)
|
m <- k (ValVar x)
|
||||||
pure $ ExpFix [(r, MkKappa [x] m)] $ ExpApply f' (xs' ++ [ValVar r])
|
pure $ ExpLetRec [(r, AbsKappa' [x] m)] $ ExpApply f' xs' r
|
||||||
|
|
||||||
convert (Scm.ExpBegin xs) k = _
|
convert (Scm.ExpBegin xs) k = _
|
||||||
|
|
||||||
|
|||||||
+286
-227
@@ -6,44 +6,33 @@
|
|||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
{-# LANGUAGE ApplicativeDo #-}
|
{-# LANGUAGE ApplicativeDo #-}
|
||||||
{-# OPTIONS_GHC -Wno-incomplete-patterns #-}
|
{-# OPTIONS_GHC -Wno-incomplete-patterns #-}
|
||||||
|
{-# LANGUAGE RecursiveDo #-}
|
||||||
{- HLINT ignore "Use camelCase" -}
|
{- HLINT ignore "Use camelCase" -}
|
||||||
module Gyehoek.CPS.Lower
|
module Gyehoek.CPS.Lower
|
||||||
(lower, lowerProgram) where
|
(lower, lowerProgram) where
|
||||||
|
|
||||||
import Gyehoek.CPS.Syntax
|
import Gyehoek.CPS.Syntax
|
||||||
import Data.Generics.Labels
|
import Data.Generics.Labels ()
|
||||||
import Gyehoek.Scheme.Syntax qualified as Scm
|
|
||||||
import Gyehoek.GenSym
|
|
||||||
import Data.List.NonEmpty (NonEmpty((:|)))
|
|
||||||
import Data.List (List)
|
|
||||||
import Effectful
|
import Effectful
|
||||||
import Control.Monad.Cont qualified as Cont
|
|
||||||
import Effectful.Writer.Static.Local
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Vector.Strict (Vector)
|
import Data.Vector.Strict (Vector)
|
||||||
import Control.Lens
|
import Control.Lens hiding (op)
|
||||||
import Data.Foldable
|
|
||||||
import Data.HashMap.Strict (HashMap)
|
|
||||||
import Numeric.Natural
|
import Numeric.Natural
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Gyehoek.Scheme.Syntax (Lit(..))
|
|
||||||
import Text.Printf
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Data.Vector.Strict as V
|
import qualified Data.Vector.Strict as V
|
||||||
import Data.IntMap.Strict (IntMap)
|
|
||||||
import Data.String.Interpolate
|
|
||||||
import Gyehoek.Wasm qualified as Wasm
|
import Gyehoek.Wasm qualified as Wasm
|
||||||
import Gyehoek.Wasm hiding (Expr)
|
import Gyehoek.Wasm hiding (Expr)
|
||||||
import Language.Sexp.Located qualified as SL
|
import Language.Sexp.Located qualified as SL
|
||||||
import Debug.Pretty.Simple
|
|
||||||
import Control.Monad.Fix
|
import Control.Monad.Fix
|
||||||
import Language.Sexp.Located (Sexp)
|
import qualified Gyehoek.Sexp
|
||||||
import Data.Functor.Foldable (cata)
|
import Data.Text qualified as T
|
||||||
|
import Data.Foldable (fold)
|
||||||
|
import Gyehoek.Sexp (encodeOrShow, toSexp)
|
||||||
|
import Debug.Pretty.Simple
|
||||||
|
|
||||||
|
|
||||||
data Env = MkEnv
|
data Env = MkEnv
|
||||||
{ runtime :: Runtime
|
{ vars :: Vector Name
|
||||||
, vars :: Vector Name
|
|
||||||
, kvars :: Vector Name
|
, kvars :: Vector Name
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
@@ -54,238 +43,308 @@ type instance IxValue Env = Name
|
|||||||
instance Ixed Env where
|
instance Ixed Env where
|
||||||
ix i = #vars . ix (fromIntegral i)
|
ix i = #vars . ix (fromIntegral i)
|
||||||
|
|
||||||
data Runtime = MkRuntime
|
|
||||||
{ argArrayType :: Idx
|
|
||||||
, argArray :: Idx
|
|
||||||
, contType :: Idx
|
|
||||||
, contStackType :: Idx
|
|
||||||
, contStackTop :: Idx
|
|
||||||
, contStack :: Idx
|
|
||||||
, result :: Idx
|
|
||||||
, halt :: Idx
|
|
||||||
}
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
tonat :: Integral a => a -> Natural
|
||||||
|
tonat = fromIntegral
|
||||||
|
|
||||||
-- | @makeSmallFixnum@ emits an expression injecting the i32 on top
|
-- | @makeSmallFixnum@ emits an expression injecting the i32 on top
|
||||||
-- of the stack into the SCM unitype.
|
-- of the stack into the SCM unitype.
|
||||||
-- makeSmallFixnum :: Wasm.Expr
|
makeSmallFixnum :: Wasm.Expr
|
||||||
-- makeSmallFixnum = mconcat
|
makeSmallFixnum = [expr|
|
||||||
-- [ ins "i32.const" [sxp @Int 1]
|
(@gyehoek "construct small fixnum")
|
||||||
-- , ins "i32.shl" []
|
(i32.const 1)
|
||||||
-- , ins "ref.i31" []
|
i32.shl
|
||||||
-- ]
|
ref.i31
|
||||||
|
|]
|
||||||
|
|
||||||
-- | Given an expression @e@ leaving a @ref eq@ atop the stack,
|
-- | Given an expression @e@ leaving a @ref eq@ atop the stack,
|
||||||
-- @pushArg rt n e@ sets the nth slot of the arg-passing array to the
|
-- @pushArg rt n e@ sets the nth slot of the arg-passing array to the
|
||||||
-- result of @e@.
|
-- result of @e@.
|
||||||
-- pushArg :: Runtime -> Int -> Wasm.Expr -> Wasm.Expr
|
pushArg :: Natural -> Wasm.Expr -> Wasm.Expr
|
||||||
-- pushArg (MkRuntime {argArrayType,argArray}) n e = mconcat
|
pushArg n e = [expr|
|
||||||
-- [ ins "global.get" [sxp argArray]
|
(@gyehoek "push argument")
|
||||||
-- , ins "i32.const" [sxp n]
|
(global.get $arg-array)
|
||||||
-- , e
|
(i32.const #{n})
|
||||||
-- , ins "array.set" [sxp argArrayType]
|
##{e}
|
||||||
-- ]
|
(array.set $arg-array-type)
|
||||||
|
|]
|
||||||
|
|
||||||
-- | Pop the nth arg from the arg-passing array onto the stack.
|
-- | Pop the nth arg from the arg-passing array onto the stack.
|
||||||
-- popArg :: Runtime -> Int -> Wasm.Expr
|
popArg :: Int -> Wasm.Expr
|
||||||
-- popArg (MkRuntime {argArrayType,argArray}) n = mconcat
|
popArg n = [expr|
|
||||||
-- [ ins "global.get" [sxp argArray]
|
(@gyehoek "pop argument")
|
||||||
-- , ins "i32.const" [sxp n]
|
(global.get $arg-array)
|
||||||
-- , ins "array.get" [sxp argArrayType]
|
(i32.const #{n})
|
||||||
-- , ins "ref.as_non_null" []
|
(array.get $arg-array-type)
|
||||||
-- ]
|
ref.as_non_null
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- lowerVal :: Env -> Val -> Wasm.Expr
|
lowerVal :: GenMod :> es => Env -> Val -> Eff es Wasm.Expr
|
||||||
|
|
||||||
-- lowerVal g (ValLit l) =
|
lowerVal g (ValLit l) =
|
||||||
-- case l of
|
pure $ case l of
|
||||||
-- LitInt n ->
|
LitInt n -> [expr|
|
||||||
-- ins "i32.const" [sxp n]
|
(i32.const #{n})
|
||||||
-- <> makeSmallFixnum
|
##{makeSmallFixnum}
|
||||||
-- LitBool b ->
|
|]
|
||||||
-- ins "i32.const" [sxp @Int $ if b then 1 else 0]
|
LitBool b -> [expr|
|
||||||
-- <> ins "ref.i31" []
|
(i32.const #{b'})
|
||||||
-- _ -> _
|
ref.i31
|
||||||
|
|]
|
||||||
|
where b' :: Int = if b then 0b11 else 0b01
|
||||||
|
_ -> _
|
||||||
|
|
||||||
-- lowerVal g (ValVar x) = ins "local.get" [sxp (1+l)]
|
lowerVal g (ValVar x) = pure $ [expr|(local.get #{l})|]
|
||||||
-- where
|
where
|
||||||
-- l = V.elemIndex x g.vars ^?! _Just
|
l = succ $ V.elemIndex x g.vars ^?! _Just
|
||||||
|
|
||||||
-- lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr
|
-- lowerVal g (ValLambda lam) = do
|
||||||
|
-- idx <- lowerLambda g lam
|
||||||
|
-- pure [expr|
|
||||||
|
-- (i32.const 0)
|
||||||
|
-- (ref.func #{idx})
|
||||||
|
-- (struct.new $closure)
|
||||||
|
-- |]
|
||||||
|
|
||||||
-- lower' g (Halt [v]) = pure . mconcat $
|
lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr
|
||||||
-- [ pushArg g.runtime 0 (lowerVal g v)
|
|
||||||
-- , ins "return_call" [sxp @Int 1]
|
|
||||||
-- ]
|
|
||||||
|
|
||||||
-- lower' g (ExpPrim p rs e) =
|
lower' g (Halt [v]) = do
|
||||||
-- case p of
|
arg <- pushArg 0 <$> lowerVal g v
|
||||||
-- PrimAdd x y -> lowerBinOp "i32.add" g x y r e
|
pure [expr|
|
||||||
-- PrimMul x y -> lowerBinOp "i32.mul" g x y r e
|
##{arg}
|
||||||
-- where
|
(return_call $halt (i32.const 1))
|
||||||
-- r = head rs
|
|]
|
||||||
|
|
||||||
-- lower' g (ExpIf c t f) = do
|
lower' g e@(ExpPrim p k) =
|
||||||
-- t' <- lower' g t
|
([expr|(@gyehoek :origin #{origin})|]<>)
|
||||||
-- f' <- lower' g f
|
<$> case p of
|
||||||
-- pure $ lowerVal g c
|
PrimAdd x y -> lowerBinOp "i32.add" g x y k
|
||||||
-- <> Wasm.if' (Wasm.result [i32]) t' f'
|
PrimMul x y -> lowerBinOp "i32.mul" g x y k
|
||||||
|
where origin = encodeOrShow @_ @Text e
|
||||||
|
|
||||||
-- lower' g (ExpContinue k [x]) = pure . mconcat $
|
lower' g (ExpIf c t f) = do
|
||||||
-- [ pushArg rt 0 (lowerVal g x)
|
c' <- lowerVal g c
|
||||||
-- , ins "i32.const" [sxp @Int 1] -- nargs
|
t' <- lower' g t
|
||||||
-- -- get the return continuation.
|
f' <- lower' g f
|
||||||
-- , ins "global.get" [sxp rt.contStack]
|
pure [expr|
|
||||||
-- , ins "global.get" [sxp rt.contStackTop]
|
##{c'}
|
||||||
-- , ins "array.get" [sxp rt.contStackType]
|
(call $gh-truthy?)
|
||||||
-- , ins "ref.as_non_null" []
|
(if (then ##{t'})
|
||||||
-- -- decrement contStackTop, completing the "pop."
|
(else ##{f'}))
|
||||||
-- , ins "global.get" [sxp rt.contStackTop]
|
|]
|
||||||
-- , ins "i32.const" [sxp @Int (1 + l)]
|
|
||||||
-- , ins "i32.sub" []
|
|
||||||
-- , ins "global.set" [sxp rt.contStackTop]
|
|
||||||
-- , ins "return_call_ref" [sxp rt.contType]
|
|
||||||
-- ]
|
|
||||||
-- where
|
|
||||||
-- rt = g.runtime
|
|
||||||
-- l = V.elemIndex k g.kvars ^?! _Just
|
|
||||||
|
|
||||||
-- lower' g (ExpLet [(r,MkLambda xs ktail m)] e) = do
|
lower' g (ExpLetRec [(r,AbsKappa kap)] e) = do
|
||||||
-- idx <- defun [i32] [] (replicate 5 scm) \_ -> do
|
idx <- lowerKappa g kap
|
||||||
-- let g' = g & #vars <>~ V.fromList xs
|
let g' = g & #kvars <>~ [r]
|
||||||
-- & #kvars <>~ [ktail]
|
e' <- lower' g' e
|
||||||
-- m' <- lower' g' m
|
let origin = encodeOrShow @_ @Text e
|
||||||
-- pure . mconcat $
|
pure [expr|
|
||||||
-- [ xs & ifoldMap \n _ ->
|
(@gyehoek :origin #{origin})
|
||||||
-- popArg g.runtime n <> ins "local.set" [sxp (1+n)]
|
(@gyehoek "push cont" :idx #{idx})
|
||||||
-- , m'
|
(array.set $cont-stack-type
|
||||||
-- ]
|
(global.get $cont-stack)
|
||||||
-- declareFuncref idx
|
(global.get $cont-stack-top)
|
||||||
-- let g' = g & #vars <>~ [r]
|
(ref.func #{idx}))
|
||||||
-- let n = length g.vars
|
(global.set $cont-stack-top
|
||||||
-- e' <- lower' g' e
|
(i32.add (global.get $cont-stack-top)
|
||||||
-- pure . mconcat $
|
(i32.const 1)))
|
||||||
-- [ ins "ref.func" [sxp idx]
|
##{e'}
|
||||||
-- , ins "local.set" [sxp (n+1)]
|
|]
|
||||||
-- , e'
|
|
||||||
-- ]
|
|
||||||
|
|
||||||
-- lower' g e = error . show $ e
|
lower' g (ExpLetRec [(r,AbsLambda lam)] e) = do
|
||||||
|
idx <- lowerLambda g lam
|
||||||
|
let g' = g & #vars <>~ [r]
|
||||||
|
let n = succ $ length g.vars
|
||||||
|
e' <- lower' g' e
|
||||||
|
pure [expr|
|
||||||
|
(i32.const 0)
|
||||||
|
(ref.func #{idx})
|
||||||
|
(struct.new $closure)
|
||||||
|
(local.set #{n})
|
||||||
|
##{e'}
|
||||||
|
|]
|
||||||
|
|
||||||
-- lowerBinOp
|
lower' g e@(ExpApply f xs ktail) = do
|
||||||
-- :: (GenMod :> es)
|
let nargs = length xs
|
||||||
-- => Text -> Env -> Val -> Val -> Name -> Exp -> Eff es Wasm.Expr
|
f' <- lowerVal g f
|
||||||
-- lowerBinOp op g x y r e = do
|
let l = succ $ V.elemIndex ktail g.kvars ^?! _Just
|
||||||
-- e' <- lower' g' e
|
args <- fold <$>
|
||||||
-- pure . mconcat $
|
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
||||||
-- [ lowerVal g x
|
let origin = encodeOrShow @_ @Text e
|
||||||
-- , ins "ref.cast" [sxp $ ref i31]
|
pure [expr|
|
||||||
-- , ins "i31.get_s" []
|
(@gyehoek :origin #{origin})
|
||||||
-- , lowerVal g y
|
(@gyehoek "load args")
|
||||||
-- , ins "ref.cast" [sxp $ ref i31]
|
##{args}
|
||||||
-- , ins "i31.get_s" []
|
(i32.const 1)
|
||||||
-- , ins op []
|
##{f'}
|
||||||
-- , ins "ref.i31" []
|
(ref.cast (ref $closure))
|
||||||
-- , ins "local.set" [sxp (1+n)]
|
(struct.get $closure $code)
|
||||||
-- , e'
|
(return_call_ref $cont-type)
|
||||||
-- ]
|
(@gyehoek todo
|
||||||
-- where
|
(f' ##{f'})
|
||||||
-- g' = g & #vars <>~ [r]
|
(ktail #{l}))
|
||||||
-- n = length (g ^. #vars)
|
|]
|
||||||
|
|
||||||
|
lower' g e@(ExpContinue k xs) = do
|
||||||
|
let nargs = length xs
|
||||||
|
args <- fold <$>
|
||||||
|
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
||||||
|
let origin = encodeOrShow @_ @Text e
|
||||||
|
pure [expr|
|
||||||
|
(@gyehoek :origin #{origin})
|
||||||
|
(@gyehoek "push args")
|
||||||
|
##{args}
|
||||||
|
(@gyehoek "nargs")
|
||||||
|
(i32.const #{nargs})
|
||||||
|
(@gyehoek "pop cont stack")
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(i32.const #{l})
|
||||||
|
i32.sub
|
||||||
|
(global.set $cont-stack-top)
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(array.get $cont-stack-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(return_call_ref $cont-type)
|
||||||
|
|]
|
||||||
|
where
|
||||||
|
l = succ $ V.elemIndex k g.kvars ^?! _Just
|
||||||
|
|
||||||
|
lower' g e = error $ case Gyehoek.Sexp.encode e of
|
||||||
|
Left _ -> show e
|
||||||
|
Right x -> T.unpack x
|
||||||
|
|
||||||
|
lowerKappa :: GenMod :> es => Env -> Kappa -> Eff es Idx
|
||||||
|
lowerKappa g e@(MkKappa xs m) = do
|
||||||
|
let g' = g & #vars .~ V.fromList xs
|
||||||
|
m' <- lower' g' m
|
||||||
|
let body = mconcat
|
||||||
|
[ xs & ifoldMap \n _ ->
|
||||||
|
let n' = succ n
|
||||||
|
in popArg n <> [expr|(local.set #{n'})|]
|
||||||
|
, m'
|
||||||
|
]
|
||||||
|
let origin = encodeOrShow @_ @Text e
|
||||||
|
idx <- Wasm.defineFunction [wat|
|
||||||
|
(func (param i32)
|
||||||
|
(@gyehoek :origin #{origin})
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
##{body})
|
||||||
|
|]
|
||||||
|
Wasm.emit [wats|(elem declare funcref (ref.func #{idx}))|]
|
||||||
|
pure idx
|
||||||
|
|
||||||
|
lowerLambda :: GenMod :> es => Env -> Lambda -> Eff es Idx
|
||||||
|
lowerLambda g e@(MkLambda xs ktail m) = do
|
||||||
|
let g' = g & #vars .~ V.fromList xs
|
||||||
|
& #kvars <>~ [ktail]
|
||||||
|
m' <- lower' g' m
|
||||||
|
let body = mconcat
|
||||||
|
[ xs & ifoldMap \n _ ->
|
||||||
|
let n' = succ n
|
||||||
|
in popArg n <> [expr|(local.set #{n'})|]
|
||||||
|
, m'
|
||||||
|
]
|
||||||
|
let origin = encodeOrShow @_ @Text e
|
||||||
|
idx <- Wasm.defineFunction [wat|
|
||||||
|
(func (param i32)
|
||||||
|
(@gyehoek :origin #{origin})
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
##{body})
|
||||||
|
|]
|
||||||
|
Wasm.emit [wats|(elem declare funcref (ref.func #{idx}))|]
|
||||||
|
pure idx
|
||||||
|
|
||||||
|
lowerBinOp
|
||||||
|
:: (GenMod :> es)
|
||||||
|
=> Text -> Env -> Val -> Val -> Kappa -> Eff es Wasm.Expr
|
||||||
|
lowerBinOp op g x y (MkKappa [r] e) = do
|
||||||
|
let op' = SL.Symbol op
|
||||||
|
let g' = g & #vars <>~ [r]
|
||||||
|
let n = succ $ length (g ^. #vars)
|
||||||
|
x' <- lowerVal g x
|
||||||
|
y' <- lowerVal g y
|
||||||
|
e' <- lower' g' e
|
||||||
|
pure [expr|
|
||||||
|
##{x'}
|
||||||
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shr_u
|
||||||
|
##{y'}
|
||||||
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shr_u
|
||||||
|
#{op'}
|
||||||
|
##{makeSmallFixnum}
|
||||||
|
(local.set #{n})
|
||||||
|
##{e'}
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- scm = ref eq
|
emitRuntime :: GenMod :> es => Eff es ()
|
||||||
|
emitRuntime = mfix \runtime -> do
|
||||||
|
Wasm.defineFunctions [wats|
|
||||||
|
(import "gyehoek" "write" (func $gh-write (param (ref eq))))
|
||||||
|
(import "gyehoek" "truthy?" (func $gh-truthy? (param (ref eq))
|
||||||
|
(result i32)))
|
||||||
|
|]
|
||||||
|
-- cont stack
|
||||||
|
Wasm.defineTypes [wats|
|
||||||
|
(type $heap-object (sub (struct (field $hash (mut i32)))))
|
||||||
|
(type $cont-type (func (param i32)))
|
||||||
|
(type $cont-stack-type (array (mut (ref null $cont-type))))
|
||||||
|
(type $closure (sub $heap-object
|
||||||
|
(struct (field $hash (mut i32))
|
||||||
|
(field $code (ref $cont-type)))))
|
||||||
|
|]
|
||||||
|
Wasm.defineGlobals [wats|
|
||||||
|
(global $cont-stack-top (mut i32) (i32.const 0))
|
||||||
|
(global $cont-stack (ref $cont-stack-type)
|
||||||
|
(array.new_default $cont-stack-type (i32.const 128)))
|
||||||
|
|]
|
||||||
|
-- arg array
|
||||||
|
Wasm.defineType [wat|
|
||||||
|
(type $arg-array-type (array (mut (ref null eq))))
|
||||||
|
|]
|
||||||
|
Wasm.defineGlobal [wat|
|
||||||
|
(global $arg-array (ref $arg-array-type)
|
||||||
|
(array.new_default $arg-array-type (i32.const 32)))
|
||||||
|
|]
|
||||||
|
-- other things 😼
|
||||||
|
Wasm.defineGlobal [wat|
|
||||||
|
(global $result (mut (ref null eq))
|
||||||
|
(ref.null eq))
|
||||||
|
|]
|
||||||
|
-- procedures
|
||||||
|
let arg = popArg 0
|
||||||
|
Wasm.defineFunction [wat|
|
||||||
|
(func $halt (param i32)
|
||||||
|
##{arg}
|
||||||
|
(global.set $result))
|
||||||
|
|]
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
lower :: Exp -> Eff es Text
|
||||||
|
lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do
|
||||||
|
runtime <- emitRuntime
|
||||||
|
let g = MkEnv mempty mempty
|
||||||
|
e' <- lower' g e
|
||||||
|
let origin = encodeOrShow @_ @Text e
|
||||||
|
Wasm.defineFunction [wat|
|
||||||
|
(func $scm-entry (param i32)
|
||||||
|
(@gyehoek :origin #{origin})
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
##{e'})
|
||||||
|
|]
|
||||||
|
Wasm.defineFunction [wat|
|
||||||
|
(func (export "main")
|
||||||
|
(call $scm-entry (i32.const 0))
|
||||||
|
(call $gh-write (ref.as_non_null (global.get $result))))
|
||||||
|
|]
|
||||||
|
|
||||||
-- emitRuntime :: GenMod :> es => Eff es Runtime
|
lowerProgram :: Program -> Eff es Text
|
||||||
-- emitRuntime = mfix \runtime -> do
|
lowerProgram (MkProgram e) = lower e
|
||||||
-- heapObjectIdx <- Wasm.deftypeNamed "$heap-object" $ Wasm.sub [] $ Wasm.struct
|
|
||||||
-- [ Wasm.mut i32 ]
|
|
||||||
-- -- cont stack
|
|
||||||
-- contType <- Wasm.deftype $ Wasm.func [i32] []
|
|
||||||
-- contStackType <- Wasm.deftype $ array $ mut $ refnull (fromIdx contType)
|
|
||||||
-- contStackTop <- Wasm.defglobal (mut i32) $ ins "i32.const" [sxp @Int 0]
|
|
||||||
-- contStack <- Wasm.defglobal (ref (Wasm.fromIdx contStackType)) $
|
|
||||||
-- ins "i32.const" [sxp @Int 128]
|
|
||||||
-- <> ins "array.new_default" [sxp contStackType]
|
|
||||||
-- -- arg array
|
|
||||||
-- argArrayType <- Wasm.deftype $ Wasm.array $ mut $ refnull eq
|
|
||||||
-- argArray <- Wasm.defglobal (ref (Wasm.fromIdx argArrayType)) $
|
|
||||||
-- ins "i32.const" [sxp @Int 32]
|
|
||||||
-- <> ins "array.new_default" [sxp argArrayType]
|
|
||||||
-- -- consIdx <- Wasm.defun _ _ _ _
|
|
||||||
-- result <- Wasm.defglobal (mut (refnull eq)) $ ins "ref.null" [sxp eq]
|
|
||||||
-- halt <- Wasm.defun [i32] [] (replicate 5 scm) \_ ->
|
|
||||||
-- pure . mconcat $
|
|
||||||
-- [ popArg runtime 0
|
|
||||||
-- , ins "global.set" [sxp result]
|
|
||||||
-- ]
|
|
||||||
-- pure $ MkRuntime
|
|
||||||
-- {argArray,argArrayType
|
|
||||||
-- ,contStack,contStackTop,contStackType,contType
|
|
||||||
-- ,result,halt}
|
|
||||||
-- -- pure $ error "todo"
|
|
||||||
|
|
||||||
-- lower :: Exp -> Eff es Text
|
|
||||||
-- lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do
|
|
||||||
-- runtime <- emitRuntime
|
|
||||||
-- let g = MkEnv runtime mempty mempty
|
|
||||||
-- scm_entry <- Wasm.defun [i32] [] (replicate 5 scm) \_ ->
|
|
||||||
-- lower' g e
|
|
||||||
-- main <- Wasm.defun [] [scm] [scm, scm, scm, scm, scm] \_ ->
|
|
||||||
-- pure . mconcat $
|
|
||||||
-- -- push return cont
|
|
||||||
-- [-- ins "ref.func" [sxp halt]
|
|
||||||
-- -- make call
|
|
||||||
-- ins "i32.const" [sxp @Int 0]
|
|
||||||
-- , ins "call" [sxp scm_entry]
|
|
||||||
-- , ins "global.get" [sxp runtime.result]
|
|
||||||
-- , ins "ref.as_non_null" []
|
|
||||||
-- ]
|
|
||||||
-- Wasm.export "main" "func" main
|
|
||||||
|
|
||||||
-- lowerProgram :: Program -> Eff es Text
|
|
||||||
-- lowerProgram (MkProgram e) = lower e
|
|
||||||
|
|
||||||
lower = _
|
|
||||||
lowerProgram = _
|
|
||||||
|
|
||||||
antiquote_example =
|
|
||||||
let
|
|
||||||
metavar :: Integer
|
|
||||||
metavar = 123
|
|
||||||
|
|
||||||
e1 :: Wasm.Expr
|
|
||||||
e1 = [expr|
|
|
||||||
(func $blah (result i32)
|
|
||||||
(i32.const #{metavar}))
|
|
||||||
|]
|
|
||||||
|
|
||||||
e2 :: Wasm.Expr
|
|
||||||
e2 = [expr|
|
|
||||||
(func $blah (result i32)
|
|
||||||
(i32.const 123))
|
|
||||||
|]
|
|
||||||
in (metavar,e1,e2,e1==e2)
|
|
||||||
|
|
||||||
antiquote_splicing_example =
|
|
||||||
let
|
|
||||||
metavars :: List Sexp
|
|
||||||
metavars = [sxs'|i32 i64 f64|]
|
|
||||||
|
|
||||||
e1 :: Wasm.Expr
|
|
||||||
e1 = [expr|
|
|
||||||
(func $blah (param ##{metavars}))
|
|
||||||
|]
|
|
||||||
|
|
||||||
e2 :: Wasm.Expr
|
|
||||||
e2 = [expr|
|
|
||||||
(func $blah (param i32 i64 f64))
|
|
||||||
|]
|
|
||||||
in (metavars, e1, e2, e1 == e2)
|
|
||||||
|
|||||||
+181
-39
@@ -1,6 +1,9 @@
|
|||||||
{-# LANGUAGE OverloadedLabels #-}
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE PatternSynonyms #-}
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE FunctionalDependencies #-}
|
||||||
module Gyehoek.CPS.Syntax
|
module Gyehoek.CPS.Syntax
|
||||||
( Val(..)
|
( Val(..)
|
||||||
, Kappa(..)
|
, Kappa(..)
|
||||||
@@ -15,80 +18,119 @@ module Gyehoek.CPS.Syntax
|
|||||||
, pattern Halt1
|
, pattern Halt1
|
||||||
, _MkKappa
|
, _MkKappa
|
||||||
, _ExpPrim
|
, _ExpPrim
|
||||||
, _ExpFix
|
, _ExpLetRec
|
||||||
, _ExpApply
|
, _ExpApply
|
||||||
|
, binders
|
||||||
|
, body
|
||||||
|
, op
|
||||||
|
, args
|
||||||
|
, cont
|
||||||
|
, cps
|
||||||
|
, pattern AbsLambda'
|
||||||
|
, pattern AbsKappa'
|
||||||
|
, Abs(..)
|
||||||
|
, free
|
||||||
|
, free'
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Language.SexpGrammar qualified as S
|
import Language.SexpGrammar qualified as S
|
||||||
import Gyehoek.Sexp qualified
|
import Gyehoek.Sexp qualified
|
||||||
import Gyehoek.Scheme.Syntax (Name (..), Prim(..), primSexpIso, Lit(..), pattern Void)
|
import Gyehoek.Scheme.Syntax (Name (..), Prim(..), primSexpIso, Lit(..), pattern Void, getName)
|
||||||
import Data.Text (Text)
|
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Language.SexpGrammar.Generic
|
import Language.SexpGrammar.Generic
|
||||||
import Control.Category
|
import Control.Category
|
||||||
import Control.Lens
|
import Control.Lens hiding (op)
|
||||||
import Data.Text qualified as T
|
|
||||||
import Data.Generics.Labels
|
|
||||||
import Prelude hiding ((.), id)
|
import Prelude hiding ((.), id)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
import Data.InvertibleGrammar.Base qualified as IGB
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
import Data.InvertibleGrammar.Base ((:-)((:-)))
|
import Data.Data (Data)
|
||||||
import qualified Data.InvertibleGrammar as IG
|
import Language.Sexp.Located (Sexp)
|
||||||
|
import qualified Data.InvertibleGrammar.Base as IG
|
||||||
|
import qualified Gyehoek.Scheme.Syntax as Gyehoek
|
||||||
|
import Data.InvertibleGrammar.Base (type (:-)((:-)))
|
||||||
|
import Data.HashSet (HashSet)
|
||||||
|
import qualified Data.HashSet as HS
|
||||||
|
import Data.Hashable (Hashable)
|
||||||
|
import Data.Monoid (Endo)
|
||||||
|
import Data.Containers.ListUtils (nubOrd)
|
||||||
|
|
||||||
-- Data types
|
-- Data types
|
||||||
|
|
||||||
data Val
|
data Val
|
||||||
= ValLabel Name
|
= ValVar Name
|
||||||
| ValVar Name
|
|
||||||
| ValLit Lit
|
| ValLit Lit
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data Kappa = MkKappa (List Name) Exp
|
data Kappa = MkKappa { binders :: List Name, body :: Exp }
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data Lambda = MkLambda (List Name) Name Exp
|
data Lambda = MkLambda { binders :: List Name, ktail :: Name, body :: Exp }
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
|
data Abs
|
||||||
|
= AbsKappa Kappa
|
||||||
|
| AbsLambda Lambda
|
||||||
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
|
pattern AbsKappa' xs e = AbsKappa (MkKappa xs e)
|
||||||
|
pattern AbsLambda' xs e ktail = AbsLambda (MkLambda xs e ktail)
|
||||||
|
|
||||||
data Exp
|
data Exp
|
||||||
= ExpPrim (Prim Val) (List Name) Exp
|
= ExpPrim (Prim Val) Kappa
|
||||||
| ExpFix (NonEmpty (Name, Kappa)) Exp
|
| ExpLetRec { binders :: NonEmpty (Name, Abs), body :: Exp }
|
||||||
| ExpLet (NonEmpty (Name, Lambda)) Exp
|
|
||||||
| ExpContinue Name (List Val)
|
| ExpContinue Name (List Val)
|
||||||
| ExpIf Val Exp Exp
|
| ExpIf Val Exp Exp
|
||||||
| ExpApply Val (List Val)
|
| ExpApply
|
||||||
deriving (Show, Generic)
|
{ op :: Val
|
||||||
|
, args :: List Val
|
||||||
|
, cont :: Name
|
||||||
|
}
|
||||||
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
pattern Halt :: List Val -> Exp
|
pattern Halt :: List Val -> Exp
|
||||||
pattern Halt xs = ExpApply (ValVar "halt") xs
|
pattern Halt xs = ExpContinue "halt" xs
|
||||||
|
|
||||||
pattern Halt1 :: Val -> Exp
|
pattern Halt1 :: Val -> Exp
|
||||||
pattern Halt1 x = ExpApply (ValVar "halt") [x]
|
pattern Halt1 x = ExpContinue "halt" [x]
|
||||||
|
|
||||||
data Def = DefConstant Name Exp
|
data Def = DefConstant Name Exp
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Program = MkProgram
|
data Program = MkProgram
|
||||||
{ body :: Exp
|
{ body :: Exp
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
makePrisms ''Kappa
|
makePrisms ''Kappa
|
||||||
|
-- makeLenses ''Kappa
|
||||||
makePrisms ''Exp
|
makePrisms ''Exp
|
||||||
|
-- makeLenses ''Exp
|
||||||
|
-- makeFieldsNoPrefix ''Exp
|
||||||
|
-- makeFieldsNoPrefix ''Kappa
|
||||||
|
-- makeLensesWith abbreviatedFields ''Exp
|
||||||
|
-- makeLensesFor [("binders", "_binders"), ("body", "_body")] ''Exp
|
||||||
|
makeFieldsId ''Exp
|
||||||
|
makeFieldsId ''Kappa
|
||||||
|
makeFieldsId ''Lambda
|
||||||
|
|
||||||
|
instance HasBinders Abs (List Name) where
|
||||||
|
binders k (AbsKappa kap) = AbsKappa <$> binders k kap
|
||||||
|
binders k (AbsLambda lam) = AbsLambda <$> binders k lam
|
||||||
|
|
||||||
|
instance HasBody Abs Exp where
|
||||||
|
body k (AbsKappa kap) = AbsKappa <$> body k kap
|
||||||
|
body k (AbsLambda lam) = AbsLambda <$> body k lam
|
||||||
|
|
||||||
|
|
||||||
-- SexpIso instances
|
-- SexpIso instances
|
||||||
|
|
||||||
instance S.SexpIso Val where
|
instance S.SexpIso Val where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
$ With (. label)
|
$ With (\var -> var . S.sexpIso)
|
||||||
$ With (. var)
|
$ With (\lit -> lit . S.sexpIso)
|
||||||
$ With (. S.sexpIso)
|
|
||||||
$ End
|
$ End
|
||||||
where
|
|
||||||
label = S.keyword >>> S.iso MkName getName
|
|
||||||
var = S.sexpIso
|
|
||||||
|
|
||||||
instance S.SexpIso Lambda where
|
instance S.SexpIso Lambda where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
@@ -97,9 +139,18 @@ instance S.SexpIso Lambda where
|
|||||||
where
|
where
|
||||||
lambda = S.list $
|
lambda = S.list $
|
||||||
S.el Gyehoek.Sexp.lambdaKeyword
|
S.el Gyehoek.Sexp.lambdaKeyword
|
||||||
>>> S.el (S.list (S.rest S.sexpIso))
|
>>> S.el binders
|
||||||
>>> S.el S.sexpIso
|
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
|
binders :: forall t.
|
||||||
|
IG.Grammar S.Position (Sexp :- t) (Name :- List Name :- t)
|
||||||
|
binders = S.list $
|
||||||
|
S.rest (S.sexpIso @Name)
|
||||||
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
|
(\(ktail:-args:-t) -> (args ++ [ktail]) :- t)
|
||||||
|
(\(args:-t) -> case args ^? _Snoc of
|
||||||
|
Just (args',ktail) -> Right $ ktail :- args' :- t
|
||||||
|
Nothing -> Left $ S.expected "cont param")
|
||||||
|
)
|
||||||
|
|
||||||
instance S.SexpIso Kappa where
|
instance S.SexpIso Kappa where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
@@ -111,11 +162,16 @@ instance S.SexpIso Kappa where
|
|||||||
>>> S.el (S.list $ S.rest S.sexpIso)
|
>>> S.el (S.list $ S.rest S.sexpIso)
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
|
|
||||||
|
instance S.SexpIso Abs where
|
||||||
|
sexpIso = match
|
||||||
|
$ With (\lambda -> lambda . S.sexpIso)
|
||||||
|
$ With (\kappa -> kappa . S.sexpIso)
|
||||||
|
$ End
|
||||||
|
|
||||||
instance S.SexpIso Exp where
|
instance S.SexpIso Exp where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
$ With (. prim)
|
$ With (. prim)
|
||||||
$ With (. fix)
|
$ With (. letrec)
|
||||||
$ With (. let_)
|
|
||||||
$ With (. continue)
|
$ With (. continue)
|
||||||
$ With (. if_)
|
$ With (. if_)
|
||||||
$ With (. app)
|
$ With (. app)
|
||||||
@@ -125,16 +181,102 @@ instance S.SexpIso Exp where
|
|||||||
S.el (S.sym "continue")
|
S.el (S.sym "continue")
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
>>> S.rest S.sexpIso
|
>>> S.rest S.sexpIso
|
||||||
fix = Gyehoek.Sexp.let_ "fix" S.sexpIso S.sexpIso S.sexpIso
|
letrec = Gyehoek.Sexp.let_ "letrec" S.sexpIso S.sexpIso S.sexpIso
|
||||||
let_ = Gyehoek.Sexp.let_ "let" S.sexpIso S.sexpIso S.sexpIso
|
|
||||||
if_ = S.list $ S.el (S.sym "if")
|
if_ = S.list $ S.el (S.sym "if")
|
||||||
>>> S.el S.sexpIso >>> S.el S.sexpIso >>> S.el S.sexpIso
|
>>> S.el S.sexpIso >>> S.el S.sexpIso >>> S.el S.sexpIso
|
||||||
app = S.list $ S.el S.sexpIso >>> S.rest S.sexpIso
|
app :: forall t.
|
||||||
|
IG.Grammar S.Position (Sexp :- t) (Name :- ([Val] :- (Val :- t)))
|
||||||
|
app = S.list $ S.el (S.sexpIso @Val)
|
||||||
|
-- >>> S.flipped Gyehoek.Sexp.nonEmptyGrammar
|
||||||
|
>>> S.rest (S.sexpIso @Val)
|
||||||
|
-- >>> _
|
||||||
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
|
(\(karg :- args :- op :- t) ->
|
||||||
|
(args ++ [ValVar karg]) :- op :- t)
|
||||||
|
(\(xs :- op :- t) -> case xs ^? _Snoc of
|
||||||
|
Just (args,preview #ValVar -> Just karg) ->
|
||||||
|
Right $ karg:- args :- op :- t
|
||||||
|
_ -> Left $ S.expected "continuation arg"
|
||||||
|
))
|
||||||
|
where
|
||||||
|
_ = S.flipped $ Gyehoek.Sexp.nonEmptyGrammar @S.Position @Val
|
||||||
prim = S.list $
|
prim = S.list $
|
||||||
S.el (S.sym "prim")
|
S.el (S.sym "prim")
|
||||||
>>> S.el (primSexpIso id (S.sexpIso @Val))
|
>>> S.el (primSexpIso id (S.sexpIso @Val))
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.sexpIso
|
||||||
>>> S.el S.sexpIso
|
|
||||||
|
|
||||||
instance S.SexpIso Program where
|
instance S.SexpIso Program where
|
||||||
sexpIso = with \prog -> S.sexpIso @Exp >>> prog
|
sexpIso = with \prog -> S.sexpIso @Exp >>> prog
|
||||||
|
|
||||||
|
|
||||||
|
-- quasiquoters
|
||||||
|
|
||||||
|
class Data a => CPS a where
|
||||||
|
toCPS :: Sexp -> a
|
||||||
|
|
||||||
|
instance CPS Exp where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Val where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Kappa where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Lambda where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Abs where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
|
||||||
|
cps :: QuasiQuoter
|
||||||
|
cps = Gyehoek.Sexp.makeSx' [| toCPS |]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deleteFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a
|
||||||
|
deleteFrom = flip $ foldr HS.delete
|
||||||
|
|
||||||
|
insertFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a
|
||||||
|
insertFrom = flip $ foldr HS.insert
|
||||||
|
|
||||||
|
toHashSetOf :: Hashable a => Getting (Endo (HashSet a)) s a -> s -> HashSet a
|
||||||
|
toHashSetOf l = foldrOf l HS.insert mempty
|
||||||
|
|
||||||
|
free :: Exp -> HashSet Name
|
||||||
|
free = go where
|
||||||
|
gokap (MkKappa xs m) = go m & deleteFrom xs
|
||||||
|
golam (MkLambda xs k m) = go m & deleteFrom xs & sans k
|
||||||
|
goabs = \case
|
||||||
|
AbsKappa kap -> gokap kap
|
||||||
|
AbsLambda lam -> golam lam
|
||||||
|
go = \case
|
||||||
|
ExpPrim p k ->
|
||||||
|
p & toHashSetOf (folded . #ValVar)
|
||||||
|
& HS.union (gokap k)
|
||||||
|
ExpLetRec bs m ->
|
||||||
|
foldMapOf (each . _2) goabs bs <> go m
|
||||||
|
& deleteFrom (bs ^.. each . _1)
|
||||||
|
ExpContinue k xs -> HS.fromList $ k : xs ^.. each . #ValVar
|
||||||
|
ExpIf c t f -> toHashSetOf #ValVar c <> go t <> go f
|
||||||
|
ExpApply f xs k -> toHashSetOf (each . #ValVar) (f:xs) <> HS.singleton k
|
||||||
|
|
||||||
|
-- | Free variables given in the order of their appearance.
|
||||||
|
free' :: Exp -> List Name
|
||||||
|
free' = nubOrd . goFree HS.empty where
|
||||||
|
|
||||||
|
goFreeKap bound (MkKappa xs m) = goFree (bound & insertFrom xs) m
|
||||||
|
goFreeLam bound (MkLambda xs k m) = goFree (bound & insertFrom (k:xs)) m
|
||||||
|
goFreeAbs bound = \case
|
||||||
|
AbsKappa kap -> goFreeKap bound kap
|
||||||
|
AbsLambda lam -> goFreeLam bound lam
|
||||||
|
|
||||||
|
goFree :: HashSet Name -> Exp -> List Name
|
||||||
|
goFree bound = \case
|
||||||
|
ExpPrim p k ->
|
||||||
|
p & toListOf (folded . #ValVar . filtered (`notElem` bound))
|
||||||
|
& (<> goFreeKap bound k)
|
||||||
|
ExpLetRec bs m ->
|
||||||
|
foldMapOf (each . _2) (goFreeAbs bound') bs <> goFree bound' m
|
||||||
|
where bound' = bound & insertFrom (bs ^.. each . _1)
|
||||||
|
ExpContinue k xs -> filter (`notElem` bound) (k : xs ^.. each . #ValVar)
|
||||||
|
ExpIf c t f ->
|
||||||
|
(c ^.. #ValVar . filtered (`notElem` bound))
|
||||||
|
<> goFree bound t <> goFree bound f
|
||||||
|
ExpApply f xs k ->
|
||||||
|
(f:xs) ^.. (each . #ValVar . filtered (`notElem` bound))
|
||||||
|
<> (k ^.. filtered (`notElem` bound))
|
||||||
|
|
||||||
|
freeLambda :: Lambda -> List Name
|
||||||
|
freeLambda (MkLambda {binders,ktail,body}) = _
|
||||||
|
|||||||
+48
-27
@@ -1,44 +1,33 @@
|
|||||||
{-# LANGUAGE OverloadedLabels #-}
|
|
||||||
{-# LANGUAGE OverloadedLists #-}
|
|
||||||
{-# LANGUAGE OverloadedRecordDot #-}
|
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
|
||||||
{-# LANGUAGE OrPatterns #-}
|
|
||||||
module Gyehoek.Driver
|
module Gyehoek.Driver
|
||||||
(main, lower_e2e, convert_e2e, parse_e2e)
|
(main, lower_e2e, convert_e2e, parse_e2e)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Gyehoek.Options
|
import Gyehoek.Options
|
||||||
import qualified Data.Text.IO as TIO
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Prelude hiding (readFile)
|
import Prelude hiding (readFile)
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Data.Generics.Labels
|
|
||||||
import System.OsPath (OsPath)
|
|
||||||
import System.FilePath ((-<.>), dropExtension)
|
|
||||||
import Effectful.FileSystem
|
import Effectful.FileSystem
|
||||||
import Effectful
|
import Effectful
|
||||||
import Effectful.FileSystem.IO qualified as FS
|
import Effectful.FileSystem.IO qualified as FS
|
||||||
import Effectful.FileSystem.IO.ByteString qualified as FB
|
import Effectful.FileSystem.IO.ByteString qualified as FB
|
||||||
import Gyehoek.GenSym (runGenSym, GenSym, gensym, gensym')
|
import Gyehoek.GenSym (runGenSym, GenSym)
|
||||||
import qualified Gyehoek.Sexp as Sexp
|
import qualified Gyehoek.Sexp as Sexp
|
||||||
import Data.Text.Lens
|
|
||||||
import Data.List (List)
|
|
||||||
import qualified Gyehoek.Scheme.Syntax as Scm
|
import qualified Gyehoek.Scheme.Syntax as Scm
|
||||||
import Effectful.Exception
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Data.Text.Encoding as T
|
import qualified Data.Text.Encoding as T
|
||||||
import System.IO (Handle)
|
import System.IO (Handle)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import System.IO qualified as IO
|
||||||
import qualified Cradle as C
|
|
||||||
import Gyehoek.CPS.Convert
|
import Gyehoek.CPS.Convert
|
||||||
import Gyehoek.CPS.Lower
|
import Gyehoek.CPS.Lower
|
||||||
import Data.Foldable
|
|
||||||
import qualified Gyehoek.Scheme.Syntax
|
|
||||||
import Gyehoek.CPS.Syntax qualified as Cps
|
import Gyehoek.CPS.Syntax qualified as Cps
|
||||||
import Data.Maybe (fromMaybe)
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Text.Pretty.Simple (pShow, pShowNoColor)
|
import Text.Pretty.Simple (pShowNoColor)
|
||||||
|
import System.Process.Typed
|
||||||
|
import Data.Text.Encoding (encodeUtf8)
|
||||||
|
import System.Environment.Blank (getEnvDefault)
|
||||||
|
import GHC.Conc (atomically)
|
||||||
|
import qualified Data.Text.IO as TIO
|
||||||
|
import qualified Data.ByteString.Lazy as BS
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
@@ -48,8 +37,8 @@ main = do
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
hPutStr :: FileSystem :> es => Handle -> Text -> Eff es ()
|
-- hPutStr :: FileSystem :> es => Handle -> Text -> Eff es ()
|
||||||
hPutStr h = FB.hPutStr h . T.encodeUtf8
|
-- hPutStr h = FB.hPutStr h . T.encodeUtf8
|
||||||
|
|
||||||
hPutStrLn :: FileSystem :> es => Handle -> Text -> Eff es ()
|
hPutStrLn :: FileSystem :> es => Handle -> Text -> Eff es ()
|
||||||
hPutStrLn h = FB.hPutStrLn h . T.encodeUtf8
|
hPutStrLn h = FB.hPutStrLn h . T.encodeUtf8
|
||||||
@@ -57,8 +46,8 @@ hPutStrLn h = FB.hPutStrLn h . T.encodeUtf8
|
|||||||
hGetContents :: FileSystem :> es => Handle -> Eff es Text
|
hGetContents :: FileSystem :> es => Handle -> Eff es Text
|
||||||
hGetContents h = T.decodeUtf8 <$> FB.hGetContents h
|
hGetContents h = T.decodeUtf8 <$> FB.hGetContents h
|
||||||
|
|
||||||
readFile :: FileSystem :> es => FilePath -> Eff es Text
|
-- readFile :: FileSystem :> es => FilePath -> Eff es Text
|
||||||
readFile f = FS.withFile f FS.ReadMode hGetContents
|
-- readFile f = FS.withFile f FS.ReadMode hGetContents
|
||||||
|
|
||||||
withFile
|
withFile
|
||||||
:: (FileSystem :> es)
|
:: (FileSystem :> es)
|
||||||
@@ -67,12 +56,41 @@ withFile "-" FS.ReadMode k = k FS.stdin
|
|||||||
withFile "-" (FS.WriteMode; FS.AppendMode) k = k FS.stdout
|
withFile "-" (FS.WriteMode; FS.AppendMode) k = k FS.stdout
|
||||||
withFile f m k = FS.withFile f m k
|
withFile f m k = FS.withFile f m k
|
||||||
|
|
||||||
|
fileName :: FilePath -> FilePath
|
||||||
|
fileName "-" = "<interactive>"
|
||||||
|
fileName e = e
|
||||||
|
|
||||||
readScm :: FileSystem :> es => FilePath -> Eff es Scm.Program
|
readScm :: FileSystem :> es => FilePath -> Eff es Scm.Program
|
||||||
readScm f =
|
readScm f =
|
||||||
withFile f FS.ReadMode $ \h ->
|
withFile f FS.ReadMode $ \h ->
|
||||||
Sexp.parseSexps @Scm.CommandOrDef f <$> hGetContents h
|
Sexp.parseSexps @Scm.CommandOrDef (fileName f) <$> hGetContents h
|
||||||
>>= either error (pure . Scm.MkProgram)
|
>>= either error (pure . Scm.MkProgram)
|
||||||
|
|
||||||
|
inspectWasm :: IOE :> es => Text -> Eff es ()
|
||||||
|
inspectWasm wat = do
|
||||||
|
pager_cmd <- liftIO $ getEnvDefault "PAGER" "less"
|
||||||
|
let wasmtools_cfg
|
||||||
|
= proc "wasm-tools" ["print", "-pf", "--print-operand-stack"
|
||||||
|
,"--color", "always", "-"]
|
||||||
|
-- & setStdin (byteStringInput . view lazy . encodeUtf8 $ wat)
|
||||||
|
-- & setStdout byteStringOutput
|
||||||
|
& setStdin createPipe
|
||||||
|
& setStdout createPipe
|
||||||
|
& setStderr inherit
|
||||||
|
let pager_cfg = proc pager_cmd []
|
||||||
|
& setStdin createPipe
|
||||||
|
& setStdout inherit
|
||||||
|
& setStderr inherit
|
||||||
|
liftIO $ withProcessWait_ wasmtools_cfg \wasmtools -> do
|
||||||
|
TIO.hPutStrLn (getStdin wasmtools) wat
|
||||||
|
IO.hFlush (getStdin wasmtools)
|
||||||
|
IO.hClose (getStdin wasmtools)
|
||||||
|
withProcessWait_ pager_cfg \pager -> do
|
||||||
|
t <- BS.hGetContents (getStdout wasmtools)
|
||||||
|
BS.hPut (getStdin pager) t
|
||||||
|
IO.hFlush (getStdin pager)
|
||||||
|
IO.hClose (getStdin pager)
|
||||||
|
|
||||||
driver
|
driver
|
||||||
:: (GenSym :> es, FileSystem :> es, IOE :> es)
|
:: (GenSym :> es, FileSystem :> es, IOE :> es)
|
||||||
=> Options -> Eff es ()
|
=> Options -> Eff es ()
|
||||||
@@ -84,8 +102,11 @@ driver opts = do
|
|||||||
when opts.dumpCPS do
|
when opts.dumpCPS do
|
||||||
hPutStrLn FS.stdout $ Sexp.encodePretty cps ^?! _Right
|
hPutStrLn FS.stdout $ Sexp.encodePretty cps ^?! _Right
|
||||||
wat <- lowerProgram cps
|
wat <- lowerProgram cps
|
||||||
withFile opts.output FS.WriteMode \h ->
|
if not opts.inspectWasm then
|
||||||
hPutStrLn h wat
|
withFile opts.output FS.WriteMode \h ->
|
||||||
|
hPutStrLn h wat
|
||||||
|
else
|
||||||
|
inspectWasm wat
|
||||||
|
|
||||||
parse_e2e :: FilePath -> IO Scm.Program
|
parse_e2e :: FilePath -> IO Scm.Program
|
||||||
parse_e2e = runEff . runFileSystem . readScm
|
parse_e2e = runEff . runFileSystem . readScm
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ data Options = MkOptions
|
|||||||
-- , dumpQBE :: Maybe FilePath
|
-- , dumpQBE :: Maybe FilePath
|
||||||
dumpCPS :: Bool
|
dumpCPS :: Bool
|
||||||
, dumpParsed :: Bool
|
, dumpParsed :: Bool
|
||||||
|
, inspectWasm :: Bool
|
||||||
, output :: FilePath
|
, output :: FilePath
|
||||||
, sourceFile :: FilePath
|
, sourceFile :: FilePath
|
||||||
}
|
}
|
||||||
@@ -49,10 +50,12 @@ parseOutput = strOption
|
|||||||
|
|
||||||
parseDumpCPS = switch (long "dump-cps")
|
parseDumpCPS = switch (long "dump-cps")
|
||||||
parseDumpParsed = switch (long "dump-parsed")
|
parseDumpParsed = switch (long "dump-parsed")
|
||||||
|
parseInspectWasm = switch $ long "inspect-wasm" <> short 'p'
|
||||||
|
|
||||||
parser :: Parser Options
|
parser :: Parser Options
|
||||||
parser = MkOptions
|
parser = MkOptions
|
||||||
<$> parseDumpCPS
|
<$> parseDumpCPS
|
||||||
<*> parseDumpParsed
|
<*> parseDumpParsed
|
||||||
|
<*> parseInspectWasm
|
||||||
<*> parseOutput
|
<*> parseOutput
|
||||||
<*> argument str (metavar "FILE")
|
<*> argument str (metavar "FILE")
|
||||||
|
|||||||
@@ -20,41 +20,44 @@ module Gyehoek.Scheme.Syntax
|
|||||||
, primSexpIso
|
, primSexpIso
|
||||||
, pattern Void
|
, pattern Void
|
||||||
, free
|
, free
|
||||||
, qexp
|
|
||||||
, qprog
|
|
||||||
, subst
|
, subst
|
||||||
|
, getName
|
||||||
|
, scm
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import Language.SexpGrammar
|
import Language.SexpGrammar
|
||||||
( SexpIso(..), list, el, (>>>), rest, sym, symbol )
|
( SexpIso(..), list, el, rest, sym, symbol )
|
||||||
import Language.SexpGrammar qualified as Sexp
|
import Language.SexpGrammar qualified as Sexp
|
||||||
import Language.Sexp.Located qualified as S
|
import Language.Sexp.Located qualified as S
|
||||||
import Language.SexpGrammar.Generic
|
import Language.SexpGrammar.Generic
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
import Prelude hiding ((.), id)
|
import Prelude hiding ((.), id)
|
||||||
import Control.Category
|
import Control.Category
|
||||||
import Data.List.NonEmpty (NonEmpty ((:|)))
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
import Gyehoek.Sexp qualified
|
import Gyehoek.Sexp qualified
|
||||||
import Gyehoek.GenSym (Gen)
|
import Gyehoek.GenSym (Gen)
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Data.String (IsString)
|
import Data.String (IsString)
|
||||||
import Data.Hashable (Hashable)
|
import Data.Hashable (Hashable)
|
||||||
import Control.Lens.Unsound (prismSum)
|
|
||||||
import Data.Data (Data)
|
import Data.Data (Data)
|
||||||
import Data.Functor.Foldable.TH (makeBaseFunctor)
|
import Data.Functor.Foldable.TH (makeBaseFunctor)
|
||||||
import Data.Functor.Foldable hiding (fold)
|
import Data.Functor.Foldable hiding (fold)
|
||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
import qualified Data.HashSet as HS
|
import qualified Data.HashSet as HS
|
||||||
import Data.Foldable (fold)
|
import Data.Foldable (fold)
|
||||||
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
|
|
||||||
|
|
||||||
newtype Name = MkName { getName :: Text }
|
newtype Name = MkName { inner :: Text }
|
||||||
deriving newtype (Show, Eq, IsString, Gen, Hashable)
|
deriving newtype (Show, Eq, Ord, IsString, Gen, Hashable)
|
||||||
deriving stock (Generic, Data)
|
deriving stock (Generic, Data)
|
||||||
|
|
||||||
|
getName :: Name -> Text
|
||||||
|
getName (MkName x) = x
|
||||||
|
|
||||||
data Prim e
|
data Prim e
|
||||||
= PrimAdd e e
|
= PrimAdd e e
|
||||||
| PrimSub e e
|
| PrimSub e e
|
||||||
@@ -69,7 +72,7 @@ data Prim e
|
|||||||
| PrimWrite e
|
| PrimWrite e
|
||||||
| PrimZeroP e
|
| PrimZeroP e
|
||||||
| PrimNewline
|
| PrimNewline
|
||||||
deriving (Show, Generic, Functor, Foldable, Traversable, Data)
|
deriving (Show, Generic, Functor, Foldable, Traversable, Data, Eq)
|
||||||
|
|
||||||
instance Each (Prim e) (Prim e') e e'
|
instance Each (Prim e) (Prim e') e e'
|
||||||
|
|
||||||
@@ -79,7 +82,7 @@ data Lit
|
|||||||
| LitBool Bool
|
| LitBool Bool
|
||||||
| LitString Text
|
| LitString Text
|
||||||
| LitQuote Sexp
|
| LitQuote Sexp
|
||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
pattern Void :: Lit
|
pattern Void :: Lit
|
||||||
pattern Void = LitNil
|
pattern Void = LitNil
|
||||||
@@ -104,7 +107,7 @@ data Sexp
|
|||||||
= SexpCons Sexp Sexp
|
= SexpCons Sexp Sexp
|
||||||
| SexpSymbol Text
|
| SexpSymbol Text
|
||||||
| SexpLit Lit
|
| SexpLit Lit
|
||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
data CommandOrDef
|
data CommandOrDef
|
||||||
= Command Exp
|
= Command Exp
|
||||||
@@ -121,8 +124,6 @@ instance Each Program Program (Either Exp Def) (Either Exp Def) where
|
|||||||
each = #commandsAndDefs . each . go
|
each = #commandsAndDefs . each . go
|
||||||
where
|
where
|
||||||
inj = either Command Definition
|
inj = either Command Definition
|
||||||
toeither (Command e) = Left e
|
|
||||||
toeither (Definition d) = Right d
|
|
||||||
go :: Traversal' CommandOrDef (Either Exp Def)
|
go :: Traversal' CommandOrDef (Either Exp Def)
|
||||||
go k (Command e) = inj <$> k (Left e)
|
go k (Command e) = inj <$> k (Left e)
|
||||||
go k (Definition d) = inj <$> k (Right d)
|
go k (Definition d) = inj <$> k (Right d)
|
||||||
@@ -184,7 +185,7 @@ instance SexpIso Lit where
|
|||||||
|
|
||||||
instance SexpIso Sexp where
|
instance SexpIso Sexp where
|
||||||
sexpIso = match
|
sexpIso = match
|
||||||
$ With (\cons -> cons . Gyehoek.Sexp.todo)
|
$ With (\conss -> conss . Gyehoek.Sexp.todo)
|
||||||
$ With (\s -> s . symbol)
|
$ With (\s -> s . symbol)
|
||||||
$ With (\lit -> lit . sexpIso)
|
$ With (\lit -> lit . sexpIso)
|
||||||
$ End
|
$ End
|
||||||
@@ -229,8 +230,8 @@ instance SexpIso CommandOrDef where
|
|||||||
|
|
||||||
-- utilities
|
-- utilities
|
||||||
|
|
||||||
qexp = Gyehoek.Sexp.makeSx $ sexpIso @Exp
|
scm :: QuasiQuoter
|
||||||
qprog = Gyehoek.Sexp.makeSxs (sexpIso @CommandOrDef) MkProgram
|
scm = Gyehoek.Sexp.makeSx [|| Gyehoek.Sexp.fromSexp @Exp ||]
|
||||||
|
|
||||||
free :: Exp -> HashSet Name
|
free :: Exp -> HashSet Name
|
||||||
free = cata \case
|
free = cata \case
|
||||||
|
|||||||
+114
-34
@@ -27,6 +27,7 @@ module Gyehoek.Sexp
|
|||||||
, encodePretty
|
, encodePretty
|
||||||
, UglySexpIso(..)
|
, UglySexpIso(..)
|
||||||
, AsSexpIso(..)
|
, AsSexpIso(..)
|
||||||
|
, SpliceSexp(..)
|
||||||
, parseSexpsWithPos
|
, parseSexpsWithPos
|
||||||
, parseSexpWithPos
|
, parseSexpWithPos
|
||||||
, parseSexp
|
, parseSexp
|
||||||
@@ -34,13 +35,15 @@ module Gyehoek.Sexp
|
|||||||
, sxs
|
, sxs
|
||||||
, makeSx
|
, makeSx
|
||||||
, makeSxs
|
, makeSxs
|
||||||
|
, makeSx'
|
||||||
, toSexp
|
, toSexp
|
||||||
, fromSexp
|
, fromSexp
|
||||||
, stripLocation
|
, stripLocation
|
||||||
, sx'
|
, format
|
||||||
, sxs'
|
, equivalent
|
||||||
|
, encodeOrShow
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Language.SexpGrammar as Sexp hiding (toSexp, List, encode, decode, encodeWith, decodeWith, iso, encodePrettyWith, encodePretty, fromSexp)
|
import Language.SexpGrammar as Sexp hiding (toSexp, List, encode, decode, encodeWith, decodeWith, iso, encodePrettyWith, encodePretty, fromSexp)
|
||||||
@@ -56,7 +59,7 @@ import Data.List (List, groupBy)
|
|||||||
import Data.Text.Encoding
|
import Data.Text.Encoding
|
||||||
import Data.Either (either)
|
import Data.Either (either)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Control.Lens
|
import Control.Lens hiding (para)
|
||||||
import Data.Generics.Labels
|
import Data.Generics.Labels
|
||||||
import System.Process
|
import System.Process
|
||||||
import GHC.IO.Unsafe (unsafePerformIO)
|
import GHC.IO.Unsafe (unsafePerformIO)
|
||||||
@@ -67,14 +70,23 @@ import Data.Void (absurd, Void)
|
|||||||
import Data.Coerce (coerce)
|
import Data.Coerce (coerce)
|
||||||
import qualified Data.Map
|
import qualified Data.Map
|
||||||
import Language.Haskell.TH.Quote
|
import Language.Haskell.TH.Quote
|
||||||
import Language.Haskell.TH (Quote, location, Loc (..), ExpQ, varE, mkName, listE, Exp, appE, conE)
|
import Language.Haskell.TH (Quote, location, Loc (..), ExpQ, varE, mkName, listE, Exp, appE, conE, Q, Code, unTypeCode)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Control.Category
|
import qualified Control.Category
|
||||||
import Data.Data (Data, Typeable, cast)
|
import Data.Data (Data (..), Typeable, cast)
|
||||||
import Language.Haskell.TH.Syntax (lift, Lift)
|
import Language.Haskell.TH.Syntax (lift, Lift, liftData)
|
||||||
import GHC.IsList (fromList)
|
import GHC.IsList (fromList)
|
||||||
import Data.Functor.Foldable (cata)
|
import Data.Functor.Foldable (cata, para, embed)
|
||||||
import Data.Functor.Classes (Show1(..))
|
import Data.Functor.Classes (Show1(..))
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
import Numeric.Natural (Natural)
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
|
import Control.Applicative (Alternative((<|>)))
|
||||||
|
import Debug.Pretty.Simple
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import qualified Data.Vector.Strict
|
||||||
|
import Data.Function (on)
|
||||||
|
import Data.String (IsString (fromString))
|
||||||
|
|
||||||
|
|
||||||
sexp :: SexpIso a => Iso' a Text
|
sexp :: SexpIso a => Iso' a Text
|
||||||
@@ -82,6 +94,9 @@ sexp = iso
|
|||||||
(either error id . encode)
|
(either error id . encode)
|
||||||
(either error id . decode)
|
(either error id . decode)
|
||||||
|
|
||||||
|
format :: Sexp -> Text
|
||||||
|
format = decodeUtf8 . view strict . SL.format
|
||||||
|
|
||||||
encode :: SexpIso a => a -> Either String Text
|
encode :: SexpIso a => a -> Either String Text
|
||||||
encode = encodeWith sexpIso
|
encode = encodeWith sexpIso
|
||||||
|
|
||||||
@@ -109,6 +124,12 @@ parseSexp :: SexpIso a => FilePath -> Text -> Either String a
|
|||||||
parseSexp f = marshal . SL.parseSexp f . view lazy . encodeUtf8
|
parseSexp f = marshal . SL.parseSexp f . view lazy . encodeUtf8
|
||||||
where marshal = join . traverseOf _Right (Sexp.fromSexp sexpIso)
|
where marshal = join . traverseOf _Right (Sexp.fromSexp sexpIso)
|
||||||
|
|
||||||
|
readSexpWithPos :: Position -> Text -> Either String Sexp
|
||||||
|
readSexpWithPos pos = SL.parseSexpWithPos pos . view lazy . encodeUtf8
|
||||||
|
|
||||||
|
readSexpsWithPos :: Position -> Text -> Either String (List Sexp)
|
||||||
|
readSexpsWithPos pos = SL.parseSexpsWithPos pos . view lazy . encodeUtf8
|
||||||
|
|
||||||
parseSexpsWithPos :: SexpGrammar a -> Position -> Text -> Either String (List a)
|
parseSexpsWithPos :: SexpGrammar a -> Position -> Text -> Either String (List a)
|
||||||
parseSexpsWithPos g pos =
|
parseSexpsWithPos g pos =
|
||||||
marshal . SL.parseSexpsWithPos pos . view lazy . encodeUtf8
|
marshal . SL.parseSexpsWithPos pos . view lazy . encodeUtf8
|
||||||
@@ -242,6 +263,9 @@ getPos = do
|
|||||||
fromSexp :: SexpIso a => Sexp -> a
|
fromSexp :: SexpIso a => Sexp -> a
|
||||||
fromSexp = either error id . Sexp.fromSexp sexpIso
|
fromSexp = either error id . Sexp.fromSexp sexpIso
|
||||||
|
|
||||||
|
fromSexp' :: SexpGrammar a -> Sexp -> a
|
||||||
|
fromSexp' g = either error id . Sexp.fromSexp g
|
||||||
|
|
||||||
toSexp :: SexpIso a => a -> Sexp
|
toSexp :: SexpIso a => a -> Sexp
|
||||||
toSexp = either error id . Sexp.toSexp sexpIso
|
toSexp = either error id . Sexp.toSexp sexpIso
|
||||||
|
|
||||||
@@ -269,12 +293,36 @@ stripLocation = cata \case
|
|||||||
SL.Compose (a SL.:< e) ->
|
SL.Compose (a SL.:< e) ->
|
||||||
SL.Fix . SL.Compose $ SL.dummyPos SL.:< e
|
SL.Fix . SL.Compose $ SL.dummyPos SL.:< e
|
||||||
|
|
||||||
metaSexp :: Sexp.Sexp -> Maybe ExpQ
|
-- | @('==')@ for 'Sexp's modulo source location — return true if the
|
||||||
metaSexp (Unquote x) =
|
-- two sexps are equal in all but 'Position' fields.
|
||||||
Just [| stripLocation . toSexp $ $(varE (mkName (T.unpack x))) |]
|
equivalent :: Sexp -> Sexp -> Bool
|
||||||
metaSexp (SL.ParenList xs)
|
equivalent = (==) `on` stripLocation
|
||||||
| (_:_) <- xs ^.. each . _UnquoteSplicing
|
|
||||||
= Just [| stripLocation . toSexp $ SL.ParenList (mconcat $(listE spans)) |]
|
instance SexpIso Natural where
|
||||||
|
sexpIso = Sexp.integer >>> Sexp.partialOsi f g
|
||||||
|
where
|
||||||
|
f n | n < 0 = Left $ Sexp.unexpected "negative"
|
||||||
|
<> Sexp.expected "natural"
|
||||||
|
| otherwise = Right $ fromIntegral n
|
||||||
|
g n = fromIntegral n
|
||||||
|
|
||||||
|
class SpliceSexp a where
|
||||||
|
spliceSexp :: a -> List Sexp
|
||||||
|
|
||||||
|
instance SexpIso a => SpliceSexp (Data.Vector.Strict.Vector a) where
|
||||||
|
spliceSexp = toSexps
|
||||||
|
|
||||||
|
instance SexpIso a => SpliceSexp (Vector a) where
|
||||||
|
spliceSexp = toSexps
|
||||||
|
|
||||||
|
instance SexpIso a => SpliceSexp (List a) where
|
||||||
|
spliceSexp = toSexps
|
||||||
|
|
||||||
|
instance SpliceSexp Sexp where
|
||||||
|
spliceSexp = toListOf each
|
||||||
|
|
||||||
|
unquoteSplicingRecursive :: List Sexp.Sexp -> ExpQ
|
||||||
|
unquoteSplicingRecursive xs = [| mconcat $(spans) |]
|
||||||
where
|
where
|
||||||
spans = xs
|
spans = xs
|
||||||
& groupBy \cases
|
& groupBy \cases
|
||||||
@@ -282,10 +330,31 @@ metaSexp (SL.ParenList xs)
|
|||||||
_ (UnquoteSplicing _) -> False
|
_ (UnquoteSplicing _) -> False
|
||||||
_ _ -> True
|
_ _ -> True
|
||||||
& fmap \case
|
& fmap \case
|
||||||
|
-- [e@(Unquote _)] ->
|
||||||
|
-- case unquote e of
|
||||||
|
-- Just x -> [| [$(x)] |]
|
||||||
|
-- Nothing -> error "unreachable"
|
||||||
[UnquoteSplicing x] ->
|
[UnquoteSplicing x] ->
|
||||||
[| stripLocation <$> toSexps $(varE (mkName (T.unpack x))) |]
|
[| spliceSexp $(varE (mkName (T.unpack x))) |]
|
||||||
x -> [| stripLocation <$> x |]
|
es -> listE $ unquoteRecursive <$> es
|
||||||
metaSexp _ = Nothing
|
& listE
|
||||||
|
|
||||||
|
unquoteRecursive :: Sexp.Sexp -> ExpQ
|
||||||
|
unquoteRecursive = \case
|
||||||
|
Unquote x -> [| toSexp $(varE (mkName (T.unpack x))) |]
|
||||||
|
SL.ParenList xs -> [|SL.ParenList $(unquoteSplicingRecursive xs)|]
|
||||||
|
e -> liftData e
|
||||||
|
|
||||||
|
_ParenList :: Prism' Sexp (List Sexp)
|
||||||
|
_ParenList = prism' SL.ParenList \case
|
||||||
|
SL.ParenList xs -> Just xs
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
metaSexps :: List Sexp.Sexp -> Maybe ExpQ
|
||||||
|
metaSexps = Just . unquoteSplicingRecursive
|
||||||
|
|
||||||
|
metaSexp :: Sexp.Sexp -> Maybe ExpQ
|
||||||
|
metaSexp = Just . unquoteRecursive
|
||||||
|
|
||||||
-- 뻘짓뻘짓뻘짓뻘짓뻘짓
|
-- 뻘짓뻘짓뻘짓뻘짓뻘짓
|
||||||
class Lift1 f where
|
class Lift1 f where
|
||||||
@@ -312,46 +381,57 @@ instance Lift1 SL.SexpF where
|
|||||||
SL.ParenListF es -> [|SL.ParenListF $(liftLift l es)|]
|
SL.ParenListF es -> [|SL.ParenListF $(liftLift l es)|]
|
||||||
SL.BracketListF es -> [|SL.BracketListF $(liftLift l es)|]
|
SL.BracketListF es -> [|SL.BracketListF $(liftLift l es)|]
|
||||||
SL.BraceListF es -> [|SL.BraceListF $(liftLift l es)|]
|
SL.BraceListF es -> [|SL.BraceListF $(liftLift l es)|]
|
||||||
SL.ModifiedF p e -> [|SL.Modified $(lift p) $(l e)|]
|
SL.ModifiedF p e -> [|SL.ModifiedF $(lift p) $(l e)|]
|
||||||
|
|
||||||
-- deriving instance Lift a => Lift (SL.SexpF a)
|
-- deriving instance Lift a => Lift (SL.SexpF a)
|
||||||
deriving instance Lift SL.Atom
|
deriving instance Lift SL.Atom
|
||||||
deriving instance Lift SL.Position
|
deriving instance Lift SL.Position
|
||||||
deriving instance Lift SL.Prefix
|
deriving instance Lift SL.Prefix
|
||||||
|
|
||||||
|
encodeOrShow :: (SexpIso a, Show a, IsString s) => a -> s
|
||||||
|
encodeOrShow a = fromString case encode a of
|
||||||
|
Left _ -> show a
|
||||||
|
Right e -> T.unpack e
|
||||||
|
|
||||||
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
||||||
extQ f g a = maybe (f a) g (cast a)
|
extQ f g a = maybe (f a) g (cast a)
|
||||||
|
|
||||||
makeSxs
|
makeSxs :: Data r => Code Q (List Sexp -> r) -> QuasiQuoter
|
||||||
:: Data b
|
makeSxs f = QuasiQuoter
|
||||||
=> (List a -> b) -> SexpGrammar a -> QuasiQuoter
|
|
||||||
makeSxs f g = QuasiQuoter
|
|
||||||
{ quoteExp = \str -> do
|
{ quoteExp = \str -> do
|
||||||
pos <- getPos
|
pos <- getPos
|
||||||
case parseSexpsWithPos g pos (T.pack str) of
|
case readSexpsWithPos pos (T.pack str) of
|
||||||
Left e -> fail e
|
Left e -> fail e
|
||||||
Right xs -> dataToExpQ (const Nothing `extQ` metaSexp) (f xs)
|
Right xs -> [| $(unTypeCode f) $e |]
|
||||||
|
where
|
||||||
|
e = dataToExpQ
|
||||||
|
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
||||||
|
xs
|
||||||
, quotePat = undefined
|
, quotePat = undefined
|
||||||
, quoteType = undefined
|
, quoteType = undefined
|
||||||
, quoteDec = undefined
|
, quoteDec = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
makeSx
|
-- | An untyped variant of 'makeSx', useful when the user function is
|
||||||
:: (Data a, Data r)
|
-- polymorphic in its return value.
|
||||||
=> (a -> r) -> SexpGrammar a -> QuasiQuoter
|
makeSx' :: ExpQ -> QuasiQuoter
|
||||||
makeSx f g = QuasiQuoter
|
makeSx' f = QuasiQuoter
|
||||||
{ quoteExp = \str -> do
|
{ quoteExp = \str -> do
|
||||||
pos <- getPos
|
pos <- getPos
|
||||||
case parseSexpWithPos g pos (T.pack str) of
|
case readSexpWithPos pos (T.pack str) of
|
||||||
Left e -> fail e
|
Left e -> fail e
|
||||||
Right x -> dataToExpQ (const Nothing `extQ` metaSexp) (f x)
|
Right x -> [| $f $e |]
|
||||||
|
where
|
||||||
|
e = dataToExpQ
|
||||||
|
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
||||||
|
x
|
||||||
, quotePat = undefined
|
, quotePat = undefined
|
||||||
, quoteType = undefined
|
, quoteType = undefined
|
||||||
, quoteDec = undefined
|
, quoteDec = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
sxs = makeSxs id (sexpIso @Sexp)
|
makeSx :: Data r => Code Q (Sexp -> r) -> QuasiQuoter
|
||||||
sx = makeSx id (sexpIso @Sexp)
|
makeSx = makeSx' . unTypeCode
|
||||||
|
|
||||||
sxs' = makeSxs (fmap stripLocation) (sexpIso @Sexp)
|
sxs = makeSxs [||id||]
|
||||||
sx' = makeSx stripLocation (sexpIso @Sexp)
|
sx = makeSx [||id||]
|
||||||
|
|||||||
+44
-37
@@ -1,15 +1,7 @@
|
|||||||
{- HLINT ignore "Use newtype instead of data" -}
|
{- HLINT ignore "Use newtype instead of data" -}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE DeepSubsumption #-}
|
|
||||||
{-# LANGUAGE NoFieldSelectors #-}
|
|
||||||
{-# LANGUAGE OverloadedRecordDot #-}
|
|
||||||
{-# LANGUAGE RecordPuns #-}
|
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE OverloadedLabels #-}
|
|
||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
{-# LANGUAGE ImpredicativeTypes #-}
|
{-# LANGUAGE TemplateHaskellQuotes #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
|
||||||
module Gyehoek.Wasm
|
module Gyehoek.Wasm
|
||||||
(
|
(
|
||||||
-- * syntax
|
-- * syntax
|
||||||
@@ -20,8 +12,6 @@ module Gyehoek.Wasm
|
|||||||
, expr
|
, expr
|
||||||
, Gyehoek.Sexp.sx
|
, Gyehoek.Sexp.sx
|
||||||
, Gyehoek.Sexp.sxs
|
, Gyehoek.Sexp.sxs
|
||||||
, Gyehoek.Sexp.sx'
|
|
||||||
, Gyehoek.Sexp.sxs'
|
|
||||||
-- * GenMod effect
|
-- * GenMod effect
|
||||||
, GenMod
|
, GenMod
|
||||||
, runGenMod
|
, runGenMod
|
||||||
@@ -29,43 +19,37 @@ module Gyehoek.Wasm
|
|||||||
, defineFunction
|
, defineFunction
|
||||||
, defineType
|
, defineType
|
||||||
, defineGlobal
|
, defineGlobal
|
||||||
, declare
|
, emit
|
||||||
|
, renderModule
|
||||||
|
, wat
|
||||||
|
, wats
|
||||||
|
, defineFunctions
|
||||||
|
, defineTypes
|
||||||
|
, defineGlobals
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Language.SexpGrammar
|
import Language.SexpGrammar
|
||||||
( SexpIso(..), list, el, (>>>), rest, sym, symbol, (:-) )
|
( SexpIso(..), (>>>) )
|
||||||
import Language.SexpGrammar qualified as Sexp
|
import Language.SexpGrammar qualified as Sexp
|
||||||
import Language.SexpGrammar.Generic
|
import Language.SexpGrammar.Generic
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import GHC.Generics (Generic, Generically(..))
|
import GHC.Generics (Generic)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.String (IsString (fromString))
|
|
||||||
import Text.Printf
|
|
||||||
import Effectful
|
import Effectful
|
||||||
import Numeric.Natural (Natural)
|
import Numeric.Natural (Natural)
|
||||||
import Effectful.Dispatch.Dynamic
|
import Effectful.Dispatch.Dynamic
|
||||||
import Effectful.State.Dynamic
|
import Effectful.State.Dynamic
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Data.Generics.Labels
|
import Data.Vector.Strict (Vector)
|
||||||
import Data.Vector (Vector)
|
import qualified Data.Vector.Strict as V
|
||||||
import Data.String.Interpolate
|
|
||||||
import qualified Data.Vector as V
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import Effectful.Writer.Dynamic
|
|
||||||
import Control.Applicative (Alternative((<|>)))
|
|
||||||
import Control.Category qualified as Cat
|
|
||||||
import Data.Vector.Lens
|
|
||||||
import Data.Either (fromLeft, fromRight)
|
|
||||||
import Language.Sexp.Located
|
import Language.Sexp.Located
|
||||||
import qualified Gyehoek.Sexp
|
import qualified Gyehoek.Sexp
|
||||||
import GHC.IsList (IsList(..))
|
import GHC.IsList (IsList(..))
|
||||||
import Data.Coerce (coerce)
|
|
||||||
import qualified Control.Category
|
|
||||||
import Data.Functor (void)
|
|
||||||
import Language.Haskell.TH.Quote (QuasiQuoter)
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
import Data.Data (Data)
|
import Data.Data (Data)
|
||||||
import Data.Functor.Foldable (cata)
|
import Gyehoek.Sexp (sx)
|
||||||
|
import Data.Foldable (traverse_)
|
||||||
|
|
||||||
|
|
||||||
newtype Module = MkModule { inner :: Vector Sexp }
|
newtype Module = MkModule { inner :: Vector Sexp }
|
||||||
@@ -121,25 +105,34 @@ data GenMod :: Effect where
|
|||||||
DefineFunction :: Sexp -> GenMod m Idx
|
DefineFunction :: Sexp -> GenMod m Idx
|
||||||
DefineType :: Sexp -> GenMod m Idx
|
DefineType :: Sexp -> GenMod m Idx
|
||||||
DefineGlobal :: Sexp -> GenMod m Idx
|
DefineGlobal :: Sexp -> GenMod m Idx
|
||||||
Declare :: Sexp -> GenMod m ()
|
Emit :: Sexp -> GenMod m ()
|
||||||
|
|
||||||
type instance DispatchOf GenMod = Dynamic
|
type instance DispatchOf GenMod = Dynamic
|
||||||
|
|
||||||
defineFunction :: GenMod :> es => Sexp -> Eff es Idx
|
defineFunction :: GenMod :> es => Sexp -> Eff es Idx
|
||||||
defineFunction = send . DefineFunction
|
defineFunction = send . DefineFunction
|
||||||
|
|
||||||
|
defineFunctions :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
||||||
|
defineFunctions = traverse (send . DefineFunction)
|
||||||
|
|
||||||
defineType :: GenMod :> es => Sexp -> Eff es Idx
|
defineType :: GenMod :> es => Sexp -> Eff es Idx
|
||||||
defineType = send . DefineType
|
defineType = send . DefineType
|
||||||
|
|
||||||
|
defineTypes :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
||||||
|
defineTypes = traverse (send . DefineType)
|
||||||
|
|
||||||
defineGlobal :: GenMod :> es => Sexp -> Eff es Idx
|
defineGlobal :: GenMod :> es => Sexp -> Eff es Idx
|
||||||
defineGlobal = send . DefineGlobal
|
defineGlobal = send . DefineGlobal
|
||||||
|
|
||||||
declare :: GenMod :> es => Sexp -> Eff es ()
|
defineGlobals :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
||||||
declare = send . Declare
|
defineGlobals = traverse (send . DefineGlobal)
|
||||||
|
|
||||||
|
emit :: GenMod :> es => List Sexp -> Eff es ()
|
||||||
|
emit = traverse_ (send . Emit)
|
||||||
|
|
||||||
appendAndIncrement
|
appendAndIncrement
|
||||||
:: State GenModState :> es
|
:: State GenModState :> es
|
||||||
=> LensLike' ((,) _) GenModState Natural
|
=> LensLike' ((,) Natural) GenModState Natural
|
||||||
-> Sexp
|
-> Sexp
|
||||||
-> Eff es Idx
|
-> Eff es Idx
|
||||||
appendAndIncrement l s =
|
appendAndIncrement l s =
|
||||||
@@ -155,11 +148,16 @@ runGenMod =
|
|||||||
_ (DefineFunction s) -> appendAndIncrement #funcs s
|
_ (DefineFunction s) -> appendAndIncrement #funcs s
|
||||||
_ (DefineType s) -> appendAndIncrement #types s
|
_ (DefineType s) -> appendAndIncrement #types s
|
||||||
_ (DefineGlobal s) -> appendAndIncrement #globals s
|
_ (DefineGlobal s) -> appendAndIncrement #globals s
|
||||||
_ (Declare s) -> #mod . #inner <>= V.singleton s
|
_ (Emit s) -> #mod . #inner <>= V.singleton s
|
||||||
|
|
||||||
execGenMod :: Eff (GenMod : es) a -> Eff es Module
|
execGenMod :: Eff (GenMod : es) a -> Eff es Module
|
||||||
execGenMod = fmap snd . runGenMod
|
execGenMod = fmap snd . runGenMod
|
||||||
|
|
||||||
|
renderModule :: Module -> Text
|
||||||
|
renderModule (MkModule ss) = Gyehoek.Sexp.format [sx|
|
||||||
|
(module ##{ss})
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
-- SexpIso instances
|
-- SexpIso instances
|
||||||
|
|
||||||
@@ -176,10 +174,19 @@ instance SexpIso Idx where
|
|||||||
instance SexpIso Instr where
|
instance SexpIso Instr where
|
||||||
sexpIso = with id
|
sexpIso = with id
|
||||||
|
|
||||||
|
instance Gyehoek.Sexp.SpliceSexp Expr where
|
||||||
|
spliceSexp = toListOf $ #inner . each . #inner
|
||||||
|
|
||||||
|
|
||||||
-- quasiquoters
|
-- quasiquoters
|
||||||
|
|
||||||
expr :: QuasiQuoter
|
expr :: QuasiQuoter
|
||||||
expr = Gyehoek.Sexp.makeSxs
|
expr = Gyehoek.Sexp.makeSxs
|
||||||
(MkExpr . V.fromList . (each . #inner %~ Gyehoek.Sexp.stripLocation))
|
[||MkExpr . V.fromList . (each . #inner %~ Gyehoek.Sexp.stripLocation)
|
||||||
(sexpIso @Instr)
|
. fmap (Gyehoek.Sexp.fromSexp @Instr) ||]
|
||||||
|
|
||||||
|
wat :: QuasiQuoter
|
||||||
|
wat = Gyehoek.Sexp.makeSx [|| id ||]
|
||||||
|
|
||||||
|
wats :: QuasiQuoter
|
||||||
|
wats = Gyehoek.Sexp.makeSxs [|| id ||]
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
const imports = {
|
|
||||||
guppy: {
|
|
||||||
print: (arg) => console.log (arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume add.wasm file exists that contains a single function adding 2 provided arguments
|
|
||||||
const fs = require('node:fs');
|
|
||||||
|
|
||||||
// Use the readFileSync function to read the contents of the "add.wasm" file
|
|
||||||
const wasmBuffer = fs.readFileSync('u.wasm');
|
|
||||||
|
|
||||||
// Use the WebAssembly.instantiate method to instantiate the WebAssembly module
|
|
||||||
WebAssembly.instantiate(wasmBuffer, imports).then(wasmModule => {
|
|
||||||
// Exported function lives under instance.exports object
|
|
||||||
const { main } = wasmModule.instance.exports;
|
|
||||||
main ()
|
|
||||||
});
|
|
||||||
@@ -1,69 +1,265 @@
|
|||||||
(module
|
(module
|
||||||
(type $heap-object (sub (struct (field (mut i32)))))
|
(import
|
||||||
(type $open-procedure (func (param i32)))
|
"gyehoek"
|
||||||
(type $closure (sub $heap-object
|
"write"
|
||||||
(struct (field (mut i32))
|
(func $gh-write (param (ref eq))))
|
||||||
(field (ref $open-procedure)))))
|
(import
|
||||||
(type $cont-stack-type (array (mut (ref null $open-procedure))))
|
"gyehoek"
|
||||||
(type $arg-array-type (array (mut (ref null eq))))
|
"truthy?"
|
||||||
(global $cont-stack-top (mut i32) (i32.const 0))
|
(func $gh-truthy? (param (ref eq)) (result i32)))
|
||||||
(global $cont-stack (ref $cont-stack-type)
|
(type $heap-object (sub (struct (field $hash (mut i32)))))
|
||||||
(i32.const 128)
|
(type $cont-type (func (param i32)))
|
||||||
(array.new_default $cont-stack-type))
|
(type $cont-stack-type (array (mut (ref null $cont-type))))
|
||||||
(global $arg-array (ref $arg-array-type)
|
(type
|
||||||
(i32.const 32)
|
$closure
|
||||||
(array.new_default $arg-array-type))
|
(sub
|
||||||
(global (mut (ref null eq)) (ref.null eq))
|
$heap-object
|
||||||
(elem declare funcref (ref.func 1))
|
(struct
|
||||||
(func
|
(field $hash (mut i32))
|
||||||
(param i32)
|
(field $code (ref $cont-type)))))
|
||||||
(result)
|
(global $cont-stack-top (mut i32) (i32.const 0))
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(global
|
||||||
(global.get 2)
|
$cont-stack
|
||||||
(i32.const 0)
|
(ref $cont-stack-type)
|
||||||
(array.get 3)
|
(array.new_default $cont-stack-type (i32.const 128)))
|
||||||
ref.as_non_null
|
(type $arg-array-type (array (mut (ref null eq))))
|
||||||
(global.set 3))
|
(global
|
||||||
(func
|
$arg-array
|
||||||
(param i32)
|
(ref $arg-array-type)
|
||||||
(result)
|
(array.new_default $arg-array-type (i32.const 32)))
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(global $result (mut (ref null eq)) (ref.null eq))
|
||||||
(global.get 2)
|
(func
|
||||||
(i32.const 0)
|
$halt
|
||||||
(array.get 3)
|
(param i32)
|
||||||
ref.as_non_null
|
(@gyehoek "pop argument")
|
||||||
(local.set 1)
|
(global.get $arg-array)
|
||||||
(global.get 2)
|
(i32.const 0)
|
||||||
(i32.const 0)
|
(array.get $arg-array-type)
|
||||||
(local.get 1)
|
ref.as_non_null
|
||||||
(array.set 3)
|
(global.set $result))
|
||||||
(i32.const 1)
|
(func
|
||||||
(global.get 1)
|
(param i32)
|
||||||
(global.get 0)
|
(@gyehoek :origin "(κ (x5) (continue λ-tail1 x5))")
|
||||||
(array.get 2)
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
ref.as_non_null
|
(@gyehoek "pop argument")
|
||||||
(global.get 0)
|
(global.get $arg-array)
|
||||||
(i32.const 1)
|
(i32.const 0)
|
||||||
i32.sub
|
(array.get $arg-array-type)
|
||||||
(global.set 0)
|
ref.as_non_null
|
||||||
(return_call_ref 1))
|
(local.set 1)
|
||||||
(func
|
(@gyehoek :origin "(continue λ-tail1 x5)")
|
||||||
(param i32)
|
(@gyehoek "push args")
|
||||||
(result)
|
(@gyehoek "push argument")
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(global.get $arg-array)
|
||||||
(ref.func 1)
|
(i32.const 0)
|
||||||
(local.set 1)
|
(local.get 4)
|
||||||
(global.get 2)
|
(array.set $arg-array-type)
|
||||||
(i32.const 0)
|
(@gyehoek "nargs")
|
||||||
(local.get 1)
|
(i32.const 1)
|
||||||
(array.set 3)
|
(@gyehoek "pop cont stack")
|
||||||
(return_call 1))
|
(global.get $cont-stack-top)
|
||||||
(func
|
(i32.const 1)
|
||||||
(param)
|
i32.sub
|
||||||
(result (ref eq))
|
(global.set $cont-stack-top)
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(global.get $cont-stack)
|
||||||
(i32.const 0)
|
(global.get $cont-stack-top)
|
||||||
(call 1)
|
(array.get $cont-stack-type)
|
||||||
(global.get 3)
|
ref.as_non_null
|
||||||
ref.as_non_null)
|
(return_call_ref $cont-type))
|
||||||
(export "main" (func 3)))
|
(elem declare funcref (ref.func 3))
|
||||||
|
(func
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
"(κ (x3) (letrec ((r4 (κ (x5) (continue λ-tail1 x5)))) (f x3 r4)))")
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(@gyehoek "pop argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(array.get $arg-array-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(local.set 1)
|
||||||
|
(@gyehoek :origin "(f x3 r4)")
|
||||||
|
(@gyehoek "push cont" :idx 3)
|
||||||
|
(array.set
|
||||||
|
$cont-stack-type
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(ref.func 3))
|
||||||
|
(global.set
|
||||||
|
$cont-stack-top
|
||||||
|
(i32.add (global.get $cont-stack-top) (i32.const 1)))
|
||||||
|
(@gyehoek :origin "(f x3 r4)")
|
||||||
|
(@gyehoek "load args")
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(local.get 3)
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(i32.const 1)
|
||||||
|
(local.get 1)
|
||||||
|
(ref.cast (ref $closure))
|
||||||
|
(struct.get $closure $code)
|
||||||
|
(return_call_ref $cont-type))
|
||||||
|
(elem declare funcref (ref.func 4))
|
||||||
|
(func
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
"(λ (f x λ-tail1) (letrec ((r2 (κ (x3) (letrec ((r4 (κ (x5) (continue λ-tail1 x5)))) (f x3 r4))))) (f x r2)))")
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(@gyehoek "pop argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(array.get $arg-array-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(local.set 1)
|
||||||
|
(@gyehoek "pop argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 1)
|
||||||
|
(array.get $arg-array-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(local.set 2)
|
||||||
|
(@gyehoek :origin "(f x r2)")
|
||||||
|
(@gyehoek "push cont" :idx 4)
|
||||||
|
(array.set
|
||||||
|
$cont-stack-type
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(ref.func 4))
|
||||||
|
(global.set
|
||||||
|
$cont-stack-top
|
||||||
|
(i32.add (global.get $cont-stack-top) (i32.const 1)))
|
||||||
|
(@gyehoek :origin "(f x r2)")
|
||||||
|
(@gyehoek "load args")
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(local.get 2)
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(i32.const 1)
|
||||||
|
(local.get 1)
|
||||||
|
(ref.cast (ref $closure))
|
||||||
|
(struct.get $closure $code)
|
||||||
|
(return_call_ref $cont-type))
|
||||||
|
(elem declare funcref (ref.func 5))
|
||||||
|
(func
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
"(λ (x λ-tail7) (prim (+ x 4) (κ (r8) (continue λ-tail7 r8))))")
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(@gyehoek "pop argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(array.get $arg-array-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(local.set 1)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
"(prim (+ x 4) (κ (r8) (continue λ-tail7 r8)))")
|
||||||
|
(local.get 1)
|
||||||
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shr_u
|
||||||
|
(i32.const 4)
|
||||||
|
(@gyehoek "construct small fixnum")
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shl
|
||||||
|
ref.i31
|
||||||
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shr_u
|
||||||
|
i32.add
|
||||||
|
(@gyehoek "construct small fixnum")
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shl
|
||||||
|
ref.i31
|
||||||
|
(local.set 2)
|
||||||
|
(@gyehoek :origin "(continue λ-tail7 r8)")
|
||||||
|
(@gyehoek "push args")
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(local.get 2)
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(@gyehoek "nargs")
|
||||||
|
(i32.const 1)
|
||||||
|
(@gyehoek "pop cont stack")
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(i32.const 1)
|
||||||
|
i32.sub
|
||||||
|
(global.set $cont-stack-top)
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(array.get $cont-stack-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(return_call_ref $cont-type))
|
||||||
|
(elem declare funcref (ref.func 6))
|
||||||
|
(func
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek :origin "(κ (x10) (continue halt x10))")
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(@gyehoek "pop argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(array.get $arg-array-type)
|
||||||
|
ref.as_non_null
|
||||||
|
(local.set 1)
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(local.get 3)
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(return_call $halt (i32.const 1)))
|
||||||
|
(elem declare funcref (ref.func 7))
|
||||||
|
(func
|
||||||
|
$scm-entry
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
"(letrec ((λ-body0 (λ (f x λ-tail1) (letrec ((r2 (κ (x3) (letrec ((r4 (κ (x5) (continue λ-tail1 x5)))) (f x3 r4))))) (f x r2))))) (letrec ((λ-body6 (λ (x λ-tail7) (prim (+ x 4) (κ (r8) (continue λ-tail7 r8)))))) (letrec ((r9 (κ (x10) (continue halt x10)))) (λ-body0 λ-body6 9 r9))))")
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(i32.const 0)
|
||||||
|
(ref.func 5)
|
||||||
|
(struct.new $closure)
|
||||||
|
(local.set 1)
|
||||||
|
(i32.const 0)
|
||||||
|
(ref.func 6)
|
||||||
|
(struct.new $closure)
|
||||||
|
(local.set 2)
|
||||||
|
(@gyehoek :origin "(λ-body0 λ-body6 9 r9)")
|
||||||
|
(@gyehoek "push cont" :idx 7)
|
||||||
|
(array.set
|
||||||
|
$cont-stack-type
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(ref.func 7))
|
||||||
|
(global.set
|
||||||
|
$cont-stack-top
|
||||||
|
(i32.add (global.get $cont-stack-top) (i32.const 1)))
|
||||||
|
(@gyehoek :origin "(λ-body0 λ-body6 9 r9)")
|
||||||
|
(@gyehoek "load args")
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(local.get 2)
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(@gyehoek "push argument")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 9)
|
||||||
|
(@gyehoek "construct small fixnum")
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shl
|
||||||
|
ref.i31
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(i32.const 1)
|
||||||
|
(local.get 1)
|
||||||
|
(ref.cast (ref $closure))
|
||||||
|
(struct.get $closure $code)
|
||||||
|
(return_call_ref $cont-type))
|
||||||
|
(func
|
||||||
|
(export "main")
|
||||||
|
(call $scm-entry (i32.const 0))
|
||||||
|
(call $gh-write (ref.as_non_null (global.get $result)))))
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
(module
|
|
||||||
(type $heap-object (sub (struct (field (mut i32)))))
|
|
||||||
(type $open-procedure (func (param i32)))
|
|
||||||
(type $closure (sub $heap-object
|
|
||||||
(struct (field (mut i32))
|
|
||||||
(field (ref $open-procedure)))))
|
|
||||||
(type $cont-stack-type (array (mut (ref null $open-procedure))))
|
|
||||||
(type $arg-array-type (array (mut eqref)))
|
|
||||||
(type (func (result (ref eq))))
|
|
||||||
(global $cont-stack-top (mut i32) (i32.const 0))
|
|
||||||
(global $cont-stack (ref $cont-stack-type)
|
|
||||||
(array.new_default $cont-stack-type (i32.const 128)))
|
|
||||||
(global $arg-array (ref $arg-array-type)
|
|
||||||
(array.new_default $arg-array-type (i32.const 32)))
|
|
||||||
(global (mut eqref) (ref.null eq))
|
|
||||||
(elem declare funcref (ref.func 1))
|
|
||||||
(func $halt (param i32)
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(global.set 3
|
|
||||||
(ref.as_non_null
|
|
||||||
(array.get $arg-array-type
|
|
||||||
(global.get $arg-array)
|
|
||||||
(i32.const 0)))))
|
|
||||||
(func $f1 (param i32)
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
;; pop arg 0
|
|
||||||
(local.set
|
|
||||||
1
|
|
||||||
(ref.as_non_null
|
|
||||||
(array.get $arg-array-type
|
|
||||||
(global.get $arg-array)
|
|
||||||
(i32.const 0))))
|
|
||||||
;; push arg 0
|
|
||||||
(array.set $arg-array-type
|
|
||||||
(global.get $arg-array)
|
|
||||||
(i32.const 0)
|
|
||||||
(local.get 1))
|
|
||||||
;; pop continuation
|
|
||||||
(return_call_ref
|
|
||||||
$open-procedure
|
|
||||||
(i32.const 1)
|
|
||||||
(ref.as_non_null (array.get $cont-stack-type
|
|
||||||
(global.get $cont-stack)
|
|
||||||
(global.get $cont-stack-top)))
|
|
||||||
(global.set $cont-stack-top
|
|
||||||
(i32.sub
|
|
||||||
(global.get $cont-stack-top)
|
|
||||||
(i32.const 1)))))
|
|
||||||
(func $f2 (type $open-procedure) (param i32)
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(local.set 1
|
|
||||||
(struct.new $closure
|
|
||||||
(i32.const 0)
|
|
||||||
(ref.func $f1)))
|
|
||||||
(array.set $arg-array-type
|
|
||||||
(global.get $arg-array)
|
|
||||||
(i32.const 0)
|
|
||||||
(local.get 1))
|
|
||||||
(i32.const 1)
|
|
||||||
(return_call $f1))
|
|
||||||
(func $main (export "main") (result (ref eq))
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
|
||||||
(call $f2 (i32.const 0))
|
|
||||||
(ref.as_non_null
|
|
||||||
(global.get 3))))
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
|
module Gyehoek.Test.CPS.Syntax (root) where
|
||||||
|
|
||||||
|
import Test.Tasty (TestTree, testGroup)
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
import Language.Sexp.Located qualified as SL
|
||||||
|
import Language.SexpGrammar ()
|
||||||
|
import Gyehoek.CPS.Syntax (cps)
|
||||||
|
import Gyehoek.CPS.Syntax qualified as Sut
|
||||||
|
import Data.Function (on)
|
||||||
|
import Gyehoek.Test.Sexp (equivto)
|
||||||
|
|
||||||
|
|
||||||
|
root :: IO TestTree
|
||||||
|
root = pure . testGroup "cps syntax" $
|
||||||
|
[ qqTree
|
||||||
|
, freeTree
|
||||||
|
]
|
||||||
|
|
||||||
|
freeTree :: TestTree
|
||||||
|
freeTree = testCase "free" do
|
||||||
|
Sut.free [cps|
|
||||||
|
(letrec ((x (lambda (r k1) (continue k1 y)))
|
||||||
|
(y (lambda (r k2) (continue k2 x))))
|
||||||
|
(continue x y k3))|] @=? ["k3"]
|
||||||
|
Sut.free' [cps|
|
||||||
|
(letrec ((x (lambda (r k1) (continue k1 y)))
|
||||||
|
(y (lambda (r k2) (continue k2 x))))
|
||||||
|
(continue x y k3))|] @=? ["k3"]
|
||||||
|
|
||||||
|
qqTree :: TestTree
|
||||||
|
qqTree = testGroup "parser"
|
||||||
|
[ testCase "lambda" do
|
||||||
|
assertEqual "" (Sut.MkLambda ["x","y"] "ktail"
|
||||||
|
(Sut.ExpContinue "ktail" [Sut.ValVar "x"]))
|
||||||
|
[cps|(λ (x y ktail) (continue ktail x))|]
|
||||||
|
assertEqual "" (Sut.MkLambda [] "ktail"
|
||||||
|
(Sut.ExpContinue "ktail" [Sut.ValVar "x"]))
|
||||||
|
[cps|(λ (ktail) (continue ktail x))|]
|
||||||
|
, testCase "kappa" do
|
||||||
|
assertEqual "" (Sut.MkKappa ["x","y"]
|
||||||
|
(Sut.ExpContinue "k123" [Sut.ValVar "x", Sut.ValVar "y"]))
|
||||||
|
[cps|(κ (x y) (continue k123 x y))|]
|
||||||
|
, testCase "application" do
|
||||||
|
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
||||||
|
[Sut.ValVar "x",Sut.ValVar "y"]
|
||||||
|
"k")
|
||||||
|
[cps|(f x y k)|]
|
||||||
|
assertEqual "" (Sut.ExpApply (Sut.ValVar "f")
|
||||||
|
[] "k")
|
||||||
|
[cps|(f k)|]
|
||||||
|
]
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
module Gyehoek.Test.Golden (root) where
|
||||||
|
|
||||||
|
import Test.Tasty (TestTree, testGroup)
|
||||||
|
import Test.Tasty.Silver
|
||||||
|
import Gyehoek.Driver qualified as Driver
|
||||||
|
import System.FilePath
|
||||||
|
import Data.List (List)
|
||||||
|
import Data.Functor ((<&>))
|
||||||
|
import System.Directory
|
||||||
|
import Data.Function
|
||||||
|
import System.Environment.Blank (getEnvDefault)
|
||||||
|
import qualified System.Process.Text as PT
|
||||||
|
|
||||||
|
|
||||||
|
disabled :: List String
|
||||||
|
disabled =
|
||||||
|
[
|
||||||
|
]
|
||||||
|
|
||||||
|
root :: IO TestTree
|
||||||
|
root = do
|
||||||
|
all_cases <- listDirectory "golden"
|
||||||
|
let tests = all_cases
|
||||||
|
& filter (`notElem` disabled)
|
||||||
|
& fmap ("golden"</>)
|
||||||
|
testGroup "golden" <$> sequenceA
|
||||||
|
[ executionTests tests
|
||||||
|
]
|
||||||
|
|
||||||
|
executionTests :: List FilePath -> IO TestTree
|
||||||
|
executionTests files = do
|
||||||
|
cmd <- getEnvDefault "GYEHOEK_RUNTIME"
|
||||||
|
"runtime/target/debug/gyehoek-runtime"
|
||||||
|
pure $ testGroup "execution" $ files <&> \test ->
|
||||||
|
let testname = takeFileName test
|
||||||
|
scmfile = test </> "source.scm"
|
||||||
|
resultfile = test </> "exec"
|
||||||
|
action = do
|
||||||
|
t <- Driver.lower_e2e scmfile
|
||||||
|
PT.readProcessWithExitCode cmd ["-"] t
|
||||||
|
in goldenVsAction
|
||||||
|
testname
|
||||||
|
resultfile
|
||||||
|
action
|
||||||
|
printProcResult
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
module Gyehoek.Test.Sexp
|
||||||
|
( root
|
||||||
|
, EquivSexp(..)
|
||||||
|
, assertEquiv
|
||||||
|
, equivto
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Test.Tasty (TestTree, testGroup)
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
import Language.Sexp.Located qualified as SL
|
||||||
|
import Language.SexpGrammar ()
|
||||||
|
import Gyehoek.Sexp (sx, equivalent)
|
||||||
|
import Data.Function (on)
|
||||||
|
|
||||||
|
|
||||||
|
root :: IO TestTree
|
||||||
|
root = pure . testGroup "sexp" $
|
||||||
|
[ sxTree
|
||||||
|
]
|
||||||
|
|
||||||
|
newtype EquivSexp = MkEquiv SL.Sexp
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
instance Eq EquivSexp where
|
||||||
|
MkEquiv x == MkEquiv y = equivalent x y
|
||||||
|
|
||||||
|
assertEquiv
|
||||||
|
:: HasCallStack
|
||||||
|
=> String -> SL.Sexp -> SL.Sexp -> Assertion
|
||||||
|
assertEquiv prefix = assertEqual prefix `on` MkEquiv
|
||||||
|
|
||||||
|
equivto = assertEquiv ""
|
||||||
|
|
||||||
|
sxTree :: TestTree
|
||||||
|
sxTree = testGroup "sx"
|
||||||
|
[ testCase "quotation" do
|
||||||
|
equivto (SL.Symbol "abc") [sx|abc|]
|
||||||
|
equivto (SL.ParenList [SL.Symbol "a", SL.Symbol "b"]) [sx|(a b)|]
|
||||||
|
, testCase "antiquotation" do
|
||||||
|
equivto [sx|123|]
|
||||||
|
let meta = 123 :: Int
|
||||||
|
in [sx|#{meta}|]
|
||||||
|
equivto [sx|(blah (blah blah) blah)|]
|
||||||
|
let meta = [sx|blah|]
|
||||||
|
in [sx|(#{meta} (#{meta} #{meta}) #{meta})|]
|
||||||
|
, testCase "splicing" do
|
||||||
|
equivto [sx|(a b c d e f g)|]
|
||||||
|
let metas = SL.Symbol <$> ["c","d","e"]
|
||||||
|
in [sx|(a b ##{metas} f g)|]
|
||||||
|
equivto [sx|(a (b c d) e f g)|]
|
||||||
|
let
|
||||||
|
e1 = SL.Symbol "c"
|
||||||
|
e2 = SL.Symbol <$> ["e","f"]
|
||||||
|
in [sx|(a (b #{e1} d) ##{e2} g)|]
|
||||||
|
]
|
||||||
+11
-49
@@ -1,57 +1,19 @@
|
|||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import Test.Tasty (TestTree, testGroup)
|
import Test.Tasty (TestTree, testGroup)
|
||||||
import Test.Tasty.Silver
|
|
||||||
import Test.Tasty.Silver.Interactive (defaultMain)
|
import Test.Tasty.Silver.Interactive (defaultMain)
|
||||||
import Data.Traversable
|
import qualified Gyehoek.Test.Golden
|
||||||
import Gyehoek.Driver qualified as Driver
|
import qualified Gyehoek.Test.Sexp
|
||||||
import System.FilePath
|
import qualified Gyehoek.Test.CPS.Syntax
|
||||||
import Data.List (List)
|
|
||||||
import Data.Functor ((<&>))
|
|
||||||
import System.Directory
|
|
||||||
import Data.Function
|
|
||||||
|
|
||||||
|
|
||||||
disabled :: List String
|
main :: IO ()
|
||||||
disabled =
|
main = defaultMain =<< root
|
||||||
[ "square"
|
|
||||||
|
root :: IO TestTree
|
||||||
|
root = testGroup "test" <$> sequenceA
|
||||||
|
[ Gyehoek.Test.Golden.root
|
||||||
|
, Gyehoek.Test.Sexp.root
|
||||||
|
, Gyehoek.Test.CPS.Syntax.root
|
||||||
]
|
]
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = defaultMain =<< goldenTests
|
|
||||||
|
|
||||||
goldenTests :: IO TestTree
|
|
||||||
goldenTests = do
|
|
||||||
all_cases <- listDirectory "golden"
|
|
||||||
let tests = all_cases
|
|
||||||
& filter (`notElem` disabled)
|
|
||||||
& fmap ("golden"</>)
|
|
||||||
pure $ testGroup "golden"
|
|
||||||
[ watTests tests
|
|
||||||
, executionTests tests
|
|
||||||
]
|
|
||||||
|
|
||||||
watTests :: List FilePath -> TestTree
|
|
||||||
watTests files =
|
|
||||||
testGroup "wat" $ files <&> \test ->
|
|
||||||
let source = test </> "source.scm"
|
|
||||||
golden = test </> "out.wat"
|
|
||||||
testname = takeFileName test
|
|
||||||
in goldenVsAction
|
|
||||||
testname
|
|
||||||
golden
|
|
||||||
(Driver.lower_e2e source)
|
|
||||||
id
|
|
||||||
|
|
||||||
executionTests :: List FilePath -> TestTree
|
|
||||||
executionTests files =
|
|
||||||
testGroup "execution" $ files <&> \test ->
|
|
||||||
let wat = test </> "out.wat"
|
|
||||||
testname = takeFileName test
|
|
||||||
resultfile = test </> "exec"
|
|
||||||
in goldenVsProg
|
|
||||||
testname
|
|
||||||
resultfile
|
|
||||||
"wasmtime"
|
|
||||||
["--invoke", "main", wat]
|
|
||||||
""
|
|
||||||
|
|||||||
@@ -1,78 +1,127 @@
|
|||||||
(module
|
(module
|
||||||
(func $print (import "guppy" "print") (param i32))
|
(import "gyehoek" "write" (func $gh-write (param (ref eq))))
|
||||||
(table 2 funcref)
|
(import "gyehoek" "truthy?" (func $gh-truthy? (param (ref eq)) (result i32)))
|
||||||
(elem (i32.const 0) $halt)
|
(type $heap-object (sub (struct (field $hash (mut i32)))))
|
||||||
|
(type $cont-type (func (param i32)))
|
||||||
(type $cont (func (param i32)))
|
(type $cont-stack-type (array (mut (ref null $cont-type))))
|
||||||
(type $cont-stack-type (array (mut (ref null $cont))))
|
(type
|
||||||
(global $cont-stack (ref $cont-stack-type)
|
$closure
|
||||||
(array.new_default $cont-stack-type (i32.const 128)))
|
(sub
|
||||||
|
$heap-object
|
||||||
|
(struct
|
||||||
|
(field $hash (mut i32))
|
||||||
|
(field $code (ref $cont-type)))))
|
||||||
(global $cont-stack-top (mut i32) (i32.const 0))
|
(global $cont-stack-top (mut i32) (i32.const 0))
|
||||||
|
(global
|
||||||
|
$cont-stack
|
||||||
|
(ref $cont-stack-type)
|
||||||
|
(array.new_default $cont-stack-type (i32.const 128)))
|
||||||
(type $arg-array-type (array (mut (ref null eq))))
|
(type $arg-array-type (array (mut (ref null eq))))
|
||||||
(global $arg-array (ref $arg-array-type)
|
(global
|
||||||
(array.new_default $arg-array-type (i32.const 32)))
|
$arg-array
|
||||||
|
(ref $arg-array-type)
|
||||||
;; (memory $memory i32 1)
|
(array.new_default $arg-array-type (i32.const 32)))
|
||||||
;; (global $arg-stack-base i32 (i32.const 0))
|
(global $result (mut (ref null eq)) (ref.null eq))
|
||||||
;; (global $arg-stack-ptr i32 (global.get $arg-stack-base))
|
(func
|
||||||
;; (global $cont-stack-base i32 (i32.const 32))
|
$halt
|
||||||
;; (global $cont-stack-ptr i32 (global.get $cont-stack-base))
|
(param i32)
|
||||||
|
(global.get $arg-array)
|
||||||
(func $add (param $nargs i32)
|
(i32.const 0)
|
||||||
(local $x (ref eq))
|
(array.get $arg-array-type)
|
||||||
(local $y (ref eq))
|
ref.as_non_null
|
||||||
(local $return (ref $cont))
|
(global.set $result))
|
||||||
(local.set $x (ref.as_non_null
|
(func
|
||||||
(array.get $arg-array-type
|
(param i32)
|
||||||
(global.get $arg-array)
|
(@gyehoek
|
||||||
(i32.const 0))))
|
:origin
|
||||||
(local.set $y (ref.as_non_null
|
(lambda (x lambda-tail1)
|
||||||
(array.get $arg-array-type
|
(prim (* x x) (kappa (r2) (continue lambda-tail1 r2)))))
|
||||||
(global.get $arg-array)
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
(i32.const 1))))
|
(global.get $arg-array)
|
||||||
(array.set $arg-array-type
|
(i32.const 0)
|
||||||
(global.get $arg-array)
|
(array.get $arg-array-type)
|
||||||
(i32.const 0)
|
ref.as_non_null
|
||||||
(ref.i31
|
(local.set 1)
|
||||||
(i32.add (i31.get_s (ref.cast (ref i31) (local.get $x)))
|
(local.get 1)
|
||||||
(i31.get_s (ref.cast (ref i31) (local.get $y))))))
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
(return_call_ref
|
(i32.const 1)
|
||||||
$cont
|
i32.shr_u
|
||||||
(i32.const 1)
|
(local.get 1)
|
||||||
(block (result (ref $cont))
|
(i31.get_s (ref.cast (ref i31)))
|
||||||
(ref.as_non_null
|
(i32.const 1)
|
||||||
(array.get $cont-stack-type
|
i32.shr_u
|
||||||
(global.get $cont-stack)
|
i32.mul
|
||||||
(global.get $cont-stack-top)))
|
(i32.const 1)
|
||||||
(global.set $cont-stack-top
|
i32.shl
|
||||||
(i32.sub (global.get $cont-stack-top)
|
ref.i31
|
||||||
(i32.const 1))))))
|
(local.set 2)
|
||||||
(func $halt (param $nargs i32)
|
(global.get $arg-array)
|
||||||
(call $print
|
(i32.const 0)
|
||||||
(i31.get_s
|
(local.get 2)
|
||||||
(ref.cast
|
(array.set $arg-array-type)
|
||||||
(ref i31)
|
(i32.const 1)
|
||||||
(ref.as_non_null
|
(global.get $cont-stack)
|
||||||
(array.get $arg-array-type
|
(global.get $cont-stack-top)
|
||||||
(global.get $arg-array)
|
(array.get $cont-stack-type)
|
||||||
(i32.const 0)))))))
|
ref.as_non_null
|
||||||
(func (export "main")
|
(global.get $cont-stack-top)
|
||||||
;; push args
|
(i32.const 1)
|
||||||
(array.set $arg-array-type
|
i32.sub
|
||||||
(global.get $arg-array)
|
(global.set $cont-stack-top)
|
||||||
(i32.const 0)
|
(return_call_ref $cont-type))
|
||||||
(ref.i31 (i32.const 4)))
|
(elem declare funcref (ref.func 3))
|
||||||
(array.set $arg-array-type
|
(func
|
||||||
(global.get $arg-array)
|
(param i32)
|
||||||
(i32.const 1)
|
(@gyehoek :origin (kappa (x4) (continue halt x4)))
|
||||||
(ref.i31 (i32.const 5)))
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
;; push return continuation
|
(global.get $arg-array)
|
||||||
(array.set $cont-stack-type
|
(i32.const 0)
|
||||||
(global.get $cont-stack)
|
(array.get $arg-array-type)
|
||||||
(i32.const 0)
|
ref.as_non_null
|
||||||
(ref.func $halt))
|
(local.set 1)
|
||||||
;; make call }:)
|
(global.get $arg-array)
|
||||||
(return_call $add
|
(i32.const 0)
|
||||||
;; inform $add how many arguments we called it with
|
(local.get 1)
|
||||||
(i32.const 2))))
|
(array.set $arg-array-type)
|
||||||
|
(return_call $halt (i32.const 1)))
|
||||||
|
(func
|
||||||
|
$scm-entry
|
||||||
|
(param i32)
|
||||||
|
(@gyehoek
|
||||||
|
:origin
|
||||||
|
(letrec ((lambda-body0
|
||||||
|
(lambda (x lambda-tail1)
|
||||||
|
(prim (* x x) (kappa (r2) (continue lambda-tail1 r2))))))
|
||||||
|
(letrec ((r3 (kappa (x4) (continue halt x4))))
|
||||||
|
(lambda-body0 5 r3))))
|
||||||
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
|
(i32.const 0)
|
||||||
|
(ref.func 3)
|
||||||
|
(struct.new $closure)
|
||||||
|
(local.set 1)
|
||||||
|
(@gyehoek "push return cont" :idx 4)
|
||||||
|
(array.set $cont-stack-type
|
||||||
|
(global.get $cont-stack)
|
||||||
|
(global.get $cont-stack-top)
|
||||||
|
(ref.func 4))
|
||||||
|
(global.set $cont-stack-top
|
||||||
|
(i32.add (global.get $cont-stack-top)
|
||||||
|
(i32.const 1)))
|
||||||
|
(@gyehoek "load args")
|
||||||
|
(global.get $arg-array)
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 5)
|
||||||
|
(i32.const 1)
|
||||||
|
i32.shl
|
||||||
|
ref.i31
|
||||||
|
(array.set $arg-array-type)
|
||||||
|
(@gyehoek todo (f' (local.get 1)) (ktail 1))
|
||||||
|
(return_call_ref $cont-type
|
||||||
|
(i32.const 1)
|
||||||
|
(struct.get $closure $code
|
||||||
|
(ref.cast (ref $closure) (local.get 1)))))
|
||||||
|
(elem declare funcref (ref.func 4))
|
||||||
|
(func
|
||||||
|
(export "main")
|
||||||
|
(call $scm-entry (i32.const 0))
|
||||||
|
(call $gh-write (ref.as_non_null (global.get $result)))))
|
||||||
|
|||||||
Reference in New Issue
Block a user