1+ const PREAMBLE : & str = r#": / /MOD SWAP DROP ;
2+ : '\n' 10 ;
3+ : BL 32 ;
4+ : CR '\n' EMIT ;
5+ : SPACE BL EMIT ;
6+ : NEGATE 0 SWAP - ;
7+ : TRUE 1 ;
8+ : FALSE 0 ;
9+ : NOT 0= ;
10+ : LITERAL IMMEDIATE ' LIT , , ;
11+ : ':' [ CHAR : ] LITERAL ;
12+ : ';' [ CHAR ; ] LITERAL ;
13+ : '"' [ CHAR " ] LITERAL ;
14+ : 'A' [ CHAR A ] LITERAL ;
15+ : '0' [ CHAR 0 ] LITERAL ;
16+ : '-' [ CHAR - ] LITERAL ;
17+ : [COMPILE] IMMEDIATE WORD FIND >CFA , ;
18+ : RECURSE IMMEDIATE LATEST @ >CFA , ;
19+ : IF IMMEDIATE ' 0BRANCH , HERE @ 0 , ;
20+ : THEN IMMEDIATE DUP HERE @ SWAP - SWAP ! ;
21+ : ELSE IMMEDIATE ' BRANCH , HERE @ 0 , SWAP DUP HERE @ SWAP - SWAP ! ;
22+ : BEGIN IMMEDIATE HERE @ ;
23+ : AGAIN IMMEDIATE ' BRANCH , HERE @ - , ;
24+ : WHILE IMMEDIATE ' 0BRANCH , HERE @ 0 , ;
25+ : REPEAT IMMEDIATE ' BRANCH , SWAP HERE @ - , DUP HERE @ SWAP - SWAP ! ;
26+ : NIP SWAP DROP ;
27+ : PICK 1+ 8 * DSP@ + @ ;
28+ : SPACES BEGIN DUP 0> WHILE SPACE 1- REPEAT DROP ;
29+ : U. BASE @ /MOD ?DUP IF RECURSE THEN DUP 10 < IF '0' ELSE 10 - 'A' THEN + EMIT ;
30+ : .S DSP@ BEGIN DUP S0 @ < WHILE DUP @ U. 8+ SPACE REPEAT DROP ;
31+ : UWIDTH BASE @ / ?DUP IF RECURSE 1+ ELSE 1 THEN ;
32+ : U.R SWAP DUP UWIDTH ROT SWAP - SPACES U. ;
33+ : .R SWAP DUP 0< IF NEGATE 1 SWAP ROT 1- ELSE 0 SWAP ROT THEN SWAP DUP
34+ UWIDTH ROT SWAP - SPACES SWAP IF '-' EMIT THEN U. ;
35+ : . 0 .R SPACE ;
36+ : U. U. SPACE ;
37+ : WITHIN -ROT OVER <= IF > IF TRUE ELSE FALSE THEN ELSE 2DROP FALSE THEN ;
38+ : ALIGNED 7 + -8 AND ;
39+ : ALIGN HERE @ ALIGNED HERE ! ;
40+ : C, HERE @ C! 1 HERE +! ;
41+ : S" IMMEDIATE STATE @ IF
42+ ' LITSTRING , HERE @ 0 , BEGIN KEY DUP '"' <> WHILE
43+ C, REPEAT DROP DUP HERE @ SWAP - 8- SWAP ! ALIGN ELSE
44+ HERE @ BEGIN KEY DUP '"' <> WHILE OVER C! 1+ REPEAT DROP HERE @ - HERE @ SWAP THEN ;
45+ : ." IMMEDIATE STATE @ IF [COMPILE] S" ' TELL , ELSE BEGIN KEY DUP '"' = IF
46+ DROP EXIT THEN EMIT AGAIN THEN ;
47+ : CELLS 8 * ;
48+ : ID. 8+ DUP C@ F_LENMASK AND BEGIN DUP 0> WHILE SWAP 1+ DUP C@ EMIT SWAP 1- REPEAT
49+ 2DROP ;
50+ : ?IMMEDIATE 8+ C@ F_IMMED AND ;
51+ : CASE IMMEDIATE 0 ;
52+ : OF IMMEDIATE ' OVER , ' = , [COMPILE] IF ' DROP , ;
53+ : ENDOF IMMEDIATE [COMPILE] ELSE ;
54+ : ENDCASE IMMEDIATE ' DROP , BEGIN ?DUP WHILE [COMPILE] THEN REPEAT ;
55+ : CFA> LATEST @ BEGIN ?DUP WHILE 2DUP >CFA = IF NIP EXIT THEN @ REPEAT DROP 0 ;
56+ : SEE WORD FIND HERE @ LATEST @ BEGIN 2 PICK OVER <> WHILE NIP DUP @ REPEAT DROP SWAP
57+ ':' EMIT SPACE DUP ID. SPACE DUP ?IMMEDIATE IF ." IMMEDIATE " THEN >DFA
58+ BEGIN 2DUP > WHILE DUP @
59+ CASE
60+ ' LIT OF 8+ DUP @ . ENDOF
61+ ' LITSTRING OF [ CHAR S ] LITERAL EMIT '"' EMIT SPACE 8+ DUP @ SWAP 8+
62+ SWAP 2DUP TELL '"' EMIT SPACE + ALIGNED 8- ENDOF
63+ ' 0BRANCH OF ." 0BRANCH ( " 8+ DUP @ . ." ) " ENDOF
64+ ' BRANCH OF ." BRANCH ( " 8+ DUP @ . ." ) " ENDOF
65+ ' ' OF [ CHAR ' ] LITERAL EMIT SPACE 8+ DUP CFA> ID. SPACE ENDOF
66+ ' EXIT OF 2DUP 8+ <> IF ." EXIT " THEN ENDOF
67+ DUP CFA> ID. SPACE
68+ ENDCASE
69+ 8+
70+ REPEAT
71+ ';' EMIT CR 2DROP ;
72+ : ['] IMMEDIATE ' LIT , ;
73+ : EXCEPTION-MARKER RDROP 0 ;
74+ : CATCH DSP@ 8+ >R ' EXCEPTION-MARKER 8+ >R EXECUTE ;
75+ : THROW ?DUP IF RSP@ BEGIN DUP R0 8- < WHILE DUP @ ' EXCEPTION-MARKER 8+ = IF
76+ 8+ RSP! DUP DUP DUP R> 8- SWAP OVER ! DSP! EXIT THEN 8+ REPEAT
77+ DROP CASE 0 1- OF ." ABORTED" CR ENDOF ." UNCAUGHT THROW " DUP . CR ENDCASE QUIT THEN
78+ ;
79+ : Z" IMMEDIATE STATE @ IF
80+ ' LITSTRING , HERE @ 0 , BEGIN KEY DUP '"' <> WHILE
81+ HERE @ C! 1 HERE +! REPEAT 0 HERE @ C! 1 HERE +! DROP DUP
82+ HERE @ SWAP - 8- SWAP ! ALIGN ' DROP , ELSE
83+ HERE @ BEGIN KEY DUP '"' <> WHILE OVER C! 1+ REPEAT DROP 0 SWAP C! HERE @ THEN ;
84+ : STRLEN DUP BEGIN DUP C@ 0<> WHILE 1+ REPEAT SWAP - ;
85+ : ARGC (ARGC) @ ;
86+ : ARGV 1+ CELLS (ARGC) + @ DUP STRLEN ;
87+ : ENVIRON ARGC 2 + CELLS (ARGC) + ;
88+ "# ;
89+
90+ #[ cfg( test) ]
91+ mod tests {
92+ use std:: process:: { Command , Stdio } ;
93+ use std:: io:: Write ;
94+ use rstest:: rstest;
95+ use super :: PREAMBLE ;
96+
97+ #[ rstest]
98+ #[ case( "" , "65 EMIT" , "A" ) ]
99+ #[ case( "" , "777 65 EMIT" , "A" ) ]
100+ #[ case( "" , "32 DUP + 1+ EMIT" , "A" ) ]
101+ #[ case( "" , "16 DUP 2DUP + + + 1+ EMIT" , "A" ) ]
102+ #[ case( "" , "8 DUP * 1+ EMIT" , "A" ) ]
103+ #[ case( "" , "CHAR A EMIT" , "A" ) ]
104+ #[ case( "" , ": SLOW WORD FIND >CFA EXECUTE ; 65 SLOW EMIT" , "A" ) ]
105+ #[ case( "" , "3480240455236671827 DSP@ 8 TELL" , "SYSCALL0" ) ]
106+ #[ case( "" , "3480240455236671827 DSP@ HERE @ 8 CMOVE HERE @ 8 TELL" , "SYSCALL0" ) ]
107+ #[ case( "" , "13622 DSP@ 2 NUMBER DROP EMIT" , "A" ) ]
108+ #[ case( "" , "64 >R RSP@ 1 TELL RDROP" , "@" ) ]
109+ #[ case( "" , "64 DSP@ RSP@ SWAP C@C! RSP@ 1 TELL" , "@" ) ]
110+ #[ case( "" , "64 >R 1 RSP@ +! RSP@ 1 TELL" , "A" ) ]
111+ #[ case( "" , r#"
112+ : <BUILDS WORD CREATE DODOES , 0 , ;
113+ : DOES> R> LATEST @ >DFA ! ;
114+ : CONST <BUILDS , DOES> @ ;
115+
116+ 65 CONST FOO
117+ FOO EMIT
118+ "# , "A" ) ]
119+ #[ case( PREAMBLE , "VERSION ." , "47 " ) ]
120+ #[ case( PREAMBLE , "CR" , "\n " ) ]
121+ #[ case( PREAMBLE , "LATEST @ ID." , "ENVIRON" ) ]
122+ #[ case( PREAMBLE , "0 1 > . 1 0 > ." , "0 -1 " ) ]
123+ #[ case( PREAMBLE , "0 1 >= . 0 0 >= ." , "0 -1 " ) ]
124+ #[ case( PREAMBLE , "0 0<> . 1 0<> ." , "0 -1 " ) ]
125+ #[ case( PREAMBLE , "1 0<= . 0 0<= ." , "0 -1 " ) ]
126+ #[ case( PREAMBLE , "-1 0>= . 0 0>= ." , "0 -1 " ) ]
127+ #[ case( PREAMBLE , "0 0 OR . 0 -1 OR ." , "0 -1 " ) ]
128+ #[ case( PREAMBLE , "-1 -1 XOR . 0 -1 XOR ." , "0 -1 " ) ]
129+ #[ case( PREAMBLE , "-1 INVERT . 0 INVERT ." , "0 -1 " ) ]
130+ #[ case( PREAMBLE , "3 4 5 .S" , "5 4 3 " ) ]
131+ #[ case( PREAMBLE , "1 2 3 4 2SWAP .S" , "2 1 4 3 " ) ]
132+ #[ case( PREAMBLE , "F_IMMED F_HIDDEN .S" , "32 128 " ) ]
133+ #[ case( PREAMBLE , ": CFA@ WORD FIND >CFA @ ; CFA@ >DFA DOCOL = ." , "-1 " ) ]
134+ #[ case( PREAMBLE , "3 4 5 WITHIN ." , "0 " ) ]
135+ #[ case( PREAMBLE , r#"S" test" SWAP 1 SYS_WRITE SYSCALL3"# , "test" ) ]
136+ #[ case( PREAMBLE , "SEE >DFA" , ": >DFA >CFA 8+ EXIT ;\n " ) ]
137+ #[ case( PREAMBLE , "SEE HIDE" , ": HIDE WORD FIND HIDDEN ;\n " ) ]
138+ #[ case( PREAMBLE , "SEE QUIT" , ": QUIT R0 RSP! INTERPRET BRANCH ( -16 ) ;\n " ) ]
139+ fn test_wait_with_output (
140+ #[ case] preamble : & str ,
141+ #[ case] input : & str ,
142+ #[ case] expected : & str ,
143+ #[ values( "./4th" , "./5th.ll" ) ] program : & str ,
144+ ) {
145+ let mut child = Command :: new ( program)
146+ . stdin ( Stdio :: piped ( ) )
147+ . stdout ( Stdio :: piped ( ) )
148+ . stderr ( Stdio :: null ( ) )
149+ . spawn ( )
150+ . expect ( "Failed to spawn command" ) ;
151+
152+ child. stdin . take ( )
153+ . unwrap ( )
154+ . write_all ( format ! ( "{} {}\n " , preamble, input) . as_bytes ( ) )
155+ . expect ( "Failed to write to stdin" ) ;
156+
157+ let output = child. wait_with_output ( ) . expect ( "Failed to read stdout" ) ;
158+
159+ assert ! ( output. status. success( ) , "Command failed with status: {:?}" , output. status) ;
160+ assert_eq ! ( output. stdout, expected. as_bytes( ) , "Mismatch for: {}" , input) ;
161+ }
162+ }
0 commit comments