Created
May 6, 2025 17:02
-
-
Save VictorTaelin/54f73328a93c109c22c3722bf331b152 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- OldCheck: | |
-- (omitted) | |
# The Interaction Calculus | |
The [Interaction Calculus](https://github.com/VictorTaelin/Interaction-Calculus) | |
is a minimal term rewriting system inspired by the Lambda Calculus (λC), but | |
with some key differences: | |
1. Vars are affine: they can only occur up to one time. | |
2. Vars are global: they can occur anywhere in the program. | |
3. There is a new core primitive: the superposition. | |
An Interaction Calculus term is defined by the following grammar: | |
haskell | |
Term ::= | |
| VAR: Name | |
| ERA: "*" | |
| LAM: "λ" Name "." Term | |
| APP: "(" Term " " Term ")" | |
| SUP: "&" Label "{" Term "," Term "}" | |
| DUP: "!" "&" Label "{" Name "," Name "}" "=" Term ";" Term | |
Where: | |
- VAR represents a variable. | |
- ERA represents an erasure. | |
- LAM represents a lambda. | |
- APP represents a application. | |
- SUP represents a superposition. | |
- DUP represents a duplication. | |
Lambdas are curried, and work like their λC counterpart, except with a relaxed | |
scope, and with affine usage. Applications eliminate lambdas, like in λC, | |
through the beta-reduce (APP-LAM) interaction. | |
Superpositions work like pairs. Duplications eliminate superpositions through | |
the DUP-SUP interaction, which works exactly like a pair projection. | |
What makes SUPs and DUPs unique is how they interact with LAMs and APPs. When a | |
SUP is applied to an argument, it reduces through the APP-SUP interaction, and | |
when a LAM is projected, it reduces through the DUP-LAM interaction. This gives | |
a computational behavior for every possible interaction: there are no runtime | |
errors on the core Interaction Calculus. | |
The 'Label' is a numeric value that affects some interactions, like DUP-SUP, | |
causing terms to commute, instead of annihilate. Read Lafont's Interaction | |
Combinators paper to learn more. | |
The core interaction rules are listed below: | |
haskell | |
(* a) | |
----- APP-ERA | |
* | |
(λx.f a) | |
-------- APP-LAM | |
x <- a | |
f | |
(&L{a,b} c) | |
----------------- APP-SUP | |
! &L{c0,c1} = c; | |
&L{(a c0),(b c1)} | |
! &L{r,s} = *; | |
K | |
-------------- DUP-ERA | |
r <- * | |
s <- * | |
K | |
! &L{r,s} = λx.f; | |
K | |
----------------- DUP-LAM | |
r <- λx0.f0 | |
s <- λx1.f1 | |
x <- &L{x0,x1} | |
! &L{f0,f1} = f; | |
K | |
! &L{x,y} = &L{a,b}; | |
K | |
-------------------- DUP-SUP (if equal labels) | |
x <- a | |
y <- b | |
K | |
! &L{x,y} = &R{a,b}; | |
K | |
-------------------- DUP-SUP (if different labels) | |
x <- &R{a0,b0} | |
y <- &R{a1,b1} | |
! &L{a0,a1} = a; | |
! &L{b0,b1} = b; | |
K | |
Where x <- t stands for a global substitution of x by t. | |
Since variables are affine, substitutions can be implemented efficiently by just | |
inserting an entry in a global substitution map (sub[var] = value). There is | |
no need to traverse the target term, or to handle name capture, as long as fresh | |
variable names are globally unique. Thread-safe substitutions can be performed | |
with a single atomic-swap. | |
Below is a pseudocode implementation of these interaction rules: | |
python | |
def app_lam(app, lam): | |
sub[lam.nam] = app.arg | |
return lam.bod | |
def app_sup(app, sup): | |
x0 = fresh() | |
x1 = fresh() | |
a0 = App(sup.lft, Var(x0)) | |
a1 = App(sup.rgt, Var(x1)) | |
return Dup(sup.lab, x0, x1, app.arg, Sup(a0, a1)) | |
def dup_lam(dup, lam): | |
x0 = fresh() | |
x1 = fresh() | |
f0 = fresh() | |
f1 = fresh() | |
sub[dup.lft] = Lam(x0, Var(f0)) | |
sub[dup.rgt] = Lam(x1, Var(f1)) | |
sub[lam.nam] = Sup(dup.lab, Var(x0), Var(x1)) | |
return Dup(dup.lab, f0, f1, lam.bod, dup.bod) | |
def dup_sup(dup, sup): | |
if dup.lab == sup.lab: | |
sub[dup.lft] = sup.lft | |
sub[dup.rgt] = sup.rgt | |
return dup.bod | |
Terms can be reduced to weak head normal form, which means reducing until the | |
outermost constructor is a value (LAM, SUP, etc.), or until no more reductions | |
are possible. Example: | |
python | |
def whnf(term): | |
while True: | |
match term: | |
case Var(nam): | |
if nam in sub: | |
term = sub[nam] | |
else: | |
return term | |
case App(fun, arg): | |
fun = whnf(fun) | |
match fun.tag: | |
case LAM: term = app_lam(term, fun) | |
case SUP: term = app_sup(term, fun) | |
case _ : return App(fun, arg) | |
case Dup(lft, rgt, val, bod): | |
val = whnf(val) | |
match val.tag: | |
case LAM: term = dup_lam(term, val) | |
case SUP: term = dup_sup(term, val) | |
case _ : return Dup(lft, rgt, val, bod) | |
case _: | |
return term | |
Terms can be reduced to full normal form by recursively taking the whnf: | |
python | |
def normal(term): | |
term = whnf(term) | |
match term: | |
case Lam(nam, bod): | |
bod_nf = normal(bod) | |
return Lam(nam, bod_nf) | |
case App(fun, arg): | |
fun_nf = normal(fun) | |
arg_nf = normal(arg) | |
return App(fun_nf, arg_nf) | |
... | |
case _: | |
return term | |
Below are some normalization examples. | |
Example 0: (simple λ-term) | |
haskell | |
(λx.λt.(t x) λy.y) | |
------------------ APP-LAM | |
λt.(t λy.y) | |
Example 1: (larger λ-term) | |
haskell | |
(λb.λt.λf.((b f) t) λT.λF.T) | |
---------------------------- APP-LAM | |
λt.λf.((λT.λF.T f) t) | |
----------------------- APP-LAM | |
λt.λf.(λF.t f) | |
-------------- APP-LAM | |
λt.λf.t | |
Example 2: (global scopes) | |
haskell | |
{x,(λx.λy.y λk.k)} | |
------------------ APP-LAM | |
{λk.k,λy.y} | |
Example 3: (superposition) | |
haskell | |
!{a,b} = {λx.x,λy.y}; (a b) | |
--------------------------- DUP-SUP | |
(λx.x λy.y) | |
----------- APP-LAM | |
λy.y | |
Example 4: (overlap) | |
haskell | |
({λx.x,λy.y} λz.z) | |
------------------ APP-SUP | |
! {x0,x1} = λz.z; {(λx.x x0),(λy.y x1)} | |
--------------------------------------- DUP-LAM | |
! {f0,f1} = {r,s}; {(λx.x λr.f0),(λy.y λs.f1)} | |
---------------------------------------------- DUP-SUP | |
{(λx.x λr.r),(λy.y λs.s)} | |
------------------------- APP-LAM | |
{λr.r,(λy.y λs.s)} | |
------------------ APP-LAM | |
{λr.r,λs.s} | |
Example 5: (default test term) | |
The following term can be used to test all interactions: | |
haskell | |
((λf.λx.!{f0,f1}=f;(f0 (f1 x)) λB.λT.λF.((B F) T)) λa.λb.a) | |
----------------------------------------------------------- 16 interactions | |
λa.λb.a | |
# Collapsing | |
An Interaction Calculus term can be collapsed to a superposed tree of pure | |
Lambda Calculus terms without SUPs and DUPs, by extending the evaluator with the | |
following collapse interactions: | |
haskell | |
λx.* | |
------ ERA-LAM | |
x <- * | |
* | |
(f *) | |
----- ERA-APP | |
* | |
λx.&L{f0,f1} | |
----------------- SUP-LAM | |
x <- &L{x0,x1} | |
&L{λx0.f0,λx1.f1} | |
(f &L{x0,x1}) | |
------------------- SUP-APP | |
!&L{f0,f1} = f; | |
&L{(f0 x0),(f1 x1)} | |
&R{&L{x0,x1},y} | |
----------------------- SUP-SUP-X (if R>L) | |
!&R{y0,y1} = y; | |
&L{&R{x0,x1},&R{y0,y1}} | |
&R{x,&L{y0,y1}} | |
----------------------- SUP-SUP-Y (if R>L) | |
!&R{x0,x1} = x; | |
&L{&R{x0,x1},&R{y0,y1}} | |
!&L{x0,x1} = x; K | |
----------------- DUP-VAR | |
x0 <- x | |
x1 <- x | |
K | |
!&L{a0,a1} = (f x); K | |
--------------------- DUP-APP | |
a0 <- (f0 x0) | |
a1 <- (f1 x1) | |
!&L{f0,f1} = f; | |
!&L{x0,x1} = x; | |
K | |
module Type where | |
import Data.Word | |
import Foreign.Ptr | |
import Control.Applicative ((<|>)) | |
import Control.Monad (forM) | |
import Data.Char (chr, ord) | |
import Data.Char (intToDigit) | |
import Data.IORef | |
import Data.List | |
import Data.Word | |
import Numeric (showIntAtBase) | |
import System.IO.Unsafe (unsafePerformIO) | |
import qualified Data.Map.Strict as MS hiding (map) | |
-- Core Types | |
-- ---------- | |
type Tag = Word8 | |
type Lab = Word32 | |
type Loc = Word32 | |
type Term = Word64 | |
type FnID = Word16 | |
type Name = String | |
type Move = (Name, Core) -- !x = term | |
data LetT = LAZY | STRI deriving (Eq, Enum) | |
data MatT = SWI | MAT Word16 | IFL Word16 deriving (Show, Eq) | |
-- **Note: we're refactoring HVM3's Code Type.** | |
-- OLD TYPE: | |
-- data Core | |
-- = Var Name -- x | |
-- | Ref Name Word16 [Core] -- @fn | |
-- | Era -- * | |
-- | Sup Lab Core Core -- &L{a b} | |
-- | Dup Lab Name Name Core Core -- ! &L{a b} = v body | |
-- | Set -- Set | |
-- | All Core Core -- ∀A.B | |
-- | Lam Name Core -- λx(F) | |
-- | App Core Core -- (f x) | |
-- | Adt Name [Core] -- #Typ{a b ...} | |
-- | Ctr Name [Core] -- #Ctr{a b ...} | |
-- | U32 -- U32 | |
-- | W32 Word32 -- 123 | |
-- | Chr Char -- 'a' | |
-- | Op2 Oper Core Core -- (+ a b) | |
-- | Let LetT Name Core Core -- ! x = v body | |
-- | Mat MatT Core [Move] [Case] -- ~ v !moves { cases } | |
-- deriving (Eq) | |
-- NEW TYPE: | |
data Core | |
= Var Name -- x | |
| Ref Name FnID [Core] -- @fun(a,b...) | |
| Let LetT Name Core Core -- !x=v;f | |
| Era -- * | |
| Sup Lab Core Core -- &L{a,b} | |
| Dup Lab Name Name Core Core -- !&L{a,b}=v;f | |
| Set -- Set | |
| Emp -- ⊥ | |
| Efq Core [Move] -- ~x!ms{} | |
| Uni -- ⊤ | |
| Nil -- () | |
| Use Core [Move] Core -- ~x!ms{():f} | |
| U32 -- U32 | |
| W32 Word32 -- 12345 | |
| Swi Core [Move] Core Core -- ~x!ms{0:z;+:s} | |
| Op2 Oper Core Core -- (+ a b) | |
| Sig Core Core -- ΣA.B | |
| Tup Core Core -- (a,b) | |
| Get Core [Move] Core -- ~x!ms{(,):f} | |
| All Core Core -- ∀A.B | |
| Lam Name Core -- λx.F | |
| App Core Core -- (f x) | |
| Ann Bool Core Core -- <x:T> | |
deriving (Eq) | |
-- The changes include: | |
-- - Addition of Type-Formers, like Emp, All, Sig, etc. | |
-- - Addition of empty: Emp/Efq | |
-- - Addition of unit: Uni/Nil/Use | |
-- - Addition of pairs: Sig/Tup/Get (behaves like a 0-label Sup/Dup) | |
-- - Removal of ADT/CTR, in favor of more primitive types | |
-- - Removal of CHR (which was just another W32) | |
-- - Removal of the generic MAT, in favor of specific pattern-matches: | |
-- - - Efq: for the Empty type | |
-- - - Use: for the Unit type | |
-- - - Swi: for the U32 type | |
-- - - Get: for the Sigma type | |
-- - For simplicity, now, SWI is always ~x{0:z;+:s} (no multi-number switch) | |
-- - FWD has been removed (it was unused) | |
-- **Our goal is to update the whole codebase to reflect this change.** | |
-- | |
-- INSTRUCTIONS: | |
-- | |
-- When asked to fill below a commented-out code, you must rewrite it completely, updating it to comply to the changes above. | |
-- Remove discarded cases (like CTR), keep old cases (like Lam/App) verbatin (important: don't change existing definitions!), include new/missing cases (like Tup). | |
-- Preserve original comments and everything else. Avoid loss of information. | |
-- | |
-- When asked to implement a missing interaction, reason about it longer, to make sure you get it right. | |
-- For example, the missing DUP-ALL interaction is: | |
-- !&L{x0,x1}=∀A.B | |
-- ----------------- DUP-ALL | |
-- !&L{A0,A1}=A | |
-- !&L{B0,B1}=B | |
-- &L{∀A0.B0,∀A1.B1} | |
-- Because All doesn't bind a variable. | |
-- Getting these right demands reasoning. | |
-- | |
-- NOTES: | |
-- | |
-- The following terms bind variables: | |
-- - λx.f: a lambda binds 'x' in its body, 'f' | |
-- - !x=v;f; a let binds 'x' in its body, 'f' | |
-- The following terms DO NOT bind variables: | |
-- - ~x{} | |
-- - ~x{():f} | |
-- - ~x{(,):f} | |
-- - ~x{0:z;+:s} | |
-- - ΣA.B | |
-- - ∀A.B | |
-- Instead, we use lambdas *inside* them. For example: | |
-- @id = λx.~x{0:0;+:λp.(+ 1 @id(p))} | |
-- @fst = λx.~x{(,):λa.λb.a} | |
-- Below is the complete list of new elims/intros/types: | |
-- Eliminators: | |
-- - APP | |
-- - USE | |
-- - GET | |
-- - SWI | |
-- - DUP | |
-- - OPX | |
-- - OPY | |
-- Introducers: | |
-- - ERA | |
-- - SUP | |
-- - NIL | |
-- - W32 | |
-- - TUP | |
-- - LAM | |
-- Type-Formers: | |
-- - SET | |
-- - EMP | |
-- - UNI | |
-- - U32 | |
-- - SIG | |
-- - ALL | |
-- STYLE GUIDE: | |
-- - Always order cases in the SAME order as they were defined on the Core type. | |
-- - As much as possible, favor SINGLE-LETTER field names, or TWO-LETTER field names (on list-like fields), inspired by the letters used in the comments on the Core type. | |
-- - For example, instead of format (Use moves body) = ..., write format (Use ms b) = ... | |
-- - Since Haskell doesn't accept uppercase variable names, prepend an underscore. Example: format (All _A _B) = .... | |
-- - Do NOT use the ' (apostrophe) character in variable names. Prefer underscores. Example: a_ instead of a' | |
-- - In general, attempt to mimic the original coding style as close as possible. | |
-- - KEEP COMMENTS, ERROR HANDLERS, ETC. FROM THE ORIGINAL CODE - DON'T LOSE INFORMATION | |
data Oper | |
= OP_ADD | OP_SUB | OP_MUL | OP_DIV | |
| OP_MOD | OP_EQ | OP_NE | OP_LT | |
| OP_GT | OP_LTE | OP_GTE | OP_AND | |
| OP_OR | OP_XOR | OP_LSH | OP_RSH | |
deriving (Eq, Enum) | |
-- A top-level function, including: | |
-- - copy: true when ref-copy mode is enabled | |
-- - args: a list of (isArgStrict, argName) pairs | |
-- - core: the function's body | |
-- Note: ref-copy improves C speed, but increases interaction count | |
type Func = ((Bool, [(Bool,String)]), Core) | |
-- Set of labels in a function's body | |
type HasLab = (MS.Map Lab ()) | |
-- data Book = Book | |
-- { fidToFun :: MS.Map Word16 Func -- func id to Func object | |
-- , fidToLab :: MS.Map Word16 HasLab -- func id to dup labels used | |
-- , fidToNam :: MS.Map Word16 Name -- func id to name | |
-- , namToFid :: MS.Map Name Word16 -- func name to id | |
-- , cidToAri :: MS.Map Word16 Word16 -- ctor id to field count (arity) | |
-- , cidToLen :: MS.Map Word16 Word16 -- ctor id to cases length (ADT ctors) | |
-- , cidToCtr :: MS.Map Word16 Name -- ctor id to name | |
-- , ctrToCid :: MS.Map Name Word16 -- ctor name to id | |
-- , cidToADT :: MS.Map Word16 Word16 -- ctor id to ADT id (first ADT cid) | |
-- , freshLab :: Lab -- auto dup label counter | |
-- } deriving (Show, Eq) | |
data Book = Book | |
{ fidToFun :: MS.Map FnID Func -- func id to Func object | |
, fidToLab :: MS.Map FnID HasLab -- func id to dup labels used | |
, fidToNam :: MS.Map FnID Name -- func id to name | |
, namToFid :: MS.Map Name FnID -- func name to id | |
, freshLab :: Lab -- auto dup label counter | |
} deriving (Show, Eq) | |
-- Runtime Types | |
-- ------------- | |
type HVM = IO | |
-- Constants | |
-- --------- | |
-- -- Tags | |
-- _DP0_ = 0x00 :: Tag | |
-- _DP1_ = 0x01 :: Tag | |
-- _VAR_ = 0x02 :: Tag | |
-- _FWD_ = 0x03 :: Tag | |
-- _REF_ = 0x04 :: Tag | |
-- _LET_ = 0x05 :: Tag | |
-- _APP_ = 0x06 :: Tag | |
-- _MAT_ = 0x08 :: Tag | |
-- _IFL_ = 0x09 :: Tag | |
-- _SWI_ = 0x0A :: Tag | |
-- _OPX_ = 0x0B :: Tag | |
-- _OPY_ = 0x0C :: Tag | |
-- _ERA_ = 0x0D :: Tag | |
-- _LAM_ = 0x0E :: Tag | |
-- _SUP_ = 0x0F :: Tag | |
-- _CTR_ = 0x10 :: Tag | |
-- _W32_ = 0x11 :: Tag | |
-- _CHR_ = 0x12 :: Tag | |
-- Tags | |
_DP0_ = 0x00 :: Tag | |
_DP1_ = 0x01 :: Tag | |
_VAR_ = 0x02 :: Tag | |
_REF_ = 0x03 :: Tag | |
_LET_ = 0x04 :: Tag | |
_ERA_ = 0x05 :: Tag | |
_SUP_ = 0x06 :: Tag | |
_DUP_ = 0x07 :: Tag | |
_SET_ = 0x08 :: Tag | |
_EMP_ = 0x09 :: Tag | |
_EFQ_ = 0x0A :: Tag | |
_UNI_ = 0x0B :: Tag | |
_NIL_ = 0x0C :: Tag | |
_USE_ = 0x0D :: Tag | |
_U32_ = 0x0E :: Tag | |
_W32_ = 0x0F :: Tag | |
_SWI_ = 0x10 :: Tag | |
_OPX_ = 0x11 :: Tag | |
_OPY_ = 0x12 :: Tag | |
_SIG_ = 0x13 :: Tag | |
_TUP_ = 0x14 :: Tag | |
_GET_ = 0x15 :: Tag | |
_ALL_ = 0x16 :: Tag | |
_LAM_ = 0x17 :: Tag | |
_APP_ = 0x18 :: Tag | |
_ANN_ = 0x19 :: Tag | |
-- Let Types | |
modeT :: Lab -> LetT | |
modeT 0x00 = LAZY | |
modeT 0x01 = STRI | |
modeT mode = error $ "unknown mode: " ++ show mode | |
-- Primitive Functions | |
_DUP_F_ = 0xFFFF :: Lab | |
_SUP_F_ = 0xFFFE :: Lab | |
_LOG_F_ = 0xFFFD :: Lab | |
primitives :: [(String, Word16)] | |
primitives = | |
[ ("SUP", fromIntegral _SUP_F_) | |
, ("DUP", fromIntegral _DUP_F_) | |
, ("LOG", fromIntegral _LOG_F_) | |
] | |
-- Utils | |
-- ----- | |
-- Getter function for maps | |
mget :: (Ord k, Show k) => MS.Map k a -> k -> a | |
mget map key = | |
case MS.lookup key map of | |
Just val -> val | |
Nothing -> error $ "key not found: " ++ show key | |
funArity :: Book -> Word16 -> Word16 | |
funArity book fid | |
| fid == fromIntegral _SUP_F_ = 3 | |
| fid == fromIntegral _DUP_F_ = 3 | |
| fid == fromIntegral _LOG_F_ = 1 | |
| otherwise = case MS.lookup fid (fidToFun book) of | |
Just ((_, args), _) -> | |
fromIntegral (length args) | |
Nothing -> | |
error $ "Function ID not found: " ++ show fid | |
-- Stringification | |
-- --------------- | |
padLeft :: String -> Int -> Char -> String | |
padLeft str n c = replicate (n - length str) c ++ str | |
showHex :: Word64 -> String | |
showHex x = showIntAtBase 16 intToDigit (fromIntegral x) "" | |
showName :: Int -> String | |
showName n = go (n + 1) "" where | |
go n ac | n == 0 = ac | |
| otherwise = go q (chr (ord 'a' + r) : ac) | |
where (q,r) = quotRem (n - 1) 26 | |
-- showTag :: Tag -> String | |
-- showTag tag | |
-- | tag == _DP0_ = "DP0" | |
-- | tag == _DP1_ = "DP1" | |
-- | tag == _VAR_ = "VAR" | |
-- | tag == _FWD_ = "FWD" | |
-- | tag == _REF_ = "REF" | |
-- | tag == _LET_ = "LET" | |
-- | tag == _APP_ = "APP" | |
-- | tag == _MAT_ = "MAT" | |
-- | tag == _IFL_ = "IFL" | |
-- | tag == _SWI_ = "SWI" | |
-- | tag == _OPX_ = "OPX" | |
-- | tag == _OPY_ = "OPY" | |
-- | tag == _ERA_ = "ERA" | |
-- | tag == _LAM_ = "LAM" | |
-- | tag == _SUP_ = "SUP" | |
-- | tag == _CTR_ = "CTR" | |
-- | tag == _W32_ = "W32" | |
-- | tag == _CHR_ = "CHR" | |
-- | otherwise = error $ "unknown tag: " ++ show tag | |
showTag :: Tag -> String | |
showTag tag | |
| tag == _DP0_ = "DP0" | |
| tag == _DP1_ = "DP1" | |
| tag == _VAR_ = "VAR" | |
| tag == _REF_ = "REF" | |
| tag == _LET_ = "LET" | |
| tag == _ERA_ = "ERA" | |
| tag == _SUP_ = "SUP" | |
| tag == _DUP_ = "DUP" | |
| tag == _SET_ = "SET" | |
| tag == _EMP_ = "EMP" | |
| tag == _EFQ_ = "EFQ" | |
| tag == _UNI_ = "UNI" | |
| tag == _NIL_ = "NIL" | |
| tag == _USE_ = "USE" | |
| tag == _U32_ = "U32" | |
| tag == _W32_ = "W32" | |
| tag == _SWI_ = "SWI" | |
| tag == _OPX_ = "OPX" | |
| tag == _OPY_ = "OPY" | |
| tag == _SIG_ = "SIG" | |
| tag == _TUP_ = "TUP" | |
| tag == _GET_ = "GET" | |
| tag == _ALL_ = "ALL" | |
| tag == _LAM_ = "LAM" | |
| tag == _APP_ = "APP" | |
| tag == _ANN_ = "ANN" | |
| otherwise = error $ "unknown tag: " ++ show tag | |
showLab :: Lab -> String | |
showLab lab = padLeft (showHex (fromIntegral lab)) 6 '0' | |
showLoc :: Loc -> String | |
showLoc loc = padLeft (showHex (fromIntegral loc)) 8 '0' | |
instance Show Oper where | |
show OP_ADD = "+" | |
show OP_SUB = "-" | |
show OP_MUL = "*" | |
show OP_DIV = "/" | |
show OP_MOD = "%" | |
show OP_EQ = "==" | |
show OP_NE = "!=" | |
show OP_LT = "<" | |
show OP_GT = ">" | |
show OP_LTE = "<=" | |
show OP_GTE = ">=" | |
show OP_AND = "&" | |
show OP_OR = "|" | |
show OP_XOR = "^" | |
show OP_LSH = "<<" | |
show OP_RSH = ">>" | |
instance Show LetT where | |
show LAZY = "" | |
show STRI = "." | |
showCore :: Core -> String | |
showCore = format | |
where | |
format :: Core -> String | |
format (Var k) = k | |
format (Ref k i xs) = | |
let xs' = intercalate " " (map showCore xs) in | |
concat ["@", k, "(", xs', ")"] | |
format (Let m k v f) = | |
let v' = showCore v in | |
let f' = showCore f in | |
if k == "" then | |
concat [v', "\n", f'] | |
else | |
concat ["! ", show m, k, " = ", v', "\n", f'] | |
format Era = "*" | |
format (Sup l a b) = | |
let a' = showCore a in | |
let b' = showCore b in | |
concat ["&", show l, "{", a', ",", b', "}"] | |
format (Dup l x y v f) = | |
let v' = showCore v in | |
let f' = showCore f in | |
concat ["! &", show l, "{", x, ",", y, "} = ", v', "\n", f'] | |
format Set = "Set" | |
format Emp = "⊥" | |
format (Efq c ms) = | |
let c' = showCore c in | |
let ms' = concatMap (\(k,v) -> concat [" !", k, "=", showCore v]) ms in | |
concat ["~", c', ms', "{}"] | |
format Uni = "⊤" | |
format Nil = "()" | |
format (Use c ms b) = | |
let c' = showCore c in | |
let ms' = concatMap (\(k,v) -> concat [" !", k, "=", showCore v]) ms in | |
let b' = showCore b in | |
concat ["~", c', ms', "{():", b', "}"] | |
format U32 = "U32" | |
format (W32 v) = show v | |
format (Swi c ms z s) = | |
let c' = showCore c in | |
let ms' = concatMap (\(k,v) -> concat [" !", k, "=", showCore v]) ms in | |
let z' = showCore z in | |
let s' = showCore s in | |
concat ["~", c', ms', "{0:", z', ";+:", s', "}"] | |
format (Op2 o a b) = | |
let a' = showCore a in | |
let b' = showCore b in | |
concat ["(", show o, " ", a', " ", b', ")"] | |
format (Sig _A _B) = | |
let a' = showCore _A in | |
let b' = showCore _B in | |
concat ["Σ", a', ".", b'] | |
format (Tup a b) = | |
let a' = showCore a in | |
let b' = showCore b in | |
concat ["(", a', ",", b', ")"] | |
format (Get c ms b) = | |
let c' = showCore c in | |
let ms' = concatMap (\(k,v) -> concat [" !", k, "=", showCore v]) ms in | |
let b' = showCore b in | |
concat ["~", c', ms', "{(,):", b', "}"] | |
format (All _A _B) = | |
let a' = showCore _A in | |
let b' = showCore _B in | |
concat ["∀", a', ".", b'] | |
format (Lam x f) = | |
let f' = showCore f in | |
concat ["λ", x, ".", f'] | |
format (App f x) = | |
let f' = showCore f in | |
let x' = showCore x in | |
concat ["(", f', " ", x', ")"] | |
format (Ann c x t) = | |
let x' = showCore x in | |
let t' = showCore t in | |
concat ["<", x', " : ", t', ">"] | |
renamer :: IORef (MS.Map String String) -> Core -> IO Core | |
renamer names core = case core of | |
Var k -> do | |
k' <- genName names k | |
return $ Var k' | |
Ref k i xs -> do | |
xs' <- mapM (renamer names) xs | |
return $ Ref k i xs' | |
Let m k v f -> do | |
k' <- genName names k | |
v' <- renamer names v | |
f' <- renamer names f | |
return $ Let m k' v' f' | |
Era -> | |
return Era | |
Sup l a b -> do | |
a' <- renamer names a | |
b' <- renamer names b | |
return $ Sup l a' b' | |
Dup l x y v f -> do | |
x' <- genName names x | |
y' <- genName names y | |
v' <- renamer names v | |
f' <- renamer names f | |
return $ Dup l x' y' v' f' | |
Set -> | |
return Set | |
Emp -> | |
return Emp | |
Efq c ms -> do | |
c' <- renamer names c | |
ms' <- forM ms $ \(k,v) -> do v' <- renamer names v; return (k,v') | |
return $ Efq c' ms' | |
Uni -> | |
return Uni | |
Nil -> | |
return Nil | |
Use c ms b -> do | |
c' <- renamer names c | |
ms' <- forM ms $ \(k,v) -> do v' <- renamer names v; return (k,v') | |
b' <- renamer names b | |
return $ Use c' ms' b' | |
U32 -> | |
return U32 | |
W32 v -> | |
return $ W32 v | |
Swi c ms z s -> do | |
c' <- renamer names c | |
ms' <- forM ms $ \(k,v) -> do v' <- renamer names v; return (k,v') | |
z' <- renamer names z | |
s' <- renamer names s | |
return $ Swi c' ms' z' s' | |
Op2 o a b -> do | |
a' <- renamer names a | |
b' <- renamer names b | |
return $ Op2 o a' b' | |
Sig _A _B -> do | |
_A' <- renamer names _A | |
_B' <- renamer names _B | |
return $ Sig _A' _B' | |
Tup a b -> do | |
a' <- renamer names a | |
b' <- renamer names b | |
return $ Tup a' b' | |
Get c ms b -> do | |
c' <- renamer names c | |
ms' <- forM ms $ \(k,v) -> do v' <- renamer names v; return (k,v') | |
b' <- renamer names b | |
return $ Get c' ms' b' | |
All _A _B -> do | |
_A' <- renamer names _A | |
_B' <- renamer names _B | |
return $ All _A' _B' | |
Lam x f -> do | |
x' <- genName names x | |
f' <- renamer names f | |
return $ Lam x' f' | |
App f x -> do | |
f' <- renamer names f | |
x' <- renamer names x | |
return $ App f' x' | |
Ann c x t -> do | |
x' <- renamer names x | |
t' <- renamer names t | |
return $ Ann c x' t' | |
rename :: Core -> Core | |
rename core = unsafePerformIO $ do | |
names <- newIORef MS.empty | |
renamer names core | |
genName :: IORef (MS.Map String String) -> String -> IO String | |
genName names name = | |
atomicModifyIORef' names $ \map -> | |
case MS.lookup name map of | |
Just val -> (map, val) | |
Nothing -> | |
let new = showName (MS.size map) | |
map' = MS.insert name new map | |
in (map', new) | |
instance Show Core where | |
show = showCore . rename | |
-- COMPLETE INTERACTION TABLE (updated) | |
-- @foo(a,b...) | |
-- ----------------- REF | |
-- book[foo](a,b...) | |
-- Let: | |
-- ! x = v ; f | |
-- ----------- LET | |
-- x <- v | |
-- f | |
-- (* a) | |
-- ----- APP-ERA | |
-- * | |
-- (λx.f a) | |
-- -------- APP-LAM | |
-- x <- a | |
-- f | |
-- (&L{f0,f1} a) | |
-- ------------------- APP-SUP | |
-- ! &L{a0,a1} = a; | |
-- &L{(f0 x0),(f1 x1)} | |
-- (() a) | |
-- ------ APP-NIL | |
-- error | |
-- ((f0,f1) a) | |
-- ----------- APP-TUP | |
-- error | |
-- (123 a) | |
-- ------- APP-W32 | |
-- error | |
-- (T a) | |
-- ----- APP-TYP | |
-- error | |
-- ~*{():f} | |
-- -------- USE-ERA | |
-- * | |
-- ~&L{a,b}{():f} | |
-- ----------------------- USE-SUP | |
-- ! &L{f0,f1} = f; | |
-- &L{~a{():f0},~b{():f1}} | |
-- ~λx.g{():f} | |
-- ----------- USE-LAM | |
-- error | |
-- ~(){():f} | |
-- --------- USE-NIL | |
-- f | |
-- ~(p,q){():f} | |
-- ------------ USE-TUP | |
-- error | |
-- ~123{():f} | |
-- ---------- USE-W32 | |
-- error | |
-- ~T{():f} | |
-- -------- USE-TYP | |
-- error | |
-- ~*{(,):f} | |
-- --------- GET-ERA | |
-- * | |
-- ~&L{a,b}{(,): f} | |
-- ------------------------- GET-SUP | |
-- ! &L{f0,f1} = f; | |
-- &L{~a{(,):f0},~b{(,):f1}} | |
-- ~(){(,):f} | |
-- ---------- GET-NIL | |
-- error | |
-- ~(a,b){(,):f} | |
-- ------------- GET-TUP | |
-- (f a b) | |
-- ~λx.g{(,):f} | |
-- ------------ GET-LAM | |
-- error | |
-- ~123{(,):f} | |
-- ----------- GET-W32 | |
-- error | |
-- ~TYP{(,):f} | |
-- ----------- GET-TYP | |
-- error | |
-- ~*{0:z;+:s} | |
-- ----------- SWI-ERA | |
-- * | |
-- ~&L{a,b}{0:z;+:s} | |
-- ------------------------------- SWI-SUP | |
-- ! &L{z0,z1} = z; | |
-- ! &L{s0,s1} = s; | |
-- &L{~a{0:z0;+:s0},~b{0:z1;+:s1}} | |
-- ~(){0:z;+:s} | |
-- ------------ SWI-NIL | |
-- error | |
-- ~(a,b){0:z;+:s} | |
-- --------------- SWI-TUP | |
-- error | |
-- ~λx.g{0:z;+:s} | |
-- -------------- SWI-LAM | |
-- error | |
-- ~n{0:z;+:s} | |
-- ----------- SWI-W32 | |
-- if n = 0: | |
-- z | |
-- else: | |
-- (s (n-1)) | |
-- ~T{0:z;+:s} | |
-- ----------- SWI-TYP | |
-- error | |
-- ! &L{r,s} = * | |
-- ------------- DUP-ERA | |
-- r <- * | |
-- s <- * | |
-- ! &L{x,y} = &L{a,b} | |
-- ------------------- DUP-SUP | |
-- x <- a | |
-- y <- b | |
-- ! &L{r,s} = λx.f | |
-- ---------------- DUP-LAM | |
-- r <- λx0.f0 | |
-- s <- λx1.f1 | |
-- x <- &L{x0,x1} | |
-- ! &L{f0,f1} = f | |
-- ! &L{x,y} = () | |
-- -------------- DUP-NIL | |
-- x <- () | |
-- y <- () | |
-- ! &L{x,y} = (a,b) | |
-- ----------------- DUP-TUP | |
-- ! &L{a0,a1} = a | |
-- ! &L{b0,b1} = b | |
-- x <- &L{a0,b0} | |
-- y <- &L{a1,b1} | |
-- ! &L{x,y} = 123 | |
-- --------------- DUP-W32 | |
-- x <- 123 | |
-- y <- 123 | |
-- ! &L{x,y} = Set | |
-- --------------- DUP-SET | |
-- x <- Set | |
-- y <- Set | |
-- ! &L{x,y} = ⊥ | |
-- ------------- DUP-EMP | |
-- x <- ⊥ | |
-- y <- ⊥ | |
-- ! &L{x,y} = ⊤ | |
-- ------------- DUP-UNI | |
-- x <- ⊤ | |
-- y <- ⊤ | |
-- ! &L{x,y} = U32 | |
-- -------------- DUP-U32 | |
-- x <- U32 | |
-- y <- U32 | |
-- ! &L{x,y} = ΣA.B | |
-- ----------------- DUP-SIG | |
-- ! &L{A0,A1} = A | |
-- ! &L{B0,B1} = B | |
-- x <- ΣA0.B0 | |
-- y <- ΣA1.B1 | |
-- ! &L{x,y} = ∀A.B | |
-- ----------------- DUP-ALL | |
-- ! &L{A0,A1} = A | |
-- ! &L{B0,B1} = B | |
-- x <- ∀A0.B0 | |
-- y <- ∀A1.B1 | |
-- (<op * y) | |
-- --------- OPX-ERA | |
-- * | |
-- (<op λx.f y) | |
-- ----------- OPX-LAM | |
-- error | |
-- (<op &L{a,b} y) | |
-- ------------------------- OPX-SUP | |
-- ! &L{y0,y1} = y; | |
-- &L{(<op a y0),(<op b y1)} | |
-- (<op () y) | |
-- ---------- OPX-NIL | |
-- error | |
-- (<op (x0,x1) y) | |
-- --------------- OPX-TUP | |
-- error | |
-- (<op x y) | |
-- --------- OPX-W32 | |
-- (>op y x) | |
-- (<op T y) | |
-- --------- OPX-TYP | |
-- error | |
-- (>op x *) | |
-- --------- OPY-ERA | |
-- * | |
-- (>op x λy.f) | |
-- ------------ OPY-LAM | |
-- error | |
-- (>op x &L{y0,y1}) | |
-- ----------------------- OPY-SUP | |
-- &L{>op(x y0),>op(x y1)} | |
-- (>op x ()) | |
-- ---------- OPY-NIL | |
-- error | |
-- (>op x (y0,y1)) | |
-- --------------- OPY-TUP | |
-- error | |
-- (>op x y) | |
-- --------- OPY-W32 | |
-- x <op> y | |
-- (>op x T) | |
-- --------- OPY-TYP | |
-- error | |
-- ! &L{x,y} = @foo(a,b...) | |
-- ------------------------ DUP-REF-COPY (when &L not in @foo) | |
-- ! &L{a0,a1} = a | |
-- ! &L{b0,b1} = b | |
-- ... | |
-- x <- @foo(a0,b0...) | |
-- y <- @foo(a1,b1...) | |
-- @foo(&L{ax,ay},b,c...) | |
-- ---------------------- REF-SUP-COPY (when @L not in @foo) | |
-- ! &L{bx,by} = b | |
-- ! &L{cx,by} = c | |
-- ... | |
-- &L{@foo(ax,bx,cx...),@foo(ay,by,cy,...)} | |
//./../IC.md// | |
//./Type.hs// | |
//#include <inttypes.h> | |
//#include <stdint.h> | |
//#include <stdio.h> | |
//#include <stdlib.h> | |
//#include <sys/mman.h> | |
//#include <unistd.h> | |
//#include <time.h> | |
//#include <stdbool.h> | |
//#define MAX_HEAP_SIZE (1ULL << 32) | |
//#define MAX_STACK_SIZE (1ULL << 28) | |
//typedef uint8_t Tag; | |
//typedef uint32_t Lab; | |
//typedef uint32_t Loc; | |
//typedef uint64_t Term; | |
//typedef uint16_t u16; | |
//typedef uint32_t u32; | |
//typedef uint64_t u64; | |
//// Runtime Types | |
//// ------------- | |
//typedef struct { | |
//Term* sbuf; // reduction stack buffer | |
//u64* spos; // reduction stack position | |
//Term* heap; // global node buffer | |
//u64* size; // global node buffer position | |
//u64* itrs; // interaction count | |
//u64* frsh; // fresh dup label count | |
//Term (*book[65536])(Term); // functions | |
//u16 cari[65536]; // arity of each constructor | |
//u16 clen[65536]; // case length of each constructor | |
//u16 cadt[65536]; // ADT id of each constructor | |
//u16 fari[65536]; // arity of each function | |
//} State; | |
//static State HVM = { | |
//.sbuf = NULL, | |
//.spos = NULL, | |
//.heap = NULL, | |
//.size = NULL, | |
//.itrs = NULL, | |
//.frsh = NULL, | |
//.book = {NULL}, | |
//.cari = {0}, | |
//.clen = {0}, | |
//.cadt = {0}, | |
//.fari = {0}, | |
//}; | |
//// Constants | |
//// --------- | |
//#define DP0 0x00 | |
//#define DP1 0x01 | |
//#define VAR 0x02 | |
//#define SUB 0x03 | |
//#define REF 0x04 | |
//#define LET 0x05 | |
//#define APP 0x06 | |
//#define MAT 0x08 | |
//#define IFL 0x09 | |
//#define SWI 0x0A | |
//#define OPX 0x0B | |
//#define OPY 0x0C | |
//#define ERA 0x0D | |
//#define LAM 0x0E | |
//#define SUP 0x0F | |
//#define CTR 0x10 | |
//#define W32 0x11 | |
//#define CHR 0x12 | |
//#define OP_ADD 0x00 | |
//#define OP_SUB 0x01 | |
//#define OP_MUL 0x02 | |
//#define OP_DIV 0x03 | |
//#define OP_MOD 0x04 | |
//#define OP_EQ 0x05 | |
//#define OP_NE 0x06 | |
//#define OP_LT 0x07 | |
//#define OP_GT 0x08 | |
//#define OP_LTE 0x09 | |
//#define OP_GTE 0x0A | |
//#define OP_AND 0x0B | |
//#define OP_OR 0x0C | |
//#define OP_XOR 0x0D | |
//#define OP_LSH 0x0E | |
//#define OP_RSH 0x0F | |
//#define DUP_F 0xFFFF | |
//#define SUP_F 0xFFFE | |
//#define LOG_F 0xFFFD | |
//#define LAZY 0x0 | |
//#define STRI 0x1 | |
//#define VOID 0x00000000000000 | |
//// Heap | |
//// ---- | |
//void set_len(u64 size) { | |
//*HVM.size = size; | |
//} | |
//void set_itr(u64 itrs) { | |
//*HVM.itrs = itrs; | |
//} | |
//u64 get_len() { | |
//return *HVM.size; | |
//} | |
//u64 get_itr() { | |
//return *HVM.itrs; | |
//} | |
//u64 fresh() { | |
//return (*HVM.frsh)++; | |
//} | |
//// Terms | |
//// ------ | |
//Term term_new(Tag tag, Lab lab, Loc loc) { | |
//Term tag_enc = tag; | |
//Term lab_enc = ((Term)lab) << 8; | |
//Term loc_enc = ((Term)loc) << 32; | |
//return tag_enc | lab_enc | loc_enc; | |
//} | |
//Tag term_tag(Term x) { | |
//return x & 0x7F; | |
//} | |
//Lab term_lab(Term x) { | |
//return (x >> 8) & 0xFFFFFF; | |
//} | |
//Loc term_loc(Term x) { | |
//return (x >> 32) & 0xFFFFFFFF; | |
//} | |
//u64 term_get_bit(Term x) { | |
//return (x >> 7) & 1; | |
//} | |
//Term term_set_bit(Term term) { | |
//return term | (1ULL << 7); | |
//} | |
//Term term_rem_bit(Term term) { | |
//return term & ~(1ULL << 7); | |
//} | |
//Term term_set_loc(Term x, Loc loc) { | |
//return (x & 0x00000000FFFFFFFF) | (((Term)loc) << 32); | |
//} | |
//_Bool term_is_atom(Term term) { | |
//switch (term_tag(term)) { | |
//case ERA: | |
//case W32: | |
//case CHR: return 1; | |
//default: return 0; | |
//} | |
//} | |
//// Atomics | |
//// ------- | |
//Term swap(Loc loc, Term term) { | |
//Term val = HVM.heap[loc]; | |
//HVM.heap[loc] = term; | |
//if (val == 0) { | |
//printf("SWAP 0 at %08llx\n", (u64)loc); | |
//exit(0); | |
//} | |
//return val; | |
//} | |
//Term got(Loc loc) { | |
//Term val = HVM.heap[loc]; | |
//if (val == 0) { | |
//printf("GOT 0 at %08llx\n", (u64)loc); | |
//exit(0); | |
//} | |
//return val; | |
//} | |
//void set(Loc loc, Term term) { | |
//HVM.heap[loc] = term; | |
//} | |
//void sub(Loc loc, Term term) { | |
//set(loc, term_set_bit(term)); | |
//} | |
//Term take(Loc loc) { | |
//return swap(loc, VOID); | |
//} | |
//// Allocation | |
//// ---------- | |
//Loc alloc_node(Loc arity) { | |
//if (*HVM.size + arity > MAX_HEAP_SIZE) { | |
//printf("Heap memory limit exceeded\n"); | |
//exit(1); | |
//} | |
//u64 old = *HVM.size; | |
//*HVM.size += arity; | |
//return old; | |
//} | |
//void inc_itr() { | |
//(*HVM.itrs)++; | |
//} | |
//// Stack | |
//// ---- | |
//void spush(Term term, Term* sbuf, u64* spos) { | |
//if (*spos >= MAX_STACK_SIZE) { | |
//printf("Stack memory limit exceeded\n"); | |
//exit(1); | |
//} | |
//sbuf[(*spos)++] = term; | |
//} | |
//Term spop(Term* sbuf, u64* spos) { | |
//return sbuf[--(*spos)]; | |
//} | |
//// Stringification | |
//// --------------- | |
//void print_tag(Tag tag) { | |
//switch (tag) { | |
//case VAR: printf("VAR"); break; | |
//case DP0: printf("DP0"); break; | |
//case DP1: printf("DP1"); break; | |
//case APP: printf("APP"); break; | |
//case LAM: printf("LAM"); break; | |
//case ERA: printf("ERA"); break; | |
//case SUP: printf("SUP"); break; | |
//case REF: printf("REF"); break; | |
//case LET: printf("LET"); break; | |
//case CTR: printf("CTR"); break; | |
//case MAT: printf("MAT"); break; | |
//case IFL: printf("IFL"); break; | |
//case SWI: printf("SWI"); break; | |
//case W32: printf("W32"); break; | |
//case CHR: printf("CHR"); break; | |
//case OPX: printf("OPX"); break; | |
//case OPY: printf("OPY"); break; | |
//default : printf("???"); break; | |
//} | |
//} | |
//void print_term(Term term) { | |
//printf("term_new("); | |
//print_tag(term_tag(term)); | |
//printf(",0x%06llx,0x%08llx)", (u64)term_lab(term), (u64)term_loc(term)); | |
//} | |
//void print_heap() { | |
//for (Loc i = 0; i < *HVM.size; i++) { | |
//Term term = got(i); | |
//if (term != 0) { | |
//printf("set(0x%08llx, ", (u64)i); | |
//print_term(term); | |
//printf(");\n"); | |
//} | |
//} | |
//} | |
//// Evaluation | |
//// ---------- | |
//// @foo(&L{ax ay} b c ...) | |
//// ----------------------- REF-SUP-COPY (when @L not in @foo) | |
//// ! &L{bx by} = b | |
//// ! &L{cx cy} = b | |
//// ... | |
//// &L{@foo(ax bx cx ...) @foo(ay by cy ...)} | |
//Term reduce_ref_sup(Term ref, u16 idx) { | |
//inc_itr(); | |
//Loc ref_loc = term_loc(ref); | |
//Lab ref_lab = term_lab(ref); | |
//u16 fun_id = ref_lab; | |
//u16 arity = HVM.fari[fun_id]; | |
//if (idx >= arity) { | |
//printf("ERROR: Invalid index in reduce_ref_sup\n"); | |
//exit(1); | |
//} | |
//Term sup = got(ref_loc + idx); | |
//if (term_tag(sup) != SUP) { | |
//printf("ERROR: Expected SUP at index %u\n", idx); | |
//exit(1); | |
//} | |
//Lab sup_lab = term_lab(sup); | |
//Loc sup_loc = term_loc(sup); | |
//Term sup0 = got(sup_loc + 0); | |
//Term sup1 = got(sup_loc + 1); | |
//// Allocate space for new REF node arguments for the second branch | |
//Loc ref1_loc = alloc_node(arity); | |
//for (u64 i = 0; i < arity; ++i) { | |
//if (i != idx) { | |
//// Duplicate argument | |
//Term arg = got(ref_loc + i); | |
//Loc dup_loc = alloc_node(1); | |
//set(dup_loc + 0, arg); | |
//set(ref_loc + i, term_new(DP0, sup_lab, dup_loc)); | |
//set(ref1_loc + i, term_new(DP1, sup_lab, dup_loc)); | |
//} else { | |
//// Set the SUP components directly | |
//set(ref_loc + i, sup0); | |
//set(ref1_loc + i, sup1); | |
//} | |
//} | |
//// Create new REF nodes | |
//Term ref0 = term_new(REF, ref_lab, ref_loc); | |
//Term ref1 = term_new(REF, ref_lab, ref1_loc); | |
//// Reuse sup_loc to create the new SUP node | |
//set(sup_loc + 0, ref0); | |
//set(sup_loc + 1, ref1); | |
//return term_new(SUP, sup_lab, sup_loc); | |
//} | |
//// @foo(a b c ...) | |
//// -------------------- REF | |
//// book[foo](a b c ...) | |
//Term reduce_ref(Term ref) { | |
////printf("reduce_ref "); print_term(ref); printf("\n"); | |
////printf("call %d %p\n", term_loc(ref), HVM.book[term_loc(ref)]); | |
//inc_itr(); | |
//return HVM.book[term_lab(ref)](ref); | |
//} | |
//// ! x = val | |
//// bod | |
//// --------- LET | |
//// x <- val | |
//// bod | |
//Term reduce_let(Term let, Term val) { | |
////printf("reduce_let "); print_term(let); printf("\n"); | |
//inc_itr(); | |
//Loc let_loc = term_loc(let); | |
//Term bod = got(let_loc + 1); | |
//sub(let_loc + 0, val); | |
//return bod; | |
//} | |
//// (* a) | |
//// ------- APP-ERA | |
//// * | |
//Term reduce_app_era(Term app, Term era) { | |
////printf("reduce_app_era "); print_term(app); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// (λx(body) arg) | |
//// ---------------- APP-LAM | |
//// x <- arg | |
//// body | |
//Term reduce_app_lam(Term app, Term lam) { | |
//inc_itr(); | |
//Loc app_loc = term_loc(app); | |
//Loc lam_loc = term_loc(lam); | |
//Term bod = got(lam_loc + 0); | |
//Term arg = got(app_loc + 1); | |
//sub(lam_loc + 0, arg); | |
//return bod; | |
//} | |
//// (&L{a b} c) | |
//// --------------------- APP-SUP | |
//// ! &L{x0 x1} = c | |
//// &L{(a x0) (b x1)} | |
//Term reduce_app_sup(Term app, Term sup) { | |
////printf("reduce_app_sup "); print_term(app); printf("\n"); | |
//inc_itr(); | |
//Loc app_loc = term_loc(app); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term arg = got(app_loc + 1); | |
////Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc ap0 = sup_loc; | |
//Loc ap1 = loc + 0; | |
//Loc su0 = app_loc; | |
//Loc dup = loc + 2; | |
////set(ap0 + 0, tm0) | |
//set(ap0 + 1, term_new(DP0, sup_lab, dup)); | |
//set(ap1 + 0, tm1); | |
//set(ap1 + 1, term_new(DP1, sup_lab, dup)); | |
//// Reuse app_loc for the result superposition | |
//set(su0 + 0, term_new(APP, 0, ap0)); | |
//set(su0 + 1, term_new(APP, 0, ap1)); | |
//set(dup + 0, arg); | |
//return term_new(SUP, sup_lab, su0); | |
//// return term_set_loc(sup, su0); | |
//} | |
//// &L(#{x y z ...} a) | |
//// ------------------ APP-CTR | |
//// ⊥ | |
//Term reduce_app_ctr(Term app, Term ctr) { | |
////printf("reduce_app_ctr "); print_term(app); printf("\n"); | |
//printf("invalid:app-ctr"); | |
//exit(0); | |
//} | |
//// &L(123 a) | |
//// --------- APP-W32 | |
//// ⊥ | |
//Term reduce_app_u32(Term app, Term u32) { | |
////printf("reduce_app_u32 "); print_term(app); printf("\n"); | |
//printf("invalid:app-u32"); | |
//exit(0); | |
//} | |
//// ! &L{x y} = * | |
//// ------------- DUP-ERA | |
//// x <- * | |
//// y <- * | |
//Term reduce_dup_era(Term dup, Term era) { | |
////printf("reduce_dup_era "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, era); | |
//return era; | |
//} | |
//// ! &L{r s} = λx(f) | |
//// ------------------- DUP-LAM | |
//// ! &L{f0 f1} = f | |
//// r <- λx0(f0) | |
//// s <- λx1(f1) | |
//// x <- &L{x0 x1} | |
//Term reduce_dup_lam(Term dup, Term lam) { | |
////printf("reduce_dup_lam "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Loc lam_loc = term_loc(lam); | |
//Lab dup_lab = term_lab(dup); | |
//Term bod = got(lam_loc + 0); | |
//Loc loc = alloc_node(5); | |
//Loc lm0 = loc + 0; | |
//Loc lm1 = loc + 1; | |
//Loc su0 = loc + 2; | |
//Loc du0 = loc + 4; | |
//sub(lam_loc + 0, term_new(SUP, dup_lab, su0)); | |
//set(lm0 + 0, term_new(DP0, dup_lab, du0)); | |
//set(lm1 + 0, term_new(DP1, dup_lab, du0)); | |
//set(su0 + 0, term_new(VAR, 0, lm0)); | |
//set(su0 + 1, term_new(VAR, 0, lm1)); | |
//set(du0 + 0, bod); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(LAM, 0, lm1)); | |
//return term_new(LAM, 0, lm0); | |
//} else { | |
//sub(dup_loc + 0, term_new(LAM, 0, lm0)); | |
//return term_new(LAM, 0, lm1); | |
//} | |
//} | |
//// ! &L{x y} = &R{a b} | |
//// ------------------- DUP-SUP | |
//// if L == R: | |
//// x <- a | |
//// y <- b | |
//// else: | |
//// x <- &R{a0 b0} | |
//// y <- &R{a1 b1} | |
//// ! &L{a0 a1} = a | |
//// ! &L{b0 b1} = b | |
//Term reduce_dup_sup(Term dup, Term sup) { | |
////printf("reduce_dup_sup %u %u | %llu ", term_lab(dup), term_lab(sup), *HVM.spos); print_term(dup); printf(" "); print_term(sup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Lab sup_lab = term_lab(sup); | |
//Loc sup_loc = term_loc(sup); | |
//if (dup_lab == sup_lab) { | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, tm1); | |
//return tm0; | |
//} else { | |
//sub(dup_loc + 0, tm0); | |
//return tm1; | |
//} | |
//} else { | |
//Loc loc = alloc_node(4); | |
//Loc du0 = sup_loc + 0; | |
//Loc du1 = sup_loc + 1; | |
//Loc su0 = loc + 0; | |
//Loc su1 = loc + 2; | |
////Term tm0 = got(sup_loc + 0); | |
////Term tm1 = got(sup_loc + 1); | |
////set(du0 + 0, tm0); | |
////set(du1 + 0, tm1); | |
//set(su0 + 0, term_new(DP0, dup_lab, du0)); | |
//set(su0 + 1, term_new(DP0, dup_lab, du1)); | |
//set(su1 + 0, term_new(DP1, dup_lab, du0)); | |
//set(su1 + 1, term_new(DP1, dup_lab, du1)); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(SUP, sup_lab, su1)); | |
//return term_new(SUP, sup_lab, su0); | |
//} else { | |
//sub(dup_loc + 0, term_new(SUP, sup_lab, su0)); | |
//return term_new(SUP, sup_lab, su1); | |
//} | |
//} | |
//} | |
//// ! &L{x y} = #{a b c ...} | |
//// ------------------------ DUP-CTR | |
//// ! &L{a0 a1} = a | |
//// ! &L{b0 b1} = b | |
//// ! &L{c0 c1} = c | |
//// ... | |
//// x <- #{a0 b0 c0 ...} | |
//// y <- #{a1 b1 c1 ...} | |
//Term reduce_dup_ctr(Term dup, Term ctr) { | |
////printf("reduce_dup_ctr "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc ctr_loc = term_loc(ctr); | |
//Lab ctr_lab = term_lab(ctr); | |
//u64 ctr_ari = HVM.cari[ctr_lab]; | |
//Loc loc = alloc_node(ctr_ari * 2); | |
////Loc ctr0 = alloc_node(ctr_ari); | |
//Loc ctr0 = ctr_loc; | |
//Loc ctr1 = loc + 0; | |
//for (u64 i = 0; i < ctr_ari; i++) { | |
//Loc du0 = loc + ctr_ari + i; | |
//set(du0 + 0, got(ctr_loc + i)); | |
//set(ctr0 + i, term_new(DP0, dup_lab, du0)); | |
//set(ctr1 + i, term_new(DP1, dup_lab, du0)); | |
//} | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(CTR, ctr_lab, ctr1)); | |
//return term_new(CTR, ctr_lab, ctr0); | |
//} else { | |
//sub(dup_loc + 0, term_new(CTR, ctr_lab, ctr0)); | |
//return term_new(CTR, ctr_lab, ctr1); | |
//} | |
//} | |
//// ! &L{x y} = 123 | |
//// --------------- DUP-W32 | |
//// x <- 123 | |
//// y <- 123 | |
//Term reduce_dup_u32(Term dup, Term u32) { | |
////printf("reduce_dup_u32 "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, u32); | |
//return u32; | |
//} | |
//// ! &L{x y} = @foo(a b c ...) | |
//// --------------------------- DUP-REF-COPY (when &L not in @foo) | |
//// ! &L{a0 a1} = a | |
//// ! &L{b0 b1} = b | |
//// ! &L{c0 c1} = c | |
//// ... | |
//// x <- @foo(a0 b0 c0 ...) | |
//// y <- @foo(a1 b1 c1 ...) | |
//Term reduce_dup_ref(Term dup, Term ref) { | |
////printf("reduce_dup_ref "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc ref_loc = term_loc(ref); | |
//Lab ref_lab = term_lab(ref); | |
//u64 ref_ari = HVM.fari[ref_lab]; | |
//Loc loc = alloc_node(ref_ari * 2); | |
//Loc ref0 = ref_loc; | |
//Loc ref1 = loc + 0; | |
//for (u64 i = 0; i < ref_ari; i++) { | |
//Loc du0 = loc + ref_ari + i; | |
//set(du0 + 0, got(ref_loc + i)); | |
//set(ref0 + i, term_new(DP0, dup_lab, du0)); | |
//set(ref1 + i, term_new(DP1, dup_lab, du0)); | |
//} | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(REF, ref_lab, ref1)); | |
//return term_new(REF, ref_lab, ref0); | |
//} else { | |
//sub(dup_loc + 0, term_new(REF, ref_lab, ref0)); | |
//return term_new(REF, ref_lab, ref1); | |
//} | |
//} | |
//// ~ * {K0 K1 K2 ...} | |
//// ------------------ MAT-ERA | |
//// * | |
//Term reduce_mat_era(Term mat, Term era) { | |
////printf("reduce_mat_era "); print_term(mat); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// ~ λx(x) {K0 K1 K2 ...} | |
//// ------------------------ MAT-LAM | |
//// ⊥ | |
//Term reduce_mat_lam(Term mat, Term lam) { | |
////printf("reduce_mat_lam "); print_term(mat); printf("\n"); | |
//printf("invalid:mat-lam"); | |
//exit(0); | |
//} | |
//// ~ &L{x y} {K0 K1 K2 ...} | |
//// ------------------------ MAT-SUP | |
//// ! &L{k0a k0b} = K0 | |
//// ! &L{k1a k1b} = K1 | |
//// ! &L{k2a k2b} = K2 | |
//// ... | |
//// &L{ ~ x {K0a K1a K2a ...} | |
//// ~ y {K0b K1b K2b ...} } | |
//Term reduce_mat_sup(Term mat, Term sup) { | |
////printf("reduce_mat_sup "); print_term(mat); printf("\n"); | |
//inc_itr(); | |
//Tag mat_tag = term_tag(mat); | |
//Lab mat_lab = term_lab(mat); | |
//Loc mat_loc = term_loc(mat); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//u64 mat_len = mat_tag == SWI ? mat_lab : mat_tag == IFL ? 2 : HVM.clen[mat_lab]; | |
//Loc loc = alloc_node(1 + mat_len + mat_len); | |
//Loc mat0 = mat_loc; | |
//Loc mat1 = loc + 0; | |
//Loc sup0 = sup_loc; | |
//set(mat0 + 0, tm0); | |
//set(mat1 + 0, tm1); | |
//for (u64 i = 0; i < mat_len; i++) { | |
//Loc du0 = loc + 1 + mat_len + i; | |
//set(du0 + 0, got(mat_loc + 1 + i)); | |
//set(mat0 + 1 + i, term_new(DP0, sup_lab, du0)); | |
//set(mat1 + 1 + i, term_new(DP1, sup_lab, du0)); | |
//} | |
//set(sup0 + 0, term_new(mat_tag, mat_lab, mat0)); | |
//set(sup0 + 1, term_new(mat_tag, mat_lab, mat1)); | |
//return term_new(SUP, sup_lab, sup0); | |
//} | |
//Term reduce_mat_ctr(Term mat, Term ctr) { | |
//inc_itr(); | |
//Tag mat_tag = term_tag(mat); | |
//Loc mat_loc = term_loc(mat); | |
//Lab mat_lab = term_lab(mat); | |
//// If-Let | |
//if (mat_tag == IFL) { | |
//Loc ctr_loc = term_loc(ctr); | |
//Lab ctr_lab = term_lab(ctr); | |
//u64 mat_ctr = mat_lab; | |
//u64 ctr_num = ctr_lab; | |
//u64 ctr_ari = HVM.cari[ctr_num]; | |
//if (mat_ctr == ctr_num) { | |
//Term app = got(mat_loc + 1); | |
//Loc loc = alloc_node(ctr_ari * 2); | |
//for (u64 i = 0; i < ctr_ari; i++) { | |
//Loc new_app = loc + i * 2; | |
//set(new_app + 0, app); | |
//set(new_app + 1, got(ctr_loc + i)); | |
//app = term_new(APP, 0, new_app); | |
//} | |
//return app; | |
//} else { | |
//Term app = got(mat_loc + 2); | |
//Loc new_app = mat_loc; | |
//set(new_app + 0, app); | |
//set(new_app + 1, ctr); | |
//app = term_new(APP, 0, new_app); | |
//return app; | |
//} | |
//// Match | |
//} else { | |
//Loc ctr_loc = term_loc(ctr); | |
//Lab ctr_lab = term_lab(ctr); | |
//u64 ctr_num = ctr_lab; | |
//u64 ctr_ari = HVM.cari[ctr_num]; | |
//u64 mat_ctr = mat_lab; | |
//u64 cse_idx = ctr_num - mat_ctr; | |
//Term app = got(mat_loc + 1 + cse_idx); | |
//Loc loc = alloc_node(ctr_ari * 2); | |
//for (u64 i = 0; i < ctr_ari; i++) { | |
//Loc new_app = loc + i * 2; | |
//set(new_app + 0, app); | |
//set(new_app + 1, got(ctr_loc + i)); | |
//app = term_new(APP, 0, new_app); | |
//} | |
//return app; | |
//} | |
//} | |
//// ~ num {K0 K1 K2 ... KN} | |
//// ----------------------- MAT-W32 | |
//// if n < N: Kn | |
//// else : KN(num-N) | |
//Term reduce_mat_u32(Term mat, Term u32) { | |
////printf("reduce_mat_u32 "); print_term(mat); printf("\n"); | |
//inc_itr(); | |
//Loc mat_loc = term_loc(mat); | |
//Lab mat_lab = term_lab(mat); | |
//u64 mat_len = mat_lab; | |
//u64 u32_val = term_loc(u32); | |
//if (u32_val < mat_len - 1) { | |
//return got(mat_loc + 1 + u32_val); | |
//} else { | |
//Term fn = got(mat_loc + mat_len); | |
//Loc app = mat_loc; | |
//set(app + 0, fn); | |
//set(app + 1, term_new(u32, 0, u32_val - (mat_len - 1))); | |
//return term_new(APP, 0, app); | |
//} | |
//} | |
//// <op(* b) | |
//// -------- OPX-ERA | |
//// * | |
//Term reduce_opx_era(Term opx, Term era) { | |
////printf("reduce_opx_era "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// <op(λx(B) y) | |
//// --------------- OPX-LAM | |
//// ⊥ | |
//Term reduce_opx_lam(Term opx, Term lam) { | |
////printf("reduce_opx_lam "); print_term(opx); printf("\n"); | |
//printf("invalid:opx-lam"); | |
//exit(0); | |
//} | |
//// <op(&L{x0 x1} y) | |
//// ------------------------- OPX-SUP | |
//// ! &L{y0 y1} = y | |
//// &L{<op(x0 y0) <op(x1 y1)} | |
//Term reduce_opx_sup(Term opx, Term sup) { | |
////printf("reduce_opx_sup "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//Loc opx_loc = term_loc(opx); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term nmy = got(opx_loc + 1); | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc op0 = opx_loc; | |
//Loc op1 = sup_loc; | |
//Loc su0 = loc + 0; | |
//Loc du0 = loc + 2; | |
//set(op0 + 0, tm0); | |
//set(op0 + 1, term_new(DP0, sup_lab, du0)); | |
//set(op1 + 0, tm1); | |
//set(op1 + 1, term_new(DP1, sup_lab, du0)); | |
//set(su0 + 0, term_new(OPX, term_lab(opx), op0)); | |
//set(su0 + 1, term_new(OPX, term_lab(opx), op1)); | |
//set(du0 + 0, nmy); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// <op(#{x0 x1 x2...} y) | |
//// --------------------- OPX-CTR | |
//// ⊥ | |
//Term reduce_opx_ctr(Term opx, Term ctr) { | |
////printf("reduce_opx_ctr "); print_term(opx); printf("\n"); | |
//printf("invalid:opx-ctr"); | |
//exit(0); | |
//} | |
//// <op(x0 x1) | |
//// ---------- OPX-W32 | |
//// >op(x0 x1) | |
//Term reduce_opx_u32(Term opx, Term nmx) { | |
////printf("reduce_opx_u32 "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//Lab opx_lab = term_lab(opx); | |
//Loc opx_loc = term_loc(opx); | |
//Term nmy = got(opx_loc + 1); | |
//set(opx_loc + 0, nmy); | |
//set(opx_loc + 1, nmx); | |
//return term_new(OPY, opx_lab, opx_loc); | |
//} | |
//// >op(a *) | |
//// -------- OPY-ERA | |
//// * | |
//Term reduce_opy_era(Term opy, Term era) { | |
////printf("reduce_opy_era "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// >op(a λx(B)) | |
//// ------------ OPY-LAM | |
//// * | |
//Term reduce_opy_lam(Term opy, Term era) { | |
////printf("reduce_opy_lam "); print_term(opy); printf("\n"); | |
//printf("invalid:opy-lam"); | |
//exit(0); | |
//} | |
//// >op(a &L{x y}) | |
//// --------------------- OPY-SUP | |
//// &L{>op(a x) >op(a y)} | |
//Term reduce_opy_sup(Term opy, Term sup) { | |
////printf("reduce_opy_sup "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//Loc opy_loc = term_loc(opy); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term nmx = got(opy_loc + 1); | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc op0 = sup_loc; | |
//Loc op1 = opy_loc; | |
//Loc su0 = alloc_node(2); | |
////set(op0 + 0, tm0); | |
//set(op0 + 1, nmx); | |
//set(op1 + 0, tm1); | |
////set(op1 + 1, nmx); | |
//set(su0 + 0, term_new(OPY, term_lab(opy), op0)); | |
//set(su0 + 1, term_new(OPY, term_lab(opy), op1)); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// >op(#{x y z ...} b) | |
//// ---------------------- OPY-CTR | |
//// ⊥ | |
//Term reduce_opy_ctr(Term opy, Term ctr) { | |
////printf("reduce_opy_ctr "); print_term(opy); printf("\n"); | |
//printf("invalid:opy-ctr"); | |
//exit(0); | |
//} | |
//// >op(x y) | |
//// --------- OPY-W32 | |
//// x op y | |
//Term reduce_opy_u32(Term opy, Term val) { | |
////printf("reduce_opy_u32 "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//Loc opy_loc = term_loc(opy); | |
//Tag t = term_tag(val); | |
//u32 x = term_loc(got(opy_loc + 1)); | |
//u32 y = term_loc(val); | |
//u32 result; | |
//switch (term_lab(opy)) { | |
//case OP_ADD: result = x + y; break; | |
//case OP_SUB: result = x - y; break; | |
//case OP_MUL: result = x * y; break; | |
//case OP_DIV: result = x / y; break; | |
//case OP_MOD: result = x % y; break; | |
//case OP_EQ: result = x == y; break; | |
//case OP_NE: result = x != y; break; | |
//case OP_LT: result = x < y; break; | |
//case OP_GT: result = x > y; break; | |
//case OP_LTE: result = x <= y; break; | |
//case OP_GTE: result = x >= y; break; | |
//case OP_AND: result = x & y; break; | |
//case OP_OR: result = x | y; break; | |
//case OP_XOR: result = x ^ y; break; | |
//case OP_LSH: result = x << y; break; | |
//case OP_RSH: result = x >> y; break; | |
//default: { | |
//printf("invalid:opy-u32"); | |
//exit(0); | |
//} | |
//} | |
//return term_new(t, 0, result); | |
//} | |
//Term reduce(Term term) { | |
//if (term_tag(term) >= ERA) return term; | |
//Term next = term; | |
//u64 stop = *HVM.spos; | |
//u64 spos = stop; | |
//Term* sbuf = HVM.sbuf; | |
//while (1) { | |
////printf("NEXT "); print_term(term); printf("\n"); | |
////printf("PATH "); | |
////for (u64 i = 0; i < *spos; ++i) { | |
////print_tag(term_tag(HVM.sbuf[i])); | |
////printf(" "); | |
////} | |
////printf(" ~ %p", HVM.sbuf); | |
////printf("\n"); | |
//Tag tag = term_tag(next); | |
//Lab lab = term_lab(next); | |
//Loc loc = term_loc(next); | |
//// On variables: substitute | |
//// On eliminators: move to field | |
//switch (tag) { | |
//case LET: { | |
//switch (lab) { | |
//case LAZY: { | |
//next = reduce_let(next, got(loc + 0)); | |
//continue; | |
//} | |
//case STRI: { | |
//spush(next, sbuf, &spos); | |
//next = got(loc + 0); | |
//continue; | |
//} | |
//default: { | |
//printf("invalid:let"); | |
//exit(0); | |
//} | |
//} | |
//} | |
//case APP: | |
//case MAT: | |
//case IFL: | |
//case SWI: | |
//case OPX: | |
//case OPY: { | |
//spush(next, sbuf, &spos); | |
//next = got(loc + 0); | |
//continue; | |
//} | |
//case DP0: | |
//case DP1: { | |
//Term sub = got(loc + 0); | |
//if (term_get_bit(sub) == 0) { | |
//spush(next, sbuf, &spos); | |
//next = sub; | |
//continue; | |
//} else { | |
//next = term_rem_bit(sub); | |
//continue; | |
//} | |
//} | |
//case VAR: { | |
//Term sub = got(loc); | |
//if (term_get_bit(sub) == 0) { | |
//break; | |
//} else { | |
//next = term_rem_bit(sub); | |
//continue; | |
//} | |
//} | |
//case REF: { | |
//*HVM.spos = spos; | |
//next = reduce_ref(next); | |
//spos = *HVM.spos; | |
//continue; | |
//} | |
//default: break; | |
//} | |
//// Empty stack: term is in WHNF | |
//if (spos == stop) { | |
//*HVM.spos = spos; | |
//return next; | |
//} | |
//// Interaction Dispatcher | |
//Term prev = spop(sbuf, &spos); | |
//Tag ptag = term_tag(prev); | |
//Lab plab = term_lab(prev); | |
//Loc ploc = term_loc(prev); | |
//switch (ptag) { | |
//case LET: { | |
//next = reduce_let(prev, next); | |
//continue; | |
//} | |
//case APP: { | |
//switch (tag) { | |
//case ERA: next = reduce_app_era(prev, next); continue; | |
//case LAM: next = reduce_app_lam(prev, next); continue; | |
//case SUP: next = reduce_app_sup(prev, next); continue; | |
//case CTR: next = reduce_app_ctr(prev, next); continue; | |
//case W32: next = reduce_app_u32(prev, next); continue; | |
//case CHR: next = reduce_app_u32(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case DP0: | |
//case DP1: { | |
//switch (tag) { | |
//case ERA: next = reduce_dup_era(prev, next); continue; | |
//case LAM: next = reduce_dup_lam(prev, next); continue; | |
//case SUP: next = reduce_dup_sup(prev, next); continue; | |
//case CTR: next = reduce_dup_ctr(prev, next); continue; | |
//case W32: next = reduce_dup_u32(prev, next); continue; | |
//case CHR: next = reduce_dup_u32(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case MAT: | |
//case IFL: | |
//case SWI: { | |
//switch (tag) { | |
//case ERA: next = reduce_mat_era(prev, next); continue; | |
//case LAM: next = reduce_mat_lam(prev, next); continue; | |
//case SUP: next = reduce_mat_sup(prev, next); continue; | |
//case CTR: next = reduce_mat_ctr(prev, next); continue; | |
//case W32: next = reduce_mat_u32(prev, next); continue; | |
//case CHR: next = reduce_mat_u32(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case OPX: { | |
//switch (tag) { | |
//case ERA: next = reduce_opx_era(prev, next); continue; | |
//case LAM: next = reduce_opx_lam(prev, next); continue; | |
//case SUP: next = reduce_opx_sup(prev, next); continue; | |
//case CTR: next = reduce_opx_ctr(prev, next); continue; | |
//case W32: next = reduce_opx_u32(prev, next); continue; | |
//case CHR: next = reduce_opx_u32(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case OPY: { | |
//switch (tag) { | |
//case ERA: next = reduce_opy_era(prev, next); continue; | |
//case LAM: next = reduce_opy_lam(prev, next); continue; | |
//case SUP: next = reduce_opy_sup(prev, next); continue; | |
//case CTR: next = reduce_opy_ctr(prev, next); continue; | |
//case W32: next = reduce_opy_u32(prev, next); continue; | |
//case CHR: next = reduce_opy_u32(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//default: break; | |
//} | |
//// No interaction: push term back to stack | |
//spush(prev, sbuf, &spos); | |
//// Update parent chain | |
//while (spos > stop) { | |
//Term host = spop(sbuf, &spos); | |
//Tag htag = term_tag(host); | |
//Lab hlab = term_lab(host); | |
//Loc hloc = term_loc(host); | |
//set(hloc + 0, next); | |
//next = host; | |
//} | |
//*HVM.spos = spos; | |
//return next; | |
//} | |
//} | |
//Term reduce_at(Loc host) { | |
//Term tm0 = got(host); | |
//if (term_tag(tm0) >= ERA) { | |
//return tm0; | |
//} | |
//Term tm1 = reduce(tm0); | |
//set(host, tm1); | |
//return tm1; | |
//} | |
//Term normal(Term term) { | |
//Term wnf = reduce(term); | |
//Tag tag = term_tag(wnf); | |
//Lab lab = term_lab(wnf); | |
//Loc loc = term_loc(wnf); | |
//switch (tag) { | |
//case LAM: { | |
//Term bod = got(loc + 0); | |
//bod = normal(bod); | |
//set(term_loc(wnf) + 1, bod); | |
//return wnf; | |
//} | |
//case APP: { | |
//Term fun = got(loc + 0); | |
//Term arg = got(loc + 1); | |
//fun = normal(fun); | |
//arg = normal(arg); | |
//set(term_loc(wnf) + 0, fun); | |
//set(term_loc(wnf) + 1, arg); | |
//return wnf; | |
//} | |
//case SUP: { | |
//Term tm0 = got(loc + 0); | |
//Term tm1 = got(loc + 1); | |
//tm0 = normal(tm0); | |
//tm1 = normal(tm1); | |
//set(term_loc(wnf) + 0, tm0); | |
//set(term_loc(wnf) + 1, tm1); | |
//return wnf; | |
//} | |
//case DP0: | |
//case DP1: { | |
//Term val = got(loc + 0); | |
//val = normal(val); | |
//set(term_loc(wnf) + 0, val); | |
//return wnf; | |
//} | |
//case CTR: { | |
//u64 cid = lab; | |
//u64 ari = HVM.cari[cid]; | |
//for (u64 i = 0; i < ari; i++) { | |
//Term arg = got(loc + i); | |
//arg = normal(arg); | |
//set(term_loc(wnf) + i, arg); | |
//} | |
//return wnf; | |
//} | |
//case MAT: | |
//case IFL: | |
//case SWI: { | |
//u64 len = tag == SWI ? lab : tag == IFL ? 2 : HVM.clen[lab]; | |
//for (u64 i = 0; i <= len; i++) { | |
//Term arg = got(loc + i); | |
//arg = normal(arg); | |
//set(term_loc(wnf) + i, arg); | |
//} | |
//return wnf; | |
//} | |
//default: | |
//return wnf; | |
//} | |
//} | |
//// Primitives | |
//// ---------- | |
//// Primitive: Dynamic Sup @SUP(lab tm0 tm1) | |
//// Allocates a new SUP node with given label. | |
//Term SUP_f(Term ref) { | |
//Loc ref_loc = term_loc(ref); | |
//Term lab = reduce(got(ref_loc + 0)); | |
//Term lab_val = term_loc(lab); | |
//if (term_tag(lab) != W32) { | |
//printf("ERROR:non-numeric-sup-label\n"); | |
//} | |
//if (lab_val > 0xFFFF) { | |
//printf("ERROR:sup-label-too-large\n"); | |
//} | |
//Term tm0 = got(ref_loc + 1); | |
//Term tm1 = got(ref_loc + 2); | |
//Loc sup = alloc_node(2); | |
//Term ret = term_new(SUP, lab_val, sup); | |
//set(sup + 0, tm0); | |
//set(sup + 1, tm1); | |
//*HVM.itrs += 1; | |
//return ret; | |
//} | |
//// Primitive: Dynamic Dup @DUP(lab val λdp0λdp1(bod)) | |
//// Creates a DUP node with given label. | |
//Term DUP_f(Term ref) { | |
//Loc ref_loc = term_loc(ref); | |
//Term lab = reduce(got(ref_loc + 0)); | |
//Term lab_val = term_loc(lab); | |
//if (term_tag(lab) != W32) { | |
//printf("ERROR:non-numeric-dup-label\n"); | |
//} | |
//if (lab_val > 0xFFFF) { | |
//printf("ERROR:dup-label-too-large\n"); | |
//} | |
//Term val = got(ref_loc + 1); | |
//Term bod = got(ref_loc + 2); | |
//Loc dup = alloc_node(1); | |
//set(dup + 0, val); | |
//if (term_tag(bod) == LAM) { | |
//Loc lam0 = term_loc(bod); | |
//Term bod0 = got(lam0 + 0); | |
//if (term_tag(bod0) == LAM) { | |
//Loc lam1 = term_loc(bod0); | |
//Term bod1 = got(lam1 + 0); | |
//sub(lam0 + 0, term_new(DP0, lab_val, dup)); | |
//sub(lam1 + 0, term_new(DP1, lab_val, dup)); | |
//*HVM.itrs += 3; | |
//return bod1; | |
//} | |
//} | |
//Loc app0 = alloc_node(2); | |
//set(app0 + 0, bod); | |
//set(app0 + 1, term_new(DP0, lab_val, dup)); | |
//Loc app1 = alloc_node(2); | |
//set(app1 + 0, term_new(APP, 0, app0)); | |
//set(app1 + 1, term_new(DP1, lab_val, dup)); | |
//*HVM.itrs += 1; | |
//return term_new(APP, 0, app1); | |
//} | |
//Term LOG_f(Term ref) { | |
//printf("TODO: LOG_f"); | |
//exit(0); | |
//} | |
//void *alloc_huge(size_t size) { | |
//void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, | |
//MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, | |
//-1, 0); | |
//if (ptr == MAP_FAILED) { | |
//perror("mmap failed"); | |
//return NULL; | |
//} | |
//return ptr; | |
//} | |
//// Runtime Memory | |
//// -------------- | |
//void hvm_init() { | |
//HVM.sbuf = alloc_huge(MAX_STACK_SIZE * sizeof(Term)); | |
//HVM.heap = alloc_huge(MAX_HEAP_SIZE * sizeof(Term)); | |
//HVM.spos = alloc_huge(sizeof(u64)); | |
//HVM.size = alloc_huge(sizeof(u64)); | |
//HVM.itrs = alloc_huge(sizeof(u64)); | |
//HVM.frsh = alloc_huge(sizeof(u64)); | |
//#define CHECK_ALLOC(ptr, name) if (!(ptr)) { printf(name " alloc failed\n"); allocs_failed++; } | |
//int allocs_failed = 0; // Track if any allocation failed | |
//CHECK_ALLOC(HVM.sbuf, "sbuf"); | |
//CHECK_ALLOC(HVM.heap, "heap"); | |
//CHECK_ALLOC(HVM.spos, "spos"); | |
//CHECK_ALLOC(HVM.size, "size"); | |
//CHECK_ALLOC(HVM.itrs, "itrs"); | |
//CHECK_ALLOC(HVM.frsh, "frsh"); | |
//if (allocs_failed > 0) { | |
//printf("hvm_init alloc's failed: %d allocations failed\n", allocs_failed); | |
//exit(1); | |
//} | |
//#undef CHECK_ALLOC | |
//*HVM.spos = 0; | |
//*HVM.size = 1; | |
//*HVM.itrs = 0; | |
//*HVM.frsh = 0x20; | |
//HVM.book[SUP_F] = SUP_f; | |
//HVM.book[DUP_F] = DUP_f; | |
//HVM.book[LOG_F] = LOG_f; | |
//for (int i = 0; i < 65536; i++) { | |
//HVM.cari[i] = 0; | |
//HVM.clen[i] = 0; | |
//HVM.cadt[i] = 0; | |
//HVM.fari[i] = 0; | |
//} | |
//} | |
//void hvm_munmap(void *ptr, size_t size, const char *name) { | |
//if (ptr != MAP_FAILED) { | |
//if (munmap(ptr, size) == -1) { | |
//perror("munmap failed"); | |
//} else { | |
//// printf("Successfully unmapped %s\n", name); | |
//} | |
//} else { | |
//printf("%s is already null or invalid.\n", name); | |
//} | |
//} | |
//void hvm_free() { | |
//hvm_munmap(HVM.sbuf, MAX_STACK_SIZE * sizeof(Term), "sbuf"); | |
//hvm_munmap(HVM.heap, MAX_HEAP_SIZE * sizeof(Term), "heap"); | |
//hvm_munmap(HVM.spos, sizeof(u64), "spos"); | |
//hvm_munmap(HVM.size, sizeof(u64), "size"); | |
//hvm_munmap(HVM.itrs, sizeof(u64), "itrs"); | |
//hvm_munmap(HVM.frsh, sizeof(u64), "frsh"); | |
//} | |
//State* hvm_get_state() { | |
//return &HVM; | |
//} | |
//void hvm_set_state(State* hvm) { | |
//HVM.sbuf = hvm->sbuf; | |
//HVM.spos = hvm->spos; | |
//HVM.heap = hvm->heap; | |
//HVM.size = hvm->size; | |
//HVM.itrs = hvm->itrs; | |
//HVM.frsh = hvm->frsh; | |
//for (int i = 0; i < 65536; i++) { | |
//HVM.book[i] = hvm->book[i]; | |
//HVM.fari[i] = hvm->fari[i]; | |
//HVM.cari[i] = hvm->cari[i]; | |
//HVM.clen[i] = hvm->clen[i]; | |
//HVM.cadt[i] = hvm->cadt[i]; | |
//} | |
//} | |
//void hvm_define(u16 fid, Term (*func)()) { | |
////printf("defined %llu %p\n", fid, func); | |
//HVM.book[fid] = func; | |
//} | |
//void hvm_set_cari(u16 cid, u16 arity) { | |
//HVM.cari[cid] = arity; | |
//} | |
//void hvm_set_fari(u16 fid, u16 arity) { | |
//HVM.fari[fid] = arity; | |
//} | |
//void hvm_set_clen(u16 cid, u16 cases) { | |
//HVM.clen[cid] = cases; | |
//} | |
//void hvm_set_cadt(u16 cid, u16 adt) { | |
//HVM.cadt[cid] = adt; | |
//} | |
// GOAL: our goal now is to fully rewrite Runtime.c taking in account the changes made to the Core type | |
// do it below. | |
// COMPLETE, UPDATED RUNTIME.C FILE: | |
//#include <inttypes.h> | |
//#include <stdint.h> | |
//#include <stdio.h> | |
//#include <stdlib.h> | |
//#include <sys/mman.h> | |
//#include <unistd.h> | |
//#include <time.h> | |
//#include <stdbool.h> | |
//#define MAX_HEAP_SIZE (1ULL << 32) | |
//#define MAX_STACK_SIZE (1ULL << 28) | |
//typedef uint8_t Tag; | |
//typedef uint32_t Lab; | |
//typedef uint32_t Loc; | |
//typedef uint64_t Term; | |
//typedef uint16_t u16; | |
//typedef uint32_t u32; | |
//typedef uint64_t u64; | |
//// Runtime Types | |
//// ------------- | |
//typedef struct { | |
//Term* sbuf; // reduction stack buffer | |
//u64* spos; // reduction stack position | |
//Term* heap; // global node buffer | |
//u64* size; // global node buffer position | |
//u64* itrs; // interaction count | |
//u64* frsh; // fresh dup label count | |
//Term (*book[65536])(Term); // functions | |
//u16 fari[65536]; // arity of each function | |
//} State; | |
//static State HVM = { | |
//.sbuf = NULL, | |
//.spos = NULL, | |
//.heap = NULL, | |
//.size = NULL, | |
//.itrs = NULL, | |
//.frsh = NULL, | |
//.book = {NULL}, | |
//.fari = {0}, | |
//}; | |
//// Constants | |
//// --------- | |
//#define DP0 0x00 | |
//#define DP1 0x01 | |
//#define VAR 0x02 | |
//#define REF 0x03 | |
//#define LET 0x04 | |
//#define ERA 0x05 | |
//#define SUP 0x06 | |
//#define DUP 0x07 | |
//#define SET 0x08 | |
//#define EMP 0x09 | |
//#define EFQ 0x0A | |
//#define UNI 0x0B | |
//#define NIL 0x0C | |
//#define USE 0x0D | |
//#define U32 0x0E | |
//#define W32 0x0F | |
//#define SWI 0x10 | |
//#define OPX 0x11 | |
//#define OPY 0x12 | |
//#define SIG 0x13 | |
//#define TUP 0x14 | |
//#define GET 0x15 | |
//#define ALL 0x16 | |
//#define LAM 0x17 | |
//#define APP 0x18 | |
//#define OP_ADD 0x00 | |
//#define OP_SUB 0x01 | |
//#define OP_MUL 0x02 | |
//#define OP_DIV 0x03 | |
//#define OP_MOD 0x04 | |
//#define OP_EQ 0x05 | |
//#define OP_NE 0x06 | |
//#define OP_LT 0x07 | |
//#define OP_GT 0x08 | |
//#define OP_LTE 0x09 | |
//#define OP_GTE 0x0A | |
//#define OP_AND 0x0B | |
//#define OP_OR 0x0C | |
//#define OP_XOR 0x0D | |
//#define OP_LSH 0x0E | |
//#define OP_RSH 0x0F | |
//#define DUP_F 0xFFFF | |
//#define SUP_F 0xFFFE | |
//#define LOG_F 0xFFFD | |
//#define LAZY 0x0 | |
//#define STRI 0x1 | |
//#define VOID 0x00000000000000 | |
//// Heap | |
//// ---- | |
//void set_len(u64 size) { | |
//*HVM.size = size; | |
//} | |
//void set_itr(u64 itrs) { | |
//*HVM.itrs = itrs; | |
//} | |
//u64 get_len() { | |
//return *HVM.size; | |
//} | |
//u64 get_itr() { | |
//return *HVM.itrs; | |
//} | |
//u64 fresh() { | |
//return (*HVM.frsh)++; | |
//} | |
//// Terms | |
//// ------ | |
//Term term_new(Tag tag, Lab lab, Loc loc) { | |
//Term tag_enc = tag; | |
//Term lab_enc = ((Term)lab) << 8; | |
//Term loc_enc = ((Term)loc) << 32; | |
//return tag_enc | lab_enc | loc_enc; | |
//} | |
//Tag term_tag(Term x) { | |
//return x & 0x7F; | |
//} | |
//Lab term_lab(Term x) { | |
//return (x >> 8) & 0xFFFFFF; | |
//} | |
//Loc term_loc(Term x) { | |
//return (x >> 32) & 0xFFFFFFFF; | |
//} | |
//u64 term_get_bit(Term x) { | |
//return (x >> 7) & 1; | |
//} | |
//Term term_set_bit(Term term) { | |
//return term | (1ULL << 7); | |
//} | |
//Term term_rem_bit(Term term) { | |
//return term & ~(1ULL << 7); | |
//} | |
//Term term_set_loc(Term x, Loc loc) { | |
//return (x & 0x00000000FFFFFFFF) | (((Term)loc) << 32); | |
//} | |
//_Bool term_is_atom(Term term) { | |
//switch (term_tag(term)) { | |
//case ERA: | |
//case W32: | |
//case NIL: | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: return 1; | |
//default: return 0; | |
//} | |
//} | |
//// Atomics | |
//// ------- | |
//Term swap(Loc loc, Term term) { | |
//Term val = HVM.heap[loc]; | |
//HVM.heap[loc] = term; | |
//if (val == 0) { | |
//printf("SWAP 0 at %08llx\n", (u64)loc); | |
//exit(0); | |
//} | |
//return val; | |
//} | |
//Term got(Loc loc) { | |
//Term val = HVM.heap[loc]; | |
//if (val == 0) { | |
//printf("GOT 0 at %08llx\n", (u64)loc); | |
//exit(0); | |
//} | |
//return val; | |
//} | |
//void set(Loc loc, Term term) { | |
//HVM.heap[loc] = term; | |
//} | |
//void sub(Loc loc, Term term) { | |
//set(loc, term_set_bit(term)); | |
//} | |
//Term take(Loc loc) { | |
//return swap(loc, VOID); | |
//} | |
//// Allocation | |
//// ---------- | |
//Loc alloc_node(Loc arity) { | |
//if (*HVM.size + arity > MAX_HEAP_SIZE) { | |
//printf("Heap memory limit exceeded\n"); | |
//exit(1); | |
//} | |
//u64 old = *HVM.size; | |
//*HVM.size += arity; | |
//return old; | |
//} | |
//void inc_itr() { | |
//(*HVM.itrs)++; | |
//} | |
//// Stack | |
//// ---- | |
//void spush(Term term, Term* sbuf, u64* spos) { | |
//if (*spos >= MAX_STACK_SIZE) { | |
//printf("Stack memory limit exceeded\n"); | |
//exit(1); | |
//} | |
//sbuf[(*spos)++] = term; | |
//} | |
//Term spop(Term* sbuf, u64* spos) { | |
//return sbuf[--(*spos)]; | |
//} | |
//// Stringification | |
//// --------------- | |
//void print_tag(Tag tag) { | |
//switch (tag) { | |
//case VAR: printf("VAR"); break; | |
//case DP0: printf("DP0"); break; | |
//case DP1: printf("DP1"); break; | |
//case REF: printf("REF"); break; | |
//case LET: printf("LET"); break; | |
//case ERA: printf("ERA"); break; | |
//case SUP: printf("SUP"); break; | |
//case DUP: printf("DUP"); break; | |
//case SET: printf("SET"); break; | |
//case EMP: printf("EMP"); break; | |
//case EFQ: printf("EFQ"); break; | |
//case UNI: printf("UNI"); break; | |
//case NIL: printf("NIL"); break; | |
//case USE: printf("USE"); break; | |
//case U32: printf("U32"); break; | |
//case W32: printf("W32"); break; | |
//case SWI: printf("SWI"); break; | |
//case OPX: printf("OPX"); break; | |
//case OPY: printf("OPY"); break; | |
//case SIG: printf("SIG"); break; | |
//case TUP: printf("TUP"); break; | |
//case GET: printf("GET"); break; | |
//case ALL: printf("ALL"); break; | |
//case LAM: printf("LAM"); break; | |
//case APP: printf("APP"); break; | |
//default : printf("???"); break; | |
//} | |
//} | |
//void print_term(Term term) { | |
//printf("term_new("); | |
//print_tag(term_tag(term)); | |
//printf(",0x%06llx,0x%08llx)", (u64)term_lab(term), (u64)term_loc(term)); | |
//} | |
//void print_heap() { | |
//for (Loc i = 0; i < *HVM.size; i++) { | |
//Term term = got(i); | |
//if (term != 0) { | |
//printf("set(0x%08llx, ", (u64)i); | |
//print_term(term); | |
//printf(");\n"); | |
//} | |
//} | |
//} | |
//// Evaluation | |
//// ---------- | |
//// @foo(&L{ax ay} b c ...) | |
//// ----------------------- REF-SUP-COPY (when @L not in @foo) | |
//// ! &L{bx by} = b | |
//// ! &L{cx cy} = b | |
//// ... | |
//// &L{@foo(ax bx cx ...) @foo(ay by cy ...)} | |
//// @foo(a b c ...) | |
//// -------------------- REF | |
//// book[foo](a b c ...) | |
//Term reduce_ref(Term ref) { | |
//inc_itr(); | |
//return HVM.book[term_lab(ref)](ref); | |
//} | |
//// ! x = val | |
//// bod | |
//// --------- LET | |
//// x <- val | |
//// bod | |
//Term reduce_let(Term let, Term val) { | |
////printf("reduce_let "); print_term(let); printf("\n"); | |
//inc_itr(); | |
//Loc let_loc = term_loc(let); | |
//Term bod = got(let_loc + 1); | |
//sub(let_loc + 0, val); | |
//return bod; | |
//} | |
//// (* a) | |
//// ------- APP-ERA | |
//// * | |
//Term reduce_app_era(Term app, Term era) { | |
////printf("reduce_app_era "); print_term(app); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// (λx.f a) | |
//// -------- APP-LAM | |
//// x <- a | |
//// f | |
//Term reduce_app_lam(Term app, Term lam) { | |
//inc_itr(); | |
//Loc app_loc = term_loc(app); | |
//Loc lam_loc = term_loc(lam); | |
//Term bod = got(lam_loc + 0); | |
//Term arg = got(app_loc + 1); | |
//sub(lam_loc + 0, arg); | |
//return bod; | |
//} | |
//// (&L{a,b} c) | |
//// ----------------- APP-SUP | |
//// ! &L{c0,c1} = c; | |
//// &L{(a c0),(b c1)} | |
//Term reduce_app_sup(Term app, Term sup) { | |
////printf("reduce_app_sup "); print_term(app); printf("\n"); | |
//inc_itr(); | |
//Loc app_loc = term_loc(app); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term arg = got(app_loc + 1); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc ap0 = sup_loc; | |
//Loc ap1 = loc + 0; | |
//Loc su0 = app_loc; | |
//Loc dup = loc + 2; | |
//set(ap0 + 1, term_new(DP0, sup_lab, dup)); | |
//set(ap1 + 0, tm1); | |
//set(ap1 + 1, term_new(DP1, sup_lab, dup)); | |
//set(su0 + 0, term_new(APP, 0, ap0)); | |
//set(su0 + 1, term_new(APP, 0, ap1)); | |
//set(dup + 0, arg); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// (() a) | |
//// ------ APP-NIL | |
//// error | |
//Term reduce_app_nil(Term app, Term nil) { | |
//printf("invalid:app-nil"); | |
//exit(0); | |
//} | |
//// ((a,b) c) | |
//// --------- APP-TUP | |
//// error | |
//Term reduce_app_tup(Term app, Term tup) { | |
//printf("invalid:app-tup"); | |
//exit(0); | |
//} | |
//// (123 a) | |
//// ------- APP-W32 | |
//// error | |
//Term reduce_app_w32(Term app, Term w32) { | |
//printf("invalid:app-w32"); | |
//exit(0); | |
//} | |
//// (T a) | |
//// ----- APP-TYP | |
//// error | |
//Term reduce_app_typ(Term app, Term typ) { | |
//printf("invalid:app-typ"); | |
//exit(0); | |
//} | |
//// ~*{():f} | |
//// -------- USE-ERA | |
//// * | |
//Term reduce_use_era(Term use, Term era) { | |
//inc_itr(); | |
//return era; | |
//} | |
//// ~&L{a,b}{():f} | |
//// ----------------------- USE-SUP | |
//// ! &L{f0,f1} = f; | |
//// &L{~a{():f0},~b{():f1}} | |
//Term reduce_use_sup(Term use, Term sup) { | |
//inc_itr(); | |
//Loc use_loc = term_loc(use); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term f = got(use_loc + 1); | |
//Term a = got(sup_loc + 0); | |
//Term b = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc us0 = sup_loc; | |
//Loc us1 = loc + 0; | |
//Loc su0 = use_loc; | |
//Loc dup = loc + 2; | |
//set(us0 + 0, a); | |
//set(us0 + 1, term_new(DP0, sup_lab, dup)); | |
//set(us1 + 0, b); | |
//set(us1 + 1, term_new(DP1, sup_lab, dup)); | |
//set(su0 + 0, term_new(USE, 0, us0)); | |
//set(su0 + 1, term_new(USE, 0, us1)); | |
//set(dup + 0, f); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// ~λx.g{():f} | |
//// ----------- USE-LAM | |
//// error | |
//Term reduce_use_lam(Term use, Term lam) { | |
//printf("invalid:use-lam"); | |
//exit(0); | |
//} | |
//// ~(){():f} | |
//// --------- USE-NIL | |
//// f | |
//Term reduce_use_nil(Term use, Term nil) { | |
//inc_itr(); | |
//Loc use_loc = term_loc(use); | |
//Term f = got(use_loc + 1); | |
//return f; | |
//} | |
//// ~(p,q){():f} | |
//// ------------ USE-TUP | |
//// error | |
//Term reduce_use_tup(Term use, Term tup) { | |
//printf("invalid:use-tup"); | |
//exit(0); | |
//} | |
//// ~123{():f} | |
//// ---------- USE-W32 | |
//// error | |
//Term reduce_use_w32(Term use, Term w32) { | |
//printf("invalid:use-w32"); | |
//exit(0); | |
//} | |
//// ~T{():f} | |
//// -------- USE-TYP | |
//// error | |
//Term reduce_use_typ(Term use, Term typ) { | |
//printf("invalid:use-typ"); | |
//exit(0); | |
//} | |
//// ~*{(,):f} | |
//// --------- GET-ERA | |
//// * | |
//Term reduce_get_era(Term get, Term era) { | |
//inc_itr(); | |
//return era; | |
//} | |
//// ~&L{a,b}{(,): f} | |
//// ------------------------- GET-SUP | |
//// ! &L{f0,f1} = f; | |
//// &L{~a{(,):f0},~b{(,):f1}} | |
//Term reduce_get_sup(Term get, Term sup) { | |
//inc_itr(); | |
//Loc get_loc = term_loc(get); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term f = got(get_loc + 1); | |
//Term a = got(sup_loc + 0); | |
//Term b = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc gt0 = sup_loc; | |
//Loc gt1 = loc + 0; | |
//Loc su0 = get_loc; | |
//Loc dup = loc + 2; | |
//set(gt0 + 0, a); | |
//set(gt0 + 1, term_new(DP0, sup_lab, dup)); | |
//set(gt1 + 0, b); | |
//set(gt1 + 1, term_new(DP1, sup_lab, dup)); | |
//set(su0 + 0, term_new(GET, 0, gt0)); | |
//set(su0 + 1, term_new(GET, 0, gt1)); | |
//set(dup + 0, f); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// ~(){(,):f} | |
//// ---------- GET-NIL | |
//// error | |
//Term reduce_get_nil(Term get, Term nil) { | |
//printf("invalid:get-nil"); | |
//exit(0); | |
//} | |
//// ~(a,b){(,):f} | |
//// ------------- GET-TUP | |
//// (f a b) | |
//Term reduce_get_tup(Term get, Term tup) { | |
//inc_itr(); | |
//Loc get_loc = term_loc(get); | |
//Loc tup_loc = term_loc(tup); | |
//Term f = got(get_loc + 1); | |
//Term a = got(tup_loc + 0); | |
//Term b = got(tup_loc + 1); | |
//Loc app1 = alloc_node(2); | |
//Loc app2 = get_loc; | |
//set(app1 + 0, f); | |
//set(app1 + 1, a); | |
//set(app2 + 0, term_new(APP, 0, app1)); | |
//set(app2 + 1, b); | |
//return term_new(APP, 0, app2); | |
//} | |
//// ~λx.g{(,):f} | |
//// ------------ GET-LAM | |
//// error | |
//Term reduce_get_lam(Term get, Term lam) { | |
//printf("invalid:get-lam"); | |
//exit(0); | |
//} | |
//// ~123{(,):f} | |
//// ----------- GET-W32 | |
//// error | |
//Term reduce_get_w32(Term get, Term w32) { | |
//printf("invalid:get-w32"); | |
//exit(0); | |
//} | |
//// ~TYP{(,):f} | |
//// ----------- GET-TYP | |
//// error | |
//Term reduce_get_typ(Term get, Term typ) { | |
//printf("invalid:get-typ"); | |
//exit(0); | |
//} | |
//// ~*{0:z;+:s} | |
//// ----------- SWI-ERA | |
//// * | |
//Term reduce_swi_era(Term swi, Term era) { | |
//inc_itr(); | |
//return era; | |
//} | |
//// ~&L{a,b}{0:z;+:s} | |
//// ------------------------------- SWI-SUP | |
//// ! &L{z0,z1} = z; | |
//// ! &L{s0,s1} = s; | |
//// &L{~a{0:z0;+:s0},~b{0:z1;+:s1}} | |
////Term reduce_swi_sup(Term swi, Term sup) { | |
////inc_itr(); | |
////Loc swi_loc = term_loc(swi); | |
////Loc sup_loc = term_loc(sup); | |
////Lab sup_lab = term_lab(sup); | |
////Term z = got(swi_loc + 1); | |
////Term s = got(swi_loc + 2); | |
////Term a = got(sup_loc + 0); | |
////Term b = got(sup_loc + 1); | |
////Loc loc = alloc_node(5); | |
////Loc sw0 = sup_loc; | |
////Loc sw1 = loc + 0; | |
////Loc su0 = swi_loc; | |
////Loc dz = loc + 2; | |
////Loc ds = loc + 3; | |
////set(sw0 + 0, a); | |
////set(sw0 + 1, term_new(DP0, sup_lab, dz)); | |
////set(sw0 + 2, term_new(DP0, sup_lab, ds)); | |
////set(sw1 + 0, b); | |
////set(sw1 + 1, term_new(DP1, sup_lab, dz)); | |
////set(sw1 + 2, term_new(DP1, sup_lab, ds)); | |
////set(su0 + 0, term_new(SWI, 0, sw0)); | |
////set(su0 + 1, term_new(SWI, 0, sw1)); | |
////set(dz + 0, z); | |
////set(ds + 0, s); | |
////return term_new(SUP, sup_lab, su0); | |
////} | |
//// BUG: the function above is INCORRECT. it is re-using a SUP node for a SWI | |
//// node, but a SUP node has only 2 fields, not 3. this will cause memory errors. | |
//// you MUST reuse the input sup node for the output sup node, and you MUST reuse | |
//// the input swi node for one of the output swi nodes - just like the original | |
//// reduce_mat_sup function did. fix it: | |
//Term reduce_swi_sup(Term swi, Term sup) { | |
//// Correct implementation that reuses the given SUP/SWI nodes | |
//inc_itr(); | |
//// Locations / labels | |
//Loc swi_loc = term_loc(swi); // original SWI (will become SWI0) | |
//Loc sup_loc = term_loc(sup); // SUP we will reuse | |
//Lab sup_lab = term_lab(sup); // label of the SUP | |
//Lab swi_lab = term_lab(swi); // (unused, still preserve) | |
//// Extract SWI arms | |
//Term z = got(swi_loc + 1); | |
//Term s = got(swi_loc + 2); | |
//// Extract SUP branches | |
//Term a = got(sup_loc + 0); | |
//Term b = got(sup_loc + 1); | |
//// Allocate: | |
//// - 3 cells for the second SWI (swi1) | |
//// - 1 cell for dup(z) (dupz) | |
//// - 1 cell for dup(s) (dups) | |
//Loc loc = alloc_node(5); | |
//Loc swi1 = loc; // 3 cells (value,z,s) | |
//Loc dupz = loc + 3; // 1 cell | |
//Loc dups = loc + 4; // 1 cell | |
//// Store originals inside dup nodes | |
//set(dupz + 0, z); | |
//set(dups + 0, s); | |
//// Build SWI0 (reuse swi_loc) | |
//set(swi_loc + 0, a); | |
//set(swi_loc + 1, term_new(DP0, sup_lab, dupz)); | |
//set(swi_loc + 2, term_new(DP0, sup_lab, dups)); | |
//// Build SWI1 (new node) | |
//set(swi1 + 0, b); | |
//set(swi1 + 1, term_new(DP1, sup_lab, dupz)); | |
//set(swi1 + 2, term_new(DP1, sup_lab, dups)); | |
//// Build resulting SUP (reuse sup_loc) | |
//set(sup_loc + 0, term_new(SWI, swi_lab, swi_loc)); | |
//set(sup_loc + 1, term_new(SWI, swi_lab, swi1)); | |
//return term_new(SUP, sup_lab, sup_loc); | |
//} | |
//// ~(){0:z;+:s} | |
//// ------------ SWI-NIL | |
//// error | |
//Term reduce_swi_nil(Term swi, Term nil) { | |
//printf("invalid:swi-nil"); | |
//exit(0); | |
//} | |
//// ~(a,b){0:z;+:s} | |
//// --------------- SWI-TUP | |
//// error | |
//Term reduce_swi_tup(Term swi, Term tup) { | |
//printf("invalid:swi-tup"); | |
//exit(0); | |
//} | |
//// ~λx.g{0:z;+:s} | |
//// -------------- SWI-LAM | |
//// error | |
//Term reduce_swi_lam(Term swi, Term lam) { | |
//printf("invalid:swi-lam"); | |
//exit(0); | |
//} | |
//// ~n{0:z;+:s} | |
//// ----------- SWI-W32 | |
//// if n = 0: | |
//// z | |
//// else: | |
//// (s (n-1)) | |
//Term reduce_swi_w32(Term swi, Term w32) { | |
//inc_itr(); | |
//Loc swi_loc = term_loc(swi); | |
//u32 val = term_loc(w32); | |
//Term z = got(swi_loc + 1); | |
//Term s = got(swi_loc + 2); | |
//if (val == 0) { | |
//return z; | |
//} else { | |
//Loc app = swi_loc; | |
//set(app + 0, s); | |
//set(app + 1, term_new(W32, 0, val - 1)); | |
//return term_new(APP, 0, app); | |
//} | |
//} | |
//// ~T{0:z;+:s} | |
//// ----------- SWI-TYP | |
//// error | |
//Term reduce_swi_typ(Term swi, Term typ) { | |
//printf("invalid:swi-typ"); | |
//exit(0); | |
//} | |
//// ! &L{r,s} = * | |
//// ------------- DUP-ERA | |
//// r <- * | |
//// s <- * | |
//Term reduce_dup_era(Term dup, Term era) { | |
////printf("reduce_dup_era "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, era); | |
//return era; | |
//} | |
//// ! &L{x,y} = &L{a,b} | |
//// ------------------- DUP-SUP | |
//// x <- a | |
//// y <- b | |
//Term reduce_dup_sup(Term dup, Term sup) { | |
////printf("reduce_dup_sup %u %u | %llu ", term_lab(dup), term_lab(sup), *HVM.spos); print_term(dup); printf(" "); print_term(sup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Lab sup_lab = term_lab(sup); | |
//Loc sup_loc = term_loc(sup); | |
//if (dup_lab == sup_lab) { | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, tm1); | |
//return tm0; | |
//} else { | |
//sub(dup_loc + 0, tm0); | |
//return tm1; | |
//} | |
//} else { | |
//Loc loc = alloc_node(4); | |
//Loc du0 = sup_loc + 0; | |
//Loc du1 = sup_loc + 1; | |
//Loc su0 = loc + 0; | |
//Loc su1 = loc + 2; | |
//set(su0 + 0, term_new(DP0, dup_lab, du0)); | |
//set(su0 + 1, term_new(DP0, dup_lab, du1)); | |
//set(su1 + 0, term_new(DP1, dup_lab, du0)); | |
//set(su1 + 1, term_new(DP1, dup_lab, du1)); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(SUP, sup_lab, su1)); | |
//return term_new(SUP, sup_lab, su0); | |
//} else { | |
//sub(dup_loc + 0, term_new(SUP, sup_lab, su0)); | |
//return term_new(SUP, sup_lab, su1); | |
//} | |
//} | |
//} | |
//// ! &L{r s} = λx.f | |
//// ---------------- DUP-LAM | |
//// r <- λx0.f0 | |
//// s <- λx1.f1 | |
//// x <- &L{x0,x1} | |
//// ! &L{f0,f1} = f | |
//Term reduce_dup_lam(Term dup, Term lam) { | |
////printf("reduce_dup_lam "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Loc lam_loc = term_loc(lam); | |
//Lab dup_lab = term_lab(dup); | |
//Term bod = got(lam_loc + 0); | |
//Loc loc = alloc_node(5); | |
//Loc lm0 = loc + 0; | |
//Loc lm1 = loc + 1; | |
//Loc su0 = loc + 2; | |
//Loc du0 = loc + 4; | |
//sub(lam_loc + 0, term_new(SUP, dup_lab, su0)); | |
//set(lm0 + 0, term_new(DP0, dup_lab, du0)); | |
//set(lm1 + 0, term_new(DP1, dup_lab, du0)); | |
//set(su0 + 0, term_new(VAR, 0, lm0)); | |
//set(su0 + 1, term_new(VAR, 0, lm1)); | |
//set(du0 + 0, bod); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(LAM, 0, lm1)); | |
//return term_new(LAM, 0, lm0); | |
//} else { | |
//sub(dup_loc + 0, term_new(LAM, 0, lm0)); | |
//return term_new(LAM, 0, lm1); | |
//} | |
//} | |
//// ! &L{x,y} = () | |
//// -------------- DUP-NIL | |
//// x <- () | |
//// y <- () | |
//Term reduce_dup_nil(Term dup, Term nil) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, nil); | |
//return nil; | |
//} | |
//// ! &L{x,y} = (a,b) | |
//// ----------------- DUP-TUP | |
//// ! &L{a0,a1} = a | |
//// ! &L{b0,b1} = b | |
//// x <- (a0,b0) | |
//// y <- (a1,b1) | |
//Term reduce_dup_tup(Term dup, Term tup) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc tup_loc = term_loc(tup); | |
//Term a = got(tup_loc + 0); | |
//Term b = got(tup_loc + 1); | |
//Loc loc = alloc_node(6); | |
//Loc tup0 = loc + 0; | |
//Loc tup1 = loc + 2; | |
//Loc dupa = loc + 4; | |
//Loc dupb = loc + 5; | |
//set(dupa + 0, a); | |
//set(dupb + 0, b); | |
//set(tup0 + 0, term_new(DP0, dup_lab, dupa)); | |
//set(tup0 + 1, term_new(DP0, dup_lab, dupb)); | |
//set(tup1 + 0, term_new(DP1, dup_lab, dupa)); | |
//set(tup1 + 1, term_new(DP1, dup_lab, dupb)); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(TUP, 0, tup1)); | |
//return term_new(TUP, 0, tup0); | |
//} else { | |
//sub(dup_loc + 0, term_new(TUP, 0, tup0)); | |
//return term_new(TUP, 0, tup1); | |
//} | |
//} | |
//// ! &L{x,y} = 123 | |
//// --------------- DUP-W32 | |
//// x <- 123 | |
//// y <- 123 | |
//Term reduce_dup_w32(Term dup, Term w32) { | |
////printf("reduce_dup_w32 "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, w32); | |
//return w32; | |
//} | |
//// ! &L{x,y} = Set | |
//// --------------- DUP-SET | |
//// x <- Set | |
//// y <- Set | |
//Term reduce_dup_set(Term dup, Term set) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, set); | |
//return set; | |
//} | |
//// ! &L{x,y} = ⊥ | |
//// ------------- DUP-EMP | |
//// x <- ⊥ | |
//// y <- ⊥ | |
//Term reduce_dup_emp(Term dup, Term emp) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, emp); | |
//return emp; | |
//} | |
//// ! &L{x,y} = ⊤ | |
//// ------------- DUP-UNI | |
//// x <- ⊤ | |
//// y <- ⊤ | |
//Term reduce_dup_uni(Term dup, Term uni) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, uni); | |
//return uni; | |
//} | |
//// ! &L{x,y} = U32 | |
//// -------------- DUP-U32 | |
//// x <- U32 | |
//// y <- U32 | |
//Term reduce_dup_u32(Term dup, Term u32) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//sub(dup_loc + 0, u32); | |
//return u32; | |
//} | |
//// ! &L{x,y} = ΣA.B | |
//// ----------------- DUP-SIG | |
//// ! &L{A0,A1} = A | |
//// ! &L{B0,B1} = B | |
//// x <- ΣA0.B0 | |
//// y <- ΣA1.B1 | |
//Term reduce_dup_sig(Term dup, Term sig) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc sig_loc = term_loc(sig); | |
//Term a = got(sig_loc + 0); | |
//Term b = got(sig_loc + 1); | |
//Loc loc = alloc_node(6); | |
//Loc sig0 = loc + 0; | |
//Loc sig1 = loc + 2; | |
//Loc dupa = loc + 4; | |
//Loc dupb = loc + 5; | |
//set(dupa + 0, a); | |
//set(dupb + 0, b); | |
//set(sig0 + 0, term_new(DP0, dup_lab, dupa)); | |
//set(sig0 + 1, term_new(DP0, dup_lab, dupb)); | |
//set(sig1 + 0, term_new(DP1, dup_lab, dupa)); | |
//set(sig1 + 1, term_new(DP1, dup_lab, dupb)); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(SIG, 0, sig1)); | |
//return term_new(SIG, 0, sig0); | |
//} else { | |
//sub(dup_loc + 0, term_new(SIG, 0, sig0)); | |
//return term_new(SIG, 0, sig1); | |
//} | |
//} | |
//// ! &L{x,y} = ∀A.B | |
//// ----------------- DUP-ALL | |
//// ! &L{A0,A1} = A | |
//// ! &L{B0,B1} = B | |
//// x <- ∀A0.B0 | |
//// y <- ∀A1.B1 | |
//Term reduce_dup_all(Term dup, Term all) { | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc all_loc = term_loc(all); | |
//Term a = got(all_loc + 0); | |
//Term b = got(all_loc + 1); | |
//Loc loc = alloc_node(6); | |
//Loc all0 = loc + 0; | |
//Loc all1 = loc + 2; | |
//Loc dupa = loc + 4; | |
//Loc dupb = loc + 5; | |
//set(dupa + 0, a); | |
//set(dupb + 0, b); | |
//set(all0 + 0, term_new(DP0, dup_lab, dupa)); | |
//set(all0 + 1, term_new(DP0, dup_lab, dupb)); | |
//set(all1 + 0, term_new(DP1, dup_lab, dupa)); | |
//set(all1 + 1, term_new(DP1, dup_lab, dupb)); | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(ALL, 0, all1)); | |
//return term_new(ALL, 0, all0); | |
//} else { | |
//sub(dup_loc + 0, term_new(ALL, 0, all0)); | |
//return term_new(ALL, 0, all1); | |
//} | |
//} | |
//// ! &L{x,y} = @foo(a b c ...) | |
//// --------------------------- DUP-REF-COPY (when &L not in @foo) | |
//// ! &L{a0,a1} = a | |
//// ! &L{b0,b1} = b | |
//// ! &L{c0,c1} = c | |
//// ... | |
//// x <- @foo(a0 b0 c0 ...) | |
//// y <- @foo(a1 b1 c1 ...) | |
//Term reduce_dup_ref(Term dup, Term ref) { | |
////printf("reduce_dup_ref "); print_term(dup); printf("\n"); | |
//inc_itr(); | |
//Loc dup_loc = term_loc(dup); | |
//Lab dup_lab = term_lab(dup); | |
//Loc ref_loc = term_loc(ref); | |
//Lab ref_lab = term_lab(ref); | |
//u64 ref_ari = HVM.fari[ref_lab]; | |
//Loc loc = alloc_node(ref_ari * 2); | |
//Loc ref0 = ref_loc; | |
//Loc ref1 = loc + 0; | |
//for (u64 i = 0; i < ref_ari; i++) { | |
//Loc du0 = loc + ref_ari + i; | |
//set(du0 + 0, got(ref_loc + i)); | |
//set(ref0 + i, term_new(DP0, dup_lab, du0)); | |
//set(ref1 + i, term_new(DP1, dup_lab, du0)); | |
//} | |
//if (term_tag(dup) == DP0) { | |
//sub(dup_loc + 0, term_new(REF, ref_lab, ref1)); | |
//return term_new(REF, ref_lab, ref0); | |
//} else { | |
//sub(dup_loc + 0, term_new(REF, ref_lab, ref0)); | |
//return term_new(REF, ref_lab, ref1); | |
//} | |
//} | |
//// (<op * y) | |
//// --------- OPX-ERA | |
//// * | |
//Term reduce_opx_era(Term opx, Term era) { | |
////printf("reduce_opx_era "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// (<op λx.f y) | |
//// ----------- OPX-LAM | |
//// error | |
//Term reduce_opx_lam(Term opx, Term lam) { | |
////printf("reduce_opx_lam "); print_term(opx); printf("\n"); | |
//printf("invalid:opx-lam"); | |
//exit(0); | |
//} | |
//// (<op &L{a,b} y) | |
//// ------------------------- OPX-SUP | |
//// ! &L{y0,y1} = y; | |
//// &L{(<op a y0),(<op b y1)} | |
//Term reduce_opx_sup(Term opx, Term sup) { | |
////printf("reduce_opx_sup "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//Loc opx_loc = term_loc(opx); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term nmy = got(opx_loc + 1); | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc loc = alloc_node(3); | |
//Loc op0 = opx_loc; | |
//Loc op1 = sup_loc; | |
//Loc su0 = loc + 0; | |
//Loc du0 = loc + 2; | |
//set(op0 + 0, tm0); | |
//set(op0 + 1, term_new(DP0, sup_lab, du0)); | |
//set(op1 + 0, tm1); | |
//set(op1 + 1, term_new(DP1, sup_lab, du0)); | |
//set(su0 + 0, term_new(OPX, term_lab(opx), op0)); | |
//set(su0 + 1, term_new(OPX, term_lab(opx), op1)); | |
//set(du0 + 0, nmy); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// (<op () y) | |
//// ---------- OPX-NIL | |
//// error | |
//Term reduce_opx_nil(Term opx, Term nil) { | |
//printf("invalid:opx-nil"); | |
//exit(0); | |
//} | |
//// (<op (x0,x1) y) | |
//// --------------- OPX-TUP | |
//// error | |
//Term reduce_opx_tup(Term opx, Term tup) { | |
//printf("invalid:opx-tup"); | |
//exit(0); | |
//} | |
//// (<op x y) | |
//// --------- OPX-W32 | |
//// (>op y x) | |
//Term reduce_opx_w32(Term opx, Term nmx) { | |
////printf("reduce_opx_w32 "); print_term(opx); printf("\n"); | |
//inc_itr(); | |
//Lab opx_lab = term_lab(opx); | |
//Loc opx_loc = term_loc(opx); | |
//Term nmy = got(opx_loc + 1); | |
//set(opx_loc + 0, nmy); | |
//set(opx_loc + 1, nmx); | |
//return term_new(OPY, opx_lab, opx_loc); | |
//} | |
//// (<op T y) | |
//// --------- OPX-TYP | |
//// error | |
//Term reduce_opx_typ(Term opx, Term typ) { | |
//printf("invalid:opx-typ"); | |
//exit(0); | |
//} | |
//// (>op x *) | |
//// --------- OPY-ERA | |
//// * | |
//Term reduce_opy_era(Term opy, Term era) { | |
////printf("reduce_opy_era "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//return era; | |
//} | |
//// (>op x λy.f) | |
//// ------------ OPY-LAM | |
//// error | |
//Term reduce_opy_lam(Term opy, Term lam) { | |
////printf("reduce_opy_lam "); print_term(opy); printf("\n"); | |
//printf("invalid:opy-lam"); | |
//exit(0); | |
//} | |
//// (>op x &L{y0,y1}) | |
//// ----------------------- OPY-SUP | |
//// &L{>op(x y0),>op(x y1)} | |
//Term reduce_opy_sup(Term opy, Term sup) { | |
////printf("reduce_opy_sup "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//Loc opy_loc = term_loc(opy); | |
//Loc sup_loc = term_loc(sup); | |
//Lab sup_lab = term_lab(sup); | |
//Term nmx = got(opy_loc + 1); | |
//Term tm0 = got(sup_loc + 0); | |
//Term tm1 = got(sup_loc + 1); | |
//Loc op0 = sup_loc; | |
//Loc op1 = opy_loc; | |
//Loc su0 = alloc_node(2); | |
//set(op0 + 1, nmx); | |
//set(op1 + 0, tm1); | |
//set(su0 + 0, term_new(OPY, term_lab(opy), op0)); | |
//set(su0 + 1, term_new(OPY, term_lab(opy), op1)); | |
//return term_new(SUP, sup_lab, su0); | |
//} | |
//// (>op x ()) | |
//// ---------- OPY-NIL | |
//// error | |
//Term reduce_opy_nil(Term opy, Term nil) { | |
//printf("invalid:opy-nil"); | |
//exit(0); | |
//} | |
//// (>op x (y0,y1)) | |
//// --------------- OPY-TUP | |
//// error | |
//Term reduce_opy_tup(Term opy, Term tup) { | |
//printf("invalid:opy-tup"); | |
//exit(0); | |
//} | |
//// (>op x y) | |
//// --------- OPY-W32 | |
//// x <op> y | |
//Term reduce_opy_w32(Term opy, Term val) { | |
////printf("reduce_opy_w32 "); print_term(opy); printf("\n"); | |
//inc_itr(); | |
//Loc opy_loc = term_loc(opy); | |
//Tag t = term_tag(val); | |
//u32 x = term_loc(got(opy_loc + 1)); | |
//u32 y = term_loc(val); | |
//printf("... %u %u\n", x, y); | |
//u32 result; | |
//switch (term_lab(opy)) { | |
//case OP_ADD: result = x + y; break; | |
//case OP_SUB: result = x - y; break; | |
//case OP_MUL: result = x * y; break; | |
//case OP_DIV: result = x / y; break; | |
//case OP_MOD: result = x % y; break; | |
//case OP_EQ: result = x == y; break; | |
//case OP_NE: result = x != y; break; | |
//case OP_LT: result = x < y; break; | |
//case OP_GT: result = x > y; break; | |
//case OP_LTE: result = x <= y; break; | |
//case OP_GTE: result = x >= y; break; | |
//case OP_AND: result = x & y; break; | |
//case OP_OR: result = x | y; break; | |
//case OP_XOR: result = x ^ y; break; | |
//case OP_LSH: result = x << y; break; | |
//case OP_RSH: result = x >> y; break; | |
//default: { | |
//printf("invalid:opy-w32"); | |
//exit(0); | |
//} | |
//} | |
//return term_new(W32, 0, result); | |
//} | |
//// (>op x T) | |
//// --------- OPY-TYP | |
//// error | |
//Term reduce_opy_typ(Term opy, Term typ) { | |
//printf("invalid:opy-typ"); | |
//exit(0); | |
//} | |
//Term reduce_ref_sup(Term ref, u16 idx) { | |
//inc_itr(); | |
//Loc ref_loc = term_loc(ref); | |
//Lab ref_lab = term_lab(ref); | |
//u16 fun_id = ref_lab; | |
//u16 arity = HVM.fari[fun_id]; | |
//if (idx >= arity) { | |
//printf("ERROR: Invalid index in reduce_ref_sup\n"); | |
//exit(1); | |
//} | |
//Term sup = got(ref_loc + idx); | |
//if (term_tag(sup) != SUP) { | |
//printf("ERROR: Expected SUP at index %u\n", idx); | |
//exit(1); | |
//} | |
//Lab sup_lab = term_lab(sup); | |
//Loc sup_loc = term_loc(sup); | |
//Term sup0 = got(sup_loc + 0); | |
//Term sup1 = got(sup_loc + 1); | |
//// Allocate space for new REF node arguments for the second branch | |
//Loc ref1_loc = alloc_node(arity); | |
//for (u64 i = 0; i < arity; ++i) { | |
//if (i != idx) { | |
//// Duplicate argument | |
//Term arg = got(ref_loc + i); | |
//Loc dup_loc = alloc_node(1); | |
//set(dup_loc + 0, arg); | |
//set(ref_loc + i, term_new(DP0, sup_lab, dup_loc)); | |
//set(ref1_loc + i, term_new(DP1, sup_lab, dup_loc)); | |
//} else { | |
//// Set the SUP components directly | |
//set(ref_loc + i, sup0); | |
//set(ref1_loc + i, sup1); | |
//} | |
//} | |
//// Create new REF nodes | |
//Term ref0 = term_new(REF, ref_lab, ref_loc); | |
//Term ref1 = term_new(REF, ref_lab, ref1_loc); | |
//// Reuse sup_loc to create the new SUP node | |
//set(sup_loc + 0, ref0); | |
//set(sup_loc + 1, ref1); | |
//return term_new(SUP, sup_lab, sup_loc); | |
//} | |
//Term reduce(Term term) { | |
//if (term_tag(term) >= ERA) return term; | |
//Term next = term; | |
//u64 stop = *HVM.spos; | |
//u64 spos = stop; | |
//Term* sbuf = HVM.sbuf; | |
//while (1) { | |
////printf("NEXT "); print_term(term); printf("\n"); | |
////printf("PATH "); | |
////for (u64 i = 0; i < *spos; ++i) { | |
////print_tag(term_tag(HVM.sbuf[i])); | |
////printf(" "); | |
////} | |
////printf(" ~ %p", HVM.sbuf); | |
////printf("\n"); | |
//Tag tag = term_tag(next); | |
//Lab lab = term_lab(next); | |
//Loc loc = term_loc(next); | |
//// On variables: substitute | |
//// On eliminators: move to field | |
//switch (tag) { | |
//case LET: { | |
//switch (lab) { | |
//case LAZY: { | |
//next = reduce_let(next, got(loc + 0)); | |
//continue; | |
//} | |
//case STRI: { | |
//spush(next, sbuf, &spos); | |
//next = got(loc + 0); | |
//continue; | |
//} | |
//default: { | |
//printf("invalid:let"); | |
//exit(0); | |
//} | |
//} | |
//} | |
//case APP: | |
//case USE: | |
//case GET: | |
//case SWI: | |
//case OPX: | |
//case OPY: { | |
//spush(next, sbuf, &spos); | |
//next = got(loc + 0); | |
//continue; | |
//} | |
//case DP0: | |
//case DP1: { | |
//Term sub = got(loc + 0); | |
//if (term_get_bit(sub) == 0) { | |
//spush(next, sbuf, &spos); | |
//next = sub; | |
//continue; | |
//} else { | |
//next = term_rem_bit(sub); | |
//continue; | |
//} | |
//} | |
//case VAR: { | |
//Term sub = got(loc); | |
//if (term_get_bit(sub) == 0) { | |
//break; | |
//} else { | |
//next = term_rem_bit(sub); | |
//continue; | |
//} | |
//} | |
//case REF: { | |
//*HVM.spos = spos; | |
//next = reduce_ref(next); | |
//spos = *HVM.spos; | |
//continue; | |
//} | |
//default: break; | |
//} | |
//// Empty stack: term is in WHNF | |
//if (spos == stop) { | |
//*HVM.spos = spos; | |
//return next; | |
//} | |
//// Interaction Dispatcher | |
//Term prev = spop(sbuf, &spos); | |
//Tag ptag = term_tag(prev); | |
//Lab plab = term_lab(prev); | |
//Loc ploc = term_loc(prev); | |
//switch (ptag) { | |
//case LET: { | |
//next = reduce_let(prev, next); | |
//continue; | |
//} | |
//case APP: { | |
//switch (tag) { | |
//case ERA: next = reduce_app_era(prev, next); continue; | |
//case LAM: next = reduce_app_lam(prev, next); continue; | |
//case SUP: next = reduce_app_sup(prev, next); continue; | |
//case NIL: next = reduce_app_nil(prev, next); continue; | |
//case TUP: next = reduce_app_tup(prev, next); continue; | |
//case W32: next = reduce_app_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_app_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case USE: { | |
//switch (tag) { | |
//case ERA: next = reduce_use_era(prev, next); continue; | |
//case SUP: next = reduce_use_sup(prev, next); continue; | |
//case LAM: next = reduce_use_lam(prev, next); continue; | |
//case NIL: next = reduce_use_nil(prev, next); continue; | |
//case TUP: next = reduce_use_tup(prev, next); continue; | |
//case W32: next = reduce_use_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_use_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case GET: { | |
//switch (tag) { | |
//case ERA: next = reduce_get_era(prev, next); continue; | |
//case SUP: next = reduce_get_sup(prev, next); continue; | |
//case NIL: next = reduce_get_nil(prev, next); continue; | |
//case TUP: next = reduce_get_tup(prev, next); continue; | |
//case LAM: next = reduce_get_lam(prev, next); continue; | |
//case W32: next = reduce_get_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_get_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case SWI: { | |
//switch (tag) { | |
//case ERA: next = reduce_swi_era(prev, next); continue; | |
//case SUP: next = reduce_swi_sup(prev, next); continue; | |
//case NIL: next = reduce_swi_nil(prev, next); continue; | |
//case TUP: next = reduce_swi_tup(prev, next); continue; | |
//case LAM: next = reduce_swi_lam(prev, next); continue; | |
//case W32: next = reduce_swi_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_swi_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case DP0: | |
//case DP1: { | |
//switch (tag) { | |
//case ERA: next = reduce_dup_era(prev, next); continue; | |
//case SUP: next = reduce_dup_sup(prev, next); continue; | |
//case LAM: next = reduce_dup_lam(prev, next); continue; | |
//case NIL: next = reduce_dup_nil(prev, next); continue; | |
//case TUP: next = reduce_dup_tup(prev, next); continue; | |
//case W32: next = reduce_dup_w32(prev, next); continue; | |
//case SET: next = reduce_dup_set(prev, next); continue; | |
//case EMP: next = reduce_dup_emp(prev, next); continue; | |
//case UNI: next = reduce_dup_uni(prev, next); continue; | |
//case U32: next = reduce_dup_u32(prev, next); continue; | |
//case SIG: next = reduce_dup_sig(prev, next); continue; | |
//case ALL: next = reduce_dup_all(prev, next); continue; | |
//case REF: next = reduce_dup_ref(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case OPX: { | |
//switch (tag) { | |
//case ERA: next = reduce_opx_era(prev, next); continue; | |
//case LAM: next = reduce_opx_lam(prev, next); continue; | |
//case SUP: next = reduce_opx_sup(prev, next); continue; | |
//case NIL: next = reduce_opx_nil(prev, next); continue; | |
//case TUP: next = reduce_opx_tup(prev, next); continue; | |
//case W32: next = reduce_opx_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_opx_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//case OPY: { | |
//switch (tag) { | |
//case ERA: next = reduce_opy_era(prev, next); continue; | |
//case LAM: next = reduce_opy_lam(prev, next); continue; | |
//case SUP: next = reduce_opy_sup(prev, next); continue; | |
//case NIL: next = reduce_opy_nil(prev, next); continue; | |
//case TUP: next = reduce_opy_tup(prev, next); continue; | |
//case W32: next = reduce_opy_w32(prev, next); continue; | |
//case SET: | |
//case EMP: | |
//case UNI: | |
//case U32: | |
//case SIG: | |
//case ALL: next = reduce_opy_typ(prev, next); continue; | |
//default: break; | |
//} | |
//} | |
//default: break; | |
//} | |
//// No interaction: push term back to stack | |
//spush(prev, sbuf, &spos); | |
//// Update parent chain | |
//while (spos > stop) { | |
//Term host = spop(sbuf, &spos); | |
//Tag htag = term_tag(host); | |
//Lab hlab = term_lab(host); | |
//Loc hloc = term_loc(host); | |
//set(hloc + 0, next); | |
//next = host; | |
//} | |
//*HVM.spos = spos; | |
//return next; | |
//} | |
//} | |
//Term reduce_at(Loc host) { | |
//Term tm0 = got(host); | |
//if (term_tag(tm0) >= ERA) { | |
//return tm0; | |
//} | |
//Term tm1 = reduce(tm0); | |
//set(host, tm1); | |
//return tm1; | |
//} | |
//Term normal(Term term) { | |
//Term wnf = reduce(term); | |
//Tag tag = term_tag(wnf); | |
//Lab lab = term_lab(wnf); | |
//Loc loc = term_loc(wnf); | |
//switch (tag) { | |
//case LAM: { | |
//Term bod = got(loc + 0); | |
//bod = normal(bod); | |
//set(loc + 0, bod); | |
//return wnf; | |
//} | |
//case APP: { | |
//Term fun = got(loc + 0); | |
//Term arg = got(loc + 1); | |
//fun = normal(fun); | |
//arg = normal(arg); | |
//set(loc + 0, fun); | |
//set(loc + 1, arg); | |
//return wnf; | |
//} | |
//case SUP: { | |
//Term tm0 = got(loc + 0); | |
//Term tm1 = got(loc + 1); | |
//tm0 = normal(tm0); | |
//tm1 = normal(tm1); | |
//set(loc + 0, tm0); | |
//set(loc + 1, tm1); | |
//return wnf; | |
//} | |
//case TUP: { | |
//Term tm0 = got(loc + 0); | |
//Term tm1 = got(loc + 1); | |
//tm0 = normal(tm0); | |
//tm1 = normal(tm1); | |
//set(loc + 0, tm0); | |
//set(loc + 1, tm1); | |
//return wnf; | |
//} | |
//case SIG: { | |
//Term tm0 = got(loc + 0); | |
//Term tm1 = got(loc + 1); | |
//tm0 = normal(tm0); | |
//tm1 = normal(tm1); | |
//set(loc + 0, tm0); | |
//set(loc + 1, tm1); | |
//return wnf; | |
//} | |
//case ALL: { | |
//Term tm0 = got(loc + 0); | |
//Term tm1 = got(loc + 1); | |
//tm0 = normal(tm0); | |
//tm1 = normal(tm1); | |
//set(loc + 0, tm0); | |
//set(loc + 1, tm1); | |
//return wnf; | |
//} | |
//case DP0: | |
//case DP1: { | |
//Term val = got(loc + 0); | |
//val = normal(val); | |
//set(loc + 0, val); | |
//return wnf; | |
//} | |
//case USE: | |
//case GET: | |
//case SWI: { | |
//for (u64 i = 0; i <= 2; i++) { | |
//Term arg = got(loc + i); | |
//arg = normal(arg); | |
//set(loc + i, arg); | |
//} | |
//return wnf; | |
//} | |
//default: | |
//return wnf; | |
//} | |
//} | |
//// Primitives | |
//// ---------- | |
//// Primitive: Dynamic Sup @SUP(lab tm0 tm1) | |
//// Allocates a new SUP node with given label. | |
//Term SUP_f(Term ref) { | |
//Loc ref_loc = term_loc(ref); | |
//Term lab = reduce(got(ref_loc + 0)); | |
//Term lab_val = term_loc(lab); | |
//if (term_tag(lab) != W32) { | |
//printf("ERROR:non-numeric-sup-label\n"); | |
//} | |
//if (lab_val > 0xFFFF) { | |
//printf("ERROR:sup-label-too-large\n"); | |
//} | |
//Term tm0 = got(ref_loc + 1); | |
//Term tm1 = got(ref_loc + 2); | |
//Loc sup = alloc_node(2); | |
//Term ret = term_new(SUP, lab_val, sup); | |
//set(sup + 0, tm0); | |
//set(sup + 1, tm1); | |
//*HVM.itrs += 1; | |
//return ret; | |
//} | |
//// Primitive: Dynamic Dup @DUP(lab val λdp0λdp1(bod)) | |
//// Creates a DUP node with given label. | |
//Term DUP_f(Term ref) { | |
//Loc ref_loc = term_loc(ref); | |
//Term lab = reduce(got(ref_loc + 0)); | |
//Term lab_val = term_loc(lab); | |
//if (term_tag(lab) != W32) { | |
//printf("ERROR:non-numeric-dup-label\n"); | |
//} | |
//if (lab_val > 0xFFFF) { | |
//printf("ERROR:dup-label-too-large\n"); | |
//} | |
//Term val = got(ref_loc + 1); | |
//Term bod = got(ref_loc + 2); | |
//Loc dup = alloc_node(1); | |
//set(dup + 0, val); | |
//if (term_tag(bod) == LAM) { | |
//Loc lam0 = term_loc(bod); | |
//Term bod0 = got(lam0 + 0); | |
//if (term_tag(bod0) == LAM) { | |
//Loc lam1 = term_loc(bod0); | |
//Term bod1 = got(lam1 + 0); | |
//sub(lam0 + 0, term_new(DP0, lab_val, dup)); | |
//sub(lam1 + 0, term_new(DP1, lab_val, dup)); | |
//*HVM.itrs += 3; | |
//return bod1; | |
//} | |
//} | |
//Loc app0 = alloc_node(2); | |
//set(app0 + 0, bod); | |
//set(app0 + 1, term_new(DP0, lab_val, dup)); | |
//Loc app1 = alloc_node(2); | |
//set(app1 + 0, term_new(APP, 0, app0)); | |
//set(app1 + 1, term_new(DP1, lab_val, dup)); | |
//*HVM.itrs += 1; | |
//return term_new(APP, 0, app1); | |
//} | |
//Term LOG_f(Term ref) { | |
//printf("TODO: LOG_f"); | |
//exit(0); | |
//} | |
//void *alloc_huge(size_t size) { | |
//void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, | |
//MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, | |
//-1, 0); | |
//if (ptr == MAP_FAILED) { | |
//perror("mmap failed"); | |
//return NULL; | |
//} | |
//return ptr; | |
//} | |
//// Runtime Memory | |
//// -------------- | |
//void hvm_init() { | |
//HVM.sbuf = alloc_huge(MAX_STACK_SIZE * sizeof(Term)); | |
//HVM.heap = alloc_huge(MAX_HEAP_SIZE * sizeof(Term)); | |
//HVM.spos = alloc_huge(sizeof(u64)); | |
//HVM.size = alloc_huge(sizeof(u64)); | |
//HVM.itrs = alloc_huge(sizeof(u64)); | |
//HVM.frsh = alloc_huge(sizeof(u64)); | |
//#define CHECK_ALLOC(ptr, name) if (!(ptr)) { printf(name " alloc failed\n"); allocs_failed++; } | |
//int allocs_failed = 0; // Track if any allocation failed | |
//CHECK_ALLOC(HVM.sbuf, "sbuf"); | |
//CHECK_ALLOC(HVM.heap, "heap"); | |
//CHECK_ALLOC(HVM.spos, "spos"); | |
//CHECK_ALLOC(HVM.size, "size"); | |
//CHECK_ALLOC(HVM.itrs, "itrs"); | |
//CHECK_ALLOC(HVM.frsh, "frsh"); | |
//if (allocs_failed > 0) { | |
//printf("hvm_init alloc's failed: %d allocations failed\n", allocs_failed); | |
//exit(1); | |
//} | |
//#undef CHECK_ALLOC | |
//*HVM.spos = 0; | |
//*HVM.size = 1; | |
//*HVM.itrs = 0; | |
//*HVM.frsh = 0x20; | |
//HVM.book[SUP_F] = SUP_f; | |
//HVM.book[DUP_F] = DUP_f; | |
//HVM.book[LOG_F] = LOG_f; | |
//for (int i = 0; i < 65536; i++) { | |
//HVM.fari[i] = 0; | |
//} | |
//} | |
//void hvm_munmap(void *ptr, size_t size, const char *name) { | |
//if (ptr != MAP_FAILED) { | |
//if (munmap(ptr, size) == -1) { | |
//perror("munmap failed"); | |
//} else { | |
//// printf("Successfully unmapped %s\n", name); | |
//} | |
//} else { | |
//printf("%s is already null or invalid.\n", name); | |
//} | |
//} | |
//void hvm_free() { | |
//hvm_munmap(HVM.sbuf, MAX_STACK_SIZE * sizeof(Term), "sbuf"); | |
//hvm_munmap(HVM.heap, MAX_HEAP_SIZE * sizeof(Term), "heap"); | |
//hvm_munmap(HVM.spos, sizeof(u64), "spos"); | |
//hvm_munmap(HVM.size, sizeof(u64), "size"); | |
//hvm_munmap(HVM.itrs, sizeof(u64), "itrs"); | |
//hvm_munmap(HVM.frsh, sizeof(u64), "frsh"); | |
//} | |
//State* hvm_get_state() { | |
//return &HVM; | |
//} | |
//void hvm_set_state(State* hvm) { | |
//HVM.sbuf = hvm->sbuf; | |
//HVM.spos = hvm->spos; | |
//HVM.heap = hvm->heap; | |
//HVM.size = hvm->size; | |
//HVM.itrs = hvm->itrs; | |
//HVM.frsh = hvm->frsh; | |
//for (int i = 0; i < 65536; i++) { | |
//HVM.book[i] = hvm->book[i]; | |
//HVM.fari[i] = hvm->fari[i]; | |
//} | |
//} | |
//void hvm_define(u16 fid, Term (*func)()) { | |
////printf("defined %llu %p\n", fid, func); | |
//HVM.book[fid] = func; | |
//} | |
//void hvm_set_fari(u16 fid, u16 arity) { | |
//HVM.fari[fid] = arity; | |
//} | |
// NOTE: I'm not actually sure if the original reduce_mat_sup function reused | |
// nodes in the same way that the new one is reusing. can you please compare | |
// them, and let us know if it is indeed following the same structure? | |
// then, you review the rest of the file, and check if the remaining functions | |
// are reusing nodes correctly. pay extra attention to the reduce_use_sup and | |
// reduce_get_sup functions. remember that they must reuse the old SUP for the | |
// new SUP, and the old matcher for the new matcher. write your report below: | |
// A: Reviewing the node reuse patterns: | |
//* **reduce_swi_sup:** As confirmed previously, this function correctly reuses swi_loc for the first resulting SWI node and sup_loc for the resulting SUP node. Only the second SWI node and the DUP helpers are allocated. **Correct.** | |
//* **reduce_use_sup:** | |
//* Reuses sup_loc for the first resulting USE node (us0). **Incorrect.** Should reuse use_loc. | |
//* Reuses use_loc for the resulting SUP node (su0). **Incorrect.** Should reuse sup_loc. | |
//* Allocates the second USE node (us1) and the DUP helper (dup). | |
//* **Conclusion:** This function swaps the intended reuse roles. | |
//* **reduce_get_sup:** | |
//* Reuses sup_loc for the first resulting GET node (gt0). **Incorrect.** Should reuse get_loc. | |
//* Reuses get_loc for the resulting SUP node (su0). **Incorrect.** Should reuse sup_loc. | |
//* Allocates the second GET node (gt1) and the DUP helper (dup). | |
//* **Conclusion:** This function swaps the intended reuse roles, similar to reduce_use_sup. | |
//* **Other reduce_..._sup functions:** | |
//* reduce_app_sup: Swaps reuse roles like reduce_use_sup. **Incorrect.** | |
//* reduce_opx_sup: Reuses opx_loc correctly for op0, but allocates the resulting SUP (su0) instead of reusing sup_loc. **Incorrect.** | |
//* reduce_opy_sup: Reuses sup_loc correctly for op0, but allocates the resulting SUP (su0) instead of reusing opy_loc for op1. **Incorrect.** | |
//* **reduce_dup_... functions (duplicating values):** | |
//* reduce_dup_tup, reduce_dup_sig, reduce_dup_all: These allocate *both* resulting value nodes (tup0/tup1, etc.) instead of reusing the original value node's location (tup_loc, etc.) for one of them. **Incorrect.** | |
//* reduce_dup_ref: Correctly reuses ref_loc for ref0. **Correct.** | |
//* reduce_dup_sup (commute case): Allocates *both* resulting SUP nodes (su0, su1) instead of reusing sup_loc for one. **Incorrect.** | |
//**Summary:** The reuse pattern described (reusing the original eliminator for one branch and the original introducer for the wrapper) is correctly implemented in reduce_swi_sup and partially in reduce_dup_ref (for the REF part). However, reduce_use_sup, reduce_get_sup, reduce_app_sup, reduce_opx_sup, reduce_opy_sup, reduce_dup_tup, reduce_dup_sig, reduce_dup_all, and reduce_dup_sup (commute) do not follow this pattern correctly and require revision for consistent memory optimization. | |
//Interesting. Now, please review it again; this time, report any bug or inconsistency you find on the new version, w.r.t old version. Assume that the old version is 100% correct, but outdated (since it uses the old Core type). Your goal is to make sure that the new Runtime.c is equivalent to the old Runtime.c, if it were written with the new Core type in mind. remember that the ORIGINAL SEMANTICS must be preserved. for example, if in the original code, a given function only reused one node - so should be the case, in the new Runtime.c. you must also look for other kinds of errors, bugs, typos, and similar update issues. double check everything you list below to make sure you only report things that are actually incorrect. | |
//Write your complete report below, in ENGLISH: | |
//**REPORT:** | |
//This report focuses *only* on discrepancies, regressions, and new bugs introduced in the updated Runtime.c compared to the semantics and structure of the original (commented-out) C code, assuming the original was the correct reference for its time. | |
//1. **Node Reuse Inconsistencies (Relative to Original Patterns):** | |
//* reduce_use_sup: This function handles a new eliminator (USE). Its reuse pattern (reusing sup_loc for the USE branch and use_loc for the result SUP) is inconsistent with the established pattern seen in the original reduce_mat_sup (which USE conceptually replaces in part). It should reuse use_loc for the USE branch and sup_loc for the result SUP. **Inconsistent Update.** | |
//* reduce_get_sup: Similar to reduce_use_sup, this handles a new eliminator (GET). Its reuse pattern (reusing sup_loc for the GET branch and get_loc for the result SUP) is also inconsistent with the original reduce_mat_sup pattern. It should reuse get_loc for the GET branch and sup_loc for the result SUP. **Inconsistent Update.** | |
//* reduce_dup_tup: This replaces the old reduce_dup_ctr. The original reduce_dup_ctr reused the input ctr_loc for one of the output CTR nodes. The new reduce_dup_tup allocates *both* output TUP nodes. This fails to preserve the original memory optimization strategy. It should reuse tup_loc for one of the branches. **Inconsistent Update/Regression.** | |
//* reduce_dup_sig: New type interaction. Following the pattern of the original reduce_dup_ctr, it should reuse sig_loc for one output SIG node, but it allocates both. **Inconsistent Update.** | |
//* reduce_dup_all: New type interaction. Following the pattern of the original reduce_dup_ctr, it should reuse all_loc for one output ALL node, but it allocates both. **Inconsistent Update.** | |
//* *Note:* Other functions like reduce_app_sup, reduce_swi_sup, reduce_opx_sup, reduce_opy_sup, reduce_dup_sup (commute), and reduce_dup_ref appear to maintain reuse patterns consistent with their original counterparts or established patterns. | |
//2. **Missing Functionality (Relative to Original Implementation):** | |
//* reduce_ref_sup: The original C code included an implementation for reduce_ref_sup (handling @foo(&L{...} ...)). This function is entirely missing in the updated code, representing a loss of functionality compared to the original implementation. **Regression.** | |
//3. **New Bugs Introduced:** | |
//* normal Function: The normalization logic for USE and GET uses a loop for (u64 i = 0; i <= 2; i++). Since USE and GET nodes only have fields at indices 0 and 1, accessing index 2 (got(loc + 2)) is an out-of-bounds error. The condition should be i <= 1. This bug was not present in the original normal function's handling of MAT/IFL. **New Bug.** | |
//4. **New Artifacts:** | |
//* reduce_opy_w32: Contains a printf statement (printf("... %u %u\n", x, y);) likely used for debugging, which was presumably not in the original reference code. **New Artifact.** | |
//**Summary:** The primary issues introduced during the update are inconsistencies in applying the original node reuse optimization strategy to new and replacement interaction rules (USE-SUP, GET-SUP, DUP-TUP, DUP-SIG, DUP-ALL), the complete omission of the previously implemented reduce_ref_sup function, a new out-of-bounds bug in the normal function, and a leftover debug print. Other aspects, including tag definitions, state management, and most interaction logic, appear correctly adapted from the original. | |
//TASK: rewrite Runtime.c again, taking in account the issues presented in the report: | |
#include <inttypes.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#include <time.h> | |
#include <stdbool.h> | |
#define MAX_HEAP_SIZE (1ULL << 32) | |
#define MAX_STACK_SIZE (1ULL << 28) | |
typedef uint8_t Tag; | |
typedef uint32_t Lab; | |
typedef uint32_t Loc; | |
typedef uint64_t Term; | |
typedef uint16_t u16; | |
typedef uint32_t u32; | |
typedef uint64_t u64; | |
// Runtime Types | |
// ------------- | |
typedef struct { | |
Term* sbuf; // reduction stack buffer | |
u64* spos; // reduction stack position | |
Term* heap; // global node buffer | |
u64* size; // global node buffer position | |
u64* itrs; // interaction count | |
u64* frsh; // fresh dup label count | |
Term (*book[65536])(Term); // functions | |
u16 fari[65536]; // arity of each function | |
} State; | |
static State HVM = { | |
.sbuf = NULL, | |
.spos = NULL, | |
.heap = NULL, | |
.size = NULL, | |
.itrs = NULL, | |
.frsh = NULL, | |
.book = {NULL}, | |
.fari = {0}, | |
}; | |
// Constants | |
// --------- | |
#define DP0 0x00 | |
#define DP1 0x01 | |
#define VAR 0x02 | |
#define REF 0x03 | |
#define LET 0x04 | |
#define ERA 0x05 | |
#define SUP 0x06 | |
#define DUP 0x07 | |
#define SET 0x08 | |
#define EMP 0x09 | |
#define EFQ 0x0A | |
#define UNI 0x0B | |
#define NIL 0x0C | |
#define USE 0x0D | |
#define U32 0x0E | |
#define W32 0x0F | |
#define SWI 0x10 | |
#define OPX 0x11 | |
#define OPY 0x12 | |
#define SIG 0x13 | |
#define TUP 0x14 | |
#define GET 0x15 | |
#define ALL 0x16 | |
#define LAM 0x17 | |
#define APP 0x18 | |
#define ANN 0x19 | |
#define OP_ADD 0x00 | |
#define OP_SUB 0x01 | |
#define OP_MUL 0x02 | |
#define OP_DIV 0x03 | |
#define OP_MOD 0x04 | |
#define OP_EQ 0x05 | |
#define OP_NE 0x06 | |
#define OP_LT 0x07 | |
#define OP_GT 0x08 | |
#define OP_LTE 0x09 | |
#define OP_GTE 0x0A | |
#define OP_AND 0x0B | |
#define OP_OR 0x0C | |
#define OP_XOR 0x0D | |
#define OP_LSH 0x0E | |
#define OP_RSH 0x0F | |
#define DUP_F 0xFFFF | |
#define SUP_F 0xFFFE | |
#define LOG_F 0xFFFD | |
#define LAZY 0x0 | |
#define STRI 0x1 | |
#define VOID 0x00000000000000 | |
// Heap | |
// ---- | |
void set_len(u64 size) { | |
*HVM.size = size; | |
} | |
void set_itr(u64 itrs) { | |
*HVM.itrs = itrs; | |
} | |
u64 get_len() { | |
return *HVM.size; | |
} | |
u64 get_itr() { | |
return *HVM.itrs; | |
} | |
u64 fresh() { | |
return (*HVM.frsh)++; | |
} | |
// Terms | |
// ------ | |
Term term_new(Tag tag, Lab lab, Loc loc) { | |
Term tag_enc = tag; | |
Term lab_enc = ((Term)lab) << 8; | |
Term loc_enc = ((Term)loc) << 32; | |
return tag_enc | lab_enc | loc_enc; | |
} | |
Tag term_tag(Term x) { | |
return x & 0x7F; | |
} | |
Lab term_lab(Term x) { | |
return (x >> 8) & 0xFFFFFF; | |
} | |
Loc term_loc(Term x) { | |
return (x >> 32) & 0xFFFFFFFF; | |
} | |
u64 term_get_bit(Term x) { | |
return (x >> 7) & 1; | |
} | |
Term term_set_bit(Term term) { | |
return term | (1ULL << 7); | |
} | |
Term term_rem_bit(Term term) { | |
return term & ~(1ULL << 7); | |
} | |
Term term_set_loc(Term x, Loc loc) { | |
return (x & 0x00000000FFFFFFFF) | (((Term)loc) << 32); | |
} | |
_Bool term_is_atom(Term term) { | |
switch (term_tag(term)) { | |
case ERA: | |
case W32: | |
case NIL: | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: return 1; | |
default: return 0; | |
} | |
} | |
_Bool term_is_whnf(Term term) { | |
switch (term_tag(term)) { | |
case ERA: | |
case SUP: | |
case SET: | |
case EMP: | |
case UNI: | |
case NIL: | |
case U32: | |
case W32: | |
case TUP: | |
case LAM: | |
return 1; | |
default: | |
return 0; | |
} | |
} | |
// Atomics | |
// ------- | |
Term swap(Loc loc, Term term) { | |
Term val = HVM.heap[loc]; | |
HVM.heap[loc] = term; | |
if (val == 0) { | |
printf("SWAP 0 at %08llx\n", (u64)loc); | |
exit(0); | |
} | |
return val; | |
} | |
Term got(Loc loc) { | |
Term val = HVM.heap[loc]; | |
if (val == 0) { | |
printf("GOT 0 at %08llx\n", (u64)loc); | |
exit(0); | |
} | |
return val; | |
} | |
void set(Loc loc, Term term) { | |
HVM.heap[loc] = term; | |
} | |
void sub(Loc loc, Term term) { | |
set(loc, term_set_bit(term)); | |
} | |
Term take(Loc loc) { | |
return swap(loc, VOID); | |
} | |
// Allocation | |
// ---------- | |
Loc alloc_node(Loc arity) { | |
if (*HVM.size + arity > MAX_HEAP_SIZE) { | |
printf("Heap memory limit exceeded\n"); | |
exit(1); | |
} | |
u64 old = *HVM.size; | |
*HVM.size += arity; | |
return old; | |
} | |
void inc_itr() { | |
(*HVM.itrs)++; | |
} | |
// Stack | |
// ---- | |
void spush(Term term, Term* sbuf, u64* spos) { | |
if (*spos >= MAX_STACK_SIZE) { | |
printf("Stack memory limit exceeded\n"); | |
exit(1); | |
} | |
sbuf[(*spos)++] = term; | |
} | |
Term spop(Term* sbuf, u64* spos) { | |
return sbuf[--(*spos)]; | |
} | |
// Stringification | |
// --------------- | |
void print_tag(Tag tag) { | |
switch (tag) { | |
case VAR: printf("VAR"); break; | |
case DP0: printf("DP0"); break; | |
case DP1: printf("DP1"); break; | |
case REF: printf("REF"); break; | |
case LET: printf("LET"); break; | |
case ERA: printf("ERA"); break; | |
case SUP: printf("SUP"); break; | |
case DUP: printf("DUP"); break; | |
case SET: printf("SET"); break; | |
case EMP: printf("EMP"); break; | |
case EFQ: printf("EFQ"); break; | |
case UNI: printf("UNI"); break; | |
case NIL: printf("NIL"); break; | |
case USE: printf("USE"); break; | |
case U32: printf("U32"); break; | |
case W32: printf("W32"); break; | |
case SWI: printf("SWI"); break; | |
case OPX: printf("OPX"); break; | |
case OPY: printf("OPY"); break; | |
case SIG: printf("SIG"); break; | |
case TUP: printf("TUP"); break; | |
case GET: printf("GET"); break; | |
case ALL: printf("ALL"); break; | |
case LAM: printf("LAM"); break; | |
case APP: printf("APP"); break; | |
case ANN: printf("ANN"); break; | |
default : printf("???"); break; | |
} | |
} | |
void print_term(Term term) { | |
printf("term_new("); | |
print_tag(term_tag(term)); | |
printf(",0x%06llx,0x%08llx)", (u64)term_lab(term), (u64)term_loc(term)); | |
} | |
void print_heap() { | |
for (Loc i = 0; i < *HVM.size; i++) { | |
Term term = got(i); | |
if (term != 0) { | |
printf("set(0x%08llx, ", (u64)i); | |
print_term(term); | |
printf(");\n"); | |
} | |
} | |
} | |
// Evaluation | |
// ---------- | |
// @foo(&L{ax ay} b c ...) | |
// ----------------------- REF-SUP-COPY (when @L not in @foo) | |
// ! &L{bx by} = b | |
// ! &L{cx cy} = b | |
// ... | |
// &L{@foo(ax bx cx ...) @foo(ay by cy ...)} | |
Term reduce_ref_sup(Term ref, u16 idx) { | |
inc_itr(); | |
Loc ref_loc = term_loc(ref); | |
Lab ref_lab = term_lab(ref); | |
u16 fun_id = ref_lab; | |
u16 arity = HVM.fari[fun_id]; | |
if (idx >= arity) { | |
printf("ERROR: Invalid index in reduce_ref_sup\n"); | |
exit(1); | |
} | |
Term sup = got(ref_loc + idx); | |
if (term_tag(sup) != SUP) { | |
printf("ERROR: Expected SUP at index %u\n", idx); | |
exit(1); | |
} | |
Lab sup_lab = term_lab(sup); | |
Loc sup_loc = term_loc(sup); | |
Term sup0 = got(sup_loc + 0); | |
Term sup1 = got(sup_loc + 1); | |
// Allocate space for new REF node arguments for the second branch | |
Loc ref1_loc = alloc_node(arity); | |
for (u64 i = 0; i < arity; ++i) { | |
if (i != idx) { | |
// Duplicate argument | |
Term arg = got(ref_loc + i); | |
Loc dup_loc = alloc_node(1); | |
set(dup_loc + 0, arg); | |
set(ref_loc + i, term_new(DP0, sup_lab, dup_loc)); | |
set(ref1_loc + i, term_new(DP1, sup_lab, dup_loc)); | |
} else { | |
// Set the SUP components directly | |
set(ref_loc + i, sup0); | |
set(ref1_loc + i, sup1); | |
} | |
} | |
// Create new REF nodes | |
Term ref0 = term_new(REF, ref_lab, ref_loc); | |
Term ref1 = term_new(REF, ref_lab, ref1_loc); | |
// Reuse sup_loc to create the new SUP node | |
set(sup_loc + 0, ref0); | |
set(sup_loc + 1, ref1); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// @foo(a b c ...) | |
// -------------------- REF | |
// book[foo](a b c ...) | |
Term reduce_ref(Term ref) { | |
inc_itr(); | |
return HVM.book[term_lab(ref)](ref); | |
} | |
// ! x = val | |
// bod | |
// --------- LET | |
// x <- val | |
// bod | |
Term reduce_let(Term let, Term val) { | |
//printf("reduce_let "); print_term(let); printf("\n"); | |
inc_itr(); | |
Loc let_loc = term_loc(let); | |
Term bod = got(let_loc + 1); | |
sub(let_loc + 0, val); | |
return bod; | |
} | |
// TODO: reduce_ann | |
// <x:T> v | |
// ------ ANN | |
// v | |
Term reduce_ann(Term ann, Term val) { | |
inc_itr(); | |
return val; | |
} | |
// (* a) | |
// ------- APP-ERA | |
// * | |
Term reduce_app_era(Term app, Term era) { | |
//printf("reduce_app_era "); print_term(app); printf("\n"); | |
inc_itr(); | |
return era; | |
} | |
// (λx.f a) | |
// -------- APP-LAM | |
// x <- a | |
// f | |
Term reduce_app_lam(Term app, Term lam) { | |
inc_itr(); | |
Loc app_loc = term_loc(app); | |
Loc lam_loc = term_loc(lam); | |
Term bod = got(lam_loc + 0); | |
Term arg = got(app_loc + 1); | |
sub(lam_loc + 0, arg); | |
return bod; | |
} | |
// (&L{a,b} c) | |
// ----------------- APP-SUP | |
// ! &L{c0,c1} = c; | |
// &L{(a c0),(b c1)} | |
Term reduce_app_sup(Term app, Term sup) { | |
//printf("reduce_app_sup "); print_term(app); printf("\n"); | |
inc_itr(); | |
Loc app_loc = term_loc(app); | |
Loc sup_loc = term_loc(sup); | |
Lab sup_lab = term_lab(sup); | |
Term arg = got(app_loc + 1); | |
Term a = got(sup_loc + 0); | |
Term b = got(sup_loc + 1); | |
Loc loc = alloc_node(3); | |
Loc ap0 = app_loc; | |
Loc ap1 = loc + 0; | |
Loc dup = loc + 2; | |
set(ap0 + 0, a); | |
set(ap0 + 1, term_new(DP0, sup_lab, dup)); | |
set(ap1 + 0, b); | |
set(ap1 + 1, term_new(DP1, sup_lab, dup)); | |
set(dup + 0, arg); | |
set(sup_loc + 0, term_new(APP, 0, ap0)); | |
set(sup_loc + 1, term_new(APP, 0, ap1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// (() a) | |
// ------ APP-NIL | |
// error | |
Term reduce_app_nil(Term app, Term nil) { | |
printf("invalid:app-nil"); | |
exit(0); | |
} | |
// ((a,b) c) | |
// --------- APP-TUP | |
// error | |
Term reduce_app_tup(Term app, Term tup) { | |
printf("invalid:app-tup"); | |
exit(0); | |
} | |
// (123 a) | |
// ------- APP-W32 | |
// error | |
Term reduce_app_w32(Term app, Term w32) { | |
printf("invalid:app-w32"); | |
exit(0); | |
} | |
// (T a) | |
// ----- APP-TYP | |
// error | |
Term reduce_app_typ(Term app, Term typ) { | |
printf("invalid:app-typ"); | |
exit(0); | |
} | |
// ~*{():f} | |
// -------- USE-ERA | |
// * | |
Term reduce_use_era(Term use, Term era) { | |
inc_itr(); | |
return era; | |
} | |
// ~&L{a,b}{():f} | |
// ----------------------- USE-SUP | |
// ! &L{f0,f1} = f; | |
// &L{~a{():f0},~b{():f1}} | |
Term reduce_use_sup(Term use, Term sup) { | |
inc_itr(); | |
Loc use_loc = term_loc(use); | |
Loc sup_loc = term_loc(sup); | |
Lab sup_lab = term_lab(sup); | |
Term f = got(use_loc + 1); | |
Term a = got(sup_loc + 0); | |
Term b = got(sup_loc + 1); | |
Loc loc = alloc_node(3); | |
Loc us0 = use_loc; | |
Loc us1 = loc + 0; | |
Loc dup = loc + 2; | |
set(us0 + 0, a); | |
set(us0 + 1, term_new(DP0, sup_lab, dup)); | |
set(us1 + 0, b); | |
set(us1 + 1, term_new(DP1, sup_lab, dup)); | |
set(dup + 0, f); | |
set(sup_loc + 0, term_new(USE, 0, us0)); | |
set(sup_loc + 1, term_new(USE, 0, us1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// ~λx.g{():f} | |
// ----------- USE-LAM | |
// error | |
Term reduce_use_lam(Term use, Term lam) { | |
printf("invalid:use-lam"); | |
exit(0); | |
} | |
// ~(){():f} | |
// --------- USE-NIL | |
// f | |
Term reduce_use_nil(Term use, Term nil) { | |
inc_itr(); | |
Loc use_loc = term_loc(use); | |
Term f = got(use_loc + 1); | |
return f; | |
} | |
// ~(p,q){():f} | |
// ------------ USE-TUP | |
// error | |
Term reduce_use_tup(Term use, Term tup) { | |
printf("invalid:use-tup"); | |
exit(0); | |
} | |
// ~123{():f} | |
// ---------- USE-W32 | |
// error | |
Term reduce_use_w32(Term use, Term w32) { | |
printf("invalid:use-w32"); | |
exit(0); | |
} | |
// ~T{():f} | |
// -------- USE-TYP | |
// error | |
Term reduce_use_typ(Term use, Term typ) { | |
printf("invalid:use-typ"); | |
exit(0); | |
} | |
// ~*{(,):f} | |
// --------- GET-ERA | |
// * | |
Term reduce_get_era(Term get, Term era) { | |
inc_itr(); | |
return era; | |
} | |
// ~&L{a,b}{(,): f} | |
// ------------------------- GET-SUP | |
// ! &L{f0,f1} = f; | |
// &L{~a{(,):f0},~b{(,):f1}} | |
Term reduce_get_sup(Term get, Term sup) { | |
inc_itr(); | |
Loc get_loc = term_loc(get); | |
Loc sup_loc = term_loc(sup); | |
Lab sup_lab = term_lab(sup); | |
Term f = got(get_loc + 1); | |
Term a = got(sup_loc + 0); | |
Term b = got(sup_loc + 1); | |
Loc loc = alloc_node(3); | |
Loc gt0 = get_loc; | |
Loc gt1 = loc + 0; | |
Loc dup = loc + 2; | |
set(gt0 + 0, a); | |
set(gt0 + 1, term_new(DP0, sup_lab, dup)); | |
set(gt1 + 0, b); | |
set(gt1 + 1, term_new(DP1, sup_lab, dup)); | |
set(dup + 0, f); | |
set(sup_loc + 0, term_new(GET, 0, gt0)); | |
set(sup_loc + 1, term_new(GET, 0, gt1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// ~(){(,):f} | |
// ---------- GET-NIL | |
// error | |
Term reduce_get_nil(Term get, Term nil) { | |
printf("invalid:get-nil"); | |
exit(0); | |
} | |
// ~(a,b){(,):f} | |
// ------------- GET-TUP | |
// (f a b) | |
Term reduce_get_tup(Term get, Term tup) { | |
inc_itr(); | |
Loc get_loc = term_loc(get); | |
Loc tup_loc = term_loc(tup); | |
Term f = got(get_loc + 1); | |
Term a = got(tup_loc + 0); | |
Term b = got(tup_loc + 1); | |
Loc app1 = alloc_node(2); | |
Loc app2 = get_loc; | |
set(app1 + 0, f); | |
set(app1 + 1, a); | |
set(app2 + 0, term_new(APP, 0, app1)); | |
set(app2 + 1, b); | |
return term_new(APP, 0, app2); | |
} | |
// ~λx.g{(,):f} | |
// ------------ GET-LAM | |
// error | |
Term reduce_get_lam(Term get, Term lam) { | |
printf("invalid:get-lam"); | |
exit(0); | |
} | |
// ~123{(,):f} | |
// ----------- GET-W32 | |
// error | |
Term reduce_get_w32(Term get, Term w32) { | |
printf("invalid:get-w32"); | |
exit(0); | |
} | |
// ~TYP{(,):f} | |
// ----------- GET-TYP | |
// error | |
Term reduce_get_typ(Term get, Term typ) { | |
printf("invalid:get-typ"); | |
exit(0); | |
} | |
// ~*{0:z;+:s} | |
// ----------- SWI-ERA | |
// * | |
Term reduce_swi_era(Term swi, Term era) { | |
inc_itr(); | |
return era; | |
} | |
// ~&L{a,b}{0:z;+:s} | |
// ------------------------------- SWI-SUP | |
// ! &L{z0,z1} = z; | |
// ! &L{s0,s1} = s; | |
// &L{~a{0:z0;+:s0},~b{0:z1;+:s1}} | |
Term reduce_swi_sup(Term swi, Term sup) { | |
// Correct implementation that reuses the given SUP/SWI nodes | |
inc_itr(); | |
// Locations / labels | |
Loc swi_loc = term_loc(swi); // original SWI (will become SWI0) | |
Loc sup_loc = term_loc(sup); // SUP we will reuse | |
Lab sup_lab = term_lab(sup); // label of the SUP | |
Lab swi_lab = term_lab(swi); // (unused, still preserve) | |
// Extract SWI arms | |
Term z = got(swi_loc + 1); | |
Term s = got(swi_loc + 2); | |
// Extract SUP branches | |
Term a = got(sup_loc + 0); | |
Term b = got(sup_loc + 1); | |
// Allocate: | |
// - 3 cells for the second SWI (swi1) | |
// - 1 cell for dup(z) (dupz) | |
// - 1 cell for dup(s) (dups) | |
Loc loc = alloc_node(5); | |
Loc swi1 = loc; // 3 cells (value,z,s) | |
Loc dupz = loc + 3; // 1 cell | |
Loc dups = loc + 4; // 1 cell | |
// Store originals inside dup nodes | |
set(dupz + 0, z); | |
set(dups + 0, s); | |
// Build SWI0 (reuse swi_loc) | |
set(swi_loc + 0, a); | |
set(swi_loc + 1, term_new(DP0, sup_lab, dupz)); | |
set(swi_loc + 2, term_new(DP0, sup_lab, dups)); | |
// Build SWI1 (new node) | |
set(swi1 + 0, b); | |
set(swi1 + 1, term_new(DP1, sup_lab, dupz)); | |
set(swi1 + 2, term_new(DP1, sup_lab, dups)); | |
// Build resulting SUP (reuse sup_loc) | |
set(sup_loc + 0, term_new(SWI, swi_lab, swi_loc)); | |
set(sup_loc + 1, term_new(SWI, swi_lab, swi1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// ~(){0:z;+:s} | |
// ------------ SWI-NIL | |
// error | |
Term reduce_swi_nil(Term swi, Term nil) { | |
printf("invalid:swi-nil"); | |
exit(0); | |
} | |
// ~(a,b){0:z;+:s} | |
// --------------- SWI-TUP | |
// error | |
Term reduce_swi_tup(Term swi, Term tup) { | |
printf("invalid:swi-tup"); | |
exit(0); | |
} | |
// ~λx.g{0:z;+:s} | |
// -------------- SWI-LAM | |
// error | |
Term reduce_swi_lam(Term swi, Term lam) { | |
printf("invalid:swi-lam"); | |
exit(0); | |
} | |
// ~n{0:z;+:s} | |
// ----------- SWI-W32 | |
// if n = 0: | |
// z | |
// else: | |
// (s (n-1)) | |
Term reduce_swi_w32(Term swi, Term w32) { | |
inc_itr(); | |
Loc swi_loc = term_loc(swi); | |
u32 val = term_loc(w32); | |
Term z = got(swi_loc + 1); | |
Term s = got(swi_loc + 2); | |
if (val == 0) { | |
return z; | |
} else { | |
Loc app = swi_loc; | |
set(app + 0, s); | |
set(app + 1, term_new(W32, 0, val - 1)); | |
return term_new(APP, 0, app); | |
} | |
} | |
// ~T{0:z;+:s} | |
// ----------- SWI-TYP | |
// error | |
Term reduce_swi_typ(Term swi, Term typ) { | |
printf("invalid:swi-typ"); | |
exit(0); | |
} | |
// ! &L{r,s} = * | |
// ------------- DUP-ERA | |
// r <- * | |
// s <- * | |
Term reduce_dup_era(Term dup, Term era) { | |
//printf("reduce_dup_era "); print_term(dup); printf("\n"); | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, era); | |
return era; | |
} | |
// ! &L{x,y} = &L{a,b} | |
// ------------------- DUP-SUP | |
// x <- a | |
// y <- b | |
Term reduce_dup_sup(Term dup, Term sup) { | |
//printf("reduce_dup_sup %u %u | %llu ", term_lab(dup), term_lab(sup), *HVM.spos); print_term(dup); printf(" "); print_term(sup); printf("\n"); | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Lab dup_lab = term_lab(dup); | |
Lab sup_lab = term_lab(sup); | |
Loc sup_loc = term_loc(sup); | |
if (dup_lab == sup_lab) { | |
Term tm0 = got(sup_loc + 0); | |
Term tm1 = got(sup_loc + 1); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, tm1); | |
return tm0; | |
} else { | |
sub(dup_loc + 0, tm0); | |
return tm1; | |
} | |
} else { | |
Loc loc = alloc_node(4); | |
Loc du0 = sup_loc + 0; | |
Loc du1 = sup_loc + 1; | |
Loc su0 = loc + 0; | |
Loc su1 = loc + 2; | |
set(su0 + 0, term_new(DP0, dup_lab, du0)); | |
set(su0 + 1, term_new(DP0, dup_lab, du1)); | |
set(su1 + 0, term_new(DP1, dup_lab, du0)); | |
set(su1 + 1, term_new(DP1, dup_lab, du1)); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(SUP, sup_lab, su1)); | |
return term_new(SUP, sup_lab, su0); | |
} else { | |
sub(dup_loc + 0, term_new(SUP, sup_lab, su0)); | |
return term_new(SUP, sup_lab, su1); | |
} | |
} | |
} | |
// ! &L{r s} = λx.f | |
// ---------------- DUP-LAM | |
// r <- λx0.f0 | |
// s <- λx1.f1 | |
// x <- &L{x0,x1} | |
// ! &L{f0,f1} = f | |
Term reduce_dup_lam(Term dup, Term lam) { | |
//printf("reduce_dup_lam "); print_term(dup); printf("\n"); | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Loc lam_loc = term_loc(lam); | |
Lab dup_lab = term_lab(dup); | |
Term bod = got(lam_loc + 0); | |
Loc loc = alloc_node(5); | |
Loc lm0 = loc + 0; | |
Loc lm1 = loc + 1; | |
Loc su0 = loc + 2; | |
Loc du0 = loc + 4; | |
sub(lam_loc + 0, term_new(SUP, dup_lab, su0)); | |
set(lm0 + 0, term_new(DP0, dup_lab, du0)); | |
set(lm1 + 0, term_new(DP1, dup_lab, du0)); | |
set(su0 + 0, term_new(VAR, 0, lm0)); | |
set(su0 + 1, term_new(VAR, 0, lm1)); | |
set(du0 + 0, bod); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(LAM, 0, lm1)); | |
return term_new(LAM, 0, lm0); | |
} else { | |
sub(dup_loc + 0, term_new(LAM, 0, lm0)); | |
return term_new(LAM, 0, lm1); | |
} | |
} | |
// ! &L{x,y} = () | |
// -------------- DUP-NIL | |
// x <- () | |
// y <- () | |
Term reduce_dup_nil(Term dup, Term nil) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, nil); | |
return nil; | |
} | |
// ! &L{x,y} = (a,b) | |
// ----------------- DUP-TUP | |
// ! &L{a0,a1} = a | |
// ! &L{b0,b1} = b | |
// x <- (a0,b0) | |
// y <- (a1,b1) | |
Term reduce_dup_tup(Term dup, Term tup) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Lab dup_lab = term_lab(dup); | |
Loc tup_loc = term_loc(tup); | |
Term a = got(tup_loc + 0); | |
Term b = got(tup_loc + 1); | |
Loc loc = alloc_node(4); | |
Loc tup1 = loc + 0; | |
Loc dupa = loc + 2; | |
Loc dupb = loc + 3; | |
set(dupa + 0, a); | |
set(dupb + 0, b); | |
set(tup_loc + 0, term_new(DP0, dup_lab, dupa)); | |
set(tup_loc + 1, term_new(DP0, dup_lab, dupb)); | |
set(tup1 + 0, term_new(DP1, dup_lab, dupa)); | |
set(tup1 + 1, term_new(DP1, dup_lab, dupb)); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(TUP, 0, tup1)); | |
return term_new(TUP, 0, tup_loc); | |
} else { | |
sub(dup_loc + 0, term_new(TUP, 0, tup_loc)); | |
return term_new(TUP, 0, tup1); | |
} | |
} | |
// ! &L{x,y} = 123 | |
// --------------- DUP-W32 | |
// x <- 123 | |
// y <- 123 | |
Term reduce_dup_w32(Term dup, Term w32) { | |
//printf("reduce_dup_w32 "); print_term(dup); printf("\n"); | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, w32); | |
return w32; | |
} | |
// ! &L{x,y} = Set | |
// --------------- DUP-SET | |
// x <- Set | |
// y <- Set | |
Term reduce_dup_set(Term dup, Term set) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, set); | |
return set; | |
} | |
// ! &L{x,y} = ⊥ | |
// ------------- DUP-EMP | |
// x <- ⊥ | |
// y <- ⊥ | |
Term reduce_dup_emp(Term dup, Term emp) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, emp); | |
return emp; | |
} | |
// ! &L{x,y} = ⊤ | |
// ------------- DUP-UNI | |
// x <- ⊤ | |
// y <- ⊤ | |
Term reduce_dup_uni(Term dup, Term uni) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, uni); | |
return uni; | |
} | |
// ! &L{x,y} = U32 | |
// -------------- DUP-U32 | |
// x <- U32 | |
// y <- U32 | |
Term reduce_dup_u32(Term dup, Term u32) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
sub(dup_loc + 0, u32); | |
return u32; | |
} | |
// ! &L{x,y} = ΣA.B | |
// ----------------- DUP-SIG | |
// ! &L{A0,A1} = A | |
// ! &L{B0,B1} = B | |
// x <- ΣA0.B0 | |
// y <- ΣA1.B1 | |
Term reduce_dup_sig(Term dup, Term sig) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Lab dup_lab = term_lab(dup); | |
Loc sig_loc = term_loc(sig); | |
Term a = got(sig_loc + 0); | |
Term b = got(sig_loc + 1); | |
Loc loc = alloc_node(4); | |
Loc sig1 = loc + 0; | |
Loc dupa = loc + 2; | |
Loc dupb = loc + 3; | |
set(dupa + 0, a); | |
set(dupb + 0, b); | |
set(sig_loc + 0, term_new(DP0, dup_lab, dupa)); | |
set(sig_loc + 1, term_new(DP0, dup_lab, dupb)); | |
set(sig1 + 0, term_new(DP1, dup_lab, dupa)); | |
set(sig1 + 1, term_new(DP1, dup_lab, dupb)); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(SIG, 0, sig1)); | |
return term_new(SIG, 0, sig_loc); | |
} else { | |
sub(dup_loc + 0, term_new(SIG, 0, sig_loc)); | |
return term_new(SIG, 0, sig1); | |
} | |
} | |
// ! &L{x,y} = ∀A.B | |
// ----------------- DUP-ALL | |
// ! &L{A0,A1} = A | |
// ! &L{B0,B1} = B | |
// x <- ∀A0.B0 | |
// y <- ∀A1.B1 | |
Term reduce_dup_all(Term dup, Term all) { | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Lab dup_lab = term_lab(dup); | |
Loc all_loc = term_loc(all); | |
Term a = got(all_loc + 0); | |
Term b = got(all_loc + 1); | |
Loc loc = alloc_node(4); | |
Loc all1 = loc + 0; | |
Loc dupa = loc + 2; | |
Loc dupb = loc + 3; | |
set(dupa + 0, a); | |
set(dupb + 0, b); | |
set(all_loc + 0, term_new(DP0, dup_lab, dupa)); | |
set(all_loc + 1, term_new(DP0, dup_lab, dupb)); | |
set(all1 + 0, term_new(DP1, dup_lab, dupa)); | |
set(all1 + 1, term_new(DP1, dup_lab, dupb)); | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(ALL, 0, all1)); | |
return term_new(ALL, 0, all_loc); | |
} else { | |
sub(dup_loc + 0, term_new(ALL, 0, all_loc)); | |
return term_new(ALL, 0, all1); | |
} | |
} | |
// ! &L{x,y} = @foo(a b c ...) | |
// --------------------------- DUP-REF-COPY (when &L not in @foo) | |
// ! &L{a0,a1} = a | |
// ! &L{b0,b1} = b | |
// ! &L{c0,c1} = c | |
// ... | |
// x <- @foo(a0 b0 c0 ...) | |
// y <- @foo(a1 b1 c1 ...) | |
Term reduce_dup_ref(Term dup, Term ref) { | |
//printf("reduce_dup_ref "); print_term(dup); printf("\n"); | |
inc_itr(); | |
Loc dup_loc = term_loc(dup); | |
Lab dup_lab = term_lab(dup); | |
Loc ref_loc = term_loc(ref); | |
Lab ref_lab = term_lab(ref); | |
u64 ref_ari = HVM.fari[ref_lab]; | |
Loc loc = alloc_node(ref_ari * 2); | |
Loc ref0 = ref_loc; | |
Loc ref1 = loc + 0; | |
for (u64 i = 0; i < ref_ari; i++) { | |
Loc du0 = loc + ref_ari + i; | |
set(du0 + 0, got(ref_loc + i)); | |
set(ref0 + i, term_new(DP0, dup_lab, du0)); | |
set(ref1 + i, term_new(DP1, dup_lab, du0)); | |
} | |
if (term_tag(dup) == DP0) { | |
sub(dup_loc + 0, term_new(REF, ref_lab, ref1)); | |
return term_new(REF, ref_lab, ref0); | |
} else { | |
sub(dup_loc + 0, term_new(REF, ref_lab, ref0)); | |
return term_new(REF, ref_lab, ref1); | |
} | |
} | |
// (<op * y) | |
// --------- OPX-ERA | |
// * | |
Term reduce_opx_era(Term opx, Term era) { | |
//printf("reduce_opx_era "); print_term(opx); printf("\n"); | |
inc_itr(); | |
return era; | |
} | |
// (<op λx.f y) | |
// ----------- OPX-LAM | |
// error | |
Term reduce_opx_lam(Term opx, Term lam) { | |
//printf("reduce_opx_lam "); print_term(opx); printf("\n"); | |
printf("invalid:opx-lam"); | |
exit(0); | |
} | |
// (<op &L{a,b} y) | |
// ------------------------- OPX-SUP | |
// ! &L{y0,y1} = y; | |
// &L{(<op a y0),(<op b y1)} | |
Term reduce_opx_sup(Term opx, Term sup) { | |
//printf("reduce_opx_sup "); print_term(opx); printf("\n"); | |
inc_itr(); | |
Loc opx_loc = term_loc(opx); | |
Loc sup_loc = term_loc(sup); | |
Lab sup_lab = term_lab(sup); | |
Term nmy = got(opx_loc + 1); | |
Term tm0 = got(sup_loc + 0); | |
Term tm1 = got(sup_loc + 1); | |
Loc loc = alloc_node(3); | |
Loc op0 = opx_loc; | |
Loc op1 = loc + 0; | |
Loc du0 = loc + 2; | |
set(op0 + 0, tm0); | |
set(op0 + 1, term_new(DP0, sup_lab, du0)); | |
set(op1 + 0, tm1); | |
set(op1 + 1, term_new(DP1, sup_lab, du0)); | |
set(du0 + 0, nmy); | |
set(sup_loc + 0, term_new(OPX, term_lab(opx), op0)); | |
set(sup_loc + 1, term_new(OPX, term_lab(opx), op1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// (<op () y) | |
// ---------- OPX-NIL | |
// error | |
Term reduce_opx_nil(Term opx, Term nil) { | |
printf("invalid:opx-nil"); | |
exit(0); | |
} | |
// (<op (x0,x1) y) | |
// --------------- OPX-TUP | |
// error | |
Term reduce_opx_tup(Term opx, Term tup) { | |
printf("invalid:opx-tup"); | |
exit(0); | |
} | |
// (<op x y) | |
// --------- OPX-W32 | |
// (>op y x) | |
Term reduce_opx_w32(Term opx, Term nmx) { | |
//printf("reduce_opx_w32 "); print_term(opx); printf("\n"); | |
inc_itr(); | |
Lab opx_lab = term_lab(opx); | |
Loc opx_loc = term_loc(opx); | |
Term nmy = got(opx_loc + 1); | |
set(opx_loc + 0, nmy); | |
set(opx_loc + 1, nmx); | |
return term_new(OPY, opx_lab, opx_loc); | |
} | |
// (<op T y) | |
// --------- OPX-TYP | |
// error | |
Term reduce_opx_typ(Term opx, Term typ) { | |
printf("invalid:opx-typ"); | |
exit(0); | |
} | |
// (>op x *) | |
// --------- OPY-ERA | |
// * | |
Term reduce_opy_era(Term opy, Term era) { | |
//printf("reduce_opy_era "); print_term(opy); printf("\n"); | |
inc_itr(); | |
return era; | |
} | |
// (>op x λy.f) | |
// ------------ OPY-LAM | |
// error | |
Term reduce_opy_lam(Term opy, Term lam) { | |
//printf("reduce_opy_lam "); print_term(opy); printf("\n"); | |
printf("invalid:opy-lam"); | |
exit(0); | |
} | |
// (>op x &L{y0,y1}) | |
// ----------------------- OPY-SUP | |
// &L{>op(x y0),>op(x y1)} | |
Term reduce_opy_sup(Term opy, Term sup) { | |
//printf("reduce_opy_sup "); print_term(opy); printf("\n"); | |
inc_itr(); | |
Loc opy_loc = term_loc(opy); | |
Loc sup_loc = term_loc(sup); | |
Lab sup_lab = term_lab(sup); | |
Term nmx = got(opy_loc + 1); | |
Term tm0 = got(sup_loc + 0); | |
Term tm1 = got(sup_loc + 1); | |
Loc op0 = opy_loc; | |
Loc op1 = alloc_node(2); | |
set(op0 + 0, nmx); | |
set(op0 + 1, tm0); | |
set(op1 + 0, nmx); | |
set(op1 + 1, tm1); | |
set(sup_loc + 0, term_new(OPY, term_lab(opy), op0)); | |
set(sup_loc + 1, term_new(OPY, term_lab(opy), op1)); | |
return term_new(SUP, sup_lab, sup_loc); | |
} | |
// (>op x ()) | |
// ---------- OPY-NIL | |
// error | |
Term reduce_opy_nil(Term opy, Term nil) { | |
printf("invalid:opy-nil"); | |
exit(0); | |
} | |
// (>op x (y0,y1)) | |
// --------------- OPY-TUP | |
// error | |
Term reduce_opy_tup(Term opy, Term tup) { | |
printf("invalid:opy-tup"); | |
exit(0); | |
} | |
// (>op x y) | |
// --------- OPY-W32 | |
// x <op> y | |
Term reduce_opy_w32(Term opy, Term val) { | |
//printf("reduce_opy_w32 "); print_term(opy); printf("\n"); | |
inc_itr(); | |
Loc opy_loc = term_loc(opy); | |
Tag t = term_tag(val); | |
u32 x = term_loc(got(opy_loc + 1)); | |
u32 y = term_loc(val); | |
u32 result; | |
switch (term_lab(opy)) { | |
case OP_ADD: result = x + y; break; | |
case OP_SUB: result = x - y; break; | |
case OP_MUL: result = x * y; break; | |
case OP_DIV: result = x / y; break; | |
case OP_MOD: result = x % y; break; | |
case OP_EQ: result = x == y; break; | |
case OP_NE: result = x != y; break; | |
case OP_LT: result = x < y; break; | |
case OP_GT: result = x > y; break; | |
case OP_LTE: result = x <= y; break; | |
case OP_GTE: result = x >= y; break; | |
case OP_AND: result = x & y; break; | |
case OP_OR: result = x | y; break; | |
case OP_XOR: result = x ^ y; break; | |
case OP_LSH: result = x << y; break; | |
case OP_RSH: result = x >> y; break; | |
default: { | |
printf("invalid:opy-w32"); | |
exit(0); | |
} | |
} | |
return term_new(W32, 0, result); | |
} | |
// (>op x T) | |
// --------- OPY-TYP | |
// error | |
Term reduce_opy_typ(Term opy, Term typ) { | |
printf("invalid:opy-typ"); | |
exit(0); | |
} | |
Term reduce(Term term) { | |
if (term_is_whnf(term)) { | |
return term; | |
} | |
Term next = term; | |
u64 stop = *HVM.spos; | |
u64 spos = stop; | |
Term* sbuf = HVM.sbuf; | |
while (1) { | |
//printf("NEXT "); print_term(term); printf("\n"); | |
//printf("PATH "); | |
//for (u64 i = 0; i < *spos; ++i) { | |
//print_tag(term_tag(HVM.sbuf[i])); | |
//printf(" "); | |
//} | |
//printf(" ~ %p", HVM.sbuf); | |
//printf("\n"); | |
Tag tag = term_tag(next); | |
Lab lab = term_lab(next); | |
Loc loc = term_loc(next); | |
// On variables: substitute | |
// On eliminators: move to field | |
switch (tag) { | |
case LET: { | |
switch (lab) { | |
case LAZY: { | |
next = reduce_let(next, got(loc + 0)); | |
continue; | |
} | |
case STRI: { | |
spush(next, sbuf, &spos); | |
next = got(loc + 0); | |
continue; | |
} | |
default: { | |
printf("invalid:let"); | |
exit(0); | |
} | |
} | |
} | |
case APP: | |
case USE: | |
case GET: | |
case SWI: | |
case OPX: | |
case OPY: { | |
spush(next, sbuf, &spos); | |
next = got(loc + 0); | |
continue; | |
} | |
case DP0: | |
case DP1: { | |
Term sub = got(loc + 0); | |
if (term_get_bit(sub) == 0) { | |
spush(next, sbuf, &spos); | |
next = sub; | |
continue; | |
} else { | |
next = term_rem_bit(sub); | |
continue; | |
} | |
} | |
case VAR: { | |
Term sub = got(loc); | |
if (term_get_bit(sub) == 0) { | |
break; | |
} else { | |
next = term_rem_bit(sub); | |
continue; | |
} | |
} | |
case REF: { | |
*HVM.spos = spos; | |
next = reduce_ref(next); | |
spos = *HVM.spos; | |
continue; | |
} | |
default: break; | |
} | |
// Empty stack: term is in WHNF | |
if (spos == stop) { | |
*HVM.spos = spos; | |
return next; | |
} | |
// Interaction Dispatcher | |
Term prev = spop(sbuf, &spos); | |
Tag ptag = term_tag(prev); | |
Lab plab = term_lab(prev); | |
Loc ploc = term_loc(prev); | |
switch (ptag) { | |
case LET: { | |
next = reduce_let(prev, next); | |
continue; | |
} | |
case ANN: { | |
next = reduce_ann(prev, next); | |
continue; | |
} | |
case APP: { | |
switch (tag) { | |
case ERA: next = reduce_app_era(prev, next); continue; | |
case LAM: next = reduce_app_lam(prev, next); continue; | |
case SUP: next = reduce_app_sup(prev, next); continue; | |
case NIL: next = reduce_app_nil(prev, next); continue; | |
case TUP: next = reduce_app_tup(prev, next); continue; | |
case W32: next = reduce_app_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_app_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
case USE: { | |
switch (tag) { | |
case ERA: next = reduce_use_era(prev, next); continue; | |
case SUP: next = reduce_use_sup(prev, next); continue; | |
case LAM: next = reduce_use_lam(prev, next); continue; | |
case NIL: next = reduce_use_nil(prev, next); continue; | |
case TUP: next = reduce_use_tup(prev, next); continue; | |
case W32: next = reduce_use_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_use_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
case GET: { | |
switch (tag) { | |
case ERA: next = reduce_get_era(prev, next); continue; | |
case SUP: next = reduce_get_sup(prev, next); continue; | |
case NIL: next = reduce_get_nil(prev, next); continue; | |
case TUP: next = reduce_get_tup(prev, next); continue; | |
case LAM: next = reduce_get_lam(prev, next); continue; | |
case W32: next = reduce_get_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_get_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
case SWI: { | |
switch (tag) { | |
case ERA: next = reduce_swi_era(prev, next); continue; | |
case SUP: next = reduce_swi_sup(prev, next); continue; | |
case NIL: next = reduce_swi_nil(prev, next); continue; | |
case TUP: next = reduce_swi_tup(prev, next); continue; | |
case LAM: next = reduce_swi_lam(prev, next); continue; | |
case W32: next = reduce_swi_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_swi_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
case DP0: | |
case DP1: { | |
switch (tag) { | |
case ERA: next = reduce_dup_era(prev, next); continue; | |
case SUP: next = reduce_dup_sup(prev, next); continue; | |
case LAM: next = reduce_dup_lam(prev, next); continue; | |
case NIL: next = reduce_dup_nil(prev, next); continue; | |
case TUP: next = reduce_dup_tup(prev, next); continue; | |
case W32: next = reduce_dup_w32(prev, next); continue; | |
case SET: next = reduce_dup_set(prev, next); continue; | |
case EMP: next = reduce_dup_emp(prev, next); continue; | |
case UNI: next = reduce_dup_uni(prev, next); continue; | |
case U32: next = reduce_dup_u32(prev, next); continue; | |
case SIG: next = reduce_dup_sig(prev, next); continue; | |
case ALL: next = reduce_dup_all(prev, next); continue; | |
case REF: next = reduce_dup_ref(prev, next); continue; | |
default: break; | |
} | |
} | |
case OPX: { | |
switch (tag) { | |
case ERA: next = reduce_opx_era(prev, next); continue; | |
case LAM: next = reduce_opx_lam(prev, next); continue; | |
case SUP: next = reduce_opx_sup(prev, next); continue; | |
case NIL: next = reduce_opx_nil(prev, next); continue; | |
case TUP: next = reduce_opx_tup(prev, next); continue; | |
case W32: next = reduce_opx_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_opx_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
case OPY: { | |
switch (tag) { | |
case ERA: next = reduce_opy_era(prev, next); continue; | |
case LAM: next = reduce_opy_lam(prev, next); continue; | |
case SUP: next = reduce_opy_sup(prev, next); continue; | |
case NIL: next = reduce_opy_nil(prev, next); continue; | |
case TUP: next = reduce_opy_tup(prev, next); continue; | |
case W32: next = reduce_opy_w32(prev, next); continue; | |
case SET: | |
case EMP: | |
case UNI: | |
case U32: | |
case SIG: | |
case ALL: next = reduce_opy_typ(prev, next); continue; | |
default: break; | |
} | |
} | |
default: break; | |
} | |
// No interaction: push term back to stack | |
spush(prev, sbuf, &spos); | |
// Update parent chain | |
while (spos > stop) { | |
Term host = spop(sbuf, &spos); | |
Tag htag = term_tag(host); | |
Lab hlab = term_lab(host); | |
Loc hloc = term_loc(host); | |
set(hloc + 0, next); | |
next = host; | |
} | |
*HVM.spos = spos; | |
return next; | |
} | |
} | |
Term reduce_at(Loc host) { | |
Term tm0 = got(host); | |
if (term_is_whnf(tm0)) { | |
return tm0; | |
} | |
Term tm1 = reduce(tm0); | |
set(host, tm1); | |
return tm1; | |
} | |
Term normal(Term term) { | |
Term wnf = reduce(term); | |
Tag tag = term_tag(wnf); | |
Lab lab = term_lab(wnf); | |
Loc loc = term_loc(wnf); | |
switch (tag) { | |
case LAM: { | |
Term bod = got(loc + 0); | |
bod = normal(bod); | |
set(loc + 0, bod); | |
return wnf; | |
} | |
case APP: { | |
Term fun = got(loc + 0); | |
Term arg = got(loc + 1); | |
fun = normal(fun); | |
arg = normal(arg); | |
set(loc + 0, fun); | |
set(loc + 1, arg); | |
return wnf; | |
} | |
case SUP: { | |
Term tm0 = got(loc + 0); | |
Term tm1 = got(loc + 1); | |
tm0 = normal(tm0); | |
tm1 = normal(tm1); | |
set(loc + 0, tm0); | |
set(loc + 1, tm1); | |
return wnf; | |
} | |
case TUP: { | |
Term tm0 = got(loc + 0); | |
Term tm1 = got(loc + 1); | |
tm0 = normal(tm0); | |
tm1 = normal(tm1); | |
set(loc + 0, tm0); | |
set(loc + 1, tm1); | |
return wnf; | |
} | |
case SIG: { | |
Term tm0 = got(loc + 0); | |
Term tm1 = got(loc + 1); | |
tm0 = normal(tm0); | |
tm1 = normal(tm1); | |
set(loc + 0, tm0); | |
set(loc + 1, tm1); | |
return wnf; | |
} | |
case ALL: { | |
Term tm0 = got(loc + 0); | |
Term tm1 = got(loc + 1); | |
tm0 = normal(tm0); | |
tm1 = normal(tm1); | |
set(loc + 0, tm0); | |
set(loc + 1, tm1); | |
return wnf; | |
} | |
case DP0: | |
case DP1: { | |
Term val = got(loc + 0); | |
val = normal(val); | |
set(loc + 0, val); | |
return wnf; | |
} | |
case USE: | |
case GET: | |
case SWI: { | |
for (u64 i = 0; i <= 1; i++) { | |
Term arg = got(loc + i); | |
arg = normal(arg); | |
set(loc + i, arg); | |
} | |
return wnf; | |
} | |
default: | |
return wnf; | |
} | |
} | |
// Primitives | |
// ---------- | |
// Primitive: Dynamic Sup @SUP(lab tm0 tm1) | |
// Allocates a new SUP node with given label. | |
Term SUP_f(Term ref) { | |
Loc ref_loc = term_loc(ref); | |
Term lab = reduce(got(ref_loc + 0)); | |
Term lab_val = term_loc(lab); | |
if (term_tag(lab) != W32) { | |
printf("ERROR:non-numeric-sup-label\n"); | |
} | |
if (lab_val > 0xFFFF) { | |
printf("ERROR:sup-label-too-large\n"); | |
} | |
Term tm0 = got(ref_loc + 1); | |
Term tm1 = got(ref_loc + 2); | |
Loc sup = alloc_node(2); | |
Term ret = term_new(SUP, lab_val, sup); | |
set(sup + 0, tm0); | |
set(sup + 1, tm1); | |
*HVM.itrs += 1; | |
return ret; | |
} | |
// Primitive: Dynamic Dup @DUP(lab val λdp0λdp1(bod)) | |
// Creates a DUP node with given label. | |
Term DUP_f(Term ref) { | |
Loc ref_loc = term_loc(ref); | |
Term lab = reduce(got(ref_loc + 0)); | |
Term lab_val = term_loc(lab); | |
if (term_tag(lab) != W32) { | |
printf("ERROR:non-numeric-dup-label\n"); | |
} | |
if (lab_val > 0xFFFF) { | |
printf("ERROR:dup-label-too-large\n"); | |
} | |
Term val = got(ref_loc + 1); | |
Term bod = got(ref_loc + 2); | |
Loc dup = alloc_node(1); | |
set(dup + 0, val); | |
if (term_tag(bod) == LAM) { | |
Loc lam0 = term_loc(bod); | |
Term bod0 = got(lam0 + 0); | |
if (term_tag(bod0) == LAM) { | |
Loc lam1 = term_loc(bod0); | |
Term bod1 = got(lam1 + 0); | |
sub(lam0 + 0, term_new(DP0, lab_val, dup)); | |
sub(lam1 + 0, term_new(DP1, lab_val, dup)); | |
*HVM.itrs += 3; | |
return bod1; | |
} | |
} | |
Loc app0 = alloc_node(2); | |
set(app0 + 0, bod); | |
set(app0 + 1, term_new(DP0, lab_val, dup)); | |
Loc app1 = alloc_node(2); | |
set(app1 + 0, term_new(APP, 0, app0)); | |
set(app1 + 1, term_new(DP1, lab_val, dup)); | |
*HVM.itrs += 1; | |
return term_new(APP, 0, app1); | |
} | |
Term LOG_f(Term ref) { | |
printf("TODO: LOG_f"); | |
exit(0); | |
} | |
void *alloc_huge(size_t size) { | |
void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, | |
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, | |
-1, 0); | |
if (ptr == MAP_FAILED) { | |
perror("mmap failed"); | |
return NULL; | |
} | |
return ptr; | |
} | |
// Runtime Memory | |
// -------------- | |
void hvm_init() { | |
HVM.sbuf = alloc_huge(MAX_STACK_SIZE * sizeof(Term)); | |
HVM.heap = alloc_huge(MAX_HEAP_SIZE * sizeof(Term)); | |
HVM.spos = alloc_huge(sizeof(u64)); | |
HVM.size = alloc_huge(sizeof(u64)); | |
HVM.itrs = alloc_huge(sizeof(u64)); | |
HVM.frsh = alloc_huge(sizeof(u64)); | |
#define CHECK_ALLOC(ptr, name) if (!(ptr)) { printf(name " alloc failed\n"); allocs_failed++; } | |
int allocs_failed = 0; // Track if any allocation failed | |
CHECK_ALLOC(HVM.sbuf, "sbuf"); | |
CHECK_ALLOC(HVM.heap, "heap"); | |
CHECK_ALLOC(HVM.spos, "spos"); | |
CHECK_ALLOC(HVM.size, "size"); | |
CHECK_ALLOC(HVM.itrs, "itrs"); | |
CHECK_ALLOC(HVM.frsh, "frsh"); | |
if (allocs_failed > 0) { | |
printf("hvm_init alloc's failed: %d allocations failed\n", allocs_failed); | |
exit(1); | |
} | |
#undef CHECK_ALLOC | |
*HVM.spos = 0; | |
*HVM.size = 1; | |
*HVM.itrs = 0; | |
*HVM.frsh = 0x20; | |
HVM.book[SUP_F] = SUP_f; | |
HVM.book[DUP_F] = DUP_f; | |
HVM.book[LOG_F] = LOG_f; | |
for (int i = 0; i < 65536; i++) { | |
HVM.fari[i] = 0; | |
} | |
} | |
void hvm_munmap(void *ptr, size_t size, const char *name) { | |
if (ptr != MAP_FAILED) { | |
if (munmap(ptr, size) == -1) { | |
perror("munmap failed"); | |
} else { | |
// printf("Successfully unmapped %s\n", name); | |
} | |
} else { | |
printf("%s is already null or invalid.\n", name); | |
} | |
} | |
void hvm_free() { | |
hvm_munmap(HVM.sbuf, MAX_STACK_SIZE * sizeof(Term), "sbuf"); | |
hvm_munmap(HVM.heap, MAX_HEAP_SIZE * sizeof(Term), "heap"); | |
hvm_munmap(HVM.spos, sizeof(u64), "spos"); | |
hvm_munmap(HVM.size, sizeof(u64), "size"); | |
hvm_munmap(HVM.itrs, sizeof(u64), "itrs"); | |
hvm_munmap(HVM.frsh, sizeof(u64), "frsh"); | |
} | |
State* hvm_get_state() { | |
return &HVM; | |
} | |
void hvm_set_state(State* hvm) { | |
HVM.sbuf = hvm->sbuf; | |
HVM.spos = hvm->spos; | |
HVM.heap = hvm->heap; | |
HVM.size = hvm->size; | |
HVM.itrs = hvm->itrs; | |
HVM.frsh = hvm->frsh; | |
for (int i = 0; i < 65536; i++) { | |
HVM.book[i] = hvm->book[i]; | |
HVM.fari[i] = hvm->fari[i]; | |
} | |
} | |
void hvm_define(u16 fid, Term (*func)()) { | |
//printf("defined %llu %p\n", fid, func); | |
HVM.book[fid] = func; | |
} | |
void hvm_set_fari(u16 fid, u16 arity) { | |
HVM.fari[fid] = arity; | |
} | |
-- TASK: write below a complete bidirectional type checker, based on OldCheck | |
-- the types must be: | |
-- infer : Int → Term → IO (Result Term) | |
-- check : Int → Term → Term → IO (Result ()) | |
-- make it a 1-to-1 correspondence to OldCheck | |
-- (omitted) | |
-- this is a good start, but: | |
-- - 1. the style of this file doesn't match the rest of the codebase. refactor its style completely. | |
-- - 2. many infer/check cases are missing. remember to consult the original OldCheck file to learn how each case should work. this file should remain a close correspondence to it. | |
-- rewrite the file again, addressing these issues: | |
-- (omitted) | |
-- the file above is better, but it still has some issues. | |
-- first: termEqual must be renamed to just equal | |
-- second: due to how superpositions work on HVM, we need to update the equal | |
-- function to handle SUPs, as follows: | |
-- &L{a0,a1} == b | |
-- ----------------------- EQUAL-SUP-VAL | |
-- ! &L{b0,b1} = b; | |
-- &L{a0 == a1 , b0 == b1} | |
-- a == &L{b0,b1} | |
-- ----------------------- EQUAL-VAL-SUP | |
-- ! &L{a0,a1} = a; | |
-- &L{a0 == a1 , b0 == b1} | |
-- Now, since EQL can now return a SUP, its return type can't be Bool anymore - it has to be Term. | |
-- As such, we will return () (One) when the terms are equal, and * (Era) otherwise. | |
-- Similarly, the infer and check functions must be updated: | |
-- infer d &L{x0,x1} | |
-- --------------------------- INFER-SUP | |
-- &L{infer d x0 , infer d x1} | |
-- check d &L{x0,x1} t | |
-- ------------------------------- CHECK-SUP-VAL | |
-- &L{check d x0 t , check d x1 t} | |
-- check d x &L{t0,t1} | |
-- ------------------------------- CHECK-SUP-VAL | |
-- &L{check d x t0 , check d x t1} | |
-- These interactions should be incorporated into equal, infer and check, directly. | |
-- That is, when a term is a SUP, we must return a SUP of both recursive calls. | |
-- Note that, since infer/equal can also return SUPs, their return can't be Result anymore. | |
-- Instead, their type will be: | |
-- infer :: Int -> Term -> IO Term | |
-- check :: Int -> Term -> Term -> IO Term | |
-- infer and check will simply return the type (when well-typed) or * (Era) otherwise. | |
-- check will either return () (One) (when well-typed), or * (Era) otherwise. | |
-- to report errors, we will just use a print (not an Error type) | |
-- Finally, since equal returns a Term rather than a Bool, we must also properly | |
-- match on its return, and dispatch SUP interactions accordingly. for better style, | |
-- create an auxiliary validate function that will do that part. | |
-- Also, note there is a logic error in your code. | |
-- The check function does NOT call whnf on the term, only on the goal. | |
-- Why did you invent that whnf call out of nowhere? | |
-- Double check the rest of the code to avoid errors like that. | |
-- Also, this style is terrible: | |
-- foo :: ... | |
-- foo ... x ... = do | |
-- x_nf <- whnf x | |
-- let xTag = tTag x_nf | |
-- case () of | |
-- _ | xTag == _XYZ_ -> ... | |
-- | |
-- Instead, let's do it as follows: | |
-- 1. *BEFORE* calling foo, we take the whnf of the | |
-- 2. Then, we write foo like: | |
-- foo :: ... | |
-- foo ... x ... | |
-- | tTag x == _XYZ = ... | |
-- | ... | |
-- | |
-- use this style in ALL functions, including equal. | |
-- NEVER use case () again. | |
-- Also, the following style is terrible: | |
-- foo = pure Something | |
-- Instead, let's ALWAYS use a do block, like: | |
-- foo = do | |
-- pure Something | |
-- Also, in many cases, you're allocating nodes like: | |
-- sup <- allocNode 2 | |
-- set (sup + 0) dp0 | |
-- set (sup + 1) dp1 | |
-- That is very repetitive and error prone. Instead, create a function: | |
-- makeNode TAG LAB [children] | |
-- And use it through your code. | |
-- Complete updated file: | |
-- (omitted) | |
-- this initial implementation is good. there is a problem, though. | |
-- it is NOT exactly aligned with the OldCheck file. | |
-- for example, on OldCheck, the LAM-ALL case is: | |
-- #LAM{f}: ~ goal !f { | |
-- #ALL{A B}: | |
-- ! &{A0 A1}=A | |
-- ~ @check((+ dep 1) (f #ANN{#VAR{dep} A0}) #APP{B #ANN{#VAR{dep} A1}}) { | |
-- #Done{_}: #Done{1} | |
-- #Fail{e}: #Fail{e} | |
-- } | |
-- goal: #Fail{#TypeMismatch{#LAM{f} #ALL{#VAR{0} #LAM{λx.#VAR{0}}} goal}} | |
-- } | |
-- yet, on this file, it is: | |
-- | tTag tm == _LAM_ && tTag goal == _ALL_ = do | |
-- bod <- field tm 0 | |
-- aTy <- field goal 0 | |
-- bTy <- field goal 1 | |
-- var <- makeNode _VAR_ (fromIntegral dep) [eraT] | |
-- app <- makeNode _APP_ 0 [bTy, var] | |
-- bTy <- whnf app | |
-- bOk <- checkGo (dep+1) bod bTy | |
-- if tTag bOk == _ERA_ | |
-- then pure eraT | |
-- else pure nilT | |
-- problems: | |
-- - 'tm' should be named 'term', since that's how it is on OldCheck | |
-- - we should first match '_LAM_', then, inside it, match '_ALL_', preserving the OldCheck structure | |
-- - the body check must be check (dep+1) (App f (Ann (Var dep) A0) ) (App B (Ann (Var dep) A1)), | |
-- where A0 and A1 are cloned variables (with a fresh DUP node). instead, what you have is: | |
-- check (dep+1) f (App B (Var dep)), which is absolutely NOT the same. | |
-- - across the implementation, there are many instances like this one, where the new checker is not | |
-- a 1-to-1 correspondence with the old one, as it was supposed to be. | |
-- your goal is to rewrite Checker.hs again, from scratch, in order to address this issue. | |
-- make sure to consult OldCheck to learn how the infer/check functions should be structured. | |
-- remember that equal, both are already correct - no need to change them. | |
-- write the updated, complete Check.hs file below: | |
-- (omitted) | |
-- in the code above, you're using 'ann' more than once. this is NOT ALLOWED. | |
-- HVM is linear! instead, what you need to do is: use a DUP node to clone | |
-- 'a', and then make separate ANN's. again, notice how, on OldCheck, we do: | |
-- ! &{A0 A1}=A | |
-- this creates a DUP NODE that CLONES 'A' as 'A0' and 'A1'. | |
-- you're struggling very hard with linearity, so, please, reason about it. | |
-- then, write below the FIXED version of every defective case: | |
-- (omitted) | |
-- OK, this approach does look sensible. now, let's apply this idea to the | |
-- entire code, in the format we used previously. reimplement the entire file, | |
-- from scratch, to include the new logic. remember that you ALWAYS need to dup | |
-- a variable that you use more than once! | |
-- also, in your reimplementation, attempt to be more consistent with variable | |
-- names and alignment. for example, this is not fine: | |
-- lam <- makeNode _LAM_ 0 [setT] | |
-- allSet <- makeNode _ALL_ 0 [setT, lam] | |
-- because 'lam' and 'allSet' don't align. | |
-- now, proceed to rewrite the COMPLETE Check.hs file below: | |
-- also: | |
-- 1. for some reason, 'infer' and 'check' are NOT in the proposed structure. | |
-- infer has been written like: | |
-- infer dep term0 = do | |
-- term <- whnf term0 | |
-- case tTag term of | |
-- t | t == _XYZ_ -> do | |
-- ... | |
-- while the correct structure is: | |
-- infer dep term0 = ... take whnf then call inferGo ... | |
-- ... | |
-- inferGo dep tm | |
-- | tTag tm == _XYZ_ = do | |
-- ... | |
-- the same is true for 'check'. | |
-- also, matching on SUP should NOT be separated from the other cases. | |
-- that makes absolutely no sense. do not do that. | |
-- complete, fixed file below: | |
-- (omitted) | |
-- ok, this looks great. now, review the code above and: | |
-- - 1. check if there is still any occurrence of a HVM-side Term being accidentally cloned in Haskell (i.e., by using its variable more than once) | |
-- - 2. review the code for bugs and issues in general | |
-- report below all your findings, in English: | |
-- • The helper dup2 is only creating the two DP-links; it never allocates the | |
-- actual _DUP_ node that owns them, so the run-time sharing discipline is | |
-- broken. | |
-- • dup2 always returns the fixed label 1 (getLabAuto is a stub). Every call | |
-- therefore re-uses the same label, violating the “fresh label per DUP” | |
-- rule. | |
-- • In inferGo (_SIG_, _APP_) and checkGo (_SIG_), the argument a/x is used | |
-- once before the call to dup2 and then twice inside the DP0/DP1 links, | |
-- yielding three usages of the same linear value. The DUP must be performed | |
-- before the very first consumption, not afterwards. | |
-- • both and equalGo forward the term b (or a) to two recursive calls without | |
-- duplicating it, so the same run-time pointer is consumed twice. | |
-- • In the _LAM_ ▸ _ALL_ rule we create two fresh variables (var0 / var1) but | |
-- use the original type a three times (once for check, twice in ANN) after a | |
-- single dup2; same linearity issue. | |
-- • Node construction for DP0/DP1 uses makeNode, but the tag set should be | |
-- _VAR_ when exposing the binder to the body; DP0/DP1 must live only inside | |
-- the DUP structure. | |
-- • Shadowing: in the _APP_ branch new bindings named “a” and “b” override the | |
-- outer ones, which is confusing and error-prone. | |
-- NOTE: no - this is actually fine and desirable. use shadowing whenever | |
-- possible. avoid prefixing names with ' and similar symbols. | |
-- • getLabAuto is only a placeholder; without a real fresh-label mechanism the | |
-- interpreter will emit duplicated labels and break reductions that depend | |
-- on label uniqueness. | |
-- let's fix this by importing the book in ALL functions (both, etc.) | |
-- • makeNode is used to create DP0 / DP1 links with a child list of length 1; | |
-- but a DP-link is *not* an allocated node: it is supposed to be a leaf term | |
-- (termNew tag lab loc=0). Allocating memory for them wastes space. | |
-- NOTE: that's correct. DUP nodes are allocated and store the duplicated term, | |
-- but the DP0/DP1 terms are leaves. | |
-- • Several inference branches (_REF_, _USE_, _GET_, _SWI_, …) still return | |
-- eraT after printing a message, whereas OldCheck propagated a #Fail | |
-- containing a structured error; the new checker therefore loses error | |
-- information. | |
-- NOTE: that's okay for now | |
-- • equalGo / both treat NIL as the only One value. They should also return a | |
-- SUP-tree when either side is a SUP of Ones, exactly like the other rules. | |
-- NOTE: what do you mean by that? I'm confused. | |
-- Fixing the points above requires: | |
-- – Implementing a real fresh-label supply and wrapping DP0/DP1 inside a | |
-- proper _DUP_ node. | |
-- – Performing DUP *before* the first duplicated use. | |
-- – Never forwarding the same Term to two different consumers without a DUP. | |
-- – Removing the stray debugging prints or turning them into proper error | |
-- nodes. | |
-- – Cleaning up variable shadowing and always using fresh names. | |
-- TASK: rewrite Check.hs from scratch, again, in order to address these issues. | |
-- Complete refactored Check.hs file. Remember to increment the fresh label. | |
-- Write the complete, final version below: | |
-- COMPLETE CHECK.HS: | |
-- (omitted) | |
-- this is still wrong. note that on rules like: | |
-- | tTag a == _SUP_ = do | |
-- a0 <- field a 0 | |
-- a1 <- field a 1 | |
-- -- Need to duplicate b because it's used twice | |
-- (b0, b1) <- makeDup bookRef b | |
-- r0 <- both bookRef a0 b0 | |
-- r1 <- both bookRef a1 b1 | |
-- makeNode _SUP_ (tLab a) [r0, r1] | |
-- we need to use the SAME label for the new dup, and the returned SUP. | |
-- reason about this and update the code to reflect this change verywhere it applies | |
-- (...) | |
-- I now believe that we should NOT use the freshLab field from the Book. in | |
-- fact, I removed it. we should still receive it so we can pass to reduce later | |
-- on. but, for now, let's instead use a global no-inline counter implemented | |
-- inside this file itself, for the fresh label generation. | |
-- final Check.hs: | |
module Check where | |
import Control.Monad (when) | |
import Data.IORef (IORef, readIORef, modifyIORef', newIORef) | |
import Data.Word | |
import System.IO.Unsafe (unsafePerformIO) | |
import Foreign | |
import Reduce | |
import Type | |
-- Global counter for fresh labels | |
{-# NOINLINE freshLabelCounter #-} | |
freshLabelCounter :: IORef Lab | |
freshLabelCounter = unsafePerformIO $ newIORef 0xC00000 | |
-- Constants | |
setT, empT, uniT, u32T, nilT, eraT :: Term | |
setT = termNew _SET_ 0 0 | |
empT = termNew _EMP_ 0 0 | |
uniT = termNew _UNI_ 0 0 | |
u32T = termNew _U32_ 0 0 | |
nilT = termNew _NIL_ 0 0 | |
eraT = termNew _ERA_ 0 0 | |
-- Runtime helpers | |
whnf :: Term -> IO Term | |
whnf = reduceC | |
field :: Term -> Int -> IO Term | |
field t i = do | |
got (tLoc t + fromIntegral i) | |
-- | Allocates a node and fills its children, returning the parent Term. | |
-- If the list of children is empty we return a leaf term (loc = 0). | |
makeNode :: Tag -> Lab -> [Term] -> IO Term | |
makeNode tag lab cs | |
| null cs = do | |
pure (termNew tag lab 0) | |
| otherwise = do | |
ptr <- allocNode (fromIntegral (length cs)) | |
mapM_ (\ (i, c) -> set (ptr + fromIntegral i) c) (zip [0 ..] cs) | |
pure (termNew tag lab ptr) | |
-- | Gets a fresh label and increments the counter | |
getFreshLabel :: IO Lab | |
getFreshLabel = do | |
lab <- readIORef freshLabelCounter | |
modifyIORef' freshLabelCounter (+1) | |
pure lab | |
-- | Create a DUP node that holds the original term, and return two DP0/DP1 terms | |
-- with the specified label | |
makeDup :: Lab -> Term -> IO (Term, Term) | |
makeDup lab term = do | |
-- Create a DUP node to hold the original term | |
dup <- makeNode _DUP_ lab [term] | |
-- Create the DP0/DP1 terms (leaf terms with the shared label) | |
let t0 = termNew _DP0_ lab 0 | |
let t1 = termNew _DP1_ lab 0 | |
-- Return the DP0/DP1 terms | |
pure (t0, t1) | |
-- | Create a DUP node with a fresh label | |
makeDupFresh :: Term -> IO (Term, Term) | |
makeDupFresh term = do | |
-- Get a fresh label | |
freshLab <- getFreshLabel | |
makeDup freshLab term | |
-- Structural equality - returns nilT for equal, eraT for not equal | |
equal :: Int -> Term -> Term -> IO Term | |
equal dep a0 b0 = do | |
a <- whnf a0 | |
b <- whnf b0 | |
if a == b | |
then pure nilT | |
else equalGo dep a b | |
-- | Boolean 'and', but for One|Era. | |
both :: Term -> Term -> IO Term | |
both a b | |
| tTag a == _SUP_ = do | |
a0 <- field a 0 | |
a1 <- field a 1 | |
-- Use the SUP's label when duplicating b | |
(b0, b1) <- makeDup (tLab a) b | |
r0 <- both a0 b0 | |
r1 <- both a1 b1 | |
makeNode _SUP_ (tLab a) [r0, r1] | |
| tTag b == _SUP_ = do | |
b0 <- field b 0 | |
b1 <- field b 1 | |
-- Use the SUP's label when duplicating a | |
(a0, a1) <- makeDup (tLab b) a | |
r0 <- both a0 b0 | |
r1 <- both a1 b1 | |
makeNode _SUP_ (tLab b) [r0, r1] | |
| tTag a == _NIL_ && tTag b == _NIL_ = do | |
pure nilT | |
| otherwise = do | |
pure eraT | |
equalGo :: Int -> Term -> Term -> IO Term | |
equalGo dep a b | |
| tTag a == _SUP_ = do | |
a0 <- field a 0 | |
a1 <- field a 1 | |
(b0, b1) <- makeDup (tLab a) b | |
r0 <- equalGo dep a0 b0 | |
r1 <- equalGo dep a1 b1 | |
makeNode _SUP_ (tLab a) [r0, r1] | |
| tTag b == _SUP_ = do | |
b0 <- field b 0 | |
b1 <- field b 1 | |
(a0, a1) <- makeDup (tLab b) a | |
r0 <- equalGo dep a0 b0 | |
r1 <- equalGo dep a1 b1 | |
makeNode _SUP_ (tLab b) [r0, r1] | |
| tTag a == _ERA_ && tTag b == _ERA_ = do | |
pure nilT | |
| tTag a == _SET_ && tTag b == _SET_ = do | |
pure nilT | |
| tTag a == _EMP_ && tTag b == _EMP_ = do | |
pure nilT | |
| tTag a == _UNI_ && tTag b == _UNI_ = do | |
pure nilT | |
| tTag a == _NIL_ && tTag b == _NIL_ = do | |
pure nilT | |
| tTag a == _U32_ && tTag b == _U32_ = do | |
pure nilT | |
| tTag a == _W32_ && tTag b == _W32_ = do | |
if tLab a == tLab b | |
then pure nilT | |
else pure eraT | |
| tTag a == _SIG_ && tTag b == _SIG_ = do | |
ax <- field a 0 | |
ay <- field a 1 | |
bx <- field b 0 | |
by <- field b 1 | |
rx <- equalGo dep ax bx | |
ry <- equalGo dep ay by | |
both rx ry | |
| tTag a == _TUP_ && tTag b == _TUP_ = do | |
ax <- field a 0 | |
ay <- field a 1 | |
bx <- field b 0 | |
by <- field b 1 | |
rx <- equalGo dep ax bx | |
ry <- equalGo dep ay by | |
both rx ry | |
| tTag a == _ALL_ && tTag b == _ALL_ = do | |
aa <- field a 0 | |
ab <- field a 1 | |
ba <- field b 0 | |
bb <- field b 1 | |
ra <- equalGo dep aa ba | |
rb <- equalGo dep ab bb | |
both ra rb | |
| tTag a == _LAM_ && tTag b == _LAM_ = do | |
ab <- field a 0 | |
bb <- field b 0 | |
equalGo (dep+1) ab bb | |
| tTag a == _APP_ && tTag b == _APP_ = do | |
af <- field a 0 | |
ax <- field a 1 | |
bf <- field b 0 | |
bx <- field b 1 | |
rf <- equalGo dep af bf | |
rx <- equalGo dep ax bx | |
both rf rx | |
| tTag a == _ANN_ && tTag b == _ANN_ = do | |
av <- field a 0 | |
at <- field a 1 | |
bv <- field b 0 | |
bt <- field b 1 | |
rv <- equalGo dep av bv | |
rt <- equalGo dep at bt | |
both rv rt | |
| otherwise = do | |
pure eraT | |
-- Inference | |
infer :: Int -> Term -> IO Term | |
infer dep term0 = do | |
term <- whnf term0 | |
inferGo dep term | |
inferGo :: Int -> Term -> IO Term | |
inferGo dep term | |
| tTag term == _SUP_ = do | |
a <- field term 0 | |
b <- field term 1 | |
aType <- inferGo dep a | |
bType <- inferGo dep b | |
makeNode _SUP_ (tLab term) [aType, bType] | |
| tTag term == _VAR_ = do | |
putStr "(cant-infer-var)" | |
pure eraT | |
| tTag term == _REF_ = do | |
putStr "(cant-infer-ref)" | |
pure eraT | |
| tTag term == _LET_ = do | |
val <- field term 0 | |
bod <- field term 1 | |
valType <- infer dep val | |
if tTag valType == _ERA_ | |
then pure eraT | |
else infer (dep+1) bod | |
| tTag term == _ERA_ = do | |
pure setT | |
| tTag term == _SET_ = do | |
pure setT | |
| tTag term == _EMP_ = do | |
pure setT | |
| tTag term == _EFQ_ = do | |
x <- field term 0 | |
rc <- check dep x empT | |
if tTag rc == _ERA_ | |
then pure eraT | |
else do | |
lamB <- makeNode _LAM_ 0 [empT] | |
makeNode _ALL_ 0 [empT, lamB] | |
| tTag term == _UNI_ = do | |
pure setT | |
| tTag term == _NIL_ = do | |
pure uniT | |
| tTag term == _USE_ = do | |
putStr "(cant-infer-use)" | |
pure eraT | |
| tTag term == _U32_ = do | |
pure setT | |
| tTag term == _W32_ = do | |
pure u32T | |
| tTag term == _SWI_ = do | |
putStr "(cant-infer-swi)" | |
pure eraT | |
| tTag term == _OPX_ || tTag term == _OPY_ = do | |
putStr "(cant-infer-op)" | |
pure eraT | |
| tTag term == _SIG_ = do | |
a <- field term 0 | |
b <- field term 1 | |
(a0, a1) <- makeDupFresh a | |
aOk <- check dep a0 setT | |
if tTag aOk == _ERA_ | |
then pure eraT | |
else do | |
lamT <- makeNode _LAM_ 0 [setT] | |
allT <- makeNode _ALL_ 0 [a1, lamT] | |
bOk <- check dep b allT | |
if tTag bOk == _ERA_ | |
then pure eraT | |
else pure setT | |
| tTag term == _TUP_ = do | |
a <- field term 0 | |
b <- field term 1 | |
aType <- infer dep a | |
if tTag aType == _ERA_ | |
then pure eraT | |
else do | |
bType <- infer dep b | |
if tTag bType == _ERA_ | |
then pure eraT | |
else do | |
lamB <- makeNode _LAM_ 0 [bType] | |
makeNode _SIG_ 0 [aType, lamB] | |
| tTag term == _GET_ = do | |
putStr "(cant-infer-get)" | |
pure eraT | |
| tTag term == _ALL_ = do | |
a <- field term 0 | |
b <- field term 1 | |
aOk <- check dep a setT | |
if tTag aOk == _ERA_ | |
then pure eraT | |
else do | |
lamT <- makeNode _LAM_ 0 [setT] | |
allT <- makeNode _ALL_ 0 [setT, lamT] | |
bOk <- check dep b allT | |
if tTag bOk == _ERA_ | |
then pure eraT | |
else pure setT | |
| tTag term == _LAM_ = do | |
putStr "(cant-infer-lam)" | |
pure eraT | |
| tTag term == _APP_ = do | |
f <- field term 0 | |
x <- field term 1 | |
(x0, x1) <- makeDupFresh x | |
fType <- infer dep f | |
if tTag fType == _ERA_ | |
then pure eraT | |
else do | |
fTypeNf <- whnf fType | |
if tTag fTypeNf /= _ALL_ | |
then do | |
putStr "(non-fun-app)" | |
pure eraT | |
else do | |
a <- field fTypeNf 0 | |
b <- field fTypeNf 1 | |
xOk <- check dep x0 a | |
if tTag xOk == _ERA_ | |
then pure eraT | |
else do | |
app <- makeNode _APP_ 0 [b, x1] | |
whnf app | |
| tTag term == _ANN_ = do | |
x <- field term 0 | |
ty <- field term 1 | |
rc <- check dep x ty | |
if tTag rc == _ERA_ | |
then pure eraT | |
else pure ty | |
| otherwise = do | |
putStr $ "(cant-infer-unknown)" | |
pure eraT | |
-- Checking | |
check :: Int -> Term -> Term -> IO Term | |
check dep term0 goal0 = do | |
term <- whnf term0 | |
goal <- whnf goal0 | |
checkGo dep term goal | |
checkGo :: Int -> Term -> Term -> IO Term | |
checkGo dep term goal | |
| tTag term == _SUP_ = do | |
a <- field term 0 | |
b <- field term 1 | |
-- Use the SUP's label when duplicating goal | |
(goal0, goal1) <- makeDup (tLab term) goal | |
ra <- checkGo dep a goal0 | |
rb <- checkGo dep b goal1 | |
makeNode _SUP_ (tLab term) [ra, rb] | |
| tTag goal == _SUP_ = do | |
a <- field goal 0 | |
b <- field goal 1 | |
-- Use the SUP's label when duplicating term | |
(term0, term1) <- makeDup (tLab goal) term | |
ra <- checkGo dep term0 a | |
rb <- checkGo dep term1 b | |
makeNode _SUP_ (tLab goal) [ra, rb] | |
| tTag term == _ERA_ = do | |
pure nilT | |
| tTag term == _NIL_ && tTag goal == _UNI_ = do | |
pure nilT | |
| tTag term == _W32_ && tTag goal == _U32_ = do | |
pure nilT | |
| tTag term == _SET_ && tTag goal == _SET_ = do | |
pure nilT | |
| tTag term == _EMP_ && tTag goal == _SET_ = do | |
pure nilT | |
| tTag term == _UNI_ && tTag goal == _SET_ = do | |
pure nilT | |
| tTag term == _U32_ && tTag goal == _SET_ = do | |
pure nilT | |
| tTag term == _SIG_ && tTag goal == _SET_ = do | |
a <- field term 0 | |
b <- field term 1 | |
-- Duplicate 'a' before first use | |
(a0, a1) <- makeDupFresh a | |
aOk <- check dep a0 setT | |
if tTag aOk == _ERA_ | |
then pure eraT | |
else do | |
lamT <- makeNode _LAM_ 0 [setT] | |
allT <- makeNode _ALL_ 0 [a1, lamT] | |
bOk <- check dep b allT | |
if tTag bOk == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _ALL_ && tTag goal == _SET_ = do | |
a <- field term 0 | |
b <- field term 1 | |
aOk <- check dep a setT | |
if tTag aOk == _ERA_ | |
then pure eraT | |
else do | |
lamT <- makeNode _LAM_ 0 [setT] | |
allT <- makeNode _ALL_ 0 [setT, lamT] | |
bOk <- check dep b allT | |
if tTag bOk == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _LAM_ && tTag goal == _ALL_ = do | |
print "a" | |
f <- field term 0 | |
a <- field goal 0 | |
b <- field goal 1 | |
(a0, a1) <- makeDupFresh a | |
-- Create fresh variables for the lambda binding | |
var0 <- makeNode _VAR_ (fromIntegral dep) [] | |
var1 <- makeNode _VAR_ (fromIntegral dep) [] | |
-- Annotate variables with types | |
ann0 <- makeNode _ANN_ 0 [var0, a0] | |
ann1 <- makeNode _ANN_ 0 [var1, a1] | |
-- Apply function body and type body to variable | |
appF <- makeNode _APP_ 0 [f, ann0] | |
appB <- makeNode _APP_ 0 [b, ann1] | |
appB_nf <- whnf appB | |
print $ showTerm b | |
-- Check with increased depth | |
check (dep + 1) appF appB_nf | |
| tTag term == _TUP_ && tTag goal == _SIG_ = do | |
a <- field term 0 | |
b <- field term 1 | |
aTy <- field goal 0 | |
bTy <- field goal 1 | |
-- Duplicate 'a' before first use | |
(a0, a1) <- makeDupFresh a | |
-- Check first component | |
aOk <- check dep a0 aTy | |
if tTag aOk == _ERA_ | |
then pure eraT | |
else do | |
-- Apply dependent type to first component | |
app <- makeNode _APP_ 0 [bTy, a1] | |
bTyA <- whnf app | |
-- Check second component | |
bOk <- check dep b bTyA | |
if tTag bOk == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _EFQ_ = do | |
c <- field term 0 | |
rc <- check dep c empT | |
if tTag rc == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _USE_ = do | |
c <- field term 0 | |
f <- field term 1 | |
rc <- check dep c uniT | |
if tTag rc == _ERA_ | |
then pure eraT | |
else do | |
rf <- check dep f goal | |
if tTag rf == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _GET_ = do | |
c <- field term 0 | |
f <- field term 1 | |
cType <- infer dep c | |
if tTag cType == _ERA_ | |
then pure eraT | |
else do | |
cTypeNf <- whnf cType | |
if tTag cTypeNf /= _SIG_ | |
then do | |
putStr "(expected-pair-type)" | |
pure eraT | |
else do | |
rf <- check dep f goal | |
if tTag rf == _ERA_ | |
then pure eraT | |
else pure nilT | |
| tTag term == _SWI_ = do | |
c <- field term 0 | |
z <- field term 1 | |
s <- field term 2 | |
rc <- check dep c u32T | |
if tTag rc == _ERA_ | |
then pure eraT | |
else do | |
-- Get a fresh label for duplicating the goal | |
freshLab <- getFreshLabel | |
(goal0, goal1) <- makeDup freshLab goal | |
rz <- check dep z goal0 | |
if tTag rz == _ERA_ | |
then pure eraT | |
else do | |
rs <- check dep s goal1 | |
if tTag rs == _ERA_ | |
then pure eraT | |
else pure nilT | |
| otherwise = do | |
ty <- infer dep term | |
if tTag ty == _ERA_ | |
then pure eraT | |
else do | |
eq <- equal dep ty goal | |
if tTag eq == _NIL_ | |
then pure nilT | |
else do | |
putStr "(type-mismatch)" | |
pure eraT | |
-- PROBLEM: I'm trying to type-check the following file: | |
-- @main = <λx.123 : ∀x:U32.U32> | |
-- But I get the following error: | |
-- Press ENTER or type command to continue | |
-- <λa.123 : ∀U32.λb.U32> | |
-- Checking @main... "a" | |
-- "term_new(LAM,0x000000,0x0000000c)" | |
-- invalid:app-w32 1.02 real 0.76 user 0.10 sys | |
-- Why? | |
just answer below why this bug is happening and nothing else | |
The bug "invalid:app-w32" occurs because the term (123 ann0) (where 123 is the body of the lambda λx.123, and ann0 is a fresh annotated variable representing x:U32) is being evaluated by whnf (via Reduce.hs or Runtime.c). The Interaction Calculus runtime (and HVM) does not allow a number (like 123, a W32 term) to be in the function position of an application; this is a runtime error. | |
Here's the trace of why this happens in your Check.hs: | |
Initial Check: You are checking @main = <λx.123 : ∀x:U32.U32>. The inferGo rule for _ANN_ is invoked. | |
x (term being annotated) = λx.123 | |
ty (the annotation type) = ∀x:U32.U32 | |
This rule calls: check dep (λx.123) (∀x:U32.U32) | |
check function call: | |
check :: Int -> Term -> Term -> IO Term | |
check dep term0 goal0 = do | |
term <- whnf term0 -- term0 is λx.123. whnf(λx.123) is λx.123. (OK so far) | |
goal <- whnf goal0 -- goal0 is ∀x:U32.U32. whnf(∀x:U32.U32) is ∀x:U32.U32. (OK so far) | |
checkGo dep term goal | |
Use code with caution. | |
Haskell | |
So, checkGo dep (λx.123) (∀x:U32.U32) is called. | |
checkGo for _LAM_ and _ALL_: This rule matches. | |
term = λx.123 | |
goal = ∀x:U32.U32 | |
Inside this rule: | |
f (lambda body) = 123 | |
a (quantified type in ∀) = U32 | |
b (type body in ∀) = λb'.U32 (where b' is the type variable) | |
An application appF is constructed: appF = (f ann0) = (123 ann0). | |
A type appB_nf is constructed (and normalized): appB_nf = whnf((b ann1)) = U32. | |
Then, a recursive call to check is made: check (dep + 1) appF appB_nf, which is check (dep + 1) (123 ann0) U32. | |
Recursive check function call: | |
term0 is now (123 ann0). | |
goal0 is now U32. | |
check :: Int -> Term -> Term -> IO Term | |
check dep term0 goal0 = do | |
term <- whnf term0 -- HERE IS THE PROBLEM: term0 is (123 ann0). | |
-- whnf((123 ann0)) is called. | |
-- The HVM runtime attempts to reduce (123 ann0). | |
-- Since 123 is a W32, this triggers the reduce_app_w32 rule, | |
-- which prints "invalid:app-w32" and exits. | |
goal <- whnf goal0 | |
checkGo dep term goal | |
Use code with caution. | |
Haskell | |
The whnf call on term0 at the beginning of your check function (and similarly in your infer function) is too eager. It attempts to normalize the term being checked before its syntactic structure is analyzed by checkGo. When checkGo's LAM-ALL rule constructs an application appF that would be ill-formed at runtime (like applying a number), and this appF is passed back to check, this initial whnf call triggers the runtime error. | |
The type checker should instead try to infer the type of (123 ann0). The inferGo rule for _APP_ would find that 123 has type U32, which is not a function type (∀...), and correctly report a type error like "(non-fun-app)" without trying to evaluate (123 ann0). This requires infer (and check) not to whnf their main term argument immediately upon entry, but rather pass it structurally to inferGo/checkGo, which can then decide if whnf is needed for specific sub-parts or specific rules. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment