Skip to content

Commit

Permalink
Merge pull request #756 from schungx/master
Browse files Browse the repository at this point in the history
Add custom types metadata.
  • Loading branch information
schungx authored Aug 31, 2023
2 parents e987c9c + fe240ac commit 1afa672
Show file tree
Hide file tree
Showing 30 changed files with 421 additions and 251 deletions.
16 changes: 13 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,27 @@ Bug fixes
* `max` and `min` for integers, strings and characters were missing from the standard library. They are now added.
* O/S features such as file access and time are no longer disabled when using `wasm32-wasi` (or any WASM target other than `wasm32-unknown`).

Enhancements
Dependencies
------------

* [`once_cell`](https://crates.io/crates/once_cell) is used in `std` environments instead of the home-brew `SusLock` (which is still kept for `no-std`).
* Originally, unit tests use the `?` operator liberally to simplify the code. However, this causes the loss of proper line numbers when it fails, making it difficult to identify the exact location of the failure. This is now fixed by using `unwrap()` instead.
* Minimal version numbers for dependencies are now specified in `Cargo.toml` to avoid breaking changes in future versions.
* [`bitflags`](https://crates.io/crates/bitflags) is bumped to version 2.
* [`syn`](https://crates.io/crates/syn) in [`rhai_codegen`](https://crates.io/crates/rhai_codegen) is bumped to version 2.
* [`hashbrown`](https://crates.io/crates/hashbrown) (used in `no-std` builds) is bumped to version 0.14.

New features
------------

* Added `Engine::max_variables` and `Engine::set_max_variables` to limit the maximum number of variables allowed within a scope at any time. This is to guard against defining a huge number of variables containing large data just beyond individual data size limits. When `max_variables` is exceeded a new error, `ErrorTooManyVariables`, is returned.
* Added `zip` function for arrays.
* Doc-comments are now included in custom type definitions within plugin modules. They can be accessed via `Module::get_custom_type_comments`. These doc-comments for custom types are also exported in JSON via `Engine::gen_fn_metadata_to_json`.

Enhancements
------------

* [`once_cell`](https://crates.io/crates/once_cell) is used in `std` environments instead of the home-brew `SusLock` which is removed.
* Originally, unit tests use the `?` operator liberally to simplify code. However, this causes the loss of proper line numbers when a test fails, making it difficult to identify the exact location of the failure. This is now fixed by changing to `unwrap()`.
* Many inlined collections are turned back into `Vec` because they are not transient and do not appear to improve performance. Using `Vec` seems to be yield better performance as it probably enables more compiler optimizations.


Version 1.15.1
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ rhai_codegen = { version = "1.5.0", path = "codegen", default-features = false }

no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat", version = "0.4.1", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2.0", default-features = false, optional = true }
hashbrown = { version = "0.13.1", optional = true }
hashbrown = { version = "0.14.0", optional = true }
core-error = { version = "0.0.0", default-features = false, features = ["alloc"], optional = true }
serde = { version = "1.0.96", default-features = false, features = ["derive", "alloc"], optional = true }
serde_json = { version = "1.0.45", default-features = false, features = ["alloc"], optional = true }
Expand Down
4 changes: 2 additions & 2 deletions codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rhai_codegen"
version = "1.5.0"
version = "1.6.0"
edition = "2018"
resolver = "2"
authors = ["jhwgh1968", "Stephen Chung"]
Expand All @@ -24,5 +24,5 @@ syn = { version = "2.0.0", features = ["full", "parsing", "printing", "proc-macr
quote = "1.0.0"

[dev-dependencies]
rhai = { path = "..", version = "1.12.0", features = ["metadata"] }
rhai = { path = "..", version = "1.16.0", features = ["metadata"] }
trybuild = "1.0.0"
2 changes: 2 additions & 0 deletions codegen/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ impl Parse for Module {
name: ident.to_string(),
typ: ty.clone(),
cfg_attrs: crate::attrs::collect_cfg_attr(attrs),
#[cfg(feature = "metadata")]
comments: crate::attrs::doc_attributes(attrs)?,
})
}
}
Expand Down
26 changes: 22 additions & 4 deletions codegen/src/rhai_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct ExportedType {
pub name: String,
pub typ: Box<syn::Type>,
pub cfg_attrs: Vec<syn::Attribute>,
#[cfg(feature = "metadata")]
pub comments: Vec<String>,
}

pub fn generate_body(
Expand Down Expand Up @@ -67,6 +69,8 @@ pub fn generate_body(
name,
typ,
cfg_attrs,
#[cfg(feature = "metadata")]
comments,
..
} in custom_types
{
Expand All @@ -77,13 +81,27 @@ pub fn generate_body(
.map(syn::Attribute::to_token_stream)
.collect();

set_const_statements.push(
#[cfg(feature = "metadata")]
let comments = comments
.iter()
.map(|s| syn::LitStr::new(s, Span::call_site()))
.collect::<Vec<_>>();
#[cfg(not(feature = "metadata"))]
let comments = Vec::<syn::LitStr>::new();

set_const_statements.push(if comments.is_empty() {
syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)*
m.set_custom_type::<#typ>(#const_literal);
})
.unwrap(),
);
.unwrap()
} else {
syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)*
m.set_custom_type_with_comments::<#typ>(#const_literal, &[#(#comments),*]);
})
.unwrap()
});
}

for item_mod in sub_modules {
Expand Down Expand Up @@ -231,7 +249,7 @@ pub fn generate_body(
syn::parse2::<syn::Stmt>(quote! {
#(#cfg_attrs)*
m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public,
#param_names, [#(#fn_input_types),*], [#(#comments),*], #fn_token_name().into());
#param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into());
})
.unwrap()
});
Expand Down
20 changes: 18 additions & 2 deletions codegen/src/test/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ mod module_tests {
pub mod one_fn {
pub type Hello = ();

/// We are the world!
pub type World = String;

pub fn get_mystic_number() -> INT {
42
}
Expand All @@ -51,8 +54,14 @@ mod module_tests {

let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
assert!(item_mod.consts().is_empty());
assert_eq!(item_mod.custom_types().len(), 1);
assert_eq!(item_mod.custom_types().len(), 2);
assert_eq!(item_mod.custom_types()[0].name.to_string(), "Hello");
assert_eq!(item_mod.custom_types()[1].name.to_string(), "World");
#[cfg(feature = "metadata")]
assert_eq!(
item_mod.custom_types()[1].comments[0],
"/// We are the world!"
);
assert_eq!(item_mod.fns().len(), 1);
assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number");
assert_eq!(item_mod.fns()[0].arg_count(), 0);
Expand Down Expand Up @@ -409,6 +418,9 @@ mod generate_tests {
/// Another line!
/// Final line!
pub mod one_fn {
/// We are the world!
pub type World = String;

/// This is a doc-comment.
/// Another line.
/** block doc-comment */
Expand All @@ -432,6 +444,9 @@ mod generate_tests {
/// Final line!
#[allow(clippy::needless_pass_by_value)]
pub mod one_fn {
/// We are the world!
pub type World = String;

/// This is a doc-comment.
/// Another line.
/** block doc-comment */
Expand All @@ -458,10 +473,11 @@ mod generate_tests {
#[doc(hidden)]
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
m.set_fn_with_comments("get_mystic_number", FnNamespace::Internal, FnAccess::Public,
Some(get_mystic_number_token::PARAM_NAMES), [], [
Some(get_mystic_number_token::PARAM_NAMES), &[], &[
"/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.",
"/** doc-comment\n in multiple lines\n */"
], get_mystic_number_token().into());
m.set_custom_type_with_comments::<String>("World", &["/// We are the world!"]);
if flatten {} else {}
}
#[allow(non_camel_case_types)]
Expand Down
2 changes: 0 additions & 2 deletions codegen/ui_tests/rhai_mod_unknown_type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,3 @@ help: consider importing one of these items
|
11 + use std::fmt::Pointer;
|
11 + use syn::__private::fmt::Pointer;
|
3 changes: 1 addition & 2 deletions src/api/custom_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::tokenizer::{is_reserved_keyword_or_symbol, is_valid_identifier, Token
use crate::types::dynamic::Variant;
use crate::{
Dynamic, Engine, EvalContext, Identifier, ImmutableString, LexError, Position, RhaiResult,
StaticVec,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
Expand Down Expand Up @@ -223,7 +222,7 @@ impl Engine {
#[allow(clippy::wildcard_imports)]
use markers::*;

let mut segments = StaticVec::<ImmutableString>::new();
let mut segments = Vec::<ImmutableString>::new();

for s in symbols.as_ref() {
let s = s.as_ref().trim();
Expand Down
10 changes: 5 additions & 5 deletions src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ impl From<(Expr, Expr)> for BinaryExpr {
#[derive(Debug, Clone, Hash)]
pub struct CustomExpr {
/// List of keywords.
pub inputs: StaticVec<Expr>,
pub inputs: Box<[Expr]>,
/// List of tokens actually parsed.
pub tokens: StaticVec<ImmutableString>,
pub tokens: Box<[ImmutableString]>,
/// State value.
pub state: Dynamic,
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
Expand Down Expand Up @@ -201,7 +201,7 @@ pub struct FnCallExpr {
/// Pre-calculated hashes.
pub hashes: FnCallHashes,
/// List of function call argument expressions.
pub args: FnArgsVec<Expr>,
pub args: Box<[Expr]>,
/// Does this function call capture the parent scope?
pub capture_parent_scope: bool,
/// Is this function call a native operator?
Expand Down Expand Up @@ -885,15 +885,15 @@ impl Expr {
}
}
Self::FnCall(x, ..) => {
for e in &x.args {
for e in x.args.iter() {
if !e.walk(path, on_node) {
return false;
}
}
}
#[cfg(not(feature = "no_custom_syntax"))]
Self::Custom(x, ..) => {
for e in &x.inputs {
for e in x.inputs.iter() {
if !e.walk(path, on_node) {
return false;
}
Expand Down
10 changes: 5 additions & 5 deletions src/ast/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::func::StraightHashMap;
use crate::tokenizer::Token;
use crate::types::dynamic::Union;
use crate::types::Span;
use crate::{calc_fn_hash, Dynamic, Position, StaticVec, INT};
use crate::{calc_fn_hash, Dynamic, Position, INT};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
Expand Down Expand Up @@ -372,11 +372,11 @@ pub type CaseBlocksList = smallvec::SmallVec<[usize; 1]>;
#[derive(Debug, Clone)]
pub struct SwitchCasesCollection {
/// List of [`ConditionalExpr`]'s.
pub expressions: StaticVec<ConditionalExpr>,
pub expressions: Vec<ConditionalExpr>,
/// Dictionary mapping value hashes to [`ConditionalExpr`]'s.
pub cases: StraightHashMap<CaseBlocksList>,
/// List of range cases.
pub ranges: StaticVec<RangeCase>,
pub ranges: Vec<RangeCase>,
/// Statements block for the default case (there can be no condition for the default case).
pub def_case: Option<usize>,
}
Expand Down Expand Up @@ -410,7 +410,7 @@ pub type StmtBlockContainer = smallvec::SmallVec<[Stmt; STMT_BLOCK_INLINE_SIZE]>
/// _(internals)_ The underlying container type for [`StmtBlock`].
/// Exported under the `internals` feature only.
#[cfg(feature = "no_std")]
pub type StmtBlockContainer = StaticVec<Stmt>;
pub type StmtBlockContainer = crate::StaticVec<Stmt>;

/// _(internals)_ A scoped block of statements.
/// Exported under the `internals` feature only.
Expand Down Expand Up @@ -1139,7 +1139,7 @@ impl Stmt {
}
}
Self::FnCall(x, ..) => {
for s in &x.args {
for s in x.args.iter() {
if !s.walk(path, on_node) {
return false;
}
Expand Down
5 changes: 4 additions & 1 deletion src/bin/rhai-repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ fn setup_editor() -> DefaultEditor {
/// Module containing sample functions.
#[export_module]
mod sample_functions {
/// My super-string type.
pub type MyType = String;

/// This is a sample function.
///
/// It takes two numbers and prints them to a string.
Expand All @@ -262,7 +265,7 @@ mod sample_functions {
///
/// print(result); // prints "42 123"
/// ```
pub fn test(x: INT, y: INT) -> String {
pub fn test(x: INT, y: INT) -> MyType {
format!("{x} {y}")
}

Expand Down
8 changes: 3 additions & 5 deletions src/defer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@ macro_rules! defer {
};
($var:ident = ( $value:expr ) if Some($guard:ident) => $restore:expr) => {
let mut __rx__;
let $var = if let Some($guard) = $guard {
__rx__ = crate::Deferred::lock($value, $restore);
&mut *__rx__
} else {
&mut *$value
let $var = match $guard {
Some($guard) => { __rx__ = crate::Deferred::lock($value, $restore); &mut *__rx__ }
_ => &mut *$value
};
};
($var:ident if $guard:expr => $restore:expr) => {
Expand Down
8 changes: 3 additions & 5 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ use crate::func::native::{
use crate::packages::{Package, StandardPackage};
use crate::tokenizer::Token;
use crate::types::StringsInterner;
use crate::{
Dynamic, Identifier, ImmutableString, Locked, OptimizationLevel, SharedModule, StaticVec,
};
use crate::{Dynamic, Identifier, ImmutableString, Locked, OptimizationLevel, SharedModule};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{collections::BTreeSet, fmt, num::NonZeroU8};
Expand Down Expand Up @@ -94,7 +92,7 @@ pub const NAMESPACE_SEPARATOR: &str = Token::DoubleColon.literal_syntax();
/// ```
pub struct Engine {
/// A collection of all modules loaded into the global namespace of the Engine.
pub(crate) global_modules: StaticVec<SharedModule>,
pub(crate) global_modules: Vec<SharedModule>,
/// A collection of all sub-modules directly loaded into the Engine.
#[cfg(not(feature = "no_module"))]
pub(crate) global_sub_modules: Option<std::collections::BTreeMap<Identifier, SharedModule>>,
Expand Down Expand Up @@ -228,7 +226,7 @@ pub fn make_setter(id: &str) -> Identifier {
impl Engine {
/// An empty raw [`Engine`].
pub const RAW: Self = Self {
global_modules: StaticVec::new_const(),
global_modules: Vec::new(),

#[cfg(not(feature = "no_module"))]
global_sub_modules: None,
Expand Down
4 changes: 2 additions & 2 deletions src/eval/chaining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ impl Engine {
"method call in dot chain should not be namespace-qualified"
);

for expr in &x.args {
for expr in x.args.iter() {
let arg_value =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
idx_values.push(arg_value.0.flatten());
Expand Down Expand Up @@ -485,7 +485,7 @@ impl Engine {
"method call in dot chain should not be namespace-qualified"
);

for expr in &x.args {
for expr in x.args.iter() {
let tp = this_ptr.as_deref_mut();
let arg_value = self.get_arg_value(global, caches, scope, tp, expr)?;
_arg_values.push(arg_value.0.flatten());
Expand Down
3 changes: 1 addition & 2 deletions src/eval/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,7 @@ impl Engine {
if let Some(fn_def) = global.lib.iter().flat_map(|m| m.iter_script_fn()).find_map(
|(_, _, f, _, func)| if f == v.3.as_str() { Some(func) } else { None },
) {
let mut fn_ptr =
crate::FnPtr::new_unchecked(v.3.clone(), crate::StaticVec::new_const());
let mut fn_ptr = crate::FnPtr::new_unchecked(v.3.clone(), Vec::new());
fn_ptr.set_fn_def(Some(fn_def.clone()));
let val: Dynamic = fn_ptr.into();
return Ok(val.into());
Expand Down
Loading

0 comments on commit 1afa672

Please sign in to comment.