Skip to content

Commit

Permalink
Merge pull request #790 from DaddyWesker/index-atom-clean
Browse files Browse the repository at this point in the history
index-atom final version, documentation and tests added
  • Loading branch information
vsbogd authored Oct 28, 2024
2 parents fe52f59 + 25767ec commit 7ea7ec1
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/src/metta/runner/arithmetics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl serial::Serializer for NumberSerializer {
}
}

struct AsPrimitive<'a> {
pub struct AsPrimitive<'a> {
atom: &'a super::Atom
}

Expand Down
7 changes: 7 additions & 0 deletions lib/src/metta/runner/stdlib.metta
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@
(@param "Tail of an expression")))
(@return "New expression consists of two input arguments"))

(@doc index-atom
(@desc "Returns atom from an expression (first argument) using index (second argument) or error if index is out of bounds")
(@params (
(@param "Expression")
(@param "Index")))
(@return "Atom from an expression in the place defined by index. Error if index is out of bounds of an expression"))

(@doc println!
(@desc "Prints a line of text to the console")
(@params (
Expand Down
37 changes: 37 additions & 0 deletions lib/src/metta/runner/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,33 @@ impl CustomExecute for IntersectionAtomOp {
}
}

#[derive(Clone, Debug)]
pub struct IndexAtomOp {}

grounded_op!(IndexAtomOp, "index-atom");

impl Grounded for IndexAtomOp {
fn type_(&self) -> Atom {
Atom::expr([ARROW_SYMBOL, ATOM_TYPE_EXPRESSION, ATOM_TYPE_NUMBER, ATOM_TYPE_ATOM])
}

fn as_execute(&self) -> Option<&dyn CustomExecute> {
Some(self)
}
}

impl CustomExecute for IndexAtomOp {
fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
let arg_error = || ExecError::from("index-atom expects two arguments: expression and atom");
let children = TryInto::<&ExpressionAtom>::try_into(args.get(0).ok_or_else(arg_error)?)?.children();
let index = AsPrimitive::from_atom(args.get(1).ok_or_else(arg_error)?).as_number().ok_or_else(arg_error)?;
match children.get(Into::<i64>::into(index) as usize) {
Some(atom) => Ok(vec![atom.clone()]),
None => Err(ExecError::from("Index is out of bounds")),
}
}
}

#[derive(Clone, Debug)]
pub struct SubtractionAtomOp {}

Expand Down Expand Up @@ -1737,6 +1764,8 @@ mod non_minimal_only_stdlib {
tref.register_token(regex(r"cdr-atom"), move |_| { cdr_atom_op.clone() });
let cons_atom_op = Atom::gnd(ConsAtomOp{});
tref.register_token(regex(r"cons-atom"), move |_| { cons_atom_op.clone() });
let index_atom_op = Atom::gnd(IndexAtomOp{});
tref.register_token(regex(r"index-atom"), move |_| { index_atom_op.clone() });
let println_op = Atom::gnd(PrintlnOp{});
tref.register_token(regex(r"println!"), move |_| { println_op.clone() });
let format_args_op = Atom::gnd(FormatArgsOp{});
Expand Down Expand Up @@ -2024,6 +2053,14 @@ mod tests {
assert_eq!(res, vec![expr!(("A" "F") ("B" "C") "D")]);
}

#[test]
fn index_atom_op() {
let res = IndexAtomOp{}.execute(&mut vec![expr!({Number::Integer(5)} {Number::Integer(4)} {Number::Integer(3)} {Number::Integer(2)} {Number::Integer(1)}), expr!({Number::Integer(2)})]).expect("No result returned");
assert_eq!(res, vec![expr!({Number::Integer(3)})]);
let res = IndexAtomOp{}.execute(&mut vec![expr!({Number::Integer(5)} {Number::Integer(4)} {Number::Integer(3)} {Number::Integer(2)} {Number::Integer(1)}), expr!({Number::Integer(5)})]);
assert_eq!(res, Err(ExecError::from("Index is out of bounds")));
}

#[test]
fn bind_new_space_op() {
let tokenizer = Shared::new(Tokenizer::new());
Expand Down
7 changes: 7 additions & 0 deletions lib/src/metta/runner/stdlib_minimal.metta
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
(@return "Deconsed expression"))
(: decons-atom (-> Expression Expression))

(@doc index-atom
(@desc "Returns atom from an expression (first argument) using index (second argument) or error if index is out of bounds")
(@params (
(@param "Expression")
(@param "Index")))
(@return "Atom from an expression in the place defined by index. Error if index is out of bounds"))

(@doc collapse-bind
(@desc "Evaluates minimal MeTTa operation (first argument) and returns an expression which contains all alternative evaluations in a form (Atom Bindings). Bindings are represented in a form of a grounded atom.")
(@params (
Expand Down
8 changes: 8 additions & 0 deletions lib/src/metta/runner/stdlib_minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ pub fn register_common_tokens(tref: &mut Tokenizer, _tokenizer: Shared<Tokenizer
tref.register_token(regex(r"nop"), move |_| { nop_op.clone() });
let match_op = Atom::gnd(stdlib::MatchOp{});
tref.register_token(regex(r"match"), move |_| { match_op.clone() });
let index_atom_op = Atom::gnd(stdlib::IndexAtomOp{});
tref.register_token(regex(r"index-atom"), move |_| { index_atom_op.clone() });
let mod_space_op = Atom::gnd(stdlib::ModSpaceOp::new(metta.clone()));
tref.register_token(regex(r"mod-space!"), move |_| { mod_space_op.clone() });
let print_mods_op = Atom::gnd(stdlib::PrintModsOp::new(metta.clone()));
Expand Down Expand Up @@ -615,6 +617,12 @@ mod tests {
assert_eq!(run_program(&format!("!(cdr-atom $a)")), Ok(vec![vec![expr!("Error" ("cdr-atom" a) {Str::from_str("cdr-atom expects a non-empty expression as an argument")})]]));
}

#[test]
fn metta_index_atom() {
assert_eq!(run_program(&format!("!(index-atom (5 4 3 2 1) 2)")), Ok(vec![vec![expr!({Number::Integer(3)})]]));
assert_eq!(run_program(&format!("!(index-atom (A B C D E) 5)")), Ok(vec![vec![expr!("Error" ({ stdlib::IndexAtomOp{} } ("A" "B" "C" "D" "E") {Number::Integer(5)}) "Index is out of bounds")]]));
}

#[test]
fn metta_switch() {
let result = run_program("!(eval (switch (A $b) ( (($a B) ($b $a)) ((B C) (C B)) )))");
Expand Down

0 comments on commit 7ea7ec1

Please sign in to comment.