mirror of
https://github.com/urbit/ares.git
synced 2024-12-25 14:23:06 +03:00
Merge branch 'status' into fast-jets
This commit is contained in:
commit
9f147bcb2c
2
.github/workflows/ares-shared.yml
vendored
2
.github/workflows/ares-shared.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
|||||||
-A clippy::missing_safety_doc
|
-A clippy::missing_safety_doc
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --release --verbose
|
run: cargo build --release --verbose --features check_all
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --verbose -- --test-threads=1
|
run: cargo test --verbose -- --test-threads=1
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
:: A small pill that runs a snasphot of azimuth state against a few
|
:: A small pill that runs a snasphot of azimuth state against a few tens of
|
||||||
:: tens of thousands of logs. Requires naive-cradle.hoon,
|
:: thousands of logs. Requires naive-cradle.hoon,
|
||||||
:: mainnet.azimuth-snapshot, and log.jam from this scaffolding
|
:: mainnet.azimuth-snapshot, and log.jam from this scaffolding directory.
|
||||||
:: directory.
|
|
||||||
::
|
::
|
||||||
/+ naive=naive-cradle, orig-naive=naive, ethereum, dice
|
/+ naive=naive-cradle, orig-naive=naive, ethereum, dice
|
||||||
/* snap %azimuth-snapshot /lib/mainnet/azimuth-snapshot
|
/* snap %azimuth-snapshot /lib/mainnet/azimuth-snapshot
|
||||||
@ -236,7 +235,6 @@
|
|||||||
++ swp :: naive rev bloq order
|
++ swp :: naive rev bloq order
|
||||||
~/ %swp
|
~/ %swp
|
||||||
|= [a=bloq b=@]
|
|= [a=bloq b=@]
|
||||||
~> %sham.%swp
|
|
||||||
(rep a (flop (rip a b)))
|
(rep a (flop (rip a b)))
|
||||||
::
|
::
|
||||||
++ met :: measure
|
++ met :: measure
|
||||||
@ -312,7 +310,6 @@
|
|||||||
++ lent :: length
|
++ lent :: length
|
||||||
~/ %lent
|
~/ %lent
|
||||||
|= a=(list)
|
|= a=(list)
|
||||||
~> %sham.%lent
|
|
||||||
^- @
|
^- @
|
||||||
=+ b=0
|
=+ b=0
|
||||||
|-
|
|-
|
||||||
@ -322,7 +319,6 @@
|
|||||||
++ slag :: suffix
|
++ slag :: suffix
|
||||||
~/ %slag
|
~/ %slag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%slag
|
|
||||||
|- ^+ b
|
|- ^+ b
|
||||||
?: =(0 a) b
|
?: =(0 a) b
|
||||||
?~ b ~
|
?~ b ~
|
||||||
@ -331,7 +327,6 @@
|
|||||||
++ snag :: index
|
++ snag :: index
|
||||||
~/ %snag
|
~/ %snag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%snag
|
|
||||||
|- ^+ ?>(?=(^ b) i.b)
|
|- ^+ ?>(?=(^ b) i.b)
|
||||||
?~ b
|
?~ b
|
||||||
~_ leaf+"snag-fail"
|
~_ leaf+"snag-fail"
|
||||||
@ -349,7 +344,6 @@
|
|||||||
++ flop :: reverse
|
++ flop :: reverse
|
||||||
~/ %flop
|
~/ %flop
|
||||||
|* a=(list)
|
|* a=(list)
|
||||||
~> %sham.%flop
|
|
||||||
=> .(a (homo a))
|
=> .(a (homo a))
|
||||||
^+ a
|
^+ a
|
||||||
=+ b=`_a`~
|
=+ b=`_a`~
|
||||||
@ -360,7 +354,6 @@
|
|||||||
++ welp :: concatenate
|
++ welp :: concatenate
|
||||||
~/ %welp
|
~/ %welp
|
||||||
=| [* *]
|
=| [* *]
|
||||||
~> %sham.%welp
|
|
||||||
|@
|
|@
|
||||||
++ $
|
++ $
|
||||||
?~ +<-
|
?~ +<-
|
||||||
@ -371,7 +364,6 @@
|
|||||||
++ reap :: replicate
|
++ reap :: replicate
|
||||||
~/ %reap
|
~/ %reap
|
||||||
|* [a=@ b=*]
|
|* [a=@ b=*]
|
||||||
~> %sham.%reap
|
|
||||||
|- ^- (list _b)
|
|- ^- (list _b)
|
||||||
?~ a ~
|
?~ a ~
|
||||||
[b $(a (dec a))]
|
[b $(a (dec a))]
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
:: A trivial working pill which requires no jets
|
:: A trivial working pill which requires no jets. Requires cradle.hoon
|
||||||
|
:: from this scaffolding directory.
|
||||||
|
::
|
||||||
/+ cradle
|
/+ cradle
|
||||||
!.
|
!.
|
||||||
=/ core
|
=/ core
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
:: This file is just tiny.hoon from urbit/urbit (but with sham jets). Required
|
||||||
|
:: to run baby.hoon as an Arvo.
|
||||||
|
::
|
||||||
!.
|
!.
|
||||||
=> %a50
|
=> %a50
|
||||||
~% %a.50 ~ ~
|
~% %a.50 ~ ~
|
||||||
@ -206,7 +209,6 @@
|
|||||||
++ swp :: naive rev bloq order
|
++ swp :: naive rev bloq order
|
||||||
~/ %swp
|
~/ %swp
|
||||||
|= [a=bloq b=@]
|
|= [a=bloq b=@]
|
||||||
~> %sham.%swp
|
|
||||||
(rep a (flop (rip a b)))
|
(rep a (flop (rip a b)))
|
||||||
::
|
::
|
||||||
++ met :: measure
|
++ met :: measure
|
||||||
@ -282,7 +284,6 @@
|
|||||||
++ lent :: length
|
++ lent :: length
|
||||||
~/ %lent
|
~/ %lent
|
||||||
|= a=(list)
|
|= a=(list)
|
||||||
~> %sham.%lent
|
|
||||||
^- @
|
^- @
|
||||||
=+ b=0
|
=+ b=0
|
||||||
|-
|
|-
|
||||||
@ -292,7 +293,6 @@
|
|||||||
++ slag :: suffix
|
++ slag :: suffix
|
||||||
~/ %slag
|
~/ %slag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%slag
|
|
||||||
|- ^+ b
|
|- ^+ b
|
||||||
?: =(0 a) b
|
?: =(0 a) b
|
||||||
?~ b ~
|
?~ b ~
|
||||||
@ -301,7 +301,6 @@
|
|||||||
++ snag :: index
|
++ snag :: index
|
||||||
~/ %snag
|
~/ %snag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%snag
|
|
||||||
|- ^+ ?>(?=(^ b) i.b)
|
|- ^+ ?>(?=(^ b) i.b)
|
||||||
?~ b
|
?~ b
|
||||||
~_ leaf+"snag-fail"
|
~_ leaf+"snag-fail"
|
||||||
@ -319,7 +318,6 @@
|
|||||||
++ flop :: reverse
|
++ flop :: reverse
|
||||||
~/ %flop
|
~/ %flop
|
||||||
|* a=(list)
|
|* a=(list)
|
||||||
~> %sham.%flop
|
|
||||||
=> .(a (homo a))
|
=> .(a (homo a))
|
||||||
^+ a
|
^+ a
|
||||||
=+ b=`_a`~
|
=+ b=`_a`~
|
||||||
@ -330,7 +328,6 @@
|
|||||||
++ welp :: concatenate
|
++ welp :: concatenate
|
||||||
~/ %welp
|
~/ %welp
|
||||||
=| [* *]
|
=| [* *]
|
||||||
~> %sham.%welp
|
|
||||||
|@
|
|@
|
||||||
++ $
|
++ $
|
||||||
?~ +<-
|
?~ +<-
|
||||||
@ -341,7 +338,6 @@
|
|||||||
++ reap :: replicate
|
++ reap :: replicate
|
||||||
~/ %reap
|
~/ %reap
|
||||||
|* [a=@ b=*]
|
|* [a=@ b=*]
|
||||||
~> %sham.%reap
|
|
||||||
|- ^- (list _b)
|
|- ^- (list _b)
|
||||||
?~ a ~
|
?~ a ~
|
||||||
[b $(a (dec a))]
|
[b $(a (dec a))]
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
:: This file is a combination of tiny.hoon and naive.hoon from urbit/urbit
|
||||||
|
:: (but with sham jets). Required to run azimuth-pill.hoon as an Arvo.
|
||||||
|
::
|
||||||
!.
|
!.
|
||||||
!=
|
!=
|
||||||
:: begin cradle.hoon
|
:: begin tiny.hoon
|
||||||
=>
|
=>
|
||||||
=> %a50
|
=> %a50
|
||||||
~% %a.50 ~ ~
|
~% %a.50 ~ ~
|
||||||
@ -209,7 +212,6 @@
|
|||||||
++ swp :: naive rev bloq order
|
++ swp :: naive rev bloq order
|
||||||
~/ %swp
|
~/ %swp
|
||||||
|= [a=bloq b=@]
|
|= [a=bloq b=@]
|
||||||
~> %sham.%swp
|
|
||||||
(rep a (flop (rip a b)))
|
(rep a (flop (rip a b)))
|
||||||
::
|
::
|
||||||
++ met :: measure
|
++ met :: measure
|
||||||
@ -285,7 +287,6 @@
|
|||||||
++ lent :: length
|
++ lent :: length
|
||||||
~/ %lent
|
~/ %lent
|
||||||
|= a=(list)
|
|= a=(list)
|
||||||
~> %sham.%lent
|
|
||||||
^- @
|
^- @
|
||||||
=+ b=0
|
=+ b=0
|
||||||
|-
|
|-
|
||||||
@ -295,7 +296,6 @@
|
|||||||
++ slag :: suffix
|
++ slag :: suffix
|
||||||
~/ %slag
|
~/ %slag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%slag
|
|
||||||
|- ^+ b
|
|- ^+ b
|
||||||
?: =(0 a) b
|
?: =(0 a) b
|
||||||
?~ b ~
|
?~ b ~
|
||||||
@ -304,7 +304,6 @@
|
|||||||
++ snag :: index
|
++ snag :: index
|
||||||
~/ %snag
|
~/ %snag
|
||||||
|* [a=@ b=(list)]
|
|* [a=@ b=(list)]
|
||||||
~> %sham.%snag
|
|
||||||
|- ^+ ?>(?=(^ b) i.b)
|
|- ^+ ?>(?=(^ b) i.b)
|
||||||
?~ b
|
?~ b
|
||||||
~_ leaf+"snag-fail"
|
~_ leaf+"snag-fail"
|
||||||
@ -322,7 +321,6 @@
|
|||||||
++ flop :: reverse
|
++ flop :: reverse
|
||||||
~/ %flop
|
~/ %flop
|
||||||
|* a=(list)
|
|* a=(list)
|
||||||
~> %sham.%flop
|
|
||||||
=> .(a (homo a))
|
=> .(a (homo a))
|
||||||
^+ a
|
^+ a
|
||||||
=+ b=`_a`~
|
=+ b=`_a`~
|
||||||
@ -333,7 +331,6 @@
|
|||||||
++ welp :: concatenate
|
++ welp :: concatenate
|
||||||
~/ %welp
|
~/ %welp
|
||||||
=| [* *]
|
=| [* *]
|
||||||
~> %sham.%welp
|
|
||||||
|@
|
|@
|
||||||
++ $
|
++ $
|
||||||
?~ +<-
|
?~ +<-
|
||||||
@ -344,7 +341,6 @@
|
|||||||
++ reap :: replicate
|
++ reap :: replicate
|
||||||
~/ %reap
|
~/ %reap
|
||||||
|* [a=@ b=*]
|
|* [a=@ b=*]
|
||||||
~> %sham.%reap
|
|
||||||
|- ^- (list _b)
|
|- ^- (list _b)
|
||||||
?~ a ~
|
?~ a ~
|
||||||
[b $(a (dec a))]
|
[b $(a (dec a))]
|
||||||
|
874
hoon/scaffolding/playpen.hoon
Normal file
874
hoon/scaffolding/playpen.hoon
Normal file
@ -0,0 +1,874 @@
|
|||||||
|
:: This file aims to approach hoon.hoon, as the pieces necessary to run a live
|
||||||
|
:: ship with Ares as Serf are written. Required to run toddler.hoon as an Arvo.
|
||||||
|
::
|
||||||
|
!.
|
||||||
|
=> %a50
|
||||||
|
~% %a.50 ~ ~
|
||||||
|
|%
|
||||||
|
::
|
||||||
|
:: Types
|
||||||
|
::
|
||||||
|
+$ cord @t
|
||||||
|
+$ knot @ta
|
||||||
|
+$ term @tas
|
||||||
|
+$ char @t
|
||||||
|
+$ ship @p
|
||||||
|
+$ life @ud
|
||||||
|
+$ rift @ud
|
||||||
|
+$ pass @
|
||||||
|
+$ bloq @
|
||||||
|
+$ step _`@u`1
|
||||||
|
+$ bite $@(bloq [=bloq =step])
|
||||||
|
+$ octs [p=@ud q=@]
|
||||||
|
+$ dime [p=@ta q=@]
|
||||||
|
+$ pint [p=[p=@ q=@] q=[p=@ q=@]]
|
||||||
|
+$ spot [p=path q=pint]
|
||||||
|
+$ mold $~(* $-(* *))
|
||||||
|
++ unit |$ [item] $@(~ [~ u=item])
|
||||||
|
++ list |$ [item] $@(~ [i=item t=(list item)])
|
||||||
|
++ lest |$ [item] [i=item t=(list item)]
|
||||||
|
+$ tape (list @tD)
|
||||||
|
+$ path (list knot)
|
||||||
|
+$ coin $~ [%$ %ud 0]
|
||||||
|
$% [%$ p=dime]
|
||||||
|
[%blob p=*]
|
||||||
|
[%many p=(list coin)]
|
||||||
|
==
|
||||||
|
+$ tone $% [%0 product=*]
|
||||||
|
[%1 block=*]
|
||||||
|
[%2 trace=(list [@ta *])]
|
||||||
|
==
|
||||||
|
++ pair
|
||||||
|
|$ [head tail]
|
||||||
|
[p=head q=tail]
|
||||||
|
++ trel
|
||||||
|
|$ [first second third]
|
||||||
|
[p=first q=second r=third]
|
||||||
|
++ qual
|
||||||
|
|$ [first second third fourth]
|
||||||
|
[p=first q=second r=third s=fourth]
|
||||||
|
+$ tank
|
||||||
|
$+ tank
|
||||||
|
$~ leaf/~
|
||||||
|
$@ cord
|
||||||
|
$% [%leaf p=tape]
|
||||||
|
[%palm p=(qual tape tape tape tape) q=(list tank)]
|
||||||
|
[%rose p=(trel tape tape tape) q=(list tank)]
|
||||||
|
==
|
||||||
|
+$ tang (list tank)
|
||||||
|
+$ toon $% [%0 p=*]
|
||||||
|
[%1 p=*]
|
||||||
|
[%2 p=tang]
|
||||||
|
==
|
||||||
|
++ tree |$ [node] $@(~ [n=node l=(tree node) r=(tree node)])
|
||||||
|
++ gate $-(* *)
|
||||||
|
::
|
||||||
|
++ map
|
||||||
|
|$ [key value]
|
||||||
|
$| (tree (pair key value))
|
||||||
|
|=(a=(tree (pair)) ?:(=(~ a) & ~(apt by a)))
|
||||||
|
::
|
||||||
|
++ set
|
||||||
|
|$ [item]
|
||||||
|
$| (tree item)
|
||||||
|
|=(a=(tree) ?:(=(~ a) & ~(apt in a)))
|
||||||
|
::
|
||||||
|
++ jug |$ [key value] (map key (set value))
|
||||||
|
::
|
||||||
|
:: Basic arithmetic
|
||||||
|
::
|
||||||
|
++ add :: unsigned addition
|
||||||
|
~/ %add
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%add
|
||||||
|
^- @
|
||||||
|
?: =(0 a) b
|
||||||
|
$(a (dec a), b +(b))
|
||||||
|
::
|
||||||
|
++ dec :: decrement
|
||||||
|
~/ %dec
|
||||||
|
|= a=@
|
||||||
|
~> %sham.%dec
|
||||||
|
~_ leaf+"decrement-underflow"
|
||||||
|
?< =(0 a)
|
||||||
|
=+ b=0
|
||||||
|
|- ^- @
|
||||||
|
?: =(a +(b)) b
|
||||||
|
$(b +(b))
|
||||||
|
::
|
||||||
|
++ div :: divide
|
||||||
|
~/ %div
|
||||||
|
|: [a=`@`1 b=`@`1]
|
||||||
|
~> %sham.%div
|
||||||
|
^- @
|
||||||
|
~_ leaf+"divide-by-zero"
|
||||||
|
?< =(0 b)
|
||||||
|
=+ c=0
|
||||||
|
|-
|
||||||
|
?: (lth a b) c
|
||||||
|
$(a (sub a b), c +(c))
|
||||||
|
::
|
||||||
|
++ dvr :: divide w/remainder
|
||||||
|
~/ %dvr
|
||||||
|
|: [a=`@`1 b=`@`1]
|
||||||
|
~> %sham.%dvr
|
||||||
|
^- [p=@ q=@]
|
||||||
|
[(div a b) (mod a b)]
|
||||||
|
::
|
||||||
|
++ gte :: greater or equal
|
||||||
|
~/ %gte
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%gte
|
||||||
|
^- ?
|
||||||
|
!(lth a b)
|
||||||
|
::
|
||||||
|
++ gth :: greater
|
||||||
|
~/ %gth
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%gth
|
||||||
|
^- ?
|
||||||
|
!(lte a b)
|
||||||
|
::
|
||||||
|
++ lte :: less or equal
|
||||||
|
~/ %lte
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%lte
|
||||||
|
|(=(a b) (lth a b))
|
||||||
|
::
|
||||||
|
++ lth :: less
|
||||||
|
~/ %lth
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%lth
|
||||||
|
^- ?
|
||||||
|
?& !=(a b)
|
||||||
|
|-
|
||||||
|
?| =(0 a)
|
||||||
|
?& !=(0 b)
|
||||||
|
$(a (dec a), b (dec b))
|
||||||
|
== == ==
|
||||||
|
::
|
||||||
|
++ mod :: modulus
|
||||||
|
~/ %mod
|
||||||
|
|: [a=`@`1 b=`@`1]
|
||||||
|
~> %sham.%mod
|
||||||
|
^- @
|
||||||
|
?< =(0 b)
|
||||||
|
(sub a (mul b (div a b)))
|
||||||
|
::
|
||||||
|
++ mul :: multiply
|
||||||
|
~/ %mul
|
||||||
|
|: [a=`@`1 b=`@`1]
|
||||||
|
~> %sham.%mul
|
||||||
|
^- @
|
||||||
|
=+ c=0
|
||||||
|
|-
|
||||||
|
?: =(0 a) c
|
||||||
|
$(a (dec a), c (add b c))
|
||||||
|
::
|
||||||
|
++ sub :: subtract
|
||||||
|
~/ %sub
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%sub
|
||||||
|
~_ leaf+"subtract-underflow"
|
||||||
|
:: difference
|
||||||
|
^- @
|
||||||
|
?: =(0 b) a
|
||||||
|
$(a (dec a), b (dec b))
|
||||||
|
::
|
||||||
|
:: Tree addressing
|
||||||
|
::
|
||||||
|
++ cap :: index in head or tail
|
||||||
|
~/ %cap
|
||||||
|
|= a=@
|
||||||
|
~> %sham.%cap
|
||||||
|
^- ?(%2 %3)
|
||||||
|
?- a
|
||||||
|
%2 %2
|
||||||
|
%3 %3
|
||||||
|
?(%0 %1) !!
|
||||||
|
* $(a (div a 2))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ mas :: axis within head/tail
|
||||||
|
~/ %mas
|
||||||
|
|= a=@
|
||||||
|
~> %sham.%mas
|
||||||
|
^- @
|
||||||
|
?- a
|
||||||
|
?(%2 %3) 1
|
||||||
|
?(%0 %1) !!
|
||||||
|
* (add (mod a 2) (mul $(a (div a 2)) 2))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: List logic
|
||||||
|
::
|
||||||
|
++ snoc :: append to end of list
|
||||||
|
|* [a=(list) b=*]
|
||||||
|
(weld a ^+(a [b]~))
|
||||||
|
::
|
||||||
|
++ flop :: reverse
|
||||||
|
~/ %flop
|
||||||
|
|* a=(list)
|
||||||
|
=> .(a (homo a))
|
||||||
|
^+ a
|
||||||
|
=+ b=`_a`~
|
||||||
|
|-
|
||||||
|
?~ a b
|
||||||
|
$(a t.a, b [i.a b])
|
||||||
|
::
|
||||||
|
++ homo :: homogenize
|
||||||
|
|* a=(list)
|
||||||
|
^+ =< $
|
||||||
|
|@ ++ $ ?:(*? ~ [i=(snag 0 a) t=$])
|
||||||
|
--
|
||||||
|
a
|
||||||
|
::
|
||||||
|
++ lent :: length
|
||||||
|
~/ %lent
|
||||||
|
|= a=(list)
|
||||||
|
^- @
|
||||||
|
=+ b=0
|
||||||
|
|-
|
||||||
|
?~ a b
|
||||||
|
$(a t.a, b +(b))
|
||||||
|
::
|
||||||
|
++ reap :: replicate
|
||||||
|
~/ %reap
|
||||||
|
|* [a=@ b=*]
|
||||||
|
|- ^- (list _b)
|
||||||
|
?~ a ~
|
||||||
|
[b $(a (dec a))]
|
||||||
|
::
|
||||||
|
++ roll :: left fold
|
||||||
|
~/ %roll
|
||||||
|
|* [a=(list) b=_=>(~ |=([* *] +<+))]
|
||||||
|
|- ^+ ,.+<+.b
|
||||||
|
?~ a
|
||||||
|
+<+.b
|
||||||
|
$(a t.a, b b(+<+ (b i.a +<+.b)))
|
||||||
|
::
|
||||||
|
++ scag :: prefix
|
||||||
|
~/ %scag
|
||||||
|
|* [a=@ b=(list)]
|
||||||
|
|- ^+ b
|
||||||
|
?: |(?=(~ b) =(0 a)) ~
|
||||||
|
[i.b $(b t.b, a (dec a))]
|
||||||
|
::
|
||||||
|
++ slag :: suffix
|
||||||
|
~/ %slag
|
||||||
|
|* [a=@ b=(list)]
|
||||||
|
|- ^+ b
|
||||||
|
?: =(0 a) b
|
||||||
|
?~ b ~
|
||||||
|
$(b t.b, a (dec a))
|
||||||
|
::
|
||||||
|
++ snag :: index
|
||||||
|
~/ %snag
|
||||||
|
|* [a=@ b=(list)]
|
||||||
|
|- ^+ ?>(?=(^ b) i.b)
|
||||||
|
?~ b
|
||||||
|
~_ leaf+"snag-fail"
|
||||||
|
!!
|
||||||
|
?: =(0 a) i.b
|
||||||
|
$(b t.b, a (dec a))
|
||||||
|
::
|
||||||
|
++ turn :: transform
|
||||||
|
~/ %turn
|
||||||
|
|* [a=(list) b=gate]
|
||||||
|
=> .(a (homo a))
|
||||||
|
^- (list _?>(?=(^ a) (b i.a)))
|
||||||
|
|-
|
||||||
|
?~ a ~
|
||||||
|
[i=(b i.a) t=$(a t.a)]
|
||||||
|
::
|
||||||
|
++ weld :: concatenate
|
||||||
|
~/ %weld
|
||||||
|
|* [a=(list) b=(list)]
|
||||||
|
=> .(a ^.(homo a), b ^.(homo b))
|
||||||
|
|- ^+ b
|
||||||
|
?~ a b
|
||||||
|
[i.a $(a t.a)]
|
||||||
|
::
|
||||||
|
++ welp :: concatenate
|
||||||
|
~/ %welp
|
||||||
|
=| [* *]
|
||||||
|
|@
|
||||||
|
++ $
|
||||||
|
?~ +<-
|
||||||
|
+<-(. +<+)
|
||||||
|
+<-(+ $(+<- +<->))
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Bit arithmetic
|
||||||
|
::
|
||||||
|
++ bex :: binary exponent
|
||||||
|
~/ %bex
|
||||||
|
|= a=bloq
|
||||||
|
~> %sham.%bex
|
||||||
|
^- @
|
||||||
|
?: =(0 a) 1
|
||||||
|
(mul 2 $(a (dec a)))
|
||||||
|
++ can :: assemble
|
||||||
|
~/ %can
|
||||||
|
|= [a=bloq b=(list [p=step q=@])]
|
||||||
|
~> %sham.%can
|
||||||
|
^- @
|
||||||
|
?~ b 0
|
||||||
|
(add (end [a p.i.b] q.i.b) (lsh [a p.i.b] $(b t.b)))
|
||||||
|
::
|
||||||
|
++ cat :: concatenate
|
||||||
|
~/ %cat
|
||||||
|
|= [a=bloq b=@ c=@]
|
||||||
|
~> %sham.%cat
|
||||||
|
(add (lsh [a (met a b)] c) b)
|
||||||
|
::
|
||||||
|
++ cut :: slice
|
||||||
|
~/ %cut
|
||||||
|
|= [a=bloq [b=step c=step] d=@]
|
||||||
|
~> %sham.%cut
|
||||||
|
(end [a c] (rsh [a b] d))
|
||||||
|
::
|
||||||
|
++ end :: tail
|
||||||
|
~/ %end
|
||||||
|
|= [a=bite b=@]
|
||||||
|
~> %sham.%end
|
||||||
|
=/ [=bloq =step] ?^(a a [a *step])
|
||||||
|
(mod b (bex (mul (bex bloq) step)))
|
||||||
|
::
|
||||||
|
++ fil :: fill bloqstream
|
||||||
|
~/ %fil
|
||||||
|
|= [a=bloq b=step c=@]
|
||||||
|
=| n=@ud
|
||||||
|
=. c (end a c)
|
||||||
|
=/ d c
|
||||||
|
|- ^- @
|
||||||
|
?: =(n b)
|
||||||
|
(rsh a d)
|
||||||
|
$(d (add c (lsh a d)), n +(n))
|
||||||
|
::
|
||||||
|
++ lsh :: left-shift
|
||||||
|
~/ %lsh
|
||||||
|
|= [a=bite b=@]
|
||||||
|
~> %sham.%lsh
|
||||||
|
=/ [=bloq =step] ?^(a a [a *step])
|
||||||
|
(mul b (bex (mul (bex bloq) step)))
|
||||||
|
::
|
||||||
|
++ met :: measure
|
||||||
|
~/ %met
|
||||||
|
|= [a=bloq b=@]
|
||||||
|
~> %sham.%met
|
||||||
|
^- @
|
||||||
|
=+ c=0
|
||||||
|
|-
|
||||||
|
?: =(0 b) c
|
||||||
|
$(b (rsh a b), c +(c))
|
||||||
|
::
|
||||||
|
++ rap :: assemble variable
|
||||||
|
~/ %rap
|
||||||
|
|= [a=bloq b=(list @)]
|
||||||
|
~> %sham.%rap
|
||||||
|
^- @
|
||||||
|
?~ b 0
|
||||||
|
(cat a i.b $(b t.b))
|
||||||
|
::
|
||||||
|
++ rep :: assemble fixed
|
||||||
|
~/ %rep
|
||||||
|
|= [a=bite b=(list @)]
|
||||||
|
~> %sham.%rep
|
||||||
|
=/ [=bloq =step] ?^(a a [a *step])
|
||||||
|
=| i=@ud
|
||||||
|
|- ^- @
|
||||||
|
?~ b 0
|
||||||
|
%+ add $(i +(i), b t.b)
|
||||||
|
(lsh [bloq (mul step i)] (end [bloq step] i.b))
|
||||||
|
::
|
||||||
|
++ rev :: reverse block order
|
||||||
|
~/ %rev
|
||||||
|
|= [boz=bloq len=@ud dat=@]
|
||||||
|
~> %sham.%rev
|
||||||
|
^- @
|
||||||
|
=. dat (end [boz len] dat)
|
||||||
|
%+ lsh
|
||||||
|
[boz (sub len (met boz dat))]
|
||||||
|
(swp boz dat)
|
||||||
|
::
|
||||||
|
++ rip :: disassemble
|
||||||
|
~/ %rip
|
||||||
|
|= [a=bite b=@]
|
||||||
|
~> %sham.%rip
|
||||||
|
^- (list @)
|
||||||
|
?: =(0 b) ~
|
||||||
|
[(end a b) $(b (rsh a b))]
|
||||||
|
::
|
||||||
|
++ rsh :: right-shift
|
||||||
|
~/ %rsh
|
||||||
|
|= [a=bite b=@]
|
||||||
|
~> %sham.%rsh
|
||||||
|
=/ [=bloq =step] ?^(a a [a *step])
|
||||||
|
(div b (bex (mul (bex bloq) step)))
|
||||||
|
::
|
||||||
|
++ swp :: naive rev bloq order
|
||||||
|
~/ %swp
|
||||||
|
|= [a=bloq b=@]
|
||||||
|
(rep a (flop (rip a b)))
|
||||||
|
::
|
||||||
|
:: Modular arithmetic
|
||||||
|
::
|
||||||
|
++ fe :: modulo bloq
|
||||||
|
|_ a=bloq
|
||||||
|
++ dif :: difference
|
||||||
|
|=([b=@ c=@] (sit (sub (add out (sit b)) (sit c))))
|
||||||
|
++ inv |=(b=@ (sub (dec out) (sit b))) :: inverse
|
||||||
|
++ net |= b=@ ^- @ :: flip byte endianness
|
||||||
|
=> .(b (sit b))
|
||||||
|
?: (lte a 3)
|
||||||
|
b
|
||||||
|
=+ c=(dec a)
|
||||||
|
%+ con
|
||||||
|
(lsh c $(a c, b (cut c [0 1] b)))
|
||||||
|
$(a c, b (cut c [1 1] b))
|
||||||
|
++ out (bex (bex a)) :: mod value
|
||||||
|
++ rol |= [b=bloq c=@ d=@] ^- @ :: roll left
|
||||||
|
=+ e=(sit d)
|
||||||
|
=+ f=(bex (sub a b))
|
||||||
|
=+ g=(mod c f)
|
||||||
|
(sit (con (lsh [b g] e) (rsh [b (sub f g)] e)))
|
||||||
|
++ ror |= [b=bloq c=@ d=@] ^- @ :: roll right
|
||||||
|
=+ e=(sit d)
|
||||||
|
=+ f=(bex (sub a b))
|
||||||
|
=+ g=(mod c f)
|
||||||
|
(sit (con (rsh [b g] e) (lsh [b (sub f g)] e)))
|
||||||
|
++ sum |=([b=@ c=@] (sit (add b c))) :: wrapping add
|
||||||
|
++ sit |=(b=@ (end a b)) :: enforce modulo
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Bit logic
|
||||||
|
::
|
||||||
|
++ con :: binary or
|
||||||
|
~/ %con
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%con
|
||||||
|
=+ [c=0 d=0]
|
||||||
|
|- ^- @
|
||||||
|
?: ?&(=(0 a) =(0 b)) d
|
||||||
|
%= $
|
||||||
|
a (rsh 0 a)
|
||||||
|
b (rsh 0 b)
|
||||||
|
c +(c)
|
||||||
|
d %+ add d
|
||||||
|
%+ lsh [0 c]
|
||||||
|
?& =(0 (end 0 a))
|
||||||
|
=(0 (end 0 b))
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ dis :: binary and
|
||||||
|
~/ %dis
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%dis
|
||||||
|
=| [c=@ d=@]
|
||||||
|
|- ^- @
|
||||||
|
?: ?|(=(0 a) =(0 b)) d
|
||||||
|
%= $
|
||||||
|
a (rsh 0 a)
|
||||||
|
b (rsh 0 b)
|
||||||
|
c +(c)
|
||||||
|
d %+ add d
|
||||||
|
%+ lsh [0 c]
|
||||||
|
?| =(0 (end 0 a))
|
||||||
|
=(0 (end 0 b))
|
||||||
|
==
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ mix :: binary xor
|
||||||
|
~/ %mix
|
||||||
|
|= [a=@ b=@]
|
||||||
|
~> %sham.%mix
|
||||||
|
^- @
|
||||||
|
=+ [c=0 d=0]
|
||||||
|
|-
|
||||||
|
?: ?&(=(0 a) =(0 b)) d
|
||||||
|
%= $
|
||||||
|
a (rsh 0 a)
|
||||||
|
b (rsh 0 b)
|
||||||
|
c +(c)
|
||||||
|
d (add d (lsh [0 c] =((end 0 a) (end 0 b))))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: Hashes
|
||||||
|
::
|
||||||
|
++ mug :: mug with murmur3
|
||||||
|
~/ %mug
|
||||||
|
|= a=*
|
||||||
|
~> %sham.%mug
|
||||||
|
|^ ?@ a (mum 0xcafe.babe 0x7fff a)
|
||||||
|
=/ b (cat 5 $(a -.a) $(a +.a))
|
||||||
|
(mum 0xdead.beef 0xfffe b)
|
||||||
|
::
|
||||||
|
++ mum
|
||||||
|
|= [syd=@uxF fal=@F key=@]
|
||||||
|
=/ wyd (met 3 key)
|
||||||
|
=| i=@ud
|
||||||
|
|- ^- @F
|
||||||
|
?: =(8 i) fal
|
||||||
|
=/ haz=@F (muk syd wyd key)
|
||||||
|
=/ ham=@F (mix (rsh [0 31] haz) (end [0 31] haz))
|
||||||
|
?.(=(0 ham) ham $(i +(i), syd +(syd)))
|
||||||
|
--
|
||||||
|
::
|
||||||
|
++ muk :: standard murmur3
|
||||||
|
~% %muk ..muk ~
|
||||||
|
=+ ~(. fe 5)
|
||||||
|
|= [syd=@ len=@ key=@]
|
||||||
|
=. syd (end 5 syd)
|
||||||
|
=/ pad (sub len (met 3 key))
|
||||||
|
=/ data (welp (rip 3 key) (reap pad 0))
|
||||||
|
=/ nblocks (div len 4) :: intentionally off-by-one
|
||||||
|
=/ h1 syd
|
||||||
|
=+ [c1=0xcc9e.2d51 c2=0x1b87.3593]
|
||||||
|
=/ blocks (rip 5 key)
|
||||||
|
=/ i nblocks
|
||||||
|
=. h1 =/ hi h1 |-
|
||||||
|
?: =(0 i) hi
|
||||||
|
=/ k1 (snag (sub nblocks i) blocks) :: negative array index
|
||||||
|
=. k1 (sit (mul k1 c1))
|
||||||
|
=. k1 (rol 0 15 k1)
|
||||||
|
=. k1 (sit (mul k1 c2))
|
||||||
|
=. hi (mix hi k1)
|
||||||
|
=. hi (rol 0 13 hi)
|
||||||
|
=. hi (sum (sit (mul hi 5)) 0xe654.6b64)
|
||||||
|
$(i (dec i))
|
||||||
|
=/ tail (slag (mul 4 nblocks) data)
|
||||||
|
=/ k1 0
|
||||||
|
=/ tlen (dis len 3)
|
||||||
|
=. h1
|
||||||
|
?+ tlen h1 :: fallthrough switch
|
||||||
|
%3 =. k1 (mix k1 (lsh [0 16] (snag 2 tail)))
|
||||||
|
=. k1 (mix k1 (lsh [0 8] (snag 1 tail)))
|
||||||
|
=. k1 (mix k1 (snag 0 tail))
|
||||||
|
=. k1 (sit (mul k1 c1))
|
||||||
|
=. k1 (rol 0 15 k1)
|
||||||
|
=. k1 (sit (mul k1 c2))
|
||||||
|
(mix h1 k1)
|
||||||
|
%2 =. k1 (mix k1 (lsh [0 8] (snag 1 tail)))
|
||||||
|
=. k1 (mix k1 (snag 0 tail))
|
||||||
|
=. k1 (sit (mul k1 c1))
|
||||||
|
=. k1 (rol 0 15 k1)
|
||||||
|
=. k1 (sit (mul k1 c2))
|
||||||
|
(mix h1 k1)
|
||||||
|
%1 =. k1 (mix k1 (snag 0 tail))
|
||||||
|
=. k1 (sit (mul k1 c1))
|
||||||
|
=. k1 (rol 0 15 k1)
|
||||||
|
=. k1 (sit (mul k1 c2))
|
||||||
|
(mix h1 k1)
|
||||||
|
==
|
||||||
|
=. h1 (mix h1 len)
|
||||||
|
|^ (fmix32 h1)
|
||||||
|
++ fmix32
|
||||||
|
|= h=@
|
||||||
|
=. h (mix h (rsh [0 16] h))
|
||||||
|
=. h (sit (mul h 0x85eb.ca6b))
|
||||||
|
=. h (mix h (rsh [0 13] h))
|
||||||
|
=. h (sit (mul h 0xc2b2.ae35))
|
||||||
|
=. h (mix h (rsh [0 16] h))
|
||||||
|
h
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Noun Ordering
|
||||||
|
::
|
||||||
|
++ dor :: tree order
|
||||||
|
~/ %dor
|
||||||
|
|= [a=* b=*]
|
||||||
|
~> %sham.%dor
|
||||||
|
^- ?
|
||||||
|
?: =(a b) &
|
||||||
|
?. ?=(@ a)
|
||||||
|
?: ?=(@ b) |
|
||||||
|
?: =(-.a -.b)
|
||||||
|
$(a +.a, b +.b)
|
||||||
|
$(a -.a, b -.b)
|
||||||
|
?. ?=(@ b) &
|
||||||
|
(lth a b)
|
||||||
|
::
|
||||||
|
++ gor :: mug order
|
||||||
|
~/ %gor
|
||||||
|
|= [a=* b=*]
|
||||||
|
~> %sham.%gor
|
||||||
|
^- ?
|
||||||
|
=+ [c=(mug a) d=(mug b)]
|
||||||
|
?: =(c d)
|
||||||
|
(dor a b)
|
||||||
|
(lth c d)
|
||||||
|
::
|
||||||
|
++ mor :: more mug order
|
||||||
|
~/ %mor
|
||||||
|
|= [a=* b=*]
|
||||||
|
~> %sham.%mor
|
||||||
|
^- ?
|
||||||
|
=+ [c=(mug (mug a)) d=(mug (mug b))]
|
||||||
|
?: =(c d)
|
||||||
|
(dor a b)
|
||||||
|
(lth c d)
|
||||||
|
::
|
||||||
|
:: Unsigned powers
|
||||||
|
::
|
||||||
|
++ pow :: unsigned exponent
|
||||||
|
~/ %pow
|
||||||
|
|= [a=@ b=@]
|
||||||
|
?: =(b 0) 1
|
||||||
|
|- ?: =(b 1) a
|
||||||
|
=+ c=$(b (div b 2))
|
||||||
|
=+ d=(mul c c)
|
||||||
|
?~ (dis b 1) d (mul d a)
|
||||||
|
::
|
||||||
|
:: Set logic
|
||||||
|
::
|
||||||
|
++ in
|
||||||
|
~/ %in
|
||||||
|
=| a=(tree) :: (set)
|
||||||
|
~> %sham.%in
|
||||||
|
|@
|
||||||
|
++ apt
|
||||||
|
=< $
|
||||||
|
~/ %apt
|
||||||
|
=| [l=(unit) r=(unit)]
|
||||||
|
~> %sham.%apt
|
||||||
|
|. ^- ?
|
||||||
|
?~ a &
|
||||||
|
?& ?~(l & (gor n.a u.l))
|
||||||
|
?~(r & (gor u.r n.a))
|
||||||
|
?~(l.a & ?&((mor n.a n.l.a) $(a l.a, l `n.a)))
|
||||||
|
?~(r.a & ?&((mor n.a n.r.a) $(a r.a, r `n.a)))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ del
|
||||||
|
~/ %del
|
||||||
|
|* b=*
|
||||||
|
~> %sham.%del
|
||||||
|
|- ^+ a
|
||||||
|
?~ a
|
||||||
|
~
|
||||||
|
?. =(b n.a)
|
||||||
|
?: (gor b n.a)
|
||||||
|
a(l $(a l.a))
|
||||||
|
a(r $(a r.a))
|
||||||
|
|- ^- [$?(~ _a)]
|
||||||
|
?~ l.a r.a
|
||||||
|
?~ r.a l.a
|
||||||
|
?: (mor n.l.a n.r.a)
|
||||||
|
l.a(r $(l.a r.l.a))
|
||||||
|
r.a(l $(r.a l.r.a))
|
||||||
|
::
|
||||||
|
++ put
|
||||||
|
~/ %put
|
||||||
|
|* b=*
|
||||||
|
~> %sham.%put
|
||||||
|
|- ^+ a
|
||||||
|
?~ a
|
||||||
|
[b ~ ~]
|
||||||
|
?: =(b n.a)
|
||||||
|
a
|
||||||
|
?: (gor b n.a)
|
||||||
|
=+ c=$(a l.a)
|
||||||
|
?> ?=(^ c)
|
||||||
|
?: (mor n.a n.c)
|
||||||
|
a(l c)
|
||||||
|
c(r a(l r.c))
|
||||||
|
=+ c=$(a r.a)
|
||||||
|
?> ?=(^ c)
|
||||||
|
?: (mor n.a n.c)
|
||||||
|
a(r c)
|
||||||
|
c(l a(r l.c))
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Map logic
|
||||||
|
::
|
||||||
|
++ by
|
||||||
|
~/ %by
|
||||||
|
=| a=(tree (pair)) :: (map)
|
||||||
|
~> %sham.%by
|
||||||
|
=* node ?>(?=(^ a) n.a)
|
||||||
|
|@
|
||||||
|
++ del
|
||||||
|
~/ %del
|
||||||
|
|* b=*
|
||||||
|
~> %sham.%del
|
||||||
|
|- ^+ a
|
||||||
|
?~ a
|
||||||
|
~
|
||||||
|
?. =(b p.n.a)
|
||||||
|
?: (gor b p.n.a)
|
||||||
|
a(l $(a l.a))
|
||||||
|
a(r $(a r.a))
|
||||||
|
|- ^- [$?(~ _a)]
|
||||||
|
?~ l.a r.a
|
||||||
|
?~ r.a l.a
|
||||||
|
?: (mor p.n.l.a p.n.r.a)
|
||||||
|
l.a(r $(l.a r.l.a))
|
||||||
|
r.a(l $(r.a l.r.a))
|
||||||
|
::
|
||||||
|
++ apt
|
||||||
|
=< $
|
||||||
|
~/ %apt
|
||||||
|
=| [l=(unit) r=(unit)]
|
||||||
|
~> %sham.%apt
|
||||||
|
|. ^- ?
|
||||||
|
?~ a &
|
||||||
|
?& ?~(l & &((gor p.n.a u.l) !=(p.n.a u.l)))
|
||||||
|
?~(r & &((gor u.r p.n.a) !=(u.r p.n.a)))
|
||||||
|
?~ l.a &
|
||||||
|
&((mor p.n.a p.n.l.a) !=(p.n.a p.n.l.a) $(a l.a, l `p.n.a))
|
||||||
|
?~ r.a &
|
||||||
|
&((mor p.n.a p.n.r.a) !=(p.n.a p.n.r.a) $(a r.a, r `p.n.a))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ get
|
||||||
|
~/ %get
|
||||||
|
|* b=*
|
||||||
|
~> %sham.%get
|
||||||
|
=> .(b `_?>(?=(^ a) p.n.a)`b)
|
||||||
|
|- ^- (unit _?>(?=(^ a) q.n.a))
|
||||||
|
?~ a
|
||||||
|
~
|
||||||
|
?: =(b p.n.a)
|
||||||
|
`q.n.a
|
||||||
|
?: (gor b p.n.a)
|
||||||
|
$(a l.a)
|
||||||
|
$(a r.a)
|
||||||
|
::
|
||||||
|
++ put
|
||||||
|
~/ %put
|
||||||
|
|* [b=* c=*]
|
||||||
|
~> %sham.%put
|
||||||
|
|- ^+ a
|
||||||
|
?~ a
|
||||||
|
[[b c] ~ ~]
|
||||||
|
?: =(b p.n.a)
|
||||||
|
?: =(c q.n.a)
|
||||||
|
a
|
||||||
|
a(n [b c])
|
||||||
|
?: (gor b p.n.a)
|
||||||
|
=+ d=$(a l.a)
|
||||||
|
?> ?=(^ d)
|
||||||
|
?: (mor p.n.a p.n.d)
|
||||||
|
a(l d)
|
||||||
|
d(r a(l r.d))
|
||||||
|
=+ d=$(a r.a)
|
||||||
|
?> ?=(^ d)
|
||||||
|
?: (mor p.n.a p.n.d)
|
||||||
|
a(r d)
|
||||||
|
d(l a(r l.d))
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Jug logic
|
||||||
|
::
|
||||||
|
++ ju
|
||||||
|
=| a=(tree (pair * (tree))) :: (jug)
|
||||||
|
|@
|
||||||
|
++ del
|
||||||
|
|* [b=* c=*]
|
||||||
|
^+ a
|
||||||
|
=+ d=(get b)
|
||||||
|
=+ e=(~(del in d) c)
|
||||||
|
?~ e
|
||||||
|
(~(del by a) b)
|
||||||
|
(~(put by a) b e)
|
||||||
|
::
|
||||||
|
++ get
|
||||||
|
|* b=*
|
||||||
|
=+ c=(~(get by a) b)
|
||||||
|
?~(c ~ u.c)
|
||||||
|
::
|
||||||
|
++ put
|
||||||
|
|* [b=* c=*]
|
||||||
|
^+ a
|
||||||
|
=+ d=(get b)
|
||||||
|
(~(put by a) b (~(put in d) c))
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Parsing
|
||||||
|
::
|
||||||
|
++ ne
|
||||||
|
|_ tig=@
|
||||||
|
++ d (add tig '0')
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Atom printing
|
||||||
|
::
|
||||||
|
++ co
|
||||||
|
!:
|
||||||
|
~% %co ..co ~
|
||||||
|
=< |_ lot=coin
|
||||||
|
++ rend
|
||||||
|
^- tape
|
||||||
|
~+
|
||||||
|
?. ?=(%$ -.lot) !!
|
||||||
|
=+ [yed=(end 3 p.p.lot) hay=(cut 3 [1 1] p.p.lot)]
|
||||||
|
|- ^- tape
|
||||||
|
?+ yed !!
|
||||||
|
%ud
|
||||||
|
::
|
||||||
|
=/ gam=tape
|
||||||
|
((ox-co [10 3] |=(a=@ ~(d ne a))) q.p.lot)
|
||||||
|
?: =(0 q.p.lot)
|
||||||
|
['0' ~]
|
||||||
|
gam
|
||||||
|
==
|
||||||
|
--
|
||||||
|
=| rep=tape
|
||||||
|
|%
|
||||||
|
:: +em-co: format in numeric base
|
||||||
|
::
|
||||||
|
:: in .bas, format .min digits of .hol with .par
|
||||||
|
::
|
||||||
|
:: - .hol is processed least-significant digit first
|
||||||
|
:: - all available digits in .hol will be processed, but
|
||||||
|
:: .min digits can exceed the number available in .hol
|
||||||
|
:: - .par handles all accumulated output on each call,
|
||||||
|
:: and can edit it, prepend or append digits, &c
|
||||||
|
:: - until .hol is exhausted, .par's sample is [| digit output],
|
||||||
|
:: subsequently, it's [& 0 output]
|
||||||
|
::
|
||||||
|
++ em-co
|
||||||
|
|= [[bas=@ min=@] par=$-([? @ tape] tape)]
|
||||||
|
|= hol=@
|
||||||
|
^- tape
|
||||||
|
?: &(=(0 hol) =(0 min))
|
||||||
|
rep
|
||||||
|
=/ [dar=@ rad=@] (dvr hol bas)
|
||||||
|
%= $
|
||||||
|
min ?:(=(0 min) 0 (dec min))
|
||||||
|
hol dar
|
||||||
|
rep (par =(0 dar) rad rep)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: +ox-co: format '.'-separated digit sequences in numeric base
|
||||||
|
::
|
||||||
|
:: in .bas, format each digit of .hol with .dug,
|
||||||
|
:: with '.' separators every .gop digits.
|
||||||
|
::
|
||||||
|
:: - .hol is processed least-significant digit first
|
||||||
|
:: - .dug handles individual digits, output is prepended
|
||||||
|
:: - every segment but the last is zero-padded to .gop
|
||||||
|
::
|
||||||
|
++ ox-co
|
||||||
|
|= [[bas=@ gop=@] dug=$-(@ @)]
|
||||||
|
%+ em-co
|
||||||
|
[(pow bas gop) 0]
|
||||||
|
|= [top=? seg=@ res=tape]
|
||||||
|
%+ weld
|
||||||
|
?:(top ~ `tape`['.' ~])
|
||||||
|
%. seg
|
||||||
|
%+ em-co(rep res)
|
||||||
|
[bas ?:(top 0 gop)]
|
||||||
|
|=([? b=@ c=tape] [(dug b) c])
|
||||||
|
--
|
||||||
|
::
|
||||||
|
:: Formatting functions
|
||||||
|
::
|
||||||
|
++ scow
|
||||||
|
~/ %scow
|
||||||
|
|= mol=dime
|
||||||
|
~> %sham.%scow
|
||||||
|
~(rend co %$ mol)
|
||||||
|
--
|
98
hoon/scaffolding/toddler.hoon
Normal file
98
hoon/scaffolding/toddler.hoon
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
:: A working pill that grows towards arvo.hoon. Requires playpen.hoon from this
|
||||||
|
:: scaffolding directory.
|
||||||
|
::
|
||||||
|
/+ playpen
|
||||||
|
!.
|
||||||
|
=/ core
|
||||||
|
=> playpen
|
||||||
|
!=
|
||||||
|
=>
|
||||||
|
|%
|
||||||
|
+$ card (cask)
|
||||||
|
++ cask |$ [a] (pair mark a)
|
||||||
|
+$ goof [mote=term =tang]
|
||||||
|
+$ mark @tas
|
||||||
|
+$ ovum [=wire =card]
|
||||||
|
+$ vere [[non=@ta rev=path] kel=wynn]
|
||||||
|
+$ wire path
|
||||||
|
+$ wasp
|
||||||
|
:: %crud: reroute $ovum with $goof
|
||||||
|
:: %wack: iterate entropy
|
||||||
|
:: %wyrd: check/record runtime kelvin stack
|
||||||
|
::
|
||||||
|
$% [%crud =goof =ovum]
|
||||||
|
[%wack p=@uvJ]
|
||||||
|
[%wyrd p=vere]
|
||||||
|
==
|
||||||
|
+$ weft [lal=@tas num=@ud]
|
||||||
|
+$ wynn (list weft)
|
||||||
|
:: mutually recursive Ackermann functions
|
||||||
|
:: test turning %spot hints on/off
|
||||||
|
++ ack
|
||||||
|
:: re-enable %spot hints
|
||||||
|
!:
|
||||||
|
|= [m=@ud n=@ud]
|
||||||
|
:: %memo hint
|
||||||
|
~+
|
||||||
|
?~ m +(n)
|
||||||
|
?~ n
|
||||||
|
(ack (dec m) 1)
|
||||||
|
(ack (dec m) $(n (dec n)))
|
||||||
|
++ slow
|
||||||
|
|= x=@ud
|
||||||
|
!:
|
||||||
|
(slow-help x 0)
|
||||||
|
++ slow-help
|
||||||
|
|= [x=@ud y=@ud]
|
||||||
|
!.
|
||||||
|
?: .= x y
|
||||||
|
x
|
||||||
|
$(y .+(y))
|
||||||
|
-- =>
|
||||||
|
::
|
||||||
|
|%
|
||||||
|
++ load !!
|
||||||
|
++ peek _~
|
||||||
|
++ wish !!
|
||||||
|
++ poke
|
||||||
|
|= [now=@da ovo=ovum]
|
||||||
|
^- ^
|
||||||
|
::
|
||||||
|
?. ?=(?(%crud %wack %wyrd) p.card.ovo)
|
||||||
|
~> %slog.[0 leaf+(scow %ud (slow (bex 23)))]
|
||||||
|
[~ ..poke]
|
||||||
|
::
|
||||||
|
=/ buz
|
||||||
|
~> %mean.'pith: bad wasp'
|
||||||
|
;;(wasp card.ovo)
|
||||||
|
?+ -.buz
|
||||||
|
~> %slog.[0 leaf+(scow %ud (ack 2 1))]
|
||||||
|
[~ ..poke]
|
||||||
|
::
|
||||||
|
%crud
|
||||||
|
=/ tang tang.goof.buz
|
||||||
|
|-
|
||||||
|
?~ tang
|
||||||
|
[~ ..poke]
|
||||||
|
~> %slog.[0 -.tang]
|
||||||
|
$(tang +.tang)
|
||||||
|
==
|
||||||
|
--
|
||||||
|
::
|
||||||
|
|= [now=@da ovo=ovum]
|
||||||
|
^- *
|
||||||
|
.(+> +:(poke now ovo))
|
||||||
|
::
|
||||||
|
|%
|
||||||
|
++ aeon
|
||||||
|
^- *
|
||||||
|
=> *[arvo=* epic=*]
|
||||||
|
!=
|
||||||
|
|- ^- *
|
||||||
|
?@ epic arvo
|
||||||
|
%= $
|
||||||
|
epic +.epic
|
||||||
|
arvo .*([arvo -.epic] [%9 2 %10 [6 %0 3] %0 2])
|
||||||
|
==
|
||||||
|
--
|
||||||
|
[%pill %toddler [aeon .*(playpen core) ~] ~ ~]
|
29
rust/ares/Cargo.lock
generated
29
rust/ares/Cargo.lock
generated
@ -20,11 +20,13 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"ibig",
|
"ibig",
|
||||||
"intmap",
|
"intmap",
|
||||||
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"memmap",
|
"memmap",
|
||||||
"murmur3",
|
"murmur3",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"signal-hook",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -230,9 +232,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
@ -378,9 +380,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.15"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
@ -569,6 +571,25 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -9,20 +9,25 @@ edition = "2018"
|
|||||||
# [patch.crates-io]
|
# [patch.crates-io]
|
||||||
# ibig = { path = "../ibig-rs" }
|
# ibig = { path = "../ibig-rs" }
|
||||||
|
|
||||||
|
# Please keep these alphabetized
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ares_macros = { path = "../ares_macros" }
|
ares_macros = { path = "../ares_macros" }
|
||||||
bitvec = "1.0.0"
|
|
||||||
either = "1.6.1"
|
|
||||||
libc = "0.2.126"
|
|
||||||
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
|
|
||||||
memmap = "0.7.0"
|
|
||||||
intmap = "1.1.0"
|
|
||||||
num-traits = "0.2"
|
|
||||||
num-derive = "0.3"
|
|
||||||
criterion = "0.4"
|
|
||||||
static_assertions = "1.1.0"
|
|
||||||
ibig = { path = "../ibig-rs" }
|
|
||||||
assert_no_alloc = "1.1.2"
|
assert_no_alloc = "1.1.2"
|
||||||
|
# use this when debugging requires allocation (e.g. eprintln)
|
||||||
|
# assert_no_alloc = {version="1.1.2", features=["warn_debug"]}
|
||||||
|
bitvec = "1.0.0"
|
||||||
|
criterion = "0.4"
|
||||||
|
either = "1.9.0"
|
||||||
|
ibig = { path = "../ibig-rs" }
|
||||||
|
intmap = "1.1.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
libc = "0.2.126"
|
||||||
|
memmap = "0.7.0"
|
||||||
|
murmur3 = { git = "https://github.com/tloncorp/murmur3", rev = "7878a0f" }
|
||||||
|
num-derive = "0.3"
|
||||||
|
num-traits = "0.2"
|
||||||
|
signal-hook = "0.3"
|
||||||
|
static_assertions = "1.1.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0.79"
|
cc = "1.0.79"
|
||||||
@ -37,6 +42,10 @@ opt-level = 3
|
|||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
|
# run with e.g. 'cargo build --features check_forwarding,check_acyclic'
|
||||||
[features]
|
[features]
|
||||||
check_acyclic=[]
|
check_all = [ "check_acyclic", "check_forwarding", "check_junior" ]
|
||||||
sham_hints=[]
|
check_acyclic = []
|
||||||
|
check_forwarding = []
|
||||||
|
check_junior = []
|
||||||
|
sham_hints = []
|
||||||
|
@ -104,7 +104,7 @@ impl<T: Copy> MutHamt<T> {
|
|||||||
mug >>= 5;
|
mug >>= 5;
|
||||||
match (*stem).entry(chunk) {
|
match (*stem).entry(chunk) {
|
||||||
None => {
|
None => {
|
||||||
let new_leaf_buffer = stack.struct_alloc(1);
|
let new_leaf_buffer = stack.struct_alloc::<(Noun, T)>(1);
|
||||||
*new_leaf_buffer = (*n, t);
|
*new_leaf_buffer = (*n, t);
|
||||||
(*stem).bitmap |= chunk_to_bit(chunk);
|
(*stem).bitmap |= chunk_to_bit(chunk);
|
||||||
(*stem).typemap &= !chunk_to_bit(chunk);
|
(*stem).typemap &= !chunk_to_bit(chunk);
|
||||||
@ -524,7 +524,7 @@ impl<T: Copy + Preserve> Preserve for Hamt<T> {
|
|||||||
};
|
};
|
||||||
*(stem.buffer.add(idx) as *mut Entry<T>) = Entry { stem: new_stem };
|
*(stem.buffer.add(idx) as *mut Entry<T>) = Entry { stem: new_stem };
|
||||||
assert!(traversal_depth <= 5); // will increment
|
assert!(traversal_depth <= 5); // will increment
|
||||||
traversal_stack[traversal_depth - 1].unwrap().1 = position + 1;
|
traversal_stack[traversal_depth - 1] = Some((stem, position + 1));
|
||||||
traversal_stack[traversal_depth] = Some((new_stem, 0));
|
traversal_stack[traversal_depth] = Some((new_stem, 0));
|
||||||
traversal_depth += 1;
|
traversal_depth += 1;
|
||||||
continue 'preserve;
|
continue 'preserve;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,38 @@
|
|||||||
pub mod cold;
|
pub mod cold;
|
||||||
pub mod hot;
|
pub mod hot;
|
||||||
pub mod math;
|
|
||||||
pub mod warm;
|
pub mod warm;
|
||||||
|
|
||||||
|
pub mod bits;
|
||||||
|
pub mod form;
|
||||||
|
pub mod hash;
|
||||||
|
pub mod math;
|
||||||
|
pub mod nock;
|
||||||
|
pub mod text;
|
||||||
|
pub mod tree;
|
||||||
|
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::bits::*;
|
||||||
|
use crate::jets::form::*;
|
||||||
|
use crate::jets::hash::*;
|
||||||
use crate::jets::math::*;
|
use crate::jets::math::*;
|
||||||
|
use crate::jets::nock::*;
|
||||||
|
use crate::jets::text::*;
|
||||||
|
use crate::jets::tree::*;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::noun::{self, Noun};
|
use crate::noun::{self, Noun, Slots};
|
||||||
use ares_macros::tas;
|
use ares_macros::tas;
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
/// Return Err if the computation crashed or should punt to Nock
|
/// Return Err if the computation crashed or should punt to Nock
|
||||||
pub type Jet = fn(&mut NockStack, Noun) -> Result<Noun, JetErr>;
|
pub type Result = std::result::Result<Noun, JetErr>;
|
||||||
|
pub type Jet = fn(&mut Context, Noun) -> Result;
|
||||||
|
|
||||||
/// Only return a deterministic error if the Nock would have deterministically crashed.
|
/**
|
||||||
|
* Only return a deterministic error if the Nock would have deterministically
|
||||||
|
* crashed.
|
||||||
|
*/
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum JetErr {
|
pub enum JetErr {
|
||||||
Punt, // Retry with the raw nock
|
Punt, // Retry with the raw nock
|
||||||
@ -21,15 +40,9 @@ pub enum JetErr {
|
|||||||
NonDeterministic, // Other error
|
NonDeterministic, // Other error
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<()> for JetErr {
|
|
||||||
fn from(_: ()) -> Self {
|
|
||||||
JetErr::NonDeterministic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<noun::Error> for JetErr {
|
impl From<noun::Error> for JetErr {
|
||||||
fn from(_err: noun::Error) -> Self {
|
fn from(_err: noun::Error) -> Self {
|
||||||
Self::NonDeterministic
|
Self::Deterministic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,32 +52,45 @@ impl From<JetErr> for () {
|
|||||||
|
|
||||||
pub fn get_jet(jet_name: Noun) -> Option<Jet> {
|
pub fn get_jet(jet_name: Noun) -> Option<Jet> {
|
||||||
match jet_name.as_direct().ok()?.data() {
|
match jet_name.as_direct().ok()?.data() {
|
||||||
tas!(b"dec") => Some(jet_dec),
|
|
||||||
tas!(b"add") => Some(jet_add),
|
tas!(b"add") => Some(jet_add),
|
||||||
tas!(b"sub") => Some(jet_sub),
|
tas!(b"dec") => Some(jet_dec),
|
||||||
tas!(b"mul") => Some(jet_mul),
|
|
||||||
tas!(b"div") => Some(jet_div),
|
tas!(b"div") => Some(jet_div),
|
||||||
tas!(b"mod") => Some(jet_mod),
|
|
||||||
tas!(b"dvr") => Some(jet_dvr),
|
tas!(b"dvr") => Some(jet_dvr),
|
||||||
tas!(b"lth") => Some(jet_lth),
|
|
||||||
tas!(b"lte") => Some(jet_lte),
|
|
||||||
tas!(b"gth") => Some(jet_gth),
|
|
||||||
tas!(b"gte") => Some(jet_gte),
|
tas!(b"gte") => Some(jet_gte),
|
||||||
|
tas!(b"gth") => Some(jet_gth),
|
||||||
|
tas!(b"lte") => Some(jet_lte),
|
||||||
|
tas!(b"lth") => Some(jet_lth),
|
||||||
|
tas!(b"mod") => Some(jet_mod),
|
||||||
|
tas!(b"mul") => Some(jet_mul),
|
||||||
|
tas!(b"sub") => Some(jet_sub),
|
||||||
|
//
|
||||||
|
tas!(b"cap") => Some(jet_cap),
|
||||||
|
tas!(b"mas") => Some(jet_mas),
|
||||||
|
//
|
||||||
|
tas!(b"lent") => Some(jet_lent),
|
||||||
|
//
|
||||||
tas!(b"bex") => Some(jet_bex),
|
tas!(b"bex") => Some(jet_bex),
|
||||||
|
tas!(b"can") => Some(jet_can),
|
||||||
|
tas!(b"cat") => Some(jet_cat),
|
||||||
|
tas!(b"cut") => Some(jet_cut),
|
||||||
|
tas!(b"end") => Some(jet_end),
|
||||||
tas!(b"lsh") => Some(jet_lsh),
|
tas!(b"lsh") => Some(jet_lsh),
|
||||||
|
tas!(b"met") => Some(jet_met),
|
||||||
|
tas!(b"rap") => Some(jet_rap),
|
||||||
|
tas!(b"rep") => Some(jet_rep),
|
||||||
|
tas!(b"rev") => Some(jet_rev),
|
||||||
|
tas!(b"rip") => Some(jet_rip),
|
||||||
tas!(b"rsh") => Some(jet_rsh),
|
tas!(b"rsh") => Some(jet_rsh),
|
||||||
|
//
|
||||||
tas!(b"con") => Some(jet_con),
|
tas!(b"con") => Some(jet_con),
|
||||||
tas!(b"dis") => Some(jet_dis),
|
tas!(b"dis") => Some(jet_dis),
|
||||||
tas!(b"mix") => Some(jet_mix),
|
tas!(b"mix") => Some(jet_mix),
|
||||||
tas!(b"end") => Some(jet_end),
|
//
|
||||||
tas!(b"cat") => Some(jet_cat),
|
|
||||||
tas!(b"cut") => Some(jet_cut),
|
|
||||||
tas!(b"can") => Some(jet_can),
|
|
||||||
tas!(b"rep") => Some(jet_rep),
|
|
||||||
tas!(b"rip") => Some(jet_rip),
|
|
||||||
tas!(b"met") => Some(jet_met),
|
|
||||||
tas!(b"mug") => Some(jet_mug),
|
tas!(b"mug") => Some(jet_mug),
|
||||||
tas!(b"rev") => Some(jet_rev),
|
//
|
||||||
|
tas!(b"scow") => Some(jet_scow),
|
||||||
|
//
|
||||||
|
tas!(b"mink") => Some(jet_mink),
|
||||||
_ => {
|
_ => {
|
||||||
// eprintln!("Unknown jet: {:?}", jet_name);
|
// eprintln!("Unknown jet: {:?}", jet_name);
|
||||||
None
|
None
|
||||||
@ -81,3 +107,288 @@ pub fn get_jet_test_mode(_jet_name: Noun) -> bool {
|
|||||||
*/
|
*/
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod util {
|
||||||
|
use super::*;
|
||||||
|
use crate::noun::Error::NotRepresentable;
|
||||||
|
use crate::noun::{Atom, Cell, DirectAtom, IndirectAtom, Noun, D};
|
||||||
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
|
use ibig::UBig;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently, only addresses indexable by the first 48 bits are reachable by
|
||||||
|
* modern 64-bit CPUs.
|
||||||
|
*/
|
||||||
|
const MAX_BIT_LENGTH: usize = (1 << 47) - 1;
|
||||||
|
|
||||||
|
/// Performs addition that returns None on Noun size overflow
|
||||||
|
pub fn checked_add(a: usize, b: usize) -> result::Result<usize, JetErr> {
|
||||||
|
a.checked_add(b)
|
||||||
|
.filter(|x| x <= &MAX_BIT_LENGTH)
|
||||||
|
.ok_or(JetErr::NonDeterministic)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs addition that returns None on Noun size overflow
|
||||||
|
pub fn checked_sub(a: usize, b: usize) -> result::Result<usize, JetErr> {
|
||||||
|
a.checked_sub(b).ok_or(JetErr::NonDeterministic)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checked_left_shift(bloq: usize, a: usize) -> result::Result<usize, JetErr> {
|
||||||
|
let res = a << bloq;
|
||||||
|
|
||||||
|
// Catch overflow
|
||||||
|
if (res >> bloq) < a || res > MAX_BIT_LENGTH {
|
||||||
|
Err(JetErr::NonDeterministic)
|
||||||
|
} else {
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert length in bits to length in 64-bit words
|
||||||
|
pub fn bits_to_word(a: usize) -> result::Result<usize, JetErr> {
|
||||||
|
checked_add(a, 63).map(|x| x >> 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert length as bite to length in 64-bit words
|
||||||
|
pub fn bite_to_word(bloq: usize, step: usize) -> result::Result<usize, JetErr> {
|
||||||
|
bits_to_word(checked_left_shift(bloq, step)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn slot(noun: Noun, axis: u64) -> Result {
|
||||||
|
noun.slot(axis).map_err(|_e| JetErr::Deterministic)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract a bloq and check that it's computable by the current system
|
||||||
|
pub fn bloq(a: Noun) -> result::Result<usize, JetErr> {
|
||||||
|
let bloq = a.as_direct()?.data() as usize;
|
||||||
|
if bloq >= 47 {
|
||||||
|
Err(JetErr::NonDeterministic)
|
||||||
|
} else {
|
||||||
|
Ok(bloq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract the bloq and step from a bite
|
||||||
|
pub fn bite(a: Noun) -> result::Result<(usize, usize), JetErr> {
|
||||||
|
if let Ok(cell) = a.as_cell() {
|
||||||
|
let bloq = bloq(cell.head())?;
|
||||||
|
let step = cell.tail().as_direct()?.data() as usize;
|
||||||
|
Ok((bloq, step))
|
||||||
|
} else {
|
||||||
|
bloq(a).map(|x| (x, 1_usize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** In a bloq space, copy from `from` for a span of `step`, to position `to`.
|
||||||
|
*
|
||||||
|
* Note: unlike the vere version, this sets the bits instead of XORing
|
||||||
|
* them. If we need the XOR version, we could use ^=.
|
||||||
|
*/
|
||||||
|
pub unsafe fn chop(
|
||||||
|
bloq: usize,
|
||||||
|
from: usize,
|
||||||
|
step: usize,
|
||||||
|
to: usize,
|
||||||
|
dest: &mut BitSlice<u64, Lsb0>,
|
||||||
|
source: &BitSlice<u64, Lsb0>,
|
||||||
|
) -> result::Result<(), JetErr> {
|
||||||
|
let from_b = checked_left_shift(bloq, from)?;
|
||||||
|
let to_b = checked_left_shift(bloq, to)?;
|
||||||
|
let mut step_b = checked_left_shift(bloq, step)?;
|
||||||
|
let end_b = checked_add(from_b, step_b)?;
|
||||||
|
|
||||||
|
if from_b >= source.len() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if end_b > source.len() {
|
||||||
|
step_b -= end_b - source.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[to_b..to_b + step_b].copy_from_bitslice(&source[from_b..from_b + step_b]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subtraction
|
||||||
|
pub fn sub(stack: &mut NockStack, a: Atom, b: Atom) -> noun::Result<Atom> {
|
||||||
|
if let (Ok(a), Ok(b)) = (a.as_direct(), b.as_direct()) {
|
||||||
|
let a_small = a.data();
|
||||||
|
let b_small = b.data();
|
||||||
|
|
||||||
|
if a_small < b_small {
|
||||||
|
Err(NotRepresentable)
|
||||||
|
} else {
|
||||||
|
Ok(Atom::new(stack, a_small - b_small))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let a_big = a.as_ubig(stack);
|
||||||
|
let b_big = b.as_ubig(stack);
|
||||||
|
|
||||||
|
if a_big < b_big {
|
||||||
|
Err(NotRepresentable)
|
||||||
|
} else {
|
||||||
|
let a_big = a.as_ubig(stack);
|
||||||
|
let b_big = b.as_ubig(stack);
|
||||||
|
let res = UBig::sub_stack(stack, a_big, b_big);
|
||||||
|
Ok(Atom::from_ubig(stack, &res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binary exponent
|
||||||
|
pub fn bex(stack: &mut NockStack, arg: usize) -> Atom {
|
||||||
|
unsafe {
|
||||||
|
if arg < 63 {
|
||||||
|
DirectAtom::new_unchecked(1 << arg).as_atom()
|
||||||
|
} else {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, (arg + 7) >> 3);
|
||||||
|
dest.set(arg, true);
|
||||||
|
atom.normalize_as_atom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Measure the number of bloqs in an atom
|
||||||
|
pub fn met(bloq: usize, a: Atom) -> usize {
|
||||||
|
if unsafe { a.as_noun().raw_equals(D(0)) } {
|
||||||
|
0
|
||||||
|
} else if bloq < 6 {
|
||||||
|
(a.bit_size() + ((1 << bloq) - 1)) >> bloq
|
||||||
|
} else {
|
||||||
|
let bloq_word = bloq - 6;
|
||||||
|
(a.size() + ((1 << bloq_word) - 1)) >> bloq_word
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rip(stack: &mut NockStack, bloq: usize, step: usize, atom: Atom) -> Result {
|
||||||
|
let len = (met(bloq, atom) + step - 1) / step;
|
||||||
|
let mut list = D(0);
|
||||||
|
for i in (0..len).rev() {
|
||||||
|
let new_atom = unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(stack, step << bloq);
|
||||||
|
chop(bloq, i * step, step, 0, new_slice, atom.as_bitslice())?;
|
||||||
|
new_indirect.normalize_as_atom()
|
||||||
|
};
|
||||||
|
list = Cell::new(stack, new_atom.as_noun(), list).as_noun();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binary OR
|
||||||
|
pub fn con(stack: &mut NockStack, a: Atom, b: Atom) -> Atom {
|
||||||
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(stack, new_size);
|
||||||
|
let a_bit = a.as_bitslice();
|
||||||
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
|
*dest |= b.as_bitslice();
|
||||||
|
atom.normalize_as_atom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::hamt::Hamt;
|
||||||
|
use crate::mem::{unifying_equality, NockStack};
|
||||||
|
use crate::noun::{Atom, Noun, D, T};
|
||||||
|
use assert_no_alloc::assert_no_alloc;
|
||||||
|
use ibig::UBig;
|
||||||
|
|
||||||
|
pub fn init_stack() -> NockStack {
|
||||||
|
NockStack::new(8 << 10 << 10, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn A(stack: &mut NockStack, ubig: &UBig) -> Noun {
|
||||||
|
Atom::from_ubig(stack, ubig).as_noun()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_noun_eq(stack: &mut NockStack, mut a: Noun, mut b: Noun) {
|
||||||
|
let eq = unsafe { unifying_equality(stack, &mut a, &mut b) };
|
||||||
|
assert!(eq, "got: {}, need: {}", a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_jet(stack: &mut NockStack, jet: Jet, sam: Noun, res: Noun) {
|
||||||
|
let mut context = Context {
|
||||||
|
stack,
|
||||||
|
newt: None,
|
||||||
|
cache: &mut Hamt::<Noun>::new(),
|
||||||
|
};
|
||||||
|
let sam = T(context.stack, &[D(0), sam, D(0)]);
|
||||||
|
let jet_res = assert_no_alloc(|| jet(&mut context, sam).unwrap());
|
||||||
|
assert_noun_eq(stack, jet_res, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_jet_ubig(stack: &mut NockStack, jet: Jet, sam: Noun, res: UBig) {
|
||||||
|
let res = A(stack, &res);
|
||||||
|
assert_jet(stack, jet, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_nary_jet_ubig(stack: &mut NockStack, jet: Jet, sam: &[Noun], res: UBig) {
|
||||||
|
let sam = T(stack, sam);
|
||||||
|
assert_jet_ubig(stack, jet, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assert_jet_err(stack: &mut NockStack, jet: Jet, sam: Noun, err: JetErr) {
|
||||||
|
let mut context = Context {
|
||||||
|
stack,
|
||||||
|
newt: None,
|
||||||
|
cache: &mut Hamt::<Noun>::new(),
|
||||||
|
};
|
||||||
|
let sam = T(context.stack, &[D(0), sam, D(0)]);
|
||||||
|
let jet_res = jet(&mut context, sam);
|
||||||
|
assert!(
|
||||||
|
jet_res.is_err(),
|
||||||
|
"with sample: {}, expected err: {:?}, got: {:?}",
|
||||||
|
sam,
|
||||||
|
err,
|
||||||
|
&jet_res
|
||||||
|
);
|
||||||
|
let jet_err = jet_res.unwrap_err();
|
||||||
|
assert_eq!(
|
||||||
|
jet_err, err,
|
||||||
|
"with sample: {}, expected err: {:?}, got: {:?}",
|
||||||
|
sam, err, jet_err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::test::{init_stack, A};
|
||||||
|
use super::*;
|
||||||
|
use ibig::ubig;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_met() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
|
||||||
|
let a = A(s, &ubig!(0xdeadbeef12345678fedcba9876543210))
|
||||||
|
.as_atom()
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(met(0, a), 128);
|
||||||
|
assert_eq!(met(1, a), 64);
|
||||||
|
assert_eq!(met(2, a), 32);
|
||||||
|
assert_eq!(met(3, a), 16);
|
||||||
|
assert_eq!(met(4, a), 8);
|
||||||
|
assert_eq!(met(5, a), 4);
|
||||||
|
assert_eq!(met(6, a), 2);
|
||||||
|
assert_eq!(met(7, a), 1);
|
||||||
|
assert_eq!(met(8, a), 1);
|
||||||
|
|
||||||
|
let a = D(0x7fffffffffffffff).as_atom().unwrap();
|
||||||
|
assert_eq!(met(0, a), 63);
|
||||||
|
assert_eq!(met(1, a), 32);
|
||||||
|
assert_eq!(met(2, a), 16);
|
||||||
|
assert_eq!(met(3, a), 8);
|
||||||
|
assert_eq!(met(4, a), 4);
|
||||||
|
assert_eq!(met(5, a), 2);
|
||||||
|
assert_eq!(met(6, a), 1);
|
||||||
|
assert_eq!(met(7, a), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
713
rust/ares/src/jets/bits.rs
Normal file
713
rust/ares/src/jets/bits.rs
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
/** Bit arithmetic & logic jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::*;
|
||||||
|
use crate::jets::JetErr::*;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::noun::{DirectAtom, IndirectAtom, Noun, D};
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit arithmetic
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn jet_bex(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?.as_direct()?.data() as usize;
|
||||||
|
Ok(bex(context.stack, arg).as_noun())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_can(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
|
let original_list = slot(arg, 3)?;
|
||||||
|
|
||||||
|
let mut len = 0usize;
|
||||||
|
let mut list = original_list;
|
||||||
|
loop {
|
||||||
|
if unsafe { list.raw_equals(D(0)) } {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
let item = cell.head().as_cell()?;
|
||||||
|
let step = item.head().as_direct()?.data() as usize;
|
||||||
|
|
||||||
|
len = checked_add(len, step)?;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
Ok(D(0))
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?);
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut list = original_list;
|
||||||
|
loop {
|
||||||
|
if list.raw_equals(D(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
let item = cell.head().as_cell()?;
|
||||||
|
let step = item.head().as_direct()?.data() as usize;
|
||||||
|
let atom = item.tail().as_atom()?;
|
||||||
|
chop(bloq, 0, step, pos, new_slice, atom.as_bitslice())?;
|
||||||
|
|
||||||
|
pos += step;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_cat(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
|
let a = slot(arg, 6)?.as_atom()?;
|
||||||
|
let b = slot(arg, 7)?.as_atom()?;
|
||||||
|
|
||||||
|
let len_a = met(bloq, a);
|
||||||
|
let len_b = met(bloq, b);
|
||||||
|
let new_len = bite_to_word(bloq, checked_add(len_a, len_b)?)?;
|
||||||
|
if new_len == 0 {
|
||||||
|
Ok(a.as_noun())
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, new_len);
|
||||||
|
chop(bloq, 0, len_a, 0, new_slice, a.as_bitslice())?;
|
||||||
|
chop(bloq, 0, len_b, len_a, new_slice, b.as_bitslice())?;
|
||||||
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_cut(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
|
let start = slot(arg, 12)?.as_direct()?.data() as usize;
|
||||||
|
let run = slot(arg, 13)?.as_direct()?.data() as usize;
|
||||||
|
let atom = slot(arg, 7)?.as_atom()?;
|
||||||
|
|
||||||
|
if run == 0 {
|
||||||
|
return Ok(D(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_indirect = unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, run)?);
|
||||||
|
chop(bloq, start, run, 0, new_slice, atom.as_bitslice())?;
|
||||||
|
new_indirect.normalize_as_atom()
|
||||||
|
};
|
||||||
|
Ok(new_indirect.as_noun())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_end(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
if step == 0 {
|
||||||
|
Ok(D(0))
|
||||||
|
} else if step >= met(bloq, a) {
|
||||||
|
Ok(a.as_noun())
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, step)?);
|
||||||
|
chop(bloq, 0, step, 0, new_slice, a.as_bitslice())?;
|
||||||
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_lsh(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
let len = met(bloq, a);
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(D(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_size = bits_to_word(checked_add(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size);
|
||||||
|
chop(bloq, 0, len, step, dest, a.as_bitslice())?;
|
||||||
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_met(_context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
Ok(D(met(bloq, a) as u64))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_rap(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let bloq = bloq(slot(arg, 2)?)?;
|
||||||
|
let original_list = slot(arg, 3)?;
|
||||||
|
|
||||||
|
let mut len = 0usize;
|
||||||
|
let mut list = original_list;
|
||||||
|
loop {
|
||||||
|
if unsafe { list.raw_equals(D(0)) } {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
|
||||||
|
len = checked_add(len, met(bloq, cell.head().as_atom()?))?;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
Ok(D(0))
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?);
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut list = original_list;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if list.raw_equals(D(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
let atom = cell.head().as_atom()?;
|
||||||
|
let step = met(bloq, atom);
|
||||||
|
chop(bloq, 0, step, pos, new_slice, atom.as_bitslice())?;
|
||||||
|
|
||||||
|
pos += step;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_rep(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
|
let original_list = slot(arg, 3)?;
|
||||||
|
|
||||||
|
let mut len = 0usize;
|
||||||
|
let mut list = original_list;
|
||||||
|
loop {
|
||||||
|
if unsafe { list.raw_equals(D(0)) } {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
|
||||||
|
len = checked_add(len, step)?;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
if len == 0 {
|
||||||
|
Ok(D(0))
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let (mut new_indirect, new_slice) =
|
||||||
|
IndirectAtom::new_raw_mut_bitslice(context.stack, bite_to_word(bloq, len)?);
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut list = original_list;
|
||||||
|
loop {
|
||||||
|
if list.raw_equals(D(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
let atom = cell.head().as_atom()?;
|
||||||
|
chop(bloq, 0, step, pos, new_slice, atom.as_bitslice())?;
|
||||||
|
|
||||||
|
pos += step;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
Ok(new_indirect.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_rev(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let boz = slot(arg, 2)?.as_atom()?.as_direct()?.data();
|
||||||
|
|
||||||
|
if boz >= 64 {
|
||||||
|
return Err(NonDeterministic);
|
||||||
|
}
|
||||||
|
|
||||||
|
let boz = boz as usize;
|
||||||
|
|
||||||
|
let len = slot(arg, 6)?.as_atom()?.as_direct()?.data();
|
||||||
|
|
||||||
|
let dat = slot(arg, 7)?.as_atom()?;
|
||||||
|
|
||||||
|
let bits = len << boz;
|
||||||
|
|
||||||
|
/* 63 is the maximum number of bits for a direct atom */
|
||||||
|
let mut output = if dat.is_direct() && bits < 64 {
|
||||||
|
unsafe { DirectAtom::new_unchecked(0).as_atom() }
|
||||||
|
} else {
|
||||||
|
unsafe { IndirectAtom::new_raw(context.stack, ((bits + 7) / 8) as usize, &0).as_atom() }
|
||||||
|
};
|
||||||
|
|
||||||
|
let src = dat.as_bitslice();
|
||||||
|
let dest = output.as_bitslice_mut();
|
||||||
|
|
||||||
|
let len = len as usize;
|
||||||
|
let total_len = len << boz;
|
||||||
|
|
||||||
|
for (start, end) in (0..len).map(|b| (b << boz, (b + 1) << boz)) {
|
||||||
|
dest[start..end].copy_from_bitslice(&src[(total_len - end)..(total_len - start)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unsafe { output.normalize() }.as_noun())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_rip(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
|
let atom = slot(arg, 3)?.as_atom()?;
|
||||||
|
rip(context.stack, bloq, step, atom)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_rsh(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let (bloq, step) = bite(slot(arg, 2)?)?;
|
||||||
|
let a = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
let len = met(bloq, a);
|
||||||
|
if step >= len {
|
||||||
|
return Ok(D(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_size = bits_to_word(checked_sub(a.bit_size(), checked_left_shift(bloq, step)?)?)?;
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size);
|
||||||
|
chop(bloq, step, len - step, 0, dest, a.as_bitslice())?;
|
||||||
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit logic
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn jet_con(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
Ok(con(context.stack, a, b).as_noun())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_dis(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size);
|
||||||
|
let a_bit = a.as_bitslice();
|
||||||
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
|
*dest &= b.as_bitslice();
|
||||||
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_mix(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let a = slot(arg, 2)?.as_atom()?;
|
||||||
|
let b = slot(arg, 3)?.as_atom()?;
|
||||||
|
|
||||||
|
let new_size = cmp::max(a.size(), b.size());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let (mut atom, dest) = IndirectAtom::new_raw_mut_bitslice(context.stack, new_size);
|
||||||
|
let a_bit = a.as_bitslice();
|
||||||
|
dest[..a_bit.len()].copy_from_bitslice(a_bit);
|
||||||
|
*dest ^= b.as_bitslice();
|
||||||
|
Ok(atom.normalize_as_atom().as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, assert_jet_ubig, init_stack, A};
|
||||||
|
use crate::mem::NockStack;
|
||||||
|
use crate::noun::{Noun, D, T};
|
||||||
|
use ibig::ubig;
|
||||||
|
|
||||||
|
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
||||||
|
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_0(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_24(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0x876543)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_63(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0x7fffffffffffffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_96(stack: &mut NockStack) -> Noun {
|
||||||
|
A(stack, &ubig!(0xfaceb00c15deadbeef123456))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_128(stack: &mut NockStack) -> Noun {
|
||||||
|
A(stack, &ubig!(0xdeadbeef12345678fedcba9876543210))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit arithmetic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bex() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
assert_jet(s, jet_bex, D(0), D(1));
|
||||||
|
assert_jet(s, jet_bex, D(5), D(32));
|
||||||
|
assert_jet(s, jet_bex, D(62), D(0x4000000000000000));
|
||||||
|
assert_jet_ubig(
|
||||||
|
s,
|
||||||
|
jet_bex,
|
||||||
|
D(256),
|
||||||
|
ubig!(_0x10000000000000000000000000000000000000000000000000000000000000000),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, _a24, _a63, _a96, a128) = atoms(s);
|
||||||
|
let bloq0 = D(0);
|
||||||
|
let bloq3 = D(3);
|
||||||
|
let bloq4 = D(4);
|
||||||
|
let sam = T(s, &[bloq0, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq3, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0));
|
||||||
|
let run1 = T(s, &[D(0), a0]);
|
||||||
|
let run2 = T(s, &[D(1), a0]);
|
||||||
|
let run3 = T(s, &[D(2), a0]);
|
||||||
|
let sam = T(s, &[bloq0, run1, run2, run3, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq3, run1, run2, run3, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0));
|
||||||
|
let run1 = T(s, &[D(1), a128]);
|
||||||
|
let run2 = T(s, &[D(3), a0]);
|
||||||
|
let sam = T(s, &[bloq3, run1, run2, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0x10));
|
||||||
|
let run1 = T(s, &[D(3), a0]);
|
||||||
|
let run2 = T(s, &[D(1), a128]);
|
||||||
|
let sam = T(s, &[bloq3, run1, run2, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0x10000000));
|
||||||
|
let run1 = T(s, &[D(8), D(0xfe)]);
|
||||||
|
let run2 = T(s, &[D(4), D(0xa)]);
|
||||||
|
let run3 = T(s, &[D(0), D(0xbbbb)]);
|
||||||
|
let run4 = T(s, &[D(1), D(0)]);
|
||||||
|
let run5 = T(s, &[D(1), D(0)]);
|
||||||
|
let run6 = T(s, &[D(1), D(1)]);
|
||||||
|
let run7 = T(s, &[D(1), D(1)]);
|
||||||
|
let sam = T(s, &[bloq0, run1, run2, run3, run4, run5, run6, run7, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0xcafe));
|
||||||
|
let run1 = T(s, &[D(1), D(0xfe)]);
|
||||||
|
let run2 = T(s, &[D(1), D(0xca)]);
|
||||||
|
let sam = T(s, &[bloq4, run1, run2, D(0)]);
|
||||||
|
assert_jet(s, jet_can, sam, D(0xca00fe));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cat() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, _a63, _a96, a128) = atoms(s);
|
||||||
|
let bloq0 = D(0);
|
||||||
|
let bloq3 = D(3);
|
||||||
|
let bloq4 = D(4);
|
||||||
|
let sam = T(s, &[bloq0, a0, a0]);
|
||||||
|
assert_jet(s, jet_cat, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq3, a0, a0]);
|
||||||
|
assert_jet(s, jet_cat, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq0, a24, a128]);
|
||||||
|
let res = A(s, &ubig!(_0xdeadbeef12345678fedcba9876543210876543));
|
||||||
|
assert_jet(s, jet_cat, sam, res);
|
||||||
|
let sam = T(s, &[bloq3, a24, a128]);
|
||||||
|
let res = A(s, &ubig!(_0xdeadbeef12345678fedcba9876543210876543));
|
||||||
|
assert_jet(s, jet_cat, sam, res);
|
||||||
|
let sam = T(s, &[bloq4, a24, a128]);
|
||||||
|
let res = A(s, &ubig!(_0xdeadbeef12345678fedcba987654321000876543));
|
||||||
|
assert_jet(s, jet_cat, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cut() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (_a0, a24, _a63, a96, a128) = atoms(s);
|
||||||
|
let run = T(s, &[D(0), D(0)]);
|
||||||
|
let sam = T(s, &[D(0), run, a24]);
|
||||||
|
assert_jet(s, jet_cut, sam, D(0));
|
||||||
|
let run = T(s, &[D(0), D(5)]);
|
||||||
|
let sam = T(s, &[D(0), run, a24]);
|
||||||
|
assert_jet(s, jet_cut, sam, D(0x3));
|
||||||
|
let run = T(s, &[D(4), D(6)]);
|
||||||
|
let sam = T(s, &[D(3), run, a96]);
|
||||||
|
assert_jet(s, jet_cut, sam, D(0xb00c15deadbe));
|
||||||
|
let run = T(s, &[D(4), D(1)]);
|
||||||
|
let sam = T(s, &[D(4), run, a24]);
|
||||||
|
assert_jet(s, jet_cut, sam, D(0));
|
||||||
|
let run = T(s, &[D(2), D(10)]);
|
||||||
|
let sam = T(s, &[D(4), run, a128]);
|
||||||
|
let res = A(s, &ubig!(0xdeadbeef12345678fedcba98));
|
||||||
|
assert_jet(s, jet_cut, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_end() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, _a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a24]);
|
||||||
|
assert_jet(s, jet_end, sam, D(0x1));
|
||||||
|
let sam = T(s, &[D(3), a24]);
|
||||||
|
assert_jet(s, jet_end, sam, D(0x43));
|
||||||
|
let sam = T(s, &[D(7), a24]);
|
||||||
|
assert_jet(s, jet_end, sam, a24);
|
||||||
|
let sam = T(s, &[D(6), a128]);
|
||||||
|
let res = A(s, &ubig!(0xfedcba9876543210));
|
||||||
|
assert_jet(s, jet_end, sam, res);
|
||||||
|
|
||||||
|
let bit = T(s, &[D(0), D(5)]);
|
||||||
|
let sam = T(s, &[bit, a24]);
|
||||||
|
assert_jet(s, jet_end, sam, D(0x3));
|
||||||
|
let bit = T(s, &[D(4), D(6)]);
|
||||||
|
let sam = T(s, &[bit, a96]);
|
||||||
|
assert_jet(s, jet_end, sam, a96);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lsh() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, _a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a24]);
|
||||||
|
assert_jet(s, jet_lsh, sam, D(0x10eca86));
|
||||||
|
let sam = T(s, &[D(3), a24]);
|
||||||
|
assert_jet(s, jet_lsh, sam, D(0x87654300));
|
||||||
|
let sam = T(s, &[D(7), a24]);
|
||||||
|
let res = A(s, &ubig!(_0x87654300000000000000000000000000000000));
|
||||||
|
assert_jet(s, jet_lsh, sam, res);
|
||||||
|
let sam = T(s, &[D(6), a128]);
|
||||||
|
let res = A(
|
||||||
|
s,
|
||||||
|
&ubig!(_0xdeadbeef12345678fedcba98765432100000000000000000),
|
||||||
|
);
|
||||||
|
assert_jet(s, jet_lsh, sam, res);
|
||||||
|
|
||||||
|
let bit = T(s, &[D(0), D(5)]);
|
||||||
|
let sam = T(s, &[bit, a24]);
|
||||||
|
assert_jet(s, jet_lsh, sam, D(0x10eca860));
|
||||||
|
let bit = T(s, &[D(4), D(6)]);
|
||||||
|
let sam = T(s, &[bit, a96]);
|
||||||
|
let res = A(
|
||||||
|
s,
|
||||||
|
&ubig!(_0xfaceb00c15deadbeef123456000000000000000000000000),
|
||||||
|
);
|
||||||
|
assert_jet(s, jet_lsh, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_met() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, _a63, _a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a0]);
|
||||||
|
assert_jet(s, jet_met, sam, D(0));
|
||||||
|
let sam = T(s, &[a0, a24]);
|
||||||
|
assert_jet(s, jet_met, sam, D(24));
|
||||||
|
let sam = T(s, &[D(3), a24]);
|
||||||
|
assert_jet(s, jet_met, sam, D(3));
|
||||||
|
let sam = T(s, &[D(1), a128]);
|
||||||
|
assert_jet(s, jet_met, sam, D(64));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rap() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let bloq0 = D(0);
|
||||||
|
let bloq2 = D(2);
|
||||||
|
let bloq3 = D(3);
|
||||||
|
let empty_list = D(0);
|
||||||
|
let zero_list = T(s, &[D(0), D(0), D(0)]);
|
||||||
|
let test_list = T(s, &[D(0xe), D(0xf), D(0xa), D(0xc), D(0)]);
|
||||||
|
let wide_list = T(s, &[D(0xafe), D(0xc), D(0)]);
|
||||||
|
let sam = T(s, &[bloq0, empty_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq0, zero_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq3, zero_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0));
|
||||||
|
let sam = T(s, &[bloq0, test_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0xcafe));
|
||||||
|
let sam = T(s, &[bloq2, test_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0xcafe));
|
||||||
|
let sam = T(s, &[bloq2, wide_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0xcafe));
|
||||||
|
let sam = T(s, &[bloq3, test_list]);
|
||||||
|
let res = A(s, &ubig!(0xc0a0f0e));
|
||||||
|
assert_jet(s, jet_rap, sam, res);
|
||||||
|
let sam = T(s, &[bloq3, wide_list]);
|
||||||
|
assert_jet(s, jet_rap, sam, D(0xc0afe));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rep() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[D(0), D(0)]);
|
||||||
|
assert_jet(s, jet_rep, sam, D(0));
|
||||||
|
let bit = T(s, &[D(3), D(2)]);
|
||||||
|
let sam = T(s, &[bit, a0, a24, a63, a96, a128, D(0)]);
|
||||||
|
let res = A(s, &ubig!(0x32103456ffff65430000));
|
||||||
|
assert_jet(s, jet_rep, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rev() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (_a0, a24, _a63, _a96, _a128) = atoms(s);
|
||||||
|
let sam = T(s, &[D(0), D(60), a24]);
|
||||||
|
assert_jet(s, jet_rev, sam, D(0xc2a6e1000000000));
|
||||||
|
let test = 0x1234567890123u64;
|
||||||
|
let sam = T(s, &[D(3), D(7), D(test)]);
|
||||||
|
assert_jet(s, jet_rev, sam, D(test.swap_bytes() >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rip() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (_a0, _a24, _a63, _a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[D(0), D(0)]);
|
||||||
|
assert_jet(s, jet_rip, sam, D(0));
|
||||||
|
let bit = T(s, &[D(1), D(2)]);
|
||||||
|
let sam = T(s, &[bit, a128]);
|
||||||
|
#[rustfmt::skip]
|
||||||
|
let res = T(
|
||||||
|
s,
|
||||||
|
&[
|
||||||
|
D(0x0), D(0x1), D(0x2), D(0x3), D(0x4), D(0x5), D(0x6), D(0x7),
|
||||||
|
D(0x8), D(0x9), D(0xa), D(0xb), D(0xc), D(0xd), D(0xe), D(0xf),
|
||||||
|
D(0x8), D(0x7), D(0x6), D(0x5), D(0x4), D(0x3), D(0x2), D(0x1),
|
||||||
|
D(0xf), D(0xe), D(0xe), D(0xb), D(0xd), D(0xa), D(0xe), D(0xd),
|
||||||
|
D(0x0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_jet(s, jet_rip, sam, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rsh() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, _a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a24]);
|
||||||
|
assert_jet(s, jet_rsh, sam, D(0x43b2a1));
|
||||||
|
let sam = T(s, &[D(3), a24]);
|
||||||
|
assert_jet(s, jet_rsh, sam, D(0x8765));
|
||||||
|
let sam = T(s, &[D(7), a24]);
|
||||||
|
assert_jet(s, jet_rsh, sam, D(0));
|
||||||
|
let sam = T(s, &[D(2), a128]);
|
||||||
|
let res = A(s, &ubig!(0xdeadbeef12345678fedcba987654321));
|
||||||
|
assert_jet(s, jet_rsh, sam, res);
|
||||||
|
let sam = T(s, &[D(6), a128]);
|
||||||
|
let res = A(s, &ubig!(0xdeadbeef12345678));
|
||||||
|
assert_jet(s, jet_rsh, sam, res);
|
||||||
|
|
||||||
|
let bit = T(s, &[D(0), D(5)]);
|
||||||
|
let sam = T(s, &[bit, a24]);
|
||||||
|
assert_jet(s, jet_rsh, sam, D(0x43b2a));
|
||||||
|
let bit = T(s, &[D(4), D(6)]);
|
||||||
|
let sam = T(s, &[bit, a96]);
|
||||||
|
assert_jet(s, jet_rsh, sam, D(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit logic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_con() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a0]);
|
||||||
|
assert_jet(s, jet_con, sam, D(0));
|
||||||
|
let sam = T(s, &[a24, a96]);
|
||||||
|
let res = A(s, &ubig!(0xfaceb00c15deadbeef977557));
|
||||||
|
assert_jet(s, jet_con, sam, res);
|
||||||
|
let sam = T(s, &[a96, a128]);
|
||||||
|
let res = A(s, &ubig!(0xdeadbeeffafef67cffdebfbeff563656));
|
||||||
|
assert_jet(s, jet_con, sam, res);
|
||||||
|
let sam = T(s, &[a24, a63]);
|
||||||
|
assert_jet(s, jet_con, sam, a63);
|
||||||
|
let sam = T(s, &[a0, a128]);
|
||||||
|
assert_jet(s, jet_con, sam, a128);
|
||||||
|
let sam = T(s, &[a128, a0]);
|
||||||
|
assert_jet(s, jet_con, sam, a128);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dis() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a0]);
|
||||||
|
assert_jet(s, jet_dis, sam, D(0));
|
||||||
|
let sam = T(s, &[a24, a96]);
|
||||||
|
assert_jet(s, jet_dis, sam, D(0x22442));
|
||||||
|
let sam = T(s, &[a96, a128]);
|
||||||
|
let res = A(s, &ubig!(0x1204100814dca89866103010));
|
||||||
|
assert_jet(s, jet_dis, sam, res);
|
||||||
|
let sam = T(s, &[a24, a63]);
|
||||||
|
assert_jet(s, jet_dis, sam, a24);
|
||||||
|
let sam = T(s, &[a0, a128]);
|
||||||
|
assert_jet(s, jet_dis, sam, a0);
|
||||||
|
let sam = T(s, &[a128, a0]);
|
||||||
|
assert_jet(s, jet_dis, sam, a0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mix() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, a63, a96, a128) = atoms(s);
|
||||||
|
let sam = T(s, &[a0, a0]);
|
||||||
|
assert_jet(s, jet_mix, sam, D(0));
|
||||||
|
let sam = T(s, &[a24, a96]);
|
||||||
|
let res = A(s, &ubig!(0xfaceb00c15deadbeef955115));
|
||||||
|
assert_jet(s, jet_mix, sam, res);
|
||||||
|
let sam = T(s, &[a96, a128]);
|
||||||
|
let res = A(s, &ubig!(0xdeadbeefe8fae674eb02172699460646));
|
||||||
|
assert_jet(s, jet_mix, sam, res);
|
||||||
|
let sam = T(s, &[a24, a63]);
|
||||||
|
let res = A(s, &ubig!(0x7fffffffff789abc));
|
||||||
|
assert_jet(s, jet_mix, sam, res);
|
||||||
|
let sam = T(s, &[a0, a128]);
|
||||||
|
assert_jet(s, jet_mix, sam, a128);
|
||||||
|
let sam = T(s, &[a128, a0]);
|
||||||
|
assert_jet(s, jet_mix, sam, a128);
|
||||||
|
}
|
||||||
|
}
|
140
rust/ares/src/jets/form.rs
Normal file
140
rust/ares/src/jets/form.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/** Formatting jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::slot;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::noun::Noun;
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
pub fn jet_scow(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let aura = slot(subject, 12)?.as_direct()?;
|
||||||
|
let atom = slot(subject, 13)?.as_atom()?;
|
||||||
|
util::scow(context.stack, aura, atom)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod util {
|
||||||
|
use crate::jets;
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::mem::NockStack;
|
||||||
|
use crate::noun::{Atom, Cell, DirectAtom, D, T};
|
||||||
|
use ares_macros::tas;
|
||||||
|
use num_traits::identities::Zero;
|
||||||
|
|
||||||
|
pub fn scow(
|
||||||
|
stack: &mut NockStack,
|
||||||
|
aura: DirectAtom, // XX: technically this should be Atom?
|
||||||
|
atom: Atom,
|
||||||
|
) -> jets::Result {
|
||||||
|
match aura.data() {
|
||||||
|
tas!(b"ud") => {
|
||||||
|
if atom.as_bitslice().first_one().is_none() {
|
||||||
|
return Ok(T(stack, &[D(b'0' as u64), D(0)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut root = D(0);
|
||||||
|
let mut lent = 0;
|
||||||
|
if atom.direct().is_some() {
|
||||||
|
let mut n = atom.as_direct()?.data();
|
||||||
|
|
||||||
|
while n != 0 {
|
||||||
|
root = T(stack, &[D(b'0' as u64 + (n % 10)), root]);
|
||||||
|
n /= 10;
|
||||||
|
lent += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut n = atom.as_indirect()?.as_ubig(stack);
|
||||||
|
|
||||||
|
while !n.is_zero() {
|
||||||
|
root = T(stack, &[D(b'0' as u64 + (&n % 10u64)), root]);
|
||||||
|
n /= 10u64;
|
||||||
|
lent += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut list = root.as_cell()?;
|
||||||
|
lent -= 1;
|
||||||
|
|
||||||
|
while lent > 2 {
|
||||||
|
if lent % 3 == 0 {
|
||||||
|
let (cell, memory) = Cell::new_raw_mut(stack);
|
||||||
|
(*memory).head = D(b'.' as u64);
|
||||||
|
(*memory).tail = list.tail();
|
||||||
|
(*(list.to_raw_pointer_mut())).tail = cell.as_noun();
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
}
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
lent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(JetErr::Punt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack, A};
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::noun::{Noun, D, T};
|
||||||
|
use ares_macros::tas;
|
||||||
|
use ibig::ubig;
|
||||||
|
|
||||||
|
// Rust can't handle implicit conversions from u8 to u64
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn B(b: u8) -> Noun {
|
||||||
|
D(b as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scow() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let aura = D(tas!(b"ud"));
|
||||||
|
let sam = T(s, &[aura, D(0)]);
|
||||||
|
let res = T(s, &[B(b'0'), D(0)]);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let sam = T(s, &[aura, D(100)]);
|
||||||
|
let res = T(s, &[B(b'1'), B(b'0'), B(b'0'), D(0)]);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let big = A(s, &ubig!(100));
|
||||||
|
let sam = T(s, &[aura, big]);
|
||||||
|
let res = T(s, &[B(b'1'), B(b'0'), B(b'0'), D(0)]);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let sam = T(s, &[aura, D(1000)]);
|
||||||
|
let res = T(s, &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)]);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let big = A(s, &ubig!(1000));
|
||||||
|
let sam = T(s, &[aura, big]);
|
||||||
|
let res = T(s, &[B(b'1'), B(b'.'), B(b'0'), B(b'0'), B(b'0'), D(0)]);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let sam = T(s, &[aura, D(9876543210)]);
|
||||||
|
let res = T(
|
||||||
|
s,
|
||||||
|
&[
|
||||||
|
B(b'9'),
|
||||||
|
B(b'.'),
|
||||||
|
B(b'8'),
|
||||||
|
B(b'7'),
|
||||||
|
B(b'6'),
|
||||||
|
B(b'.'),
|
||||||
|
B(b'5'),
|
||||||
|
B(b'4'),
|
||||||
|
B(b'3'),
|
||||||
|
B(b'.'),
|
||||||
|
B(b'2'),
|
||||||
|
B(b'1'),
|
||||||
|
B(b'0'),
|
||||||
|
D(0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_jet(s, jet_scow, sam, res);
|
||||||
|
let bad_aura = D(tas!(b"ux"));
|
||||||
|
let sam = T(s, &[bad_aura, D(0)]);
|
||||||
|
assert_jet_err(s, jet_scow, sam, JetErr::Punt);
|
||||||
|
}
|
||||||
|
}
|
68
rust/ares/src/jets/hash.rs
Normal file
68
rust/ares/src/jets/hash.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/** Hash jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::*;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::mug::mug;
|
||||||
|
use crate::noun::Noun;
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
pub fn jet_mug(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
Ok(mug(context.stack, arg).as_noun())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, init_stack, A};
|
||||||
|
use crate::mem::NockStack;
|
||||||
|
use crate::noun::{Noun, D, T};
|
||||||
|
use ibig::ubig;
|
||||||
|
|
||||||
|
fn atoms(s: &mut NockStack) -> (Noun, Noun, Noun, Noun, Noun) {
|
||||||
|
(atom_0(s), atom_24(s), atom_63(s), atom_96(s), atom_128(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_0(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_24(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0x876543)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_63(_stack: &mut NockStack) -> Noun {
|
||||||
|
D(0x7fffffffffffffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_96(stack: &mut NockStack) -> Noun {
|
||||||
|
A(stack, &ubig!(0xfaceb00c15deadbeef123456))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atom_128(stack: &mut NockStack) -> Noun {
|
||||||
|
A(stack, &ubig!(0xdeadbeef12345678fedcba9876543210))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mug() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
let (a0, a24, a63, a96, a128) = atoms(s);
|
||||||
|
assert_jet(s, jet_mug, a0, D(0x79ff04e8));
|
||||||
|
assert_jet(s, jet_mug, a24, D(0x69d59d90));
|
||||||
|
assert_jet(s, jet_mug, a63, D(0x7a9f252e));
|
||||||
|
assert_jet(s, jet_mug, a96, D(0x2aa4c8fb));
|
||||||
|
assert_jet(s, jet_mug, a128, D(0x44fb2c0c));
|
||||||
|
let sam = T(s, &[a128, a128]);
|
||||||
|
assert_jet(s, jet_mug, sam, D(0x61c0ea5c));
|
||||||
|
let sam = T(s, &[a96, a128]);
|
||||||
|
assert_jet(s, jet_mug, sam, D(0x20fb143f));
|
||||||
|
let sam = T(s, &[a0, a0]);
|
||||||
|
assert_jet(s, jet_mug, sam, D(0x192f5588));
|
||||||
|
let sam = T(s, &[a0, a24, a63, a96, a128]);
|
||||||
|
let sam = T(s, &[sam, a0, a24, a63, a96, a128]);
|
||||||
|
let sam = T(s, &[sam, a0, a24, a63, a96, a128]);
|
||||||
|
assert_jet(s, jet_mug, sam, D(0x7543cac7));
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
375
rust/ares/src/jets/nock.rs
Normal file
375
rust/ares/src/jets/nock.rs
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
/** Virtualization jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::slot;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::noun::Noun;
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
// XX: interpret should accept optional scry function and potentially produce blocked
|
||||||
|
pub fn jet_mink(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
// mink sample = [nock scry_namespace]
|
||||||
|
// = [[subject formula] scry_namespace]
|
||||||
|
let v_subject = slot(arg, 4)?;
|
||||||
|
let v_formula = slot(arg, 5)?;
|
||||||
|
let _scry = slot(arg, 3)?;
|
||||||
|
util::mink(context, v_subject, v_formula)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod util {
|
||||||
|
use crate::interpreter::{interpret, Context, NockErr, Tone};
|
||||||
|
use crate::jets;
|
||||||
|
use crate::jets::form::util::scow;
|
||||||
|
use crate::jets::util::rip;
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::mem::NockStack;
|
||||||
|
use crate::noun::{tape, Cell, Noun, D, T};
|
||||||
|
use ares_macros::tas;
|
||||||
|
use std::result;
|
||||||
|
|
||||||
|
const LEAF: Noun = D(tas!(b"leaf"));
|
||||||
|
const ROSE: Noun = D(tas!(b"rose"));
|
||||||
|
|
||||||
|
pub fn mink(context: &mut Context, subject: Noun, formula: Noun) -> jets::Result {
|
||||||
|
// XX: no partial traces; all of our traces go down to the "home road"
|
||||||
|
match interpret(context, subject, formula) {
|
||||||
|
Ok(res) => Ok(T(context.stack, &[D(0), res])),
|
||||||
|
Err(err) => match err {
|
||||||
|
Tone::Blocked(block) => Ok(T(context.stack, &[D(1), block])),
|
||||||
|
Tone::Error(err, trace) => match err {
|
||||||
|
NockErr::Deterministic => Ok(T(context.stack, &[D(2), trace])),
|
||||||
|
NockErr::NonDeterministic => Err(JetErr::NonDeterministic),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Consume $tone, produce $toon
|
||||||
|
*/
|
||||||
|
// XX: should write a jet_mook wrapper for this function
|
||||||
|
pub fn mook(context: &mut Context, tone: Cell, flop: bool) -> result::Result<Cell, JetErr> {
|
||||||
|
let tag = tone.head().as_direct()?;
|
||||||
|
let original_list = tone.tail();
|
||||||
|
|
||||||
|
match tag.data() {
|
||||||
|
x if x < 2 => return Ok(tone),
|
||||||
|
x if x > 2 => return Err(JetErr::Deterministic),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if unsafe { original_list.raw_equals(D(0)) } {
|
||||||
|
return Ok(tone);
|
||||||
|
} else if original_list.atom().is_some() {
|
||||||
|
return Err(JetErr::Deterministic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XX: trim traces longer than 1024 frames
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let mut res = D(0);
|
||||||
|
let mut list = original_list;
|
||||||
|
// Unused if flopping
|
||||||
|
let (mut new_cell, mut new_memory) = Cell::new_raw_mut(context.stack);
|
||||||
|
let mut memory = new_memory;
|
||||||
|
|
||||||
|
// loop guaranteed to run at least once
|
||||||
|
loop {
|
||||||
|
if list.raw_equals(D(0)) {
|
||||||
|
break;
|
||||||
|
} else if !flop && res.raw_equals(D(0)) {
|
||||||
|
res = new_cell.as_noun();
|
||||||
|
} else if !flop {
|
||||||
|
(new_cell, new_memory) = Cell::new_raw_mut(context.stack);
|
||||||
|
(*memory).tail = new_cell.as_noun();
|
||||||
|
memory = new_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
let trace = cell.head().as_cell()?;
|
||||||
|
let tag = trace.head().as_direct()?;
|
||||||
|
let dat = trace.tail();
|
||||||
|
|
||||||
|
let tank: Noun = match tag.data() {
|
||||||
|
tas!(b"mean") => {
|
||||||
|
if let Ok(atom) = dat.as_atom() {
|
||||||
|
let tape = rip(context.stack, 3, 1, atom)?;
|
||||||
|
T(context.stack, &[LEAF, tape])
|
||||||
|
} else {
|
||||||
|
let tone = mink(context, dat, dat.as_cell()?.head())?.as_cell()?;
|
||||||
|
if !tone.head().raw_equals(D(0)) {
|
||||||
|
let tape = tape(context.stack, "####");
|
||||||
|
T(context.stack, &[LEAF, tape])
|
||||||
|
} else {
|
||||||
|
// XX: need to check that this is actually a tank
|
||||||
|
// return leaf+"mean.mook" if not
|
||||||
|
tone.tail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tas!(b"spot") => {
|
||||||
|
let stack = &mut context.stack;
|
||||||
|
let spot = dat.as_cell()?;
|
||||||
|
let pint = spot.tail().as_cell()?;
|
||||||
|
let pstr = pint.head().as_cell()?;
|
||||||
|
let pend = pint.tail().as_cell()?;
|
||||||
|
|
||||||
|
let colo = T(*stack, &[D(b':' as u64), D(0)]);
|
||||||
|
let trel = T(*stack, &[colo, D(0), D(0)]);
|
||||||
|
|
||||||
|
let smyt = smyt(stack, spot.head())?;
|
||||||
|
|
||||||
|
let aura = D(tas!(b"ud")).as_direct()?;
|
||||||
|
let str_lin = scow(stack, aura, pstr.head().as_atom()?)?;
|
||||||
|
let str_col = scow(stack, aura, pstr.tail().as_atom()?)?;
|
||||||
|
let end_lin = scow(stack, aura, pend.head().as_atom()?)?;
|
||||||
|
let end_col = scow(stack, aura, pend.tail().as_atom()?)?;
|
||||||
|
|
||||||
|
let mut list = end_col.as_cell()?;
|
||||||
|
loop {
|
||||||
|
if list.tail().atom().is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
}
|
||||||
|
// "{end_col}]>"
|
||||||
|
let p4 = T(*stack, &[D(b']' as u64), D(b'>' as u64), D(0)]);
|
||||||
|
(*list.tail_as_mut()) = p4;
|
||||||
|
|
||||||
|
list = end_lin.as_cell()?;
|
||||||
|
loop {
|
||||||
|
if list.tail().atom().is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
}
|
||||||
|
// "{end_lin} {end_col}]>"
|
||||||
|
let p3 = T(*stack, &[D(b' ' as u64), end_col]);
|
||||||
|
(*list.tail_as_mut()) = p3;
|
||||||
|
|
||||||
|
list = str_col.as_cell()?;
|
||||||
|
loop {
|
||||||
|
if list.tail().atom().is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
}
|
||||||
|
// "{str_col}].[{end_lin} {end_col}]>"
|
||||||
|
let p2 = T(
|
||||||
|
*stack,
|
||||||
|
&[D(b']' as u64), D(b'.' as u64), D(b'[' as u64), end_lin],
|
||||||
|
);
|
||||||
|
(*list.tail_as_mut()) = p2;
|
||||||
|
|
||||||
|
list = str_lin.as_cell()?;
|
||||||
|
loop {
|
||||||
|
if list.tail().atom().is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list = list.tail().as_cell()?;
|
||||||
|
}
|
||||||
|
// "{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
||||||
|
let p1 = T(*stack, &[D(b' ' as u64), str_col]);
|
||||||
|
(*list.tail_as_mut()) = p1;
|
||||||
|
|
||||||
|
// "<[{str_lin} {str_col}].[{end_lin} {end_col}]>"
|
||||||
|
let tape = T(*stack, &[D(b'<' as u64), D(b'[' as u64), str_lin]);
|
||||||
|
let finn = T(*stack, &[LEAF, tape]);
|
||||||
|
|
||||||
|
T(*stack, &[ROSE, trel, smyt, finn, D(0)])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let tape = rip(context.stack, 3, 1, tag.as_atom())?;
|
||||||
|
T(
|
||||||
|
context.stack,
|
||||||
|
&[
|
||||||
|
D(tas!(b"m")),
|
||||||
|
D(tas!(b"o")),
|
||||||
|
D(tas!(b"o")),
|
||||||
|
D(tas!(b"k")),
|
||||||
|
D(tas!(b".")),
|
||||||
|
tape,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
} // XX: TODO
|
||||||
|
// %hand
|
||||||
|
// %hunk
|
||||||
|
// %lose
|
||||||
|
};
|
||||||
|
|
||||||
|
if flop {
|
||||||
|
res = T(context.stack, &[tank, res]);
|
||||||
|
} else {
|
||||||
|
(*memory).head = tank;
|
||||||
|
}
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !flop {
|
||||||
|
(*memory).tail = D(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let toon = Cell::new(context.stack, D(2), res);
|
||||||
|
Ok(toon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn smyt(stack: &mut NockStack, path: Noun) -> jets::Result {
|
||||||
|
let lash = D(tas!(b"/"));
|
||||||
|
let zero = D(0);
|
||||||
|
let sep = T(stack, &[lash, zero]);
|
||||||
|
|
||||||
|
let trel = T(stack, &[sep, sep, zero]);
|
||||||
|
let tank = smyt_help(stack, path)?;
|
||||||
|
|
||||||
|
Ok(T(stack, &[ROSE, trel, tank]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smyt_help(stack: &mut NockStack, path: Noun) -> jets::Result {
|
||||||
|
// XX: switch to using Cell:new_raw_mut
|
||||||
|
if unsafe { path.raw_equals(D(0)) } {
|
||||||
|
return Ok(D(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = path.as_cell()?;
|
||||||
|
let tail = smyt_help(stack, cell.tail())?;
|
||||||
|
let trip = rip(stack, 3, 1, cell.head().as_atom()?)?;
|
||||||
|
let head = T(stack, &[LEAF, trip]);
|
||||||
|
|
||||||
|
Ok(T(stack, &[head, tail]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, init_stack};
|
||||||
|
use crate::mem::NockStack;
|
||||||
|
use crate::noun::{D, T};
|
||||||
|
use crate::serf::TERMINATOR;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn init() {
|
||||||
|
// This needs to be done because TERMINATOR is lazy allocated, and if you don't
|
||||||
|
// do it before you call the unit tests it'll get allocated on the Rust heap
|
||||||
|
// inside an assert_no_alloc block.
|
||||||
|
//
|
||||||
|
// Also Rust has no primitive for pre-test setup / post-test teardown, so we
|
||||||
|
// do it in a test that we rely on being called before any other in this file,
|
||||||
|
// since we're already using single-threaded test mode to avoid race conditions
|
||||||
|
// (because Rust doesn't support test order dependencies either).
|
||||||
|
let _ = Arc::clone(&TERMINATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mink_success() {
|
||||||
|
let sack = &mut init_stack();
|
||||||
|
let subj = D(0);
|
||||||
|
let form = T(sack, &[D(1), D(53)]);
|
||||||
|
let nock = T(sack, &[subj, form]);
|
||||||
|
let scry = D(0);
|
||||||
|
let samp = T(sack, &[nock, scry]);
|
||||||
|
let rest = T(sack, &[D(0), D(53)]);
|
||||||
|
assert_jet(sack, jet_mink, samp, rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mink_zapzap() {
|
||||||
|
let sack = &mut init_stack();
|
||||||
|
let subj = D(0);
|
||||||
|
let form = T(sack, &[D(0), D(0)]);
|
||||||
|
let nock = T(sack, &[subj, form]);
|
||||||
|
let scry = D(0);
|
||||||
|
let samp = T(sack, &[nock, scry]);
|
||||||
|
let rest = T(sack, &[D(2), D(0)]);
|
||||||
|
assert_jet(sack, jet_mink, samp, rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mink_trace() {
|
||||||
|
let sack = &mut init_stack();
|
||||||
|
let subj = D(0);
|
||||||
|
let scry = D(0);
|
||||||
|
|
||||||
|
// != !: ?~ 0 !! 53
|
||||||
|
// [ 11
|
||||||
|
// [1.953.460.339 1 [1.953.719.668 0] [1 9] [1 22]]
|
||||||
|
// [ 8
|
||||||
|
// [11 [1.953.460.339 1 [1.953.719.668 0] [1 13] [1 14]] [1 0]]
|
||||||
|
// [ 6
|
||||||
|
// [5 [1 0] [0 2]]
|
||||||
|
// [7 [0 3] [11 [1.953.460.339 1 [1.953.719.668 0] [1 16] [1 18]] [0 0]]]
|
||||||
|
// [7 [0 3] [11 [1.953.460.339 1 [1.953.719.668 0] [1 20] [1 22]] [1 53]]]
|
||||||
|
// ]
|
||||||
|
// ]
|
||||||
|
// ]
|
||||||
|
//
|
||||||
|
// 1.953.719.668 = 'test'
|
||||||
|
// 1.953.460.339 = 'spot'
|
||||||
|
//
|
||||||
|
// All of this below is because of "two-phase borrow checks"
|
||||||
|
// https://stackoverflow.com/questions/60686259/mutable-borrow-in-function-argument
|
||||||
|
|
||||||
|
let hint_spot = D(1953460339);
|
||||||
|
let hint_path = T(sack, &[D(1953719668), D(0)]);
|
||||||
|
let hint_dyn = D(1);
|
||||||
|
let hint_row = D(1);
|
||||||
|
|
||||||
|
let make_hint = |sack: &mut NockStack, col_start: u64, col_end: u64| {
|
||||||
|
let start = T(sack, &[hint_row, D(col_start)]);
|
||||||
|
let end = T(sack, &[hint_row, D(col_end)]);
|
||||||
|
|
||||||
|
T(sack, &[hint_spot, hint_dyn, hint_path, start, end])
|
||||||
|
};
|
||||||
|
|
||||||
|
let sss3s1 = T(sack, &[D(0), D(3)]);
|
||||||
|
let sss3s2s1 = make_hint(sack, 20, 22);
|
||||||
|
let sss3s2s2 = T(sack, &[D(1), D(53)]);
|
||||||
|
let sss3s2 = T(sack, &[D(11), sss3s2s1, sss3s2s2]);
|
||||||
|
let sss3 = T(sack, &[D(7), sss3s1, sss3s2]);
|
||||||
|
|
||||||
|
let sss2s1 = sss3s1;
|
||||||
|
let sss2s2s1 = make_hint(sack, 16, 18);
|
||||||
|
let sss2s2s2 = T(sack, &[D(0), D(0)]);
|
||||||
|
let sss2s2 = T(sack, &[D(11), sss2s2s1, sss2s2s2]);
|
||||||
|
let sss2 = T(sack, &[D(7), sss2s1, sss2s2]);
|
||||||
|
|
||||||
|
let sss1s1 = T(sack, &[D(1), D(0)]);
|
||||||
|
let sss1s2 = T(sack, &[D(0), D(2)]);
|
||||||
|
let sss1 = T(sack, &[D(5), sss1s1, sss1s2]);
|
||||||
|
|
||||||
|
let ss2 = T(sack, &[D(6), sss1, sss2, sss3]);
|
||||||
|
|
||||||
|
let ss1s1 = make_hint(sack, 13, 14);
|
||||||
|
let ss1s2 = sss1s1;
|
||||||
|
let ss1 = T(sack, &[D(11), ss1s1, ss1s2]);
|
||||||
|
|
||||||
|
let s2 = T(sack, &[D(8), ss1, ss2]);
|
||||||
|
let s1 = make_hint(sack, 9, 22);
|
||||||
|
let form = T(sack, &[D(11), s1, s2]);
|
||||||
|
|
||||||
|
let nock = T(sack, &[subj, form]);
|
||||||
|
let samp = T(sack, &[nock, scry]);
|
||||||
|
|
||||||
|
// trace
|
||||||
|
// [%2 trace=~[[~.spot [[1.953.719.668 0] [1 16] 1 18]] [~.spot [[1.953.719.668 0] [1 9] 1 22]]]]
|
||||||
|
let ttt2t1 = T(sack, &[D(1), D(9)]);
|
||||||
|
let ttt2t2 = T(sack, &[D(1), D(22)]);
|
||||||
|
let ttt2 = T(sack, &[hint_path, ttt2t1, ttt2t2]);
|
||||||
|
|
||||||
|
let ttt1t1 = T(sack, &[D(1), D(16)]);
|
||||||
|
let ttt1t2 = T(sack, &[D(1), D(18)]);
|
||||||
|
let ttt1 = T(sack, &[hint_path, ttt1t1, ttt1t2]);
|
||||||
|
|
||||||
|
let tt2 = T(sack, &[hint_spot, ttt2]);
|
||||||
|
let tt1 = T(sack, &[hint_spot, ttt1]);
|
||||||
|
|
||||||
|
let t1 = T(sack, &[tt1, tt2, D(0)]);
|
||||||
|
|
||||||
|
let rest = T(sack, &[D(2), t1]);
|
||||||
|
|
||||||
|
assert_jet(sack, jet_mink, samp, rest);
|
||||||
|
}
|
||||||
|
}
|
58
rust/ares/src/jets/text.rs
Normal file
58
rust/ares/src/jets/text.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/** Text processing jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::slot;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::noun::{Noun, D};
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
pub fn jet_lent(_context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let tape = slot(subject, 6)?;
|
||||||
|
util::lent(tape).map(|x| D(x as u64))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod util {
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::noun::Noun;
|
||||||
|
|
||||||
|
pub fn lent(tape: Noun) -> Result<usize, JetErr> {
|
||||||
|
let mut len = 0usize;
|
||||||
|
let mut list = tape;
|
||||||
|
loop {
|
||||||
|
if let Some(atom) = list.atom() {
|
||||||
|
if atom.as_bitslice().first_one().is_none() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return Err(JetErr::Deterministic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cell = list.as_cell()?;
|
||||||
|
// don't need checked_add or indirect atom result: 2^63-1 atoms would be 64 ebibytes
|
||||||
|
len += 1;
|
||||||
|
list = cell.tail();
|
||||||
|
}
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::noun::{D, T};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lent() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
assert_jet(s, jet_lent, D(0), D(0));
|
||||||
|
let sam = T(s, &[D(1), D(2), D(3), D(0)]);
|
||||||
|
assert_jet(s, jet_lent, sam, D(3));
|
||||||
|
let sam = T(s, &[D(3), D(2), D(1), D(0)]);
|
||||||
|
assert_jet(s, jet_lent, sam, D(3));
|
||||||
|
assert_jet_err(s, jet_lent, D(1), JetErr::Deterministic);
|
||||||
|
let sam = T(s, &[D(3), D(2), D(1)]);
|
||||||
|
assert_jet_err(s, jet_lent, sam, JetErr::Deterministic);
|
||||||
|
}
|
||||||
|
}
|
82
rust/ares/src/jets/tree.rs
Normal file
82
rust/ares/src/jets/tree.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/** Tree jets
|
||||||
|
*/
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::jets::util::*;
|
||||||
|
use crate::jets::JetErr::*;
|
||||||
|
use crate::jets::Result;
|
||||||
|
use crate::noun::{Noun, D};
|
||||||
|
|
||||||
|
crate::gdb!();
|
||||||
|
|
||||||
|
pub fn jet_cap(_context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let tom = arg.as_atom()?;
|
||||||
|
let met = met(0, tom);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if met < 2 {
|
||||||
|
Err(Deterministic)
|
||||||
|
} else if *(tom.as_bitslice().get_unchecked(met - 2)) {
|
||||||
|
Ok(D(3))
|
||||||
|
} else {
|
||||||
|
Ok(D(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jet_mas(context: &mut Context, subject: Noun) -> Result {
|
||||||
|
let stack = &mut context.stack;
|
||||||
|
let arg = slot(subject, 6)?;
|
||||||
|
let tom = arg.as_atom()?;
|
||||||
|
let met = met(0, tom);
|
||||||
|
|
||||||
|
if met < 2 {
|
||||||
|
Err(Deterministic)
|
||||||
|
} else {
|
||||||
|
let c = bex(stack, met - 1);
|
||||||
|
let d = bex(stack, met - 2);
|
||||||
|
let e = sub(stack, tom, c)?;
|
||||||
|
|
||||||
|
Ok(con(stack, e, d).as_noun())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::jets::util::test::{assert_jet, assert_jet_err, init_stack};
|
||||||
|
use crate::jets::JetErr;
|
||||||
|
use crate::noun::D;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cap() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
|
||||||
|
assert_jet_err(s, jet_cap, D(0), JetErr::Deterministic);
|
||||||
|
assert_jet_err(s, jet_cap, D(1), JetErr::Deterministic);
|
||||||
|
|
||||||
|
assert_jet(s, jet_cap, D(2), D(2));
|
||||||
|
assert_jet(s, jet_cap, D(3), D(3));
|
||||||
|
assert_jet(s, jet_cap, D(4), D(2));
|
||||||
|
assert_jet(s, jet_cap, D(5), D(2));
|
||||||
|
assert_jet(s, jet_cap, D(6), D(3));
|
||||||
|
assert_jet(s, jet_cap, D(7), D(3));
|
||||||
|
assert_jet(s, jet_cap, D(8), D(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mas() {
|
||||||
|
let s = &mut init_stack();
|
||||||
|
|
||||||
|
assert_jet_err(s, jet_mas, D(0), JetErr::Deterministic);
|
||||||
|
assert_jet_err(s, jet_mas, D(1), JetErr::Deterministic);
|
||||||
|
|
||||||
|
assert_jet(s, jet_mas, D(2), D(1));
|
||||||
|
assert_jet(s, jet_mas, D(3), D(1));
|
||||||
|
assert_jet(s, jet_mas, D(4), D(2));
|
||||||
|
assert_jet(s, jet_mas, D(5), D(3));
|
||||||
|
assert_jet(s, jet_mas, D(6), D(2));
|
||||||
|
assert_jet(s, jet_mas, D(7), D(3));
|
||||||
|
assert_jet(s, jet_mas, D(8), D(4));
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
pub mod jets;
|
pub mod jets;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use ares::interpreter::interpret;
|
use ares::hamt::Hamt;
|
||||||
|
use ares::interpreter::{interpret, Context};
|
||||||
use ares::jets::cold::Cold;
|
use ares::jets::cold::Cold;
|
||||||
use ares::jets::hot::Hot;
|
use ares::jets::hot::Hot;
|
||||||
use ares::jets::warm::Warm;
|
use ares::jets::warm::Warm;
|
||||||
use ares::mem::NockStack;
|
use ares::mem::NockStack;
|
||||||
use ares::noun::IndirectAtom;
|
use ares::noun::{IndirectAtom, Noun};
|
||||||
use ares::serf::serf;
|
use ares::serf::serf;
|
||||||
use ares::serialization::{cue, jam};
|
use ares::serialization::{cue, jam};
|
||||||
use memmap::Mmap;
|
use memmap::Mmap;
|
||||||
@ -27,7 +28,11 @@ fn main() -> io::Result<()> {
|
|||||||
if filename == "see gdb! definition in lib.rs about this" {
|
if filename == "see gdb! definition in lib.rs about this" {
|
||||||
ares::interpreter::use_gdb();
|
ares::interpreter::use_gdb();
|
||||||
ares::jets::use_gdb();
|
ares::jets::use_gdb();
|
||||||
|
ares::jets::bits::use_gdb();
|
||||||
|
ares::jets::hash::use_gdb();
|
||||||
ares::jets::math::use_gdb();
|
ares::jets::math::use_gdb();
|
||||||
|
ares::jets::nock::use_gdb();
|
||||||
|
ares::jets::tree::use_gdb();
|
||||||
ares::mem::use_gdb();
|
ares::mem::use_gdb();
|
||||||
ares::mug::use_gdb();
|
ares::mug::use_gdb();
|
||||||
ares::newt::use_gdb();
|
ares::newt::use_gdb();
|
||||||
@ -47,9 +52,6 @@ fn main() -> io::Result<()> {
|
|||||||
let f = File::open(filename)?;
|
let f = File::open(filename)?;
|
||||||
let in_len = f.metadata()?.len();
|
let in_len = f.metadata()?.len();
|
||||||
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
let mut stack = NockStack::new(8 << 10 << 10, 0);
|
||||||
let mut cold = Cold::new(&mut stack);
|
|
||||||
let mut warm = Warm::new();
|
|
||||||
let hot = Hot::init(&mut stack);
|
|
||||||
let jammed_input = unsafe {
|
let jammed_input = unsafe {
|
||||||
let in_map = Mmap::map(&f)?;
|
let in_map = Mmap::map(&f)?;
|
||||||
let word_len = (in_len + 7) >> 3;
|
let word_len = (in_len + 7) >> 3;
|
||||||
@ -63,15 +65,16 @@ fn main() -> io::Result<()> {
|
|||||||
let input_cell = input
|
let input_cell = input
|
||||||
.as_cell()
|
.as_cell()
|
||||||
.expect("Input must be jam of subject/formula pair");
|
.expect("Input must be jam of subject/formula pair");
|
||||||
let result = interpret(
|
let mut context = Context {
|
||||||
&mut stack,
|
stack: &mut stack,
|
||||||
&mut None,
|
newt: None,
|
||||||
&mut cold,
|
cache: &mut Hamt::<Noun>::new(),
|
||||||
&mut warm,
|
cold: &mut Cold::new(&mut stack);
|
||||||
hot,
|
warm: &mut Warm::new();
|
||||||
input_cell.head(),
|
hot: &mut Hot::init(&mut stack);
|
||||||
input_cell.tail(),
|
};
|
||||||
);
|
let result =
|
||||||
|
interpret(&mut context, input_cell.head(), input_cell.tail()).expect("nock failed");
|
||||||
if let Ok(atom) = result.as_atom() {
|
if let Ok(atom) = result.as_atom() {
|
||||||
println!("Result: {}", atom);
|
println!("Result: {}", atom);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::assert_acyclic;
|
use crate::assert_acyclic;
|
||||||
|
use crate::assert_no_forwarding_pointers;
|
||||||
|
use crate::assert_no_junior_pointers;
|
||||||
use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator};
|
use crate::noun::{Atom, Cell, CellMemory, IndirectAtom, Noun, NounAllocator};
|
||||||
use crate::snapshot::pma::{pma_in_arena, pma_malloc_w};
|
use crate::snapshot::pma::{pma_in_arena, pma_malloc_w};
|
||||||
|
use assert_no_alloc::permit_alloc;
|
||||||
use either::Either::{self, Left, Right};
|
use either::Either::{self, Left, Right};
|
||||||
use ibig::Stack;
|
use ibig::Stack;
|
||||||
use libc::{c_void, memcmp};
|
use libc::{c_void, memcmp};
|
||||||
@ -58,22 +60,22 @@ impl NockStack {
|
|||||||
* The initial frame is a west frame. When the stack is initialized, a number of slots is given.
|
* The initial frame is a west frame. When the stack is initialized, a number of slots is given.
|
||||||
* We add three extra slots to store the “previous” frame, stack, and allocation pointer. For the
|
* We add three extra slots to store the “previous” frame, stack, and allocation pointer. For the
|
||||||
* initial frame, the previous allocation pointer is set to the beginning (low boundary) of the
|
* initial frame, the previous allocation pointer is set to the beginning (low boundary) of the
|
||||||
* arena, the previous frame pointer is set to NULL, and the previous stack pointer is set to XX */
|
* arena, the previous frame pointer is set to NULL, and the previous stack pointer is set to NULL */
|
||||||
|
|
||||||
/** Size is in 64 bit words.
|
/** size is in 64-bit (i.e. 8-byte) words.
|
||||||
* top_slots is how many slots to allocate to the top stack frame.
|
* top_slots is how many slots to allocate to the top stack frame.
|
||||||
*/
|
*/
|
||||||
pub fn new(size: usize, top_slots: usize) -> NockStack {
|
pub fn new(size: usize, top_slots: usize) -> NockStack {
|
||||||
let memory = MmapMut::map_anon(size << 3).expect("Mapping memory for nockstack failed");
|
let memory = MmapMut::map_anon(size << 3).expect("Mapping memory for nockstack failed");
|
||||||
let start = memory.as_ptr() as *const u64;
|
let start = memory.as_ptr() as *const u64;
|
||||||
// Here, frame_pointer < alloc_pointer, so the initial frame is West
|
// Here, frame_pointer < alloc_pointer, so the initial frame is West
|
||||||
let frame_pointer = unsafe { start.add(top_slots + RESERVED) } as *mut u64;
|
let frame_pointer = unsafe { start.add(RESERVED + top_slots) } as *mut u64;
|
||||||
let stack_pointer = frame_pointer;
|
let stack_pointer = frame_pointer;
|
||||||
let alloc_pointer = unsafe { start.add(size) } as *mut u64;
|
let alloc_pointer = unsafe { start.add(size) } as *mut u64;
|
||||||
unsafe {
|
unsafe {
|
||||||
*frame_pointer = ptr::null::<u64>() as u64; // "frame pointer" from "previous" frame
|
*frame_pointer.sub(FRAME + 1) = ptr::null::<u64>() as u64; // "frame pointer" from "previous" frame
|
||||||
*frame_pointer.sub(STACK) = ptr::null::<u64>() as u64; // "stack pointer" from "previous" frame
|
*frame_pointer.sub(STACK + 1) = ptr::null::<u64>() as u64; // "stack pointer" from "previous" frame
|
||||||
*frame_pointer.sub(ALLOC) = start as u64; // "alloc pointer" from "previous" frame
|
*frame_pointer.sub(ALLOC + 1) = ptr::null::<u64>() as u64; // "alloc pointer" from "previous" frame
|
||||||
};
|
};
|
||||||
NockStack {
|
NockStack {
|
||||||
start,
|
start,
|
||||||
@ -86,6 +88,11 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Current frame pointer of this NockStack */
|
||||||
|
pub fn get_frame_pointer(&self) -> *const u64 {
|
||||||
|
self.frame_pointer
|
||||||
|
}
|
||||||
|
|
||||||
/** Checks if the current stack frame has West polarity */
|
/** Checks if the current stack frame has West polarity */
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_west(&self) -> bool {
|
pub fn is_west(&self) -> bool {
|
||||||
@ -351,6 +358,10 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn copy(&mut self, noun: &mut Noun) {
|
unsafe fn copy(&mut self, noun: &mut Noun) {
|
||||||
|
assert_acyclic!(*noun);
|
||||||
|
assert_no_forwarding_pointers!(*noun);
|
||||||
|
assert_no_junior_pointers!(self, *noun);
|
||||||
|
|
||||||
self.pre_copy();
|
self.pre_copy();
|
||||||
assert!(self.stack_is_empty());
|
assert!(self.stack_is_empty());
|
||||||
let noun_ptr = noun as *mut Noun;
|
let noun_ptr = noun as *mut Noun;
|
||||||
@ -438,7 +449,10 @@ impl NockStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set saved previous allocation pointer its new value after this allocation
|
// Set saved previous allocation pointer its new value after this allocation
|
||||||
|
|
||||||
assert_acyclic!(*noun);
|
assert_acyclic!(*noun);
|
||||||
|
assert_no_forwarding_pointers!(*noun);
|
||||||
|
assert_no_junior_pointers!(self, *noun);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn struct_is_in<T>(&self, ptr: *const T, count: usize) {
|
pub unsafe fn struct_is_in<T>(&self, ptr: *const T, count: usize) {
|
||||||
@ -570,7 +584,6 @@ impl NockStack {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_acyclic!(*noun);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn frame_pop(&mut self) {
|
pub unsafe fn frame_pop(&mut self) {
|
||||||
@ -582,6 +595,18 @@ impl NockStack {
|
|||||||
self.stack_pointer = prev_stack_ptr;
|
self.stack_pointer = prev_stack_ptr;
|
||||||
self.alloc_pointer = prev_alloc_ptr;
|
self.alloc_pointer = prev_alloc_ptr;
|
||||||
|
|
||||||
|
if self.frame_pointer.is_null()
|
||||||
|
|| self.stack_pointer.is_null()
|
||||||
|
|| self.alloc_pointer.is_null()
|
||||||
|
{
|
||||||
|
permit_alloc(|| {
|
||||||
|
panic!(
|
||||||
|
"serf: frame_pop: null NockStack pointer f={:p} s={:p} a={:p}",
|
||||||
|
self.frame_pointer, self.stack_pointer, self.alloc_pointer
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.pc = false;
|
self.pc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,6 +745,88 @@ impl NockStack {
|
|||||||
unsafe { self.stack_pointer == self.alloc_pointer.add(RESERVED) }
|
unsafe { self.stack_pointer == self.alloc_pointer.add(RESERVED) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_junior_pointers(&self, noun: Noun) -> bool {
|
||||||
|
unsafe {
|
||||||
|
if let Ok(c) = noun.as_cell() {
|
||||||
|
let mut fp: *mut u64;
|
||||||
|
let mut sp = self.stack_pointer;
|
||||||
|
let mut ap = self.alloc_pointer;
|
||||||
|
let mut pfp = *(self.prev_frame_pointer_pointer());
|
||||||
|
let mut psp = *(self.prev_stack_pointer_pointer());
|
||||||
|
let mut pap = *(self.prev_alloc_pointer_pointer());
|
||||||
|
|
||||||
|
let mut dbg_stack = Vec::new();
|
||||||
|
|
||||||
|
// Detemine range
|
||||||
|
let (rlo, rhi) = loop {
|
||||||
|
if psp.is_null() {
|
||||||
|
psp = ((self.start as u64) + ((self.size << 3) as u64)) as *mut u64;
|
||||||
|
}
|
||||||
|
let (lo, hi) = if sp < ap { (ap, psp) } else { (psp, ap) };
|
||||||
|
let ptr = c.to_raw_pointer() as *mut u64;
|
||||||
|
if ptr >= lo && ptr < hi {
|
||||||
|
break if sp < ap { (sp, ap) } else { (ap, sp) };
|
||||||
|
} else {
|
||||||
|
fp = pfp;
|
||||||
|
sp = psp;
|
||||||
|
ap = pap;
|
||||||
|
if sp < ap {
|
||||||
|
pfp = *(fp.sub(FRAME + 1)) as *mut u64;
|
||||||
|
psp = *(fp.sub(STACK + 1)) as *mut u64;
|
||||||
|
pap = *(fp.sub(ALLOC + 1)) as *mut u64;
|
||||||
|
} else {
|
||||||
|
pfp = *(fp.add(FRAME)) as *mut u64;
|
||||||
|
psp = *(fp.add(STACK)) as *mut u64;
|
||||||
|
pap = *(fp.add(ALLOC)) as *mut u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg_stack.push(c.head());
|
||||||
|
dbg_stack.push(c.tail());
|
||||||
|
while let Some(n) = dbg_stack.pop() {
|
||||||
|
if let Ok(a) = n.as_allocated() {
|
||||||
|
let ptr = a.to_raw_pointer();
|
||||||
|
if ptr >= rlo && ptr < rhi {
|
||||||
|
eprintln!(
|
||||||
|
"\rserf: Noun {:x} has Noun {:x} in junior of range {:p}-{:p}",
|
||||||
|
(noun.raw << 3),
|
||||||
|
(n.raw << 3),
|
||||||
|
rlo,
|
||||||
|
rhi
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let Some(c) = a.cell() {
|
||||||
|
dbg_stack.push(c.tail());
|
||||||
|
dbg_stack.push(c.head());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "check_junior")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_no_junior_pointers {
|
||||||
|
( $x:expr, $y:expr ) => {
|
||||||
|
assert_no_alloc::permit_alloc(|| {
|
||||||
|
assert!($x.no_junior_pointers($y));
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "check_junior"))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_no_junior_pointers {
|
||||||
|
( $x:expr, $y:expr ) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Noun) -> bool {
|
||||||
@ -746,6 +853,13 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
|||||||
* senior noun, *never vice versa*, to avoid introducing references from more senior frames
|
* senior noun, *never vice versa*, to avoid introducing references from more senior frames
|
||||||
* into more junior frames, which would result in incorrect operation of the copier.
|
* into more junior frames, which would result in incorrect operation of the copier.
|
||||||
*/
|
*/
|
||||||
|
assert_acyclic!(*a);
|
||||||
|
assert_acyclic!(*b);
|
||||||
|
assert_no_forwarding_pointers!(*a);
|
||||||
|
assert_no_forwarding_pointers!(*b);
|
||||||
|
assert_no_junior_pointers!(stack, *a);
|
||||||
|
assert_no_junior_pointers!(stack, *b);
|
||||||
|
|
||||||
// If the nouns are already word-equal we have nothing to do
|
// If the nouns are already word-equal we have nothing to do
|
||||||
if (*a).raw_equals(*b) {
|
if (*a).raw_equals(*b) {
|
||||||
return true;
|
return true;
|
||||||
@ -792,7 +906,6 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
|||||||
) == 0
|
) == 0
|
||||||
{
|
{
|
||||||
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
let (_senior, junior) = senior_pointer_first(stack, x_as_ptr, y_as_ptr);
|
||||||
// unify
|
|
||||||
if x_as_ptr == junior {
|
if x_as_ptr == junior {
|
||||||
*x = *y;
|
*x = *y;
|
||||||
} else {
|
} else {
|
||||||
@ -842,8 +955,14 @@ pub unsafe fn unifying_equality(stack: &mut NockStack, a: *mut Noun, b: *mut Nou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.frame_pop();
|
stack.frame_pop();
|
||||||
|
|
||||||
assert_acyclic!(*a);
|
assert_acyclic!(*a);
|
||||||
assert_acyclic!(*b);
|
assert_acyclic!(*b);
|
||||||
|
assert_no_forwarding_pointers!(*a);
|
||||||
|
assert_no_forwarding_pointers!(*b);
|
||||||
|
assert_no_junior_pointers!(stack, *a);
|
||||||
|
assert_no_junior_pointers!(stack, *b);
|
||||||
|
|
||||||
(*a).raw_equals(*b)
|
(*a).raw_equals(*b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,17 +983,19 @@ unsafe fn senior_pointer_first(
|
|||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if low_pointer.is_null() || high_pointer.is_null() {
|
||||||
|
// we found the bottom of the stack; check entirety of the stack
|
||||||
|
low_pointer = stack.start;
|
||||||
|
high_pointer = stack.start.add(stack.size);
|
||||||
|
}
|
||||||
|
|
||||||
match (
|
match (
|
||||||
a < high_pointer && a >= low_pointer,
|
a < high_pointer && a >= low_pointer,
|
||||||
b < high_pointer && b >= low_pointer,
|
b < high_pointer && b >= low_pointer,
|
||||||
) {
|
) {
|
||||||
(true, true) => {
|
(true, true) => {
|
||||||
// both pointers are in the same frame, pick arbitrarily (lower in mem)
|
// both pointers are in the same frame, pick arbitrarily (lower in mem)
|
||||||
if a < b {
|
break lower_pointer_first(a, b);
|
||||||
break (a, b);
|
|
||||||
} else {
|
|
||||||
break (b, a);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
(true, false) => break (b, a), // a is in the frame, b is not, so b is senior
|
(true, false) => break (b, a), // a is in the frame, b is not, so b is senior
|
||||||
(false, true) => break (a, b), // b is in the frame, a is not, so a is senior
|
(false, true) => break (a, b), // b is in the frame, a is not, so a is senior
|
||||||
@ -887,30 +1008,23 @@ unsafe fn senior_pointer_first(
|
|||||||
alloc_pointer = *(frame_pointer.sub(ALLOC + 1)) as *const u64;
|
alloc_pointer = *(frame_pointer.sub(ALLOC + 1)) as *const u64;
|
||||||
frame_pointer = *(frame_pointer.sub(FRAME + 1)) as *const u64;
|
frame_pointer = *(frame_pointer.sub(FRAME + 1)) as *const u64;
|
||||||
|
|
||||||
|
// both pointers are in the PMA, pick arbitrarily (lower in mem)
|
||||||
if frame_pointer.is_null() {
|
if frame_pointer.is_null() {
|
||||||
if a < b {
|
break lower_pointer_first(a, b);
|
||||||
break (a, b);
|
|
||||||
} else {
|
|
||||||
break (b, a);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// previous allocation pointer
|
// previous allocation pointer
|
||||||
high_pointer = alloc_pointer;
|
high_pointer = alloc_pointer;
|
||||||
// "previous previous" stack pointer. this is the other boundary of the previous allocation arena
|
// "previous previous" stack pointer. this is the other boundary of the previous allocation arena
|
||||||
low_pointer = *(frame_pointer.add(STACK)) as *const u64;
|
low_pointer = *(frame_pointer.add(STACK)) as *const u64;
|
||||||
continue;
|
|
||||||
} else if stack_pointer > alloc_pointer {
|
} else if stack_pointer > alloc_pointer {
|
||||||
stack_pointer = *(frame_pointer.add(STACK)) as *const u64;
|
stack_pointer = *(frame_pointer.add(STACK)) as *const u64;
|
||||||
alloc_pointer = *(frame_pointer.add(ALLOC)) as *const u64;
|
alloc_pointer = *(frame_pointer.add(ALLOC)) as *const u64;
|
||||||
frame_pointer = *(frame_pointer.add(FRAME)) as *const u64;
|
frame_pointer = *(frame_pointer.add(FRAME)) as *const u64;
|
||||||
|
|
||||||
|
// both pointers are in the PMA, pick arbitrarily (lower in mem)
|
||||||
if frame_pointer.is_null() {
|
if frame_pointer.is_null() {
|
||||||
if a < b {
|
break lower_pointer_first(a, b);
|
||||||
break (a, b);
|
|
||||||
} else {
|
|
||||||
break (b, a);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// previous allocation pointer
|
// previous allocation pointer
|
||||||
@ -925,6 +1039,14 @@ unsafe fn senior_pointer_first(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_pointer_first(a: *const u64, b: *const u64) -> (*const u64, *const u64) {
|
||||||
|
if a < b {
|
||||||
|
(a, b)
|
||||||
|
} else {
|
||||||
|
(b, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NounAllocator for NockStack {
|
impl NounAllocator for NockStack {
|
||||||
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
|
unsafe fn alloc_indirect(&mut self, words: usize) -> *mut u64 {
|
||||||
self.indirect_alloc(words)
|
self.indirect_alloc(words)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use crate::assert_acyclic;
|
use crate::assert_acyclic;
|
||||||
|
use crate::assert_no_forwarding_pointers;
|
||||||
|
use crate::assert_no_junior_pointers;
|
||||||
use crate::mem::*;
|
use crate::mem::*;
|
||||||
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
use crate::noun::{Allocated, Atom, DirectAtom, Noun};
|
||||||
use either::Either::*;
|
use either::Either::*;
|
||||||
@ -119,7 +121,11 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
|||||||
if let Some(mug) = get_mug(noun) {
|
if let Some(mug) = get_mug(noun) {
|
||||||
return mug;
|
return mug;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_acyclic!(noun);
|
assert_acyclic!(noun);
|
||||||
|
assert_no_forwarding_pointers!(noun);
|
||||||
|
assert_no_junior_pointers!(stack, noun);
|
||||||
|
|
||||||
stack.frame_push(0);
|
stack.frame_push(0);
|
||||||
unsafe {
|
unsafe {
|
||||||
*(stack.push()) = noun;
|
*(stack.push()) = noun;
|
||||||
@ -171,6 +177,11 @@ pub fn mug_u32(stack: &mut NockStack, noun: Noun) -> u32 {
|
|||||||
unsafe {
|
unsafe {
|
||||||
stack.frame_pop();
|
stack.frame_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert_acyclic!(noun);
|
||||||
|
assert_no_forwarding_pointers!(noun);
|
||||||
|
assert_no_junior_pointers!(stack, noun);
|
||||||
|
|
||||||
get_mug(noun).expect("Noun should have a mug once it is mugged.")
|
get_mug(noun).expect("Noun should have a mug once it is mugged.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ use either::Either;
|
|||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::os::unix::prelude::FromRawFd;
|
use std::os::unix::prelude::FromRawFd;
|
||||||
use std::ptr::copy_nonoverlapping;
|
use std::ptr::copy_nonoverlapping;
|
||||||
|
use std::slice::from_raw_parts_mut;
|
||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
@ -82,7 +83,9 @@ impl Newt {
|
|||||||
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) {
|
fn write_noun(&mut self, stack: &mut NockStack, noun: Noun) {
|
||||||
let atom = jam(stack, noun);
|
let atom = jam(stack, noun);
|
||||||
let size = atom.size() << 3;
|
let size = atom.size() << 3;
|
||||||
let mut buf = vec![0u8; size + 5];
|
// XX: checked add?
|
||||||
|
let buf = unsafe { from_raw_parts_mut(stack.struct_alloc::<u8>(size + 5), size + 5) };
|
||||||
|
buf[0] = 0u8;
|
||||||
buf[1] = size as u8;
|
buf[1] = size as u8;
|
||||||
buf[2] = (size >> 8) as u8;
|
buf[2] = (size >> 8) as u8;
|
||||||
buf[3] = (size >> 16) as u8;
|
buf[3] = (size >> 16) as u8;
|
||||||
@ -104,10 +107,14 @@ impl Newt {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.output.write_all(&buf).unwrap();
|
self.output.write_all(buf).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %ripe, the first event. */
|
/** Send %ripe, the first event.
|
||||||
|
*
|
||||||
|
* eve = event number
|
||||||
|
* mug = mug of Arvo after above event
|
||||||
|
*/
|
||||||
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) {
|
pub fn ripe(&mut self, stack: &mut NockStack, eve: u64, mug: u64) {
|
||||||
let version = T(
|
let version = T(
|
||||||
stack,
|
stack,
|
||||||
@ -127,7 +134,11 @@ impl Newt {
|
|||||||
self.write_noun(stack, live);
|
self.write_noun(stack, live);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %slog, pretty-printed debug output. */
|
/** Send %slog, pretty-printed debug output.
|
||||||
|
*
|
||||||
|
* pri = debug priority
|
||||||
|
* tank = output as tank
|
||||||
|
*/
|
||||||
pub fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) {
|
pub fn slog(&mut self, stack: &mut NockStack, pri: u64, tank: Noun) {
|
||||||
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank]);
|
let slog = T(stack, &[D(tas!(b"slog")), D(pri), tank]);
|
||||||
self.write_noun(stack, slog);
|
self.write_noun(stack, slog);
|
||||||
@ -145,19 +156,30 @@ impl Newt {
|
|||||||
self.write_noun(stack, peek);
|
self.write_noun(stack, peek);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %peek %bail, unsuccessfully scried. */
|
/** Send %peek %bail, unsuccessfully scried.
|
||||||
|
*
|
||||||
|
* dud = goof
|
||||||
|
*/
|
||||||
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) {
|
pub fn peek_bail(&mut self, stack: &mut NockStack, dud: Noun) {
|
||||||
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud]);
|
let peek = T(stack, &[D(tas!(b"peek")), D(tas!(b"bail")), dud]);
|
||||||
self.write_noun(stack, peek);
|
self.write_noun(stack, peek);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %play %done, successfully replayed events. */
|
/** Send %play %done, successfully replayed events.
|
||||||
|
*
|
||||||
|
* mug = mug of Arvo after full replay
|
||||||
|
*/
|
||||||
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) {
|
pub fn play_done(&mut self, stack: &mut NockStack, mug: u64) {
|
||||||
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)]);
|
let play = T(stack, &[D(tas!(b"play")), D(tas!(b"done")), D(mug)]);
|
||||||
self.write_noun(stack, play);
|
self.write_noun(stack, play);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %play %bail, failed to replay events. */
|
/** Send %play %bail, failed to replay events.
|
||||||
|
*
|
||||||
|
* eve = last good event number
|
||||||
|
* mug = mug of Arvo after above event
|
||||||
|
* dud = goof when trying next event
|
||||||
|
*/
|
||||||
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) {
|
pub fn play_bail(&mut self, stack: &mut NockStack, eve: u64, mug: u64, dud: Noun) {
|
||||||
let play = T(
|
let play = T(
|
||||||
stack,
|
stack,
|
||||||
@ -166,7 +188,12 @@ impl Newt {
|
|||||||
self.write_noun(stack, play);
|
self.write_noun(stack, play);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %work %done, successfully ran event. */
|
/** Send %work %done, successfully ran event.
|
||||||
|
*
|
||||||
|
* eve = new event number
|
||||||
|
* mug = mug of Arvo after above event
|
||||||
|
* fec = list of effects
|
||||||
|
*/
|
||||||
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) {
|
pub fn work_done(&mut self, stack: &mut NockStack, eve: u64, mug: u64, fec: Noun) {
|
||||||
let work = T(
|
let work = T(
|
||||||
stack,
|
stack,
|
||||||
@ -175,7 +202,13 @@ impl Newt {
|
|||||||
self.write_noun(stack, work);
|
self.write_noun(stack, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %work %swap, successfully replaced failed event. */
|
/** Send %work %swap, successfully replaced failed event.
|
||||||
|
*
|
||||||
|
* eve = new event number
|
||||||
|
* mug = mug of Arvo after above event
|
||||||
|
* job = event performed instead of the one given to serf by king
|
||||||
|
* fec = list of effects
|
||||||
|
*/
|
||||||
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) {
|
pub fn work_swap(&mut self, stack: &mut NockStack, eve: u64, mug: u64, job: Noun, fec: Noun) {
|
||||||
let work = T(
|
let work = T(
|
||||||
stack,
|
stack,
|
||||||
@ -184,7 +217,10 @@ impl Newt {
|
|||||||
self.write_noun(stack, work);
|
self.write_noun(stack, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send %work %bail, failed to run event. */
|
/** Send %work %bail, failed to run event.
|
||||||
|
*
|
||||||
|
* lud = list of goof
|
||||||
|
*/
|
||||||
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) {
|
pub fn work_bail(&mut self, stack: &mut NockStack, lud: Noun) {
|
||||||
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud]);
|
let work = T(stack, &[D(tas!(b"work")), D(tas!(b"bail")), lud]);
|
||||||
self.write_noun(stack, work);
|
self.write_noun(stack, work);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::mem::{word_size_of, NockStack};
|
use crate::mem::{word_size_of, NockStack};
|
||||||
use bitvec::prelude::{BitSlice, Lsb0};
|
use bitvec::prelude::{BitSlice, Lsb0};
|
||||||
use either::Either;
|
use either::{Either, Left, Right};
|
||||||
use ibig::{Stack, UBig};
|
use ibig::{Stack, UBig};
|
||||||
use intmap::IntMap;
|
use intmap::IntMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -44,7 +44,9 @@ pub const NO: Noun = D(1);
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_acyclic {
|
macro_rules! assert_acyclic {
|
||||||
( $x:expr ) => {
|
( $x:expr ) => {
|
||||||
assert!(crate::noun::acyclic_noun($x));
|
assert_no_alloc::permit_alloc(|| {
|
||||||
|
assert!(crate::noun::acyclic_noun($x));
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,8 +63,8 @@ pub fn acyclic_noun(noun: Noun) -> bool {
|
|||||||
|
|
||||||
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
||||||
match noun.as_either_atom_cell() {
|
match noun.as_either_atom_cell() {
|
||||||
Either::Left(_atom) => true,
|
Left(_atom) => true,
|
||||||
Either::Right(cell) => {
|
Right(cell) => {
|
||||||
if seen.get(cell.0).is_some() {
|
if seen.get(cell.0).is_some() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@ -82,6 +84,42 @@ fn acyclic_noun_go(noun: Noun, seen: &mut IntMap<()>) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "check_forwarding")]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_no_forwarding_pointers {
|
||||||
|
( $x:expr ) => {
|
||||||
|
assert_no_alloc::permit_alloc(|| {
|
||||||
|
assert!(crate::noun::no_forwarding_pointers($x));
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "check_forwarding"))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_no_forwarding_pointers {
|
||||||
|
( $x:expr ) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn no_forwarding_pointers(noun: Noun) -> bool {
|
||||||
|
let mut dbg_stack = Vec::new();
|
||||||
|
dbg_stack.push(noun);
|
||||||
|
|
||||||
|
while !dbg_stack.is_empty() {
|
||||||
|
if let Some(noun) = dbg_stack.pop() {
|
||||||
|
if unsafe { noun.raw & FORWARDING_MASK == FORWARDING_TAG } {
|
||||||
|
return false;
|
||||||
|
} else if let Ok(cell) = noun.as_cell() {
|
||||||
|
dbg_stack.push(cell.tail());
|
||||||
|
dbg_stack.push(cell.head());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/** Test if a noun is a direct atom. */
|
/** Test if a noun is a direct atom. */
|
||||||
fn is_direct_atom(noun: u64) -> bool {
|
fn is_direct_atom(noun: u64) -> bool {
|
||||||
noun & DIRECT_MASK == DIRECT_TAG
|
noun & DIRECT_MASK == DIRECT_TAG
|
||||||
@ -186,6 +224,11 @@ impl DirectAtom {
|
|||||||
pub fn as_bitslice_mut(&mut self) -> &mut BitSlice<u64, Lsb0> {
|
pub fn as_bitslice_mut(&mut self) -> &mut BitSlice<u64, Lsb0> {
|
||||||
BitSlice::from_element_mut(&mut self.0)
|
BitSlice::from_element_mut(&mut self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
let bytes: &[u8; 8] = unsafe { std::mem::transmute(&self.0) };
|
||||||
|
&bytes[..]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DirectAtom {
|
impl fmt::Display for DirectAtom {
|
||||||
@ -227,6 +270,16 @@ pub fn T<A: NounAllocator>(allocator: &mut A, tup: &[Noun]) -> Noun {
|
|||||||
Cell::new_tuple(allocator, tup).as_noun()
|
Cell::new_tuple(allocator, tup).as_noun()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create $tape Noun from ASCII string
|
||||||
|
pub fn tape<A: NounAllocator>(allocator: &mut A, text: &str) -> Noun {
|
||||||
|
// XX: Needs unit tests
|
||||||
|
let mut res = D(0);
|
||||||
|
for c in text.bytes().rev() {
|
||||||
|
res = T(allocator, &[D(c as u64), res])
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
/** An indirect atom.
|
/** An indirect atom.
|
||||||
*
|
*
|
||||||
* Indirect atoms represent atoms above DIRECT_MAX as a tagged pointer to a memory buffer
|
* Indirect atoms represent atoms above DIRECT_MAX as a tagged pointer to a memory buffer
|
||||||
@ -444,6 +497,9 @@ impl IndirectAtom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XX: Need a version that either:
|
||||||
|
// a) allocates on the NockStack directly for creating a tape (or even a string?)
|
||||||
|
// b) disables no-allocation, creates a string, utilitzes it (eprintf or generate tape), and then deallocates
|
||||||
impl fmt::Display for IndirectAtom {
|
impl fmt::Display for IndirectAtom {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "0x")?;
|
write!(f, "0x")?;
|
||||||
@ -480,7 +536,7 @@ impl Cell {
|
|||||||
(self.0 << 3) as *const CellMemory
|
(self.0 << 3) as *const CellMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn to_raw_pointer_mut(&mut self) -> *mut CellMemory {
|
pub unsafe fn to_raw_pointer_mut(&mut self) -> *mut CellMemory {
|
||||||
(self.0 << 3) as *mut CellMemory
|
(self.0 << 3) as *mut CellMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,6 +631,28 @@ impl fmt::Display for Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Slots for Cell {}
|
||||||
|
impl private::RawSlots for Cell {
|
||||||
|
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
|
||||||
|
let mut noun: Noun = self.as_noun();
|
||||||
|
// Panic because all of the logic to guard against this is in Noun::RawSlots, Noun::Slots
|
||||||
|
let mut cursor = axis.last_one().expect("raw_slow somehow by-passed 0 check");
|
||||||
|
|
||||||
|
while cursor != 0 {
|
||||||
|
cursor -= 1;
|
||||||
|
|
||||||
|
// Returns Err if axis tried to descend through atom
|
||||||
|
if axis[cursor] {
|
||||||
|
noun = noun.as_cell()?.tail();
|
||||||
|
} else {
|
||||||
|
noun = noun.as_cell()?.head();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(noun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory representation of the contents of a cell
|
* Memory representation of the contents of a cell
|
||||||
*/
|
*/
|
||||||
@ -648,9 +726,9 @@ impl Atom {
|
|||||||
|
|
||||||
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
|
pub fn as_either(&self) -> Either<DirectAtom, IndirectAtom> {
|
||||||
if self.is_indirect() {
|
if self.is_indirect() {
|
||||||
unsafe { Either::Right(self.indirect) }
|
unsafe { Right(self.indirect) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Left(self.direct) }
|
unsafe { Left(self.direct) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,24 +756,40 @@ impl Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn direct(&self) -> Option<DirectAtom> {
|
||||||
|
if self.is_direct() {
|
||||||
|
unsafe { Some(self.direct) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn indirect(&self) -> Option<IndirectAtom> {
|
||||||
|
if self.is_indirect() {
|
||||||
|
unsafe { Some(self.indirect) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(_direct) => 1,
|
Left(_direct) => 1,
|
||||||
Either::Right(indirect) => indirect.size(),
|
Right(indirect) => indirect.size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bit_size(&self) -> usize {
|
pub fn bit_size(&self) -> usize {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(direct) => direct.bit_size(),
|
Left(direct) => direct.bit_size(),
|
||||||
Either::Right(indirect) => indirect.bit_size(),
|
Right(indirect) => indirect.bit_size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_pointer(&self) -> *const u64 {
|
pub fn data_pointer(&self) -> *const u64 {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(_direct) => (self as *const Atom) as *const u64,
|
Left(_direct) => (self as *const Atom) as *const u64,
|
||||||
Either::Right(indirect) => indirect.data_pointer(),
|
Right(indirect) => indirect.data_pointer(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,6 +804,14 @@ impl Atom {
|
|||||||
pub fn as_noun(self) -> Noun {
|
pub fn as_noun(self) -> Noun {
|
||||||
Noun { atom: self }
|
Noun { atom: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
if self.is_direct() {
|
||||||
|
unsafe { self.direct.as_bytes() }
|
||||||
|
} else {
|
||||||
|
unsafe { self.indirect.as_bytes() }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Atom {
|
impl fmt::Display for Atom {
|
||||||
@ -750,8 +852,8 @@ impl Allocated {
|
|||||||
|
|
||||||
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
|
pub unsafe fn forwarding_pointer(&self) -> Option<Allocated> {
|
||||||
match self.as_either() {
|
match self.as_either() {
|
||||||
Either::Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
|
Left(indirect) => indirect.forwarding_pointer().map(|i| i.as_allocated()),
|
||||||
Either::Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
|
Right(cell) => cell.forwarding_pointer().map(|c| c.as_allocated()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,9 +867,17 @@ impl Allocated {
|
|||||||
|
|
||||||
pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
|
pub fn as_either(&self) -> Either<IndirectAtom, Cell> {
|
||||||
if self.is_indirect() {
|
if self.is_indirect() {
|
||||||
unsafe { Either::Left(self.indirect) }
|
unsafe { Left(self.indirect) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Right(self.cell) }
|
unsafe { Right(self.cell) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cell(&self) -> Option<Cell> {
|
||||||
|
if self.is_cell() {
|
||||||
|
unsafe { Some(self.cell) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,17 +978,57 @@ impl Noun {
|
|||||||
|
|
||||||
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
|
pub fn as_either_atom_cell(&self) -> Either<Atom, Cell> {
|
||||||
if self.is_cell() {
|
if self.is_cell() {
|
||||||
unsafe { Either::Right(self.cell) }
|
unsafe { Right(self.cell) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Left(self.atom) }
|
unsafe { Left(self.atom) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
|
pub fn as_either_direct_allocated(&self) -> Either<DirectAtom, Allocated> {
|
||||||
if self.is_direct() {
|
if self.is_direct() {
|
||||||
unsafe { Either::Left(self.direct) }
|
unsafe { Left(self.direct) }
|
||||||
} else {
|
} else {
|
||||||
unsafe { Either::Right(self.allocated) }
|
unsafe { Right(self.allocated) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atom(&self) -> Option<Atom> {
|
||||||
|
if self.is_atom() {
|
||||||
|
unsafe { Some(self.atom) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cell(&self) -> Option<Cell> {
|
||||||
|
if self.is_cell() {
|
||||||
|
unsafe { Some(self.cell) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn direct(&self) -> Option<DirectAtom> {
|
||||||
|
if self.is_direct() {
|
||||||
|
unsafe { Some(self.direct) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn indirect(&self) -> Option<IndirectAtom> {
|
||||||
|
if self.is_indirect() {
|
||||||
|
unsafe { Some(self.indirect) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocated(&self) -> Option<Allocated> {
|
||||||
|
if self.is_allocated() {
|
||||||
|
unsafe { Some(self.allocated) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -950,8 +1100,8 @@ impl Noun {
|
|||||||
if allocated.get_metadata() & (1 << 32) == 0 {
|
if allocated.get_metadata() & (1 << 32) == 0 {
|
||||||
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
|
allocated.set_metadata(allocated.get_metadata() | (1 << 32));
|
||||||
match allocated.as_either() {
|
match allocated.as_either() {
|
||||||
Either::Left(indirect) => indirect.size() + 2,
|
Left(indirect) => indirect.size() + 2,
|
||||||
Either::Right(cell) => {
|
Right(cell) => {
|
||||||
word_size_of::<CellMemory>()
|
word_size_of::<CellMemory>()
|
||||||
+ cell.head().mass_wind(inside)
|
+ cell.head().mass_wind(inside)
|
||||||
+ cell.tail().mass_wind(inside)
|
+ cell.tail().mass_wind(inside)
|
||||||
@ -973,7 +1123,7 @@ impl Noun {
|
|||||||
if let Ok(allocated) = self.as_allocated() {
|
if let Ok(allocated) = self.as_allocated() {
|
||||||
if inside(allocated.to_raw_pointer()) {
|
if inside(allocated.to_raw_pointer()) {
|
||||||
allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
|
allocated.set_metadata(allocated.get_metadata() & !(1 << 32));
|
||||||
if let Either::Right(cell) = allocated.as_either() {
|
if let Right(cell) = allocated.as_either() {
|
||||||
cell.head().mass_unwind(inside);
|
cell.head().mass_unwind(inside);
|
||||||
cell.tail().mass_unwind(inside);
|
cell.tail().mass_unwind(inside);
|
||||||
}
|
}
|
||||||
@ -1010,6 +1160,23 @@ impl fmt::Display for Noun {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Slots for Noun {}
|
||||||
|
impl private::RawSlots for Noun {
|
||||||
|
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun> {
|
||||||
|
match self.as_either_atom_cell() {
|
||||||
|
Right(cell) => cell.raw_slot(axis),
|
||||||
|
Left(_atom) => {
|
||||||
|
if axis.last_one() == Some(0) {
|
||||||
|
Ok(*self)
|
||||||
|
} else {
|
||||||
|
// Axis tried to descend through atom
|
||||||
|
Err(Error::NotCell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An allocation object (probably a mem::NockStack) which can allocate a memory buffer sized to
|
* An allocation object (probably a mem::NockStack) which can allocate a memory buffer sized to
|
||||||
* a certain number of nouns
|
* a certain number of nouns
|
||||||
@ -1024,3 +1191,44 @@ pub trait NounAllocator: Sized {
|
|||||||
/** Allocate memory for a cell */
|
/** Allocate memory for a cell */
|
||||||
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
|
unsafe fn alloc_cell(&mut self) -> *mut CellMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing types allow component Nouns to be retreived by numeric axis
|
||||||
|
*/
|
||||||
|
pub trait Slots: private::RawSlots {
|
||||||
|
/**
|
||||||
|
* Retrieve component Noun at given axis, or fail with descriptive error
|
||||||
|
*/
|
||||||
|
fn slot(&self, axis: u64) -> Result<Noun> {
|
||||||
|
if axis == 0 {
|
||||||
|
// 0 is not allowed as an axis
|
||||||
|
Err(Error::NotRepresentable)
|
||||||
|
} else {
|
||||||
|
self.raw_slot(BitSlice::from_element(&axis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve component Noun at axis given as Atom, or fail with descriptive error
|
||||||
|
*/
|
||||||
|
fn slot_atom(&self, atom: Atom) -> Result<Noun> {
|
||||||
|
self.raw_slot(atom.as_bitslice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation methods that should not be made available to derived crates
|
||||||
|
*/
|
||||||
|
mod private {
|
||||||
|
use crate::noun::{BitSlice, Lsb0, Noun, Result};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the Slots trait
|
||||||
|
*/
|
||||||
|
pub trait RawSlots {
|
||||||
|
/**
|
||||||
|
* Actual logic of retreiving Noun object at some axis
|
||||||
|
*/
|
||||||
|
fn raw_slot(&self, axis: &BitSlice<u64, Lsb0>) -> Result<Noun>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +1,174 @@
|
|||||||
use crate::interpreter::{interpret, raw_slot};
|
use crate::hamt::Hamt;
|
||||||
|
use crate::interpreter;
|
||||||
|
use crate::interpreter::{inc, interpret, Tone};
|
||||||
use crate::jets::cold::Cold;
|
use crate::jets::cold::Cold;
|
||||||
use crate::jets::hot::Hot;
|
use crate::jets::hot::Hot;
|
||||||
use crate::jets::warm::Warm;
|
use crate::jets::warm::Warm;
|
||||||
|
use crate::jets::nock::util::mook;
|
||||||
|
use crate::jets::text::util::lent;
|
||||||
use crate::mem::NockStack;
|
use crate::mem::NockStack;
|
||||||
use crate::mug::mug_u32;
|
use crate::mug::mug_u32;
|
||||||
use crate::newt::Newt;
|
use crate::newt::Newt;
|
||||||
use crate::noun::{Noun, D, T};
|
use crate::noun::{Cell, Noun, Slots, D, T};
|
||||||
use crate::snapshot::{self, Snapshot};
|
use crate::snapshot::double_jam::DoubleJam;
|
||||||
|
use crate::snapshot::Snapshot;
|
||||||
use ares_macros::tas;
|
use ares_macros::tas;
|
||||||
|
use signal_hook;
|
||||||
|
use signal_hook::consts::SIGINT;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::thread::sleep;
|
use std::result::Result;
|
||||||
use std::time;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
crate::gdb!();
|
crate::gdb!();
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
epoch: u64,
|
||||||
|
event_num: u64,
|
||||||
|
snapshot: DoubleJam,
|
||||||
|
arvo: Noun,
|
||||||
|
mug: u32,
|
||||||
|
stack: NockStack,
|
||||||
|
newt: Newt,
|
||||||
|
cache: Hamt<Noun>,
|
||||||
|
// XX: persistent memo cache
|
||||||
|
cold: Cold,
|
||||||
|
warm: Warm,
|
||||||
|
hot: Hot,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn new(snap_path: &PathBuf) -> Self {
|
||||||
|
// TODO: switch to Pma when ready
|
||||||
|
// let snap = &mut snapshot::pma::Pma::new(snap_path);
|
||||||
|
let mut snapshot = DoubleJam::new(snap_path);
|
||||||
|
let mut stack = NockStack::new(256 << 10 << 10, 0);
|
||||||
|
let newt = Newt::new();
|
||||||
|
let cache = Hamt::<Noun>::new();
|
||||||
|
|
||||||
|
let cold = Cold::new(stack);
|
||||||
|
let warm = Warm::new();
|
||||||
|
let hot = Hot::init(stack);
|
||||||
|
|
||||||
|
let (epoch, event_num, arvo) = snapshot.load(&mut stack).unwrap_or((0, 0, D(0)));
|
||||||
|
let mug = mug_u32(&mut stack, arvo);
|
||||||
|
|
||||||
|
Context {
|
||||||
|
epoch,
|
||||||
|
event_num,
|
||||||
|
snapshot,
|
||||||
|
arvo,
|
||||||
|
mug,
|
||||||
|
stack,
|
||||||
|
newt,
|
||||||
|
cache,
|
||||||
|
cold,
|
||||||
|
warm,
|
||||||
|
hot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Getters
|
||||||
|
//
|
||||||
|
|
||||||
|
pub fn epoch(&self) -> u64 {
|
||||||
|
self.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_num(&self) -> u64 {
|
||||||
|
self.event_num
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arvo(&self) -> Noun {
|
||||||
|
self.arvo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack_as_mut(&mut self) -> &mut NockStack {
|
||||||
|
&mut self.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_interpreter(&mut self) -> interpreter::Context {
|
||||||
|
self.cache = Hamt::<Noun>::new();
|
||||||
|
|
||||||
|
interpreter::Context {
|
||||||
|
stack: &mut self.stack,
|
||||||
|
newt: Some(&mut self.newt),
|
||||||
|
cache: &mut self.cache,
|
||||||
|
cold: &mut self.cold,
|
||||||
|
warm: &mut self.warm,
|
||||||
|
hot: &mut self.hot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setters
|
||||||
|
//
|
||||||
|
|
||||||
|
pub fn event_update(&mut self, new_event_num: u64, new_arvo: Noun) {
|
||||||
|
// XX: assert event numbers are continuous
|
||||||
|
self.arvo = new_arvo;
|
||||||
|
self.event_num = new_event_num;
|
||||||
|
self.snapshot.save(&mut self.stack, &mut self.arvo);
|
||||||
|
self.mug = mug_u32(&mut self.stack, self.arvo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Snapshot functions
|
||||||
|
//
|
||||||
|
|
||||||
|
pub fn sync(&mut self) {
|
||||||
|
self.snapshot
|
||||||
|
.sync(&mut self.stack, self.epoch, self.event_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Newt functions
|
||||||
|
//
|
||||||
|
|
||||||
|
pub fn next(&mut self) -> Option<Noun> {
|
||||||
|
self.newt.next(&mut self.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ripe(&mut self) {
|
||||||
|
self.newt
|
||||||
|
.ripe(&mut self.stack, self.event_num, self.mug as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn live(&mut self) {
|
||||||
|
self.newt.live(&mut self.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek_done(&mut self, dat: Noun) {
|
||||||
|
self.newt.peek_done(&mut self.stack, dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_done(&mut self) {
|
||||||
|
self.newt.play_done(&mut self.stack, self.mug as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_bail(&mut self, dud: Noun) {
|
||||||
|
self.newt
|
||||||
|
.play_bail(&mut self.stack, self.event_num, self.mug as u64, dud);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn work_done(&mut self, fec: Noun) {
|
||||||
|
self.newt
|
||||||
|
.work_done(&mut self.stack, self.event_num, self.mug as u64, fec);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn work_swap(&mut self, job: Noun, fec: Noun) {
|
||||||
|
self.newt
|
||||||
|
.work_swap(&mut self.stack, self.event_num, self.mug as u64, job, fec);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn work_bail(&mut self, lud: Noun) {
|
||||||
|
self.newt.work_bail(&mut self.stack, lud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const LOAD_AXIS: u64 = 4;
|
const LOAD_AXIS: u64 = 4;
|
||||||
const PEEK_AXIS: u64 = 22;
|
const PEEK_AXIS: u64 = 22;
|
||||||
@ -23,12 +176,20 @@ const POKE_AXIS: u64 = 23;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const WISH_AXIS: u64 = 10;
|
const WISH_AXIS: u64 = 10;
|
||||||
|
|
||||||
|
// Necessary because Arc::new is not const
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref TERMINATOR: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is suitable for talking to the king process. To test, change the arg_c[0] line in
|
* This is suitable for talking to the king process. To test, change the arg_c[0] line in
|
||||||
* u3_lord_init in vere to point at this binary and start vere like normal.
|
* u3_lord_init in vere to point at this binary and start vere like normal.
|
||||||
*/
|
*/
|
||||||
pub fn serf() -> io::Result<()> {
|
pub fn serf() -> io::Result<()> {
|
||||||
sleep(time::Duration::from_secs(0));
|
// Register SIGINT signal hook to set flag first time, shutdown second time
|
||||||
|
signal_hook::flag::register_conditional_shutdown(SIGINT, 1, Arc::clone(&TERMINATOR))?;
|
||||||
|
signal_hook::flag::register(SIGINT, Arc::clone(&TERMINATOR))?;
|
||||||
|
|
||||||
let snap_path_string = std::env::args()
|
let snap_path_string = std::env::args()
|
||||||
.nth(2)
|
.nth(2)
|
||||||
.ok_or(io::Error::new(io::ErrorKind::Other, "no pier path"))?;
|
.ok_or(io::Error::new(io::ErrorKind::Other, "no pier path"))?;
|
||||||
@ -36,114 +197,203 @@ pub fn serf() -> io::Result<()> {
|
|||||||
snap_path.push(".urb");
|
snap_path.push(".urb");
|
||||||
snap_path.push("chk");
|
snap_path.push("chk");
|
||||||
create_dir_all(&snap_path)?;
|
create_dir_all(&snap_path)?;
|
||||||
// TODO: switch to Pma when ready
|
|
||||||
// let snap = &mut snapshot::pma::Pma::new(snap_path);
|
|
||||||
let snap = &mut snapshot::double_jam::DoubleJam::new(snap_path);
|
|
||||||
|
|
||||||
let stack = &mut NockStack::new(96 << 10 << 10, 0);
|
let mut context = Context::new(&snap_path);
|
||||||
let mut cold = Cold::new(stack);
|
context.ripe();
|
||||||
let mut warm = Warm::new();
|
|
||||||
let hot = Hot::init(stack);
|
|
||||||
let newt = &mut Newt::new();
|
|
||||||
|
|
||||||
let (_epoch, mut event_number, mut arvo) = snap.load(stack).unwrap_or((0, 0, D(0)));
|
|
||||||
let mug = mug_u32(stack, arvo);
|
|
||||||
|
|
||||||
newt.ripe(stack, event_number, mug as u64);
|
|
||||||
|
|
||||||
// Can't use for loop because it borrows newt
|
// Can't use for loop because it borrows newt
|
||||||
while let Some(writ) = newt.next(stack) {
|
while let Some(writ) = context.next() {
|
||||||
let tag = raw_slot(writ, 2).as_direct().unwrap();
|
// XX: probably want to bookend this logic frame_push / frame_pop
|
||||||
|
// preserve jet state and persistent cache, lose everything else
|
||||||
|
let tag = slot(writ, 2)?.as_direct().unwrap();
|
||||||
match tag.data() {
|
match tag.data() {
|
||||||
tas!(b"live") => {
|
tas!(b"live") => {
|
||||||
let inner = raw_slot(writ, 6);
|
let inner = slot(writ, 6)?.as_direct().unwrap();
|
||||||
match inner.as_direct().unwrap().data() {
|
match inner.data() {
|
||||||
tas!(b"cram") => eprintln!("cram"),
|
tas!(b"cram") => eprintln!("cram"),
|
||||||
tas!(b"exit") => eprintln!("exit"),
|
tas!(b"exit") => eprintln!("exit"),
|
||||||
tas!(b"save") => {
|
tas!(b"save") => {
|
||||||
// XX what is eve for?
|
// XX what is eve for?
|
||||||
eprintln!("save");
|
eprintln!("save");
|
||||||
snap.sync(stack, 0, event_number);
|
context.sync();
|
||||||
}
|
}
|
||||||
tas!(b"meld") => eprintln!("meld"),
|
tas!(b"meld") => eprintln!("meld"),
|
||||||
tas!(b"pack") => eprintln!("pack"),
|
tas!(b"pack") => eprintln!("pack"),
|
||||||
_ => eprintln!("unknown live"),
|
_ => eprintln!("unknown live"),
|
||||||
}
|
}
|
||||||
newt.live(stack);
|
context.live();
|
||||||
}
|
}
|
||||||
tas!(b"peek") => {
|
tas!(b"peek") => {
|
||||||
let sam = raw_slot(writ, 7);
|
let sam = slot(writ, 7)?;
|
||||||
let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, PEEK_AXIS, sam);
|
let res =
|
||||||
newt.peek_done(stack, res);
|
slam(&mut context, PEEK_AXIS, sam).expect("peek error handling unimplemented");
|
||||||
|
context.peek_done(res);
|
||||||
}
|
}
|
||||||
tas!(b"play") => {
|
tas!(b"play") => {
|
||||||
let run = if event_number == 0 {
|
let lit = slot(writ, 7)?;
|
||||||
|
if context.epoch() == 0 && context.event_num() == 0 {
|
||||||
// apply lifecycle to first batch
|
// apply lifecycle to first batch
|
||||||
let lit = raw_slot(writ, 7);
|
play_life(&mut context, lit);
|
||||||
let sub = T(stack, &[D(0), D(3)]);
|
|
||||||
let lyf = T(stack, &[D(2), sub, D(0), D(2)]);
|
|
||||||
let gat =
|
|
||||||
interpret(stack, &mut Some(newt), &mut cold, &mut warm, hot, lit, lyf);
|
|
||||||
arvo = raw_slot(gat, 7);
|
|
||||||
false
|
|
||||||
} else {
|
} else {
|
||||||
true
|
play_list(&mut context, lit);
|
||||||
};
|
};
|
||||||
|
|
||||||
// do we need to assert something here?
|
|
||||||
// event_number = raw_slot(writ, 6).as_direct().unwrap().data();
|
|
||||||
|
|
||||||
let mut lit = raw_slot(writ, 7);
|
|
||||||
while let Ok(cell) = lit.as_cell() {
|
|
||||||
if run {
|
|
||||||
let ovo = cell.head();
|
|
||||||
let res =
|
|
||||||
slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo)
|
|
||||||
.as_cell()
|
|
||||||
.unwrap();
|
|
||||||
arvo = res.tail();
|
|
||||||
}
|
|
||||||
event_number += 1;
|
|
||||||
lit = cell.tail();
|
|
||||||
}
|
|
||||||
|
|
||||||
snap.save(stack, &mut arvo);
|
|
||||||
newt.play_done(stack, 0);
|
|
||||||
}
|
}
|
||||||
tas!(b"work") => {
|
tas!(b"work") => {
|
||||||
let ovo = raw_slot(writ, 7);
|
// XX: what is in slot 6? it's mil_w in Vere Serf
|
||||||
let res = slam(stack, newt, &mut cold, &mut warm, hot, arvo, POKE_AXIS, ovo)
|
let job = slot(writ, 7)?;
|
||||||
.as_cell()
|
work(&mut context, job);
|
||||||
.unwrap();
|
|
||||||
let fec = res.head();
|
|
||||||
arvo = res.tail();
|
|
||||||
snap.save(stack, &mut arvo);
|
|
||||||
|
|
||||||
event_number += 1;
|
|
||||||
|
|
||||||
newt.work_done(stack, event_number, 0, fec);
|
|
||||||
}
|
}
|
||||||
_ => panic!("got message with unknown tag {}", tag),
|
_ => panic!("got message with unknown tag {}", tag),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
clear_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
fn burn(context: &mut Context, subject: Noun, formula: Noun) -> Result<Noun, Tone> {
|
||||||
pub fn slam(
|
let burn_context = &mut context.for_interpreter();
|
||||||
stack: &mut NockStack,
|
interpret(burn_context, subject, formula)
|
||||||
newt: &mut Newt,
|
}
|
||||||
cold: &mut Cold,
|
|
||||||
warm: &mut Warm,
|
fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result<Noun, Tone> {
|
||||||
hot: Hot,
|
let arvo = context.arvo();
|
||||||
core: Noun,
|
let pul = T(context.stack_as_mut(), &[D(9), D(axis), D(0), D(2)]);
|
||||||
axis: u64,
|
let sam = T(context.stack_as_mut(), &[D(6), D(0), D(7)]);
|
||||||
ovo: Noun,
|
let fol = T(
|
||||||
) -> Noun {
|
context.stack_as_mut(),
|
||||||
let pul = T(stack, &[D(9), D(axis), D(0), D(2)]);
|
&[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)],
|
||||||
let sam = T(stack, &[D(6), D(0), D(7)]);
|
);
|
||||||
let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]);
|
let sub = T(context.stack_as_mut(), &[arvo, ovo]);
|
||||||
let sub = T(stack, &[core, ovo]);
|
burn(context, sub, fol)
|
||||||
interpret(stack, &mut Some(newt), cold, warm, hot, sub, fol)
|
}
|
||||||
|
|
||||||
|
fn goof(context: &mut Context, trace: Noun) -> Noun {
|
||||||
|
let tone = Cell::new(context.stack_as_mut(), D(2), trace);
|
||||||
|
let mook_context = &mut context.for_interpreter();
|
||||||
|
|
||||||
|
let tang = mook(mook_context, tone, false)
|
||||||
|
.expect("serf: goof: +mook crashed on bail")
|
||||||
|
.tail();
|
||||||
|
// XX: noun::Tone or noun::NockErr should use a bail enum system similar to u3m_bail motes;
|
||||||
|
// might be able to replace NockErr with mote and map determinism to individual motes;
|
||||||
|
// for, always set to %exit
|
||||||
|
T(mook_context.stack, &[D(tas!(b"exit")), tang])
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Run slam, process stack trace to tang if error */
|
||||||
|
fn soft(context: &mut Context, ovo: Noun) -> Result<Noun, Noun> {
|
||||||
|
match slam(context, POKE_AXIS, ovo) {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err(Tone::Error(_, trace)) => Err(goof(context, trace)),
|
||||||
|
Err(Tone::Blocked(_)) => panic!("soft: blocked err handling unimplemented"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_life(context: &mut Context, eve: Noun) {
|
||||||
|
let sub = T(context.stack_as_mut(), &[D(0), D(3)]);
|
||||||
|
let lyf = T(context.stack_as_mut(), &[D(2), sub, D(0), D(2)]);
|
||||||
|
match burn(context, eve, lyf) {
|
||||||
|
Ok(gat) => {
|
||||||
|
let eved = lent(eve).expect("serf: play: boot event number failure") as u64;
|
||||||
|
let arvo = slot(gat, 7).expect("serf: play: lifecycle didn't return initial Arvo");
|
||||||
|
|
||||||
|
context.event_update(eved, arvo);
|
||||||
|
context.play_done();
|
||||||
|
}
|
||||||
|
Err(Tone::Error(_, trace)) => {
|
||||||
|
let goof = goof(context, trace);
|
||||||
|
context.play_bail(goof);
|
||||||
|
}
|
||||||
|
Err(Tone::Blocked(_)) => {
|
||||||
|
panic!("play: blocked err handling unimplemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_list(context: &mut Context, mut lit: Noun) {
|
||||||
|
let mut eve = context.event_num();
|
||||||
|
while let Ok(cell) = lit.as_cell() {
|
||||||
|
let ovo = cell.head();
|
||||||
|
match soft(context, ovo) {
|
||||||
|
Ok(res) => {
|
||||||
|
let arvo = res
|
||||||
|
.as_cell()
|
||||||
|
.expect("serf: work: +slam returned atom")
|
||||||
|
.tail();
|
||||||
|
eve += 1;
|
||||||
|
|
||||||
|
context.event_update(eve, arvo);
|
||||||
|
}
|
||||||
|
Err(goof) => {
|
||||||
|
return context.play_bail(goof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lit = cell.tail();
|
||||||
|
}
|
||||||
|
context.play_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn work(context: &mut Context, job: Noun) {
|
||||||
|
match soft(context, job) {
|
||||||
|
Ok(res) => {
|
||||||
|
let cell = res.as_cell().expect("serf: work: +slam returned atom");
|
||||||
|
let fec = cell.head();
|
||||||
|
let eve = context.event_num();
|
||||||
|
|
||||||
|
context.event_update(eve + 1, cell.tail());
|
||||||
|
context.work_done(fec);
|
||||||
|
}
|
||||||
|
Err(goof) => {
|
||||||
|
work_swap(context, job, goof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn work_swap(context: &mut Context, job: Noun, goof: Noun) {
|
||||||
|
// TODO: on decryption failure in aes_siv, should bail as fast as
|
||||||
|
// possible, without rendering stack trace or injecting crud event. See
|
||||||
|
// c3__evil in vere.
|
||||||
|
|
||||||
|
clear_interrupt();
|
||||||
|
|
||||||
|
// crud = [+(now) [%$ %arvo ~] [%crud goof ovo]]
|
||||||
|
let job_cell = job.as_cell().expect("serf: work: job not a cell");
|
||||||
|
let job_now = job_cell.head().as_atom().expect("serf: work: now not atom");
|
||||||
|
let now = inc(context.stack_as_mut(), job_now).as_noun();
|
||||||
|
let wire = T(context.stack_as_mut(), &[D(0), D(tas!(b"arvo")), D(0)]);
|
||||||
|
let crud = T(
|
||||||
|
context.stack_as_mut(),
|
||||||
|
&[now, wire, D(tas!(b"crud")), goof, job_cell.tail()],
|
||||||
|
);
|
||||||
|
|
||||||
|
match soft(context, crud) {
|
||||||
|
Ok(res) => {
|
||||||
|
let cell = res.as_cell().expect("serf: work: crud +slam returned atom");
|
||||||
|
let fec = cell.head();
|
||||||
|
let eve = context.event_num();
|
||||||
|
|
||||||
|
context.event_update(eve + 1, cell.tail());
|
||||||
|
context.work_swap(crud, fec);
|
||||||
|
}
|
||||||
|
Err(goof_crud) => {
|
||||||
|
work_bail(context, &[goof_crud, goof]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn work_bail(context: &mut Context, goofs: &[Noun]) {
|
||||||
|
let lest = T(context.stack_as_mut(), goofs);
|
||||||
|
let lud = T(context.stack_as_mut(), &[lest, D(0)]);
|
||||||
|
context.work_bail(lud);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slot(noun: Noun, axis: u64) -> io::Result<Noun> {
|
||||||
|
noun.slot(axis)
|
||||||
|
.map_err(|_e| io::Error::new(io::ErrorKind::InvalidInput, "Bad axis"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_interrupt() {
|
||||||
|
(*TERMINATOR).store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,7 @@ impl Snapshot for DoubleJam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self, _stack: &mut NockStack, noun: &mut Noun) {
|
fn save(&mut self, _stack: &mut NockStack, noun: &mut Noun) {
|
||||||
|
// XX: I don't think this needs to be mut
|
||||||
self.noun = *noun;
|
self.noun = *noun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user