Skip to content

Commit

Permalink
FRTH fingerprint
Browse files Browse the repository at this point in the history
  • Loading branch information
tjol committed Aug 26, 2021
1 parent abd7be2 commit f2b9225
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 0 deletions.
197 changes: 197 additions & 0 deletions src/interpreter/fingerprints/FRTH.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
rfunge – a Funge-98 interpreter
Copyright © 2021 Thomas Jollans
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use hashbrown::HashMap;
use num::{FromPrimitive, ToPrimitive, Zero};

use crate::fungespace::SrcIO;
use crate::interpreter::instruction_set::{Instruction, InstructionResult, InstructionSet};
use crate::interpreter::MotionCmds;
use crate::{FungeSpace, FungeValue, InstructionPointer, InterpreterEnv};

/// From the rcFunge docs
///
/// D ( .. -- .. n) Push depth of stack to tos
/// L ( .. n -- .. n) Forth Roll command
/// O (a b -- a b a) Forth Over command
/// P (.. n -- .. n) Forth Pick command
/// R (a b c -- b c a) Forth Rot command
///
/// Stack operations are subject to the modes set by MODE
///
/// Clarification
///
/// * P should reflect on a negative argument
/// * P should push 0 if argument is greater than stack size
/// * L should act like forth -roll with a negative argument
/// * L with an argument larger than the stack size is allowed, enough
/// zeroes will be created in order to fulfill the request. Example:
/// n543210a-L will leave a stack of: 2 3 4 5 0 0 0 0 0 0 1
/// * L,P the top of stack is position 0
pub fn load<Idx, Space, Env>(instructionset: &mut InstructionSet<Idx, Space, Env>) -> bool
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
let mut layer = HashMap::<char, Instruction<Idx, Space, Env>>::new();
layer.insert('D', depth);
layer.insert('L', roll);
layer.insert('O', over);
layer.insert('P', pick);
layer.insert('R', rot);
instructionset.add_layer(layer);
true
}

pub fn unload<Idx, Space, Env>(instructionset: &mut InstructionSet<Idx, Space, Env>) -> bool
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
instructionset.pop_layer(&['D', 'L', 'O', 'P', 'R'][..])
}

fn depth<Idx, Space, Env>(
ip: &mut InstructionPointer<Idx, Space, Env>,
_space: &mut Space,
_env: &mut Env,
) -> InstructionResult
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
ip.push(FromPrimitive::from_usize(ip.stack().len()).unwrap_or_else(Zero::zero));

InstructionResult::Continue
}

fn roll<Idx, Space, Env>(
ip: &mut InstructionPointer<Idx, Space, Env>,
_space: &mut Space,
_env: &mut Env,
) -> InstructionResult
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
let stack = ip.stack_mut();
let u = stack.pop().and_then(|v| v.to_isize()).unwrap_or_default();
if u > Zero::zero() {
// roll mode
let u = u as usize;
let l = stack.len();
let v = if u < l {
stack.remove(l - 1 - u)
} else {
Zero::zero()
};
ip.push(v);
} else if u < Zero::zero() {
// -roll mode
let u = (-u) as usize;
let v = stack.pop().unwrap_or(Zero::zero());
while stack.len() < u {
stack.insert(0, Zero::zero());
}
stack.insert(stack.len() - u, v);
}

InstructionResult::Continue
}

fn over<Idx, Space, Env>(
ip: &mut InstructionPointer<Idx, Space, Env>,
_space: &mut Space,
_env: &mut Env,
) -> InstructionResult
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
let stack = ip.stack();
let v = if stack.len() >= 2 {
stack[stack.len() - 2]
} else {
Zero::zero()
};
ip.push(v);

InstructionResult::Continue
}

fn pick<Idx, Space, Env>(
ip: &mut InstructionPointer<Idx, Space, Env>,
_space: &mut Space,
_env: &mut Env,
) -> InstructionResult
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
let u = ip.pop();
if u < Zero::zero() {
ip.reflect()
} else {
let u = u.to_usize().unwrap_or_default();
let stack = ip.stack();
let l = stack.len();
let v = if u < l {
stack[l - 1 - u]
} else {
Zero::zero()
};
ip.push(v);
}

InstructionResult::Continue
}

fn rot<Idx, Space, Env>(
ip: &mut InstructionPointer<Idx, Space, Env>,
_space: &mut Space,
_env: &mut Env,
) -> InstructionResult
where
Idx: MotionCmds<Space, Env> + SrcIO<Space>,
Space: FungeSpace<Idx>,
Space::Output: FungeValue,
Env: InterpreterEnv,
{
let stack = ip.stack_mut();
let l = stack.len();
let v = if l >= 3 {
stack.remove(l - 3)
} else {
Zero::zero()
};
ip.push(v);

InstructionResult::Continue
}
6 changes: 6 additions & 0 deletions src/interpreter/fingerprints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod FIXP;
mod FPDP;
mod FPRT;
mod FPSP;
mod FRTH;
mod HRTI;
mod JSTR;
mod LONG;
Expand Down Expand Up @@ -60,6 +61,7 @@ pub fn safe_fingerprints() -> Vec<i32> {
string_to_fingerprint("LONG"),
string_to_fingerprint("FPRT"),
string_to_fingerprint("JSTR"),
string_to_fingerprint("FRTH"),
]
}

Expand Down Expand Up @@ -99,6 +101,8 @@ where
FPRT::load(instructionset)
} else if fpr == string_to_fingerprint("JSTR") {
JSTR::load(instructionset)
} else if fpr == string_to_fingerprint("FRTH") {
FRTH::load(instructionset)
} else {
false
}
Expand Down Expand Up @@ -138,6 +142,8 @@ where
FPRT::unload(instructionset)
} else if fpr == string_to_fingerprint("JSTR") {
JSTR::unload(instructionset)
} else if fpr == string_to_fingerprint("FRTH") {
FRTH::unload(instructionset)
} else {
false
}
Expand Down
14 changes: 14 additions & 0 deletions tests/test_cases/FRTH.b98
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
v >0a"HTRF gnidaol rorre">:#,_@
>"HTRF"4#^(D2-#v_0"HTRF"aPv+**8 '< ^:"Did L with "<
@,k7"D wrong"a< > O|>"r gra evitagen"^
@,kd"P or O wrong?"a_v#-P3<^"eflect?"0<
-30"HFRT":L3"kino"OR"go od"<vLL\R-60-50 'l'L^#
did not reflect!"a0Pv#-10< v"01-P
> #; >:#,_a,@ ;<

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This looks like another case with many buggy ;
; implementations. RCFunge is the reference ;
; implementation, PyFunge looks good. CCBI and ;
; cfunge handle L with -ve argument incorrectly ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1 change: 1 addition & 0 deletions tests/test_cases/FRTH.b98.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FRTH looking good
2 changes: 2 additions & 0 deletions tests/test_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ fn get_b98_tests() -> io::Result<Vec<(PathBuf, PathBuf)>> {
}
}

result.sort();

return Ok(result);
}

Expand Down

0 comments on commit f2b9225

Please sign in to comment.