diff --git a/src/interpreter/primitive_props.rs b/src/interpreter/primitive_props.rs index fc7e866..560440d 100644 --- a/src/interpreter/primitive_props.rs +++ b/src/interpreter/primitive_props.rs @@ -878,6 +878,26 @@ pub fn get_prim_prop(target: Value, name: String) -> Result Value::fn_native(move |args, _| { + let target = target.clone(); + let target_len = target.read().unwrap().len(); + async move { + let mut args = args.into_iter(); + let idx = f64::try_from(args.next().unwrap_or_default())? as isize; + let index = if idx < 0 { + target_len as isize + idx + } else { + idx + }; + Ok(if index < 0 { + None + } else { + target.read().unwrap().get(index as usize).cloned() + } + .unwrap_or_else(|| args.next().unwrap_or_default())) + } + .boxed() + }), _ => Err(AiScriptRuntimeError::Runtime(format!( "No such prop ({name}) in string." )))?, diff --git a/tests/test.rs b/tests/test.rs index ff38a22..54a7d49 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -4897,6 +4897,120 @@ mod primitive_props { .await .unwrap(); } + + #[tokio::test] + async fn at_without_default_value() { + test( + r#" + let arr1 = [10, 20, 30] + <: [ + arr1 + arr1.at(0), arr1.at(1), arr1.at(2) + arr1.at(-3), arr1.at(-2), arr1.at(-1) + arr1.at(3), arr1.at(4), arr1.at(5) + arr1.at(-6), arr1.at(-5), arr1.at(-4) + ] + "#, + |res| { + assert_eq!( + res, + arr([ + arr([num(10), num(20), num(30)]), + num(10), + num(20), + num(30), + num(10), + num(20), + num(30), + null(), + null(), + null(), + null(), + null(), + null(), + ]) + ) + }, + ) + .await + .unwrap(); + } + + #[tokio::test] + async fn at_with_default_value() { + test( + r#" + let arr1 = [10, 20, 30] + <: [ + arr1 + arr1.at(0, 100), arr1.at(1, 100), arr1.at(2, 100) + arr1.at(-3, 100), arr1.at(-2, 100), arr1.at(-1, 100) + arr1.at(3, 100), arr1.at(4, 100), arr1.at(5, 100) + arr1.at(-6, 100), arr1.at(-5, 100), arr1.at(-4, 100) + ] + "#, + |res| { + assert_eq!( + res, + arr([ + arr([num(10), num(20), num(30)]), + num(10), + num(20), + num(30), + num(10), + num(20), + num(30), + num(100), + num(100), + num(100), + num(100), + num(100), + num(100), + ]) + ) + }, + ) + .await + .unwrap(); + } + + #[tokio::test] + async fn at_fraction() { + test( + r#" + let arr1 = [10, 20, 30] + <: [ + arr1 + arr1.at(0.1), arr1.at(1.4), arr1.at(2.5) + arr1.at(-3.1), arr1.at(-2.4), arr1.at(-1.5) + arr1.at(3.1), arr1.at(4.4), arr1.at(5.5) + arr1.at(-6.1), arr1.at(-5.4), arr1.at(-4.5) + ] + "#, + |res| { + assert_eq!( + res, + arr([ + arr([num(10), num(20), num(30)]), + num(10), + num(20), + num(30), + num(10), + num(20), + num(30), + null(), + null(), + null(), + null(), + null(), + null(), + ]) + ) + }, + ) + .await + .unwrap(); + } } }