rhai/src/packages/lang_core.rs

300 lines
8.7 KiB
Rust
Raw Normal View History

2021-05-02 23:57:35 +08:00
use crate::def_package;
use crate::plugin::*;
2021-11-13 22:36:23 +08:00
use crate::types::dynamic::Tag;
2021-12-27 12:27:31 +08:00
use crate::{Dynamic, RhaiResultOf, ERR, INT};
2021-05-02 23:57:35 +08:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
2021-12-20 11:42:39 +08:00
def_package! {
/// Package of core language features.
2022-02-10 12:33:48 +08:00
pub LanguageCorePackage(lib) {
2021-12-20 11:42:39 +08:00
lib.standard = true;
2022-01-20 08:16:38 +08:00
combine_with_exported_module!(lib, "core", core_functions);
2022-01-22 17:27:18 +08:00
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
2022-01-20 08:16:38 +08:00
combine_with_exported_module!(lib, "reflection", reflection_functions);
2021-12-20 11:42:39 +08:00
}
}
2021-05-02 23:57:35 +08:00
#[export_module]
mod core_functions {
2022-03-08 18:26:32 +08:00
/// Return the _tag_ of a `Dynamic` value.
///
/// # Example
///
/// ```rhai
/// let x = "hello, world!";
///
/// x.tag = 42;
///
/// print(x.tag); // prints 42
/// ```
2021-05-02 23:57:35 +08:00
#[rhai_fn(name = "tag", get = "tag", pure)]
pub fn get_tag(value: &mut Dynamic) -> INT {
value.tag() as INT
}
2022-03-08 18:26:32 +08:00
/// Set the _tag_ of a `Dynamic` value.
///
/// # Example
///
/// ```rhai
/// let x = "hello, world!";
///
/// x.tag = 42;
///
/// print(x.tag); // prints 42
/// ```
2021-05-02 23:57:35 +08:00
#[rhai_fn(name = "set_tag", set = "tag", return_raw)]
2021-12-25 23:49:14 +08:00
pub fn set_tag(value: &mut Dynamic, tag: INT) -> RhaiResultOf<()> {
2021-05-02 23:57:35 +08:00
if tag < Tag::MIN as INT {
2021-12-27 12:27:31 +08:00
Err(ERR::ErrorArithmetic(
2021-05-02 23:57:35 +08:00
format!(
"{} is too small to fit into a tag (must be between {} and {})",
tag,
Tag::MIN,
Tag::MAX
),
Position::NONE,
2021-06-29 21:58:05 +08:00
)
.into())
2021-05-02 23:57:35 +08:00
} else if tag > Tag::MAX as INT {
2021-12-27 12:27:31 +08:00
Err(ERR::ErrorArithmetic(
2021-05-02 23:57:35 +08:00
format!(
"{} is too large to fit into a tag (must be between {} and {})",
tag,
Tag::MIN,
Tag::MAX
),
Position::NONE,
2021-06-29 21:58:05 +08:00
)
.into())
2021-05-02 23:57:35 +08:00
} else {
value.set_tag(tag as Tag);
Ok(())
}
}
2022-03-08 18:26:32 +08:00
/// Block the current thread for a particular number of `seconds`.
#[cfg(not(feature = "no_float"))]
2022-03-09 09:41:53 +08:00
#[cfg(not(feature = "no_std"))]
#[rhai_fn(name = "sleep")]
2022-03-28 12:53:49 +08:00
pub fn sleep_float(seconds: crate::FLOAT) {
2022-03-08 18:26:32 +08:00
if seconds <= 0.0 {
return;
}
#[cfg(not(feature = "f32_float"))]
std::thread::sleep(std::time::Duration::from_secs_f64(seconds));
#[cfg(feature = "f32_float")]
std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
}
/// Block the current thread for a particular number of `seconds`.
2022-03-09 09:41:53 +08:00
#[cfg(not(feature = "no_std"))]
2022-03-08 18:26:32 +08:00
pub fn sleep(seconds: INT) {
if seconds <= 0 {
return;
}
std::thread::sleep(std::time::Duration::from_secs(seconds as u64));
}
2022-01-20 08:16:38 +08:00
}
2022-01-20 08:16:38 +08:00
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
#[export_module]
mod reflection_functions {
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> crate::Array {
2022-01-20 08:16:38 +08:00
collect_fn_metadata(ctx, |_, _, _, _, _| true)
}
#[rhai_fn(name = "get_fn_metadata_list")]
pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> crate::Array {
collect_fn_metadata(ctx, |_, _, n, _, _| n == name)
}
#[rhai_fn(name = "get_fn_metadata_list")]
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array {
if params < 0 {
crate::Array::new()
} else {
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
}
}
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
2022-01-20 08:16:38 +08:00
fn collect_fn_metadata(
ctx: NativeCallContext,
filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared<crate::ast::ScriptFnDef>) -> bool
+ Copy,
) -> crate::Array {
use crate::{ast::ScriptFnDef, Array, Identifier, Map};
use std::collections::BTreeSet;
// Create a metadata record for a function.
fn make_metadata(
dict: &BTreeSet<Identifier>,
2022-03-05 17:57:23 +08:00
#[cfg(not(feature = "no_module"))] namespace: Identifier,
func: &ScriptFnDef,
) -> Map {
const DICT: &str = "key exists";
let mut map = Map::new();
2022-01-29 11:09:43 +08:00
#[cfg(not(feature = "no_module"))]
2022-03-05 17:57:23 +08:00
if !namespace.is_empty() {
map.insert(dict.get("namespace").expect(DICT).clone(), namespace.into());
}
map.insert(
dict.get("name").expect(DICT).clone(),
func.name.clone().into(),
);
map.insert(
dict.get("access").expect(DICT).clone(),
match func.access {
FnAccess::Public => dict.get("public").expect(DICT).clone(),
FnAccess::Private => dict.get("private").expect(DICT).clone(),
}
.into(),
);
map.insert(
dict.get("is_anonymous").expect(DICT).clone(),
func.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
);
map.insert(
dict.get("params").expect(DICT).clone(),
func.params
.iter()
.cloned()
.map(Into::into)
.collect::<Array>()
.into(),
);
2022-07-25 16:59:11 +08:00
#[cfg(feature = "metadata")]
if !func.comments.is_empty() {
map.insert(
dict.get("comments").expect(DICT).clone(),
func.comments
.iter()
.map(|s| Into::into(&**s))
.collect::<Array>()
.into(),
);
}
map
}
// Intern strings
let dict: BTreeSet<Identifier> = [
2022-01-29 11:09:43 +08:00
#[cfg(not(feature = "no_module"))]
"namespace",
"name",
"access",
"public",
"private",
"is_anonymous",
"params",
2022-07-25 16:59:11 +08:00
#[cfg(feature = "metadata")]
"comments",
]
.iter()
.map(|&s| s.into())
.collect();
2022-01-20 08:16:38 +08:00
let mut list = Array::new();
ctx.iter_namespaces()
.flat_map(Module::iter_script_fn)
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
2022-02-08 09:02:15 +08:00
.for_each(|(.., f)| {
2022-01-29 11:09:43 +08:00
list.push(
make_metadata(
&dict,
#[cfg(not(feature = "no_module"))]
2022-03-05 17:57:23 +08:00
Identifier::new_const(),
2022-01-29 11:09:43 +08:00
f,
)
.into(),
)
});
2022-01-20 08:16:38 +08:00
ctx.engine()
.global_modules
.iter()
.flat_map(|m| m.iter_script_fn())
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
2022-02-08 09:02:15 +08:00
.for_each(|(.., f)| {
2022-01-29 11:09:43 +08:00
list.push(
make_metadata(
&dict,
#[cfg(not(feature = "no_module"))]
2022-03-05 17:57:23 +08:00
Identifier::new_const(),
2022-01-29 11:09:43 +08:00
f,
)
.into(),
)
});
2022-01-20 08:16:38 +08:00
2022-01-29 11:09:43 +08:00
#[cfg(not(feature = "no_module"))]
2022-01-20 08:16:38 +08:00
ctx.engine()
.global_sub_modules
.values()
.flat_map(|m| m.iter_script_fn())
.filter(|(ns, a, n, p, f)| filter(*ns, *a, n, *p, f))
2022-02-08 09:02:15 +08:00
.for_each(|(.., f)| {
2022-01-29 11:09:43 +08:00
list.push(
make_metadata(
&dict,
#[cfg(not(feature = "no_module"))]
2022-03-05 17:57:23 +08:00
Identifier::new_const(),
2022-01-29 11:09:43 +08:00
f,
)
.into(),
)
});
#[cfg(not(feature = "no_module"))]
{
// Recursively scan modules for script-defined functions.
fn scan_module(
list: &mut Array,
dict: &BTreeSet<Identifier>,
namespace: Identifier,
module: &Module,
2022-01-20 08:16:38 +08:00
filter: impl Fn(
FnNamespace,
FnAccess,
&str,
usize,
&crate::Shared<crate::ast::ScriptFnDef>,
) -> bool
+ Copy,
) {
2022-01-20 08:16:38 +08:00
module
.iter_script_fn()
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
2022-03-05 17:57:23 +08:00
.for_each(|(.., f)| list.push(make_metadata(dict, namespace.clone(), f).into()));
2022-01-28 18:59:18 +08:00
for (ns, m) in module.iter_sub_modules() {
let ns = format!(
"{}{}{}",
namespace,
crate::tokenizer::Token::DoubleColon.literal_syntax(),
ns
);
2022-07-05 16:26:38 +08:00
scan_module(list, dict, ns.into(), &**m, filter)
2022-01-28 18:59:18 +08:00
}
}
2022-01-28 18:59:18 +08:00
for (ns, m) in ctx.iter_imports_raw() {
2022-07-05 16:26:38 +08:00
scan_module(&mut list, &dict, ns.clone(), &**m, filter)
2022-01-28 18:59:18 +08:00
}
}
2022-01-20 08:16:38 +08:00
list
2021-05-02 23:57:35 +08:00
}