1 Commits

Author SHA1 Message Date
Oleksandr Kozachuk 35b78193fd feat(boot): add -ROT <= >= gforth extensions
CI / check (push) Has been cancelled
Non-standard but ubiquitous words; absence aborted otherwise-valid
gforth programs with unknown-word errors.
2026-07-18 15:40:39 +02:00
3 changed files with 38 additions and 10 deletions
+13
View File
@@ -72,6 +72,19 @@
1-
REPEAT ;
\ ---------------------------------------------------------------
\ Common extensions (not in Forth 2012, gforth-compatible)
\ ---------------------------------------------------------------
\ -ROT ( x1 x2 x3 -- x3 x1 x2 ) rotate top item to third place
: -ROT ROT ROT ;
\ <= ( n1 n2 -- flag ) true if n1 <= n2 (signed)
: <= > 0= ;
\ >= ( n1 n2 -- flag ) true if n1 >= n2 (signed)
: >= < 0= ;
\ ---------------------------------------------------------------
\ Phase 2: Double-cell arithmetic
\ ---------------------------------------------------------------
+5 -10
View File
@@ -1088,12 +1088,10 @@ fn emit_do_loop(f: &mut Function, body: &[IrOp], is_plus_loop: bool, ctx: &mut E
.instruction(&Instruction::End);
}
// Forth 2012: LOOP exits when the index crosses the boundary between
// limit-1 and limit. With step +1 that is exactly new_index == limit
// in wraparound arithmetic — start >= limit must wrap, not exit early.
// if index >= limit, exit
f.instruction(&Instruction::LocalGet(index_local))
.instruction(&Instruction::LocalGet(limit_local))
.instruction(&Instruction::I32Eq)
.instruction(&Instruction::I32GeS)
.instruction(&Instruction::BrIf(1)) // break to $exit
.instruction(&Instruction::Br(0)) // continue loop
.instruction(&Instruction::End) // end loop
@@ -1899,8 +1897,7 @@ fn emit_promoted_op(f: &mut Function, op: &IrOp, sim: &mut StackSim) {
// Fix up stack for next iteration (LOOP body is stack-neutral)
emit_promoted_loop_fixup(f, sim, &loop_top_stack);
// LOOP: increment by 1, exit when new_index == limit
// (Forth 2012 boundary crossing; start >= limit wraps around)
// LOOP: increment by 1, check >= limit
f.instruction(&Instruction::LocalGet(index_local));
f.instruction(&Instruction::I32Const(1));
f.instruction(&Instruction::I32Add);
@@ -1908,7 +1905,7 @@ fn emit_promoted_op(f: &mut Function, op: &IrOp, sim: &mut StackSim) {
f.instruction(&Instruction::LocalGet(index_local));
f.instruction(&Instruction::LocalGet(limit_local));
f.instruction(&Instruction::I32Eq);
f.instruction(&Instruction::I32GeS);
f.instruction(&Instruction::BrIf(1)); // break to $exit
}
@@ -2832,11 +2829,9 @@ fn emit_consolidated_do_loop(
.instruction(&Instruction::End);
}
// Forth 2012 boundary crossing: exit when new_index == limit
// (start >= limit wraps around instead of exiting early).
f.instruction(&Instruction::LocalGet(index_local))
.instruction(&Instruction::LocalGet(limit_local))
.instruction(&Instruction::I32Eq)
.instruction(&Instruction::I32GeS)
.instruction(&Instruction::BrIf(1))
.instruction(&Instruction::Br(0))
.instruction(&Instruction::End)
+20
View File
@@ -7462,6 +7462,12 @@ mod tests {
assert_eq!(eval_stack("1 2 3 ROT"), vec![1, 3, 2]);
}
#[test]
fn test_minus_rot() {
// ( 1 2 3 -- 3 1 2 ) top-first: [2, 1, 3]
assert_eq!(eval_stack("1 2 3 -ROT"), vec![2, 1, 3]);
}
// -- Comparison --
#[test]
@@ -7482,6 +7488,20 @@ mod tests {
assert_eq!(eval_stack("3 5 >"), vec![0]);
}
#[test]
fn test_less_or_equal() {
assert_eq!(eval_stack("3 5 <="), vec![-1]);
assert_eq!(eval_stack("5 5 <="), vec![-1]);
assert_eq!(eval_stack("5 3 <="), vec![0]);
}
#[test]
fn test_greater_or_equal() {
assert_eq!(eval_stack("5 3 >="), vec![-1]);
assert_eq!(eval_stack("5 5 >="), vec![-1]);
assert_eq!(eval_stack("3 5 >="), vec![0]);
}
// -- Logic --
#[test]