def test_drop(self): m = forth.Machine() ret = m.eval('1 DROP') assert ret == ' ok' assert not m.data_stack m = forth.Machine() ret = m.eval('DROP') assert ret == ' ? stack underflow'
def test_tuck(self): m = forth.Machine() ret = m.eval('1 2 TUCK') assert ret == ' ok' assert m.data_stack == [2, 1, 2] m = forth.Machine() ret = m.eval('1 TUCK') assert ret == ' ? stack underflow'
def test_rot(self): m = forth.Machine() ret = m.eval('1 2 3 ROT') assert ret == ' ok' assert m.data_stack == [2, 3, 1] m = forth.Machine() ret = m.eval('1 2 ROT') assert ret == ' ? stack underflow'
def test_over(self): m = forth.Machine() ret = m.eval('1 2 OVER') assert ret == ' ok' assert m.data_stack == [1, 2, 1] m = forth.Machine() ret = m.eval('1 OVER') assert ret == ' ? stack underflow'
def test_dup(self): m = forth.Machine() ret = m.eval('9 DUP') assert ret == ' ok' assert m.data_stack == [9, 9] m = forth.Machine() ret = m.eval('DUP') assert ret == ' ? stack underflow'
def test_two_operand_underflow(self): for oper in ['+', '-', '*', '/', 'MOD', '/MOD', 'SWAP']: m = forth.Machine() ret = m.eval('1 ' + oper) assert ret == ' ? stack underflow' assert not m.data_stack
def test_bad_compile(self): m = forth.Machine() ret = m.eval(': STAR NO-SUCH-WORD') assert 'undefined word' in ret assert 'NO-SUCH-WORD' in ret assert m.mode is forth.IMMEDIATE_MODE
def test_multi_loop(self): m = forth.Machine() ret = m.eval(': CR 10 EMIT ;\n' ': STAR 42 EMIT ;\n' ': STARS 0 DO STAR LOOP ;\n' ': STAR-LINES 0 DO 5 STARS CR LOOP ;\n' '2 STAR-LINES') assert ret == '*****\n*****\n ok' m = forth.Machine() ret = m.eval(': CR 10 EMIT ;\n' ': STAR-LINES 0 DO 5 0 DO 42 EMIT LOOP CR LOOP ;\n' '2 STAR-LINES') assert ret == '*****\n*****\n ok'
def test_interpret(self): m = forth.Machine() ret = m.interpret([('NUMBER', 42), ('NUMBER', 30), ('CALL', m.words['.'])]) assert ret == '30 ' assert m.data_stack == [42]
def test_quit(self): m = forth.Machine() ret = m.eval('4 QUIT 5') assert ret == '' assert 4 in m.data_stack assert 5 not in m.data_stack
def test_plus_loop(self): m = forth.Machine() assert 'missing DO' in m.eval(': OOPS +LOOP ;') assert 'underflow' in m.eval(': OOPS 2 0 DO 42 EMIT +LOOP ; OOPS') ret = m.eval(': JUMP-TWO DO 42 EMIT 2 +LOOP ; 4 0 JUMP-TWO') assert ret == '** ok'
def test_wrong_loop_close(self): m = forth.Machine() ret = m.eval(': BLAH') m.return_stack.append('OOPSIE') ret = m.eval('LOOP') assert 'unclosed OOPSIE' in ret
def test_printstack(self): m = forth.Machine() ret = m.eval('42 1 2 3 .S') assert m.data_stack == [42, 1, 2, 3] # Kind of a fragile test, as it relies on the implementation of .S # always including repr(self.data_stack), which it might not do in # future. Nonetheless, it's currently sufficiently correct. assert repr(m.data_stack) in ret
def forth_repl(): print('Type "BYE" or input an end of file (Ctrl+D) to quit.') m = forth.Machine() cmd = raw_input(PROMPT) while cmd.upper() != 'BYE': print(m.eval(cmd)) cmd = raw_input(PROMPT)
def test_twin_operators(self): m = forth.Machine() ret = m.eval('10 7 2DUP') assert ret == ' ok' assert m.data_stack == [10, 7, 10, 7] m = forth.Machine() ret = m.eval('1 2 3 4 2SWAP') assert ret == ' ok' assert m.data_stack == [3, 4, 1, 2] m = forth.Machine() ret = m.eval('1 2 3 4 2OVER') assert ret == ' ok' assert m.data_stack == [1, 2, 3, 4, 1, 2]
def test_if_else_on_stack(self): m = forth.Machine() ret = m.eval(': TEST IF ELSE') assert 'compiled' in ret assert 'IF' in m.return_stack assert 'ELSE' in m.return_stack assert 'IF' in m.data_stack assert 'ELSE' in m.data_stack
def test_multi_eval(self): m = forth.Machine() ret = m.eval('12 34') assert ret == ' ok' assert m.data_stack == [12, 34] ret = m.eval('+') assert ret == ' ok' assert m.data_stack == [46]
def test_comparisons(self): m = forth.Machine() ret = m.eval('''10 7 2DUP > . 2DUP >= . 2DUP < . 2DUP <= . 2DUP == . 2DUP != .''') assert ret == '-1 -1 0 0 0 -1 ok'
def test_empty_if(self): m = forth.Machine() ret = m.eval(': TEST IF ELSE THEN ; 1 TEST') assert ret == ' ok' assert 'TEST' in m.words assert not m.data_stack assert not m.return_stack ret = m.eval(': TEST IF 42 EMIT THEN ; 1 TEST 0 TEST') assert ret == '* ok'
def test_if(self): m = forth.Machine() ret = m.eval(': TEST IF 42 ELSE 33 THEN . ;') assert ret == ' ok' assert 'TEST' in m.words assert not m.data_stack assert not m.return_stack assert m.eval('1 TEST 0 TEST') == '42 33 ok' assert 'stack underflow' in m.eval('TEST')
def test_error_clears_stack(self): m = forth.Machine() ret = m.eval('42') assert ret == ' ok' assert m.data_stack == [42] ret = m.eval('NO-SUCH-WORD') assert 'undefined word' in ret assert not m.data_stack
def test_simple_math(self): for oper, expected in { '+': 24, '-': 16, '*': 80, '/': 5, 'MOD': 0 }.iteritems(): m = forth.Machine() ret = m.eval('20 4 ' + oper) assert ret == ' ok' assert expected in m.data_stack
def test_complete_compile(self): m = forth.Machine() ret = m.eval(': STAR 42 EMIT ;') assert 'ok' in ret assert 'STAR' in m.words assert m.data_stack == [] assert m.mode is forth.IMMEDIATE_MODE ret = m.eval('STAR') assert ret == '* ok' assert m.data_stack == []
def test_begin_until(self): m = forth.Machine() assert 'compile-only' in m.eval('BEGIN') assert 'compile-only' in m.eval('UNTIL') assert 'missing BEGIN' in m.eval(': TEST UNTIL') assert 'unclosed DO' in m.eval(': TEST DO UNTIL') ret = m.eval(''': TEST 0 BEGIN DUP . 1 + DUP 4 > UNTIL ; TEST''') assert ret == '0 1 2 3 4 ok'
def test_leave(self): m = forth.Machine() assert 'compile-only' in m.eval('LEAVE') assert '? not looping' in m.eval(': TEST LEAVE ; TEST') ret = m.eval(''': TEST 10 5 2 0 DO DUP 7 > IF LEAVE THEN . LOOP ; TEST''') assert ret == '5 ok'
def test_return_stack_fuckery(self): m = forth.Machine() ret = m.eval('1 2 3 >R SWAP R> . . .') assert ret == '3 1 2 ok' assert not m.data_stack assert m.eval('2 >R R@ R> . .') == '2 2 ok' assert not m.return_stack assert 'return stack underflow' in m.eval('R>') assert m.eval(': TEST 5 0 DO I . LOOP ; TEST') == '0 1 2 3 4 ok' assert m.eval(': TEST 5 0 DO R> . 5 >R LOOP ; TEST') == '0 ok' ret = m.eval( ': TEST 12 10 DO 22 20 DO 42 EMIT J . I . LOOP LOOP ; TEST') assert ret == '*10 20 *10 21 *11 20 *11 21 ok'
def test_begin_while_repeat(self): m = forth.Machine() assert 'compile-only' in m.eval('BEGIN') assert 'compile-only' in m.eval('WHILE') assert 'compile-only' in m.eval('REPEAT') assert 'missing BEGIN' in m.eval(': TEST WHILE') assert 'missing WHILE' in m.eval(': TEST REPEAT') assert 'unclosed DO' in m.eval(': TEST DO WHILE') assert 'unclosed DO' in m.eval(': TEST DO REPEAT') ret = m.eval(''': TEST 0 BEGIN DUP 4 < WHILE DUP . 1 + REPEAT ; TEST''') assert ret == '0 1 2 3 ok'
def test_two_part_compile(self): m = forth.Machine() ret = m.eval(': STAR') ret = m.eval('42 EMIT') assert ret == ' compiled' assert ':' in m.data_stack assert m.return_stack == [':'] assert m.mode is forth.COMPILE_MODE assert 'STAR' not in m.words ret = m.eval(';') assert ret == ' ok' assert m.data_stack == [] assert not m.return_stack assert m.mode is forth.IMMEDIATE_MODE assert 'STAR' in m.words ret = m.eval('STAR STAR') assert ret == '** ok' assert m.data_stack == []
def test_swap(self): m = forth.Machine() ret = m.eval('5 12 SWAP') assert ret == ' ok' assert m.data_stack == [12, 5]
def test_divmod(self): m = forth.Machine() ret = m.eval('17 3 /MOD') assert ret == ' ok' assert m.data_stack == [2, 5]