mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			266 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| library Stack  // advanced stack manupulation library
 | |
| "Lists.fif" include
 | |
| // S(a b c - a c 2 a b) would compile to code performing the requested stack manipulation
 | |
| 
 | |
| // interface to low-level stack manipulation primitives
 | |
| { (number) 1- abort"index expected" dup 0 < over 255 > or
 | |
|   abort"index 0..255 expected"
 | |
| } : (idx)
 | |
| // push(n) : a0 .. an - a0 .. an a0  equivalent to "n pick"
 | |
| // push(0) = dup, push(1) = over
 | |
| { 0 char ) word (idx) <push> } ::_ push(
 | |
| // pop(n) : a0 a1 .. a(n-1) an - an a1 .. a(n-1)
 | |
| // pop(0) = drop, pop(1) = nip
 | |
| { 0 char ) word (idx) <pop> } ::_ pop(
 | |
| // xchg(i,j) : equivalent to "i j exch2"
 | |
| { 0 char , word (idx) char ) word (idx) <xchg> } ::_ xchg(
 | |
| // xchg0(i) : equivalent to "i exch" or "xchg(0,i)"
 | |
| // xchg0(1) = swap
 | |
| { 0 char ) word (idx) 0 <xchg> } ::_ xchg0(
 | |
| forget (idx)
 | |
| 
 | |
| // parser for stack notation expressions
 | |
| ")" 34 hold +"  -" constant stk-delims
 | |
| anon constant stk-start
 | |
| anon constant stk-to
 | |
| variable stk-mode
 | |
| { stk-delims 11 (word) } : stk-token
 | |
| 'nop : mk-lit
 | |
| // stk-start vn ... v0 -- stk-start ... v0 i  where v[i]=v0
 | |
| { 0 {
 | |
|   1+ 2dup 2+ pick dup stk-start eq? { 2drop drop 0 true } { eqv? } cond
 | |
|   } until
 | |
| } : stk-lookup
 | |
| // stk-start a1 .. an stk-to b1 .. bm -- [a1 .. an] [b1 .. bm]
 | |
| { stk-mode @ 0= abort"identifier expected" } : chk-lit
 | |
| { stk-to list-until-marker stk-mode !
 | |
|   stk-start list-until-marker stk-mode @
 | |
|   stk-mode 0!
 | |
| } : build-stk-effect
 | |
| { stk-start stk-mode 0! {
 | |
|   stk-token dup ")" $= { drop true } {
 | |
|   dup "-" $= {
 | |
|     drop stk-mode @ abort"duplicate -" true stk-mode ! stk-to false } {
 | |
|   dup 34 chr $= { chk-lit drop char " word mk-lit false } {
 | |
|   dup (number) ?dup { chk-lit 1- { swap mk-lit -rot } if mk-lit nip false } {
 | |
|   atom dup `_ eq? { stk-mode @ abort"identifier expected" false } {
 | |
|   stk-lookup 0= stk-mode @ = {
 | |
|     stk-mode @ { atom>$ +" -?" } { atom>$ +" redefined" } cond abort } {
 | |
|   false
 | |
|   } cond } cond } cond } cond } cond } cond } until
 | |
|   stk-mode @ 0= abort"'-' expected"
 | |
|   build-stk-effect
 | |
| } :_ parse-stk-list(
 | |
| 
 | |
| // stack operation list construction
 | |
| variable op-rlist
 | |
| { op-rlist null! } : clear-op-list
 | |
| { op-rlist @ list-reverse } : get-op-list
 | |
| { op-rlist @ cons op-rlist ! } : issue-op
 | |
| { minmax `xchg -rot triple } : op-xchg
 | |
| { `push swap pair } : op-push
 | |
| { `lit swap pair } : op-lit
 | |
| { `pop swap pair } : op-pop
 | |
| 0 op-pop constant op-drop
 | |
| { 2dup <> { op-xchg issue-op } if } : issue-xchg
 | |
| { op-push issue-op } : issue-push
 | |
| { op-lit issue-op } : issue-lit
 | |
| { op-pop issue-op } : issue-pop
 | |
| { op-drop issue-op } : issue-drop
 | |
| { ' issue-drop swap times } : issue-drop-#
 | |
| 
 | |
| // emulated stack contents
 | |
| variable emul-stk
 | |
| { emul-stk @ count } : emul-depth
 | |
| { emul-depth 1- swap - } : adj-i
 | |
| { emul-depth 1- tuck swap - swap rot - swap } : adj-ij
 | |
| // i j --
 | |
| { adj-ij 2dup emul-stk @ tuck swap [] swap rot [] rot // i sj si j
 | |
|   emul-stk @ -rot []= swap rot []= emul-stk !
 | |
| } : emul-xchg
 | |
| { emul-stk @ tpop drop emul-stk ! } : emul-drop
 | |
| // i --
 | |
| { 0 emul-xchg emul-drop } : emul-pop
 | |
| // i -- s[i]
 | |
| { emul-stk @ swap [] } : emul-stk[]
 | |
| // i -- si
 | |
| { adj-i emul-stk[] } : emul-get
 | |
| { 0 emul-get } : emul-tos
 | |
| // v i -- ?   Check whether s[i]=v
 | |
| { dup emul-depth < { emul-stk[] eqv? } { 2drop false } cond } : emul[]-eq?
 | |
| // v -- i or -1   Returns maximum i with s[i]=v
 | |
| { emul-stk @ dup count { // v s i
 | |
|   ?dup 0= { -1 true } { 1- 2dup [] 3 pick eqv? } cond  // v s i' ?
 | |
|   } until nip nip
 | |
| } : emul-stk-lookup-rev
 | |
| // i --
 | |
| { emul-get emul-stk @ swap , emul-stk ! } : emul-push
 | |
| { emul-stk @ swap , emul-stk ! } : emul-lit
 | |
| // show emulated stack contents similarly to .s
 | |
| { emul-stk @ explode dup 1 reverse ' .l swap times cr } : .e
 | |
| 
 | |
| // both issue an operation and emulate it
 | |
| { 2dup issue-xchg emul-xchg } : issue-emul-xchg
 | |
| { dup issue-push emul-push } : issue-emul-push
 | |
| { dup issue-lit emul-lit } : issue-emul-lit
 | |
| { dup issue-pop emul-pop } : issue-emul-pop
 | |
| { issue-drop emul-drop } : issue-emul-drop
 | |
| { ' issue-emul-drop swap times } : issue-emul-drop-#
 | |
| 
 | |
| // b.. s -- b.. s   moves tos value to stk[s]
 | |
| { dup emul-stk[] 2 pick cdr list-member-eqv? {
 | |
|   dup adj-i 0 issue-emul-xchg } { dup adj-i issue-emul-pop } cond
 | |
| } : move-tos-to
 | |
| 
 | |
| // new s -- ops registered
 | |
| { { over null? not } {
 | |
|   // .sl .e get-op-list .l cr 
 | |
|   // get-op-list list-length 100 > abort"too long"
 | |
|   emul-depth over >
 | |
|     { over emul-tos swap list-member-eqv? not } { false } cond {
 | |
|   // b.. s  tos unneeded
 | |
|   issue-emul-drop } {
 | |
|   over car // b.. s b1
 | |
|   2dup swap emul[]-eq? { drop swap cdr swap 1+ } {
 | |
|   dup emul-stk-lookup-rev // b.. s b1 i
 | |
|   dup 0< { // b.. s b1 i  not found, must be a literal
 | |
|     drop dup atom? abort"unavailable value"
 | |
|     issue-emul-lit } {
 | |
|   dup 3 pick < { // b.. s b1 i  found in bottom s stack values
 | |
|     nip adj-i issue-emul-push  // b.. s
 | |
|     dup emul-depth 1- < { move-tos-to } if
 | |
|   } {
 | |
|   emul-depth 1- over = { // b.. s b1 i  found in tos
 | |
|     2drop move-tos-to
 | |
|   } { // b.. s b1 i
 | |
|     nip over adj-ij issue-emul-xchg
 | |
|   } cond } cond } cond } cond } cond } while
 | |
|   nip emul-depth swap - issue-emul-drop-#
 | |
| } : generate-reorder-ops
 | |
| 
 | |
| // old new -- op-list
 | |
| { emul-stk @ op-rlist @ 2swap 
 | |
|   swap list>tuple emul-stk ! clear-op-list
 | |
|   0 generate-reorder-ops get-op-list
 | |
|   -rot op-rlist ! emul-stk !
 | |
| } : generate-reorder
 | |
| { parse-stk-list( generate-reorder } :_ SG(
 | |
| 
 | |
| // op-list rewriting according to a ruleset 
 | |
| // l f l1 l2 -- l' -1 or l f  with l' = l2 + (l - l1)
 | |
| { push(3) rot list- { list+ nip nip true } { drop } cond
 | |
| } : try-rule
 | |
| // l f ll -- l' -1 or l f
 | |
| { { dup null? not } { uncons 3 -roll unpair try-rule rot } while drop
 | |
| } : try-ruleset
 | |
| // l ll -- l'
 | |
| { swap { over false swap try-ruleset 0= } until nip
 | |
| } : try-ruleset*
 | |
| // l ruleset -- l'
 | |
| recursive try-ruleset*-everywhere {
 | |
|   tuck try-ruleset* dup null? { nip } {
 | |
|     uncons rot try-ruleset*-everywhere cons } cond
 | |
| } swap !
 | |
| LIST(
 | |
|  [([xchg 0 1] [xchg 0 2]) ([rot])]
 | |
|  [([xchg 0 1] [xchg 1 2]) ([-rot])]
 | |
|  [([xchg 0 2] [xchg 1 2]) ([rot])]
 | |
|  [([xchg 0 2] [xchg 0 1]) ([-rot])]
 | |
|  [([xchg 1 2] [xchg 0 1]) ([rot])]
 | |
|  [([xchg 1 2] [xchg 0 2]) ([-rot])]
 | |
|  [([xchg 0 1] [rot]) ([xchg 0 2])]
 | |
|  [([-rot] [xchg 0 1]) ([xchg 0 2])]
 | |
|  [([xchg 0 2] [xchg 1 3]) ([2swap])]
 | |
|  [([xchg 1 3] [xchg 0 2]) ([2swap])]
 | |
|  [([push 1] [push 1]) ([2dup])]
 | |
|  [([push 3] [push 3]) ([2over])]
 | |
|  [([pop 0] [pop 0]) ([2drop])]
 | |
|  [([pop 1] [pop 0]) ([2drop])]
 | |
|  [([xchg 0 1] [push 1]) ([tuck])]
 | |
|  [([rot] [-rot]) ()]
 | |
|  [([-rot] [rot]) ()]
 | |
| ) constant fift-stack-ruleset
 | |
| { fift-stack-ruleset try-ruleset*-everywhere } : fift-ops-rewrite
 | |
| { SG( fift-ops-rewrite } :_ SGF(
 | |
| 
 | |
| // helpers for creating Fift source strings for one fift-op
 | |
| // i j -- s
 | |
| { minmax over { "xchg(" rot (.) $+ +"," swap (.) $+ +")" }
 | |
|   { nip dup 1 = { drop "swap" } { 
 | |
|     ?dup { "xchg0(" swap (.) $+ +")" } { "" } cond
 | |
|   } cond } cond
 | |
| } : source-<xchg>
 | |
| // i -- s
 | |
| { dup 1 = { drop "over" } {
 | |
|   ?dup { "push(" swap (.) $+ +")" } { "dup" } cond
 | |
|   } cond
 | |
| } : source-<push>
 | |
| // i -- s
 | |
| { dup 1 = { drop "nip" } {
 | |
|   ?dup { "pop(" swap (.) $+ +")" } { "drop" } cond
 | |
|   } cond
 | |
| } : source-<pop>
 | |
| // lit -- s
 | |
| { dup string? { char " chr swap $+ char " hold } { (.) } cond
 | |
| } : source-<lit> 
 | |
| 
 | |
| // dictionary with all fift op compilation/source creation
 | |
| { 0 swap (compile) } : fop-compile
 | |
| ( _( `xchg 2 { <xchg> fop-compile } { source-<xchg> swap cons } )
 | |
|   _( `push 1 { <push> fop-compile } { source-<push> swap cons } )
 | |
|   _( `pop 1 { <pop> fop-compile } { source-<pop> swap cons } )
 | |
|   _( `lit 1 { 1 'nop (compile) } { source-<lit> swap cons } )
 | |
|   _( `rot 0 { ' rot fop-compile } { "rot" swap cons } )
 | |
|   _( `-rot 0 { ' -rot fop-compile } { "-rot" swap cons } )
 | |
|   _( `tuck 0 { ' tuck fop-compile } { "tuck" swap cons } )
 | |
|   _( `2swap 0 { ' 2swap fop-compile } { "2swap" swap cons } )
 | |
|   _( `2drop 0 { ' 2drop fop-compile } { "2drop" swap cons } )
 | |
|   _( `2dup 0 { ' 2dup fop-compile } { "2dup" swap cons } )
 | |
|   _( `2over 0 { ' 2over fop-compile } { "2over" swap cons } )
 | |
| ) box constant fift-op-dict
 | |
| 
 | |
| { dup atom? { atom>$ } { drop "" } cond
 | |
|   "unknown operation " swap $+ abort
 | |
| } : report-unknown-op
 | |
| variable 'fop-entry-exec
 | |
| // process fift-op according to 'fop-entry-exec
 | |
| // ... op - ...
 | |
| { dup first dup fift-op-dict @ assq { report-unknown-op } ifnot
 | |
|   dup second 1+ push(3) count <> abort"incorrect param count"
 | |
|   nip swap explode dup roll drop 1- roll // o2 .. on entry
 | |
|   'fop-entry-exec @ execute 
 | |
| } : process-fift-op
 | |
| 
 | |
| // compile op-list into Fift wordlist
 | |
| // wl op-list -- wl'
 | |
| { { third execute } 'fop-entry-exec !
 | |
|   swap ' process-fift-op foldl } : compile-fift-op*
 | |
| // op-list -- e
 | |
| { fift-ops-rewrite ({) swap compile-fift-op* (}) } : ops>wdef
 | |
| 
 | |
| // S(<orig-stack> - <new-stack>) compiles a "word" performing required action
 | |
| { SG( ops>wdef 0 swap } ::_ S(
 | |
| // 1 2 3 S(a b c - c a b a) .s  would print 3 1 2 1
 | |
| 
 | |
| // transform op-list into Fift source
 | |
| // ls op -- ls'
 | |
| { fift-ops-rewrite 
 | |
|   { 3 [] execute } 'fop-entry-exec !
 | |
|   null ' process-fift-op foldl
 | |
|   dup null? { drop "" } { { +" " swap $+ } foldr-ne } cond
 | |
| } : ops>$
 | |
| { SG( ops>$ 1 'nop } ::_ $S(
 | |
| { SG( ops>$ type } :_ .$S(
 | |
| // $S(a b c - b c a c a c) => string "rot 2dup over"
 | |
| // S(a b c - b c a c a c) => compile/execute block { rot 2dup over }
 | |
| // $S(_ x y _ - y x) => string "drop pop(2)"
 | |
| // .$S(x1 x2 - 17 x1) => print string "drop 17 swap"
 | |
| 
 | |
| // simplify/transform sequences of stack manipulation operations
 | |
| LIST(. [a b c d e f g h i j]) constant std-stack
 | |
| { stk-start std-stack explode drop stk-to std-stack explode drop
 | |
| } : simplify<{
 | |
| { build-stk-effect generate-reorder ops>$ } : }>stack
 | |
| // simplify<{ drop drop over over -13 }>stack => string "2drop 2dup -13"
 | |
| // simplify<{ 17 rot }>stack => string "swap 17 swap"
 | |
| // simplify<{ 5 1 reverse }>stack => string "xchg(1,5) xchg(2,4)"
 |