Encapsulate getters/setters.

This commit is contained in:
Stephen Chung 2020-03-30 16:10:50 +08:00
parent 273fc59a30
commit 9f3113b11c
2 changed files with 56 additions and 32 deletions

View File

@ -2,7 +2,7 @@
use crate::any::{Any, AnyExt, Dynamic}; use crate::any::{Any, AnyExt, Dynamic};
use crate::call::FuncArgs; use crate::call::FuncArgs;
use crate::engine::{Engine, FnAny, FnSpec, FUNC_GETTER, FUNC_SETTER}; use crate::engine::{make_getter, make_setter, Engine, FnAny, FnSpec};
use crate::error::ParseError; use crate::error::ParseError;
use crate::fn_register::RegisterFn; use crate::fn_register::RegisterFn;
use crate::parser::{lex, parse, parse_global_expr, FnDef, Position, AST}; use crate::parser::{lex, parse, parse_global_expr, FnDef, Position, AST};
@ -15,7 +15,6 @@ use crate::optimize::optimize_into_ast;
use crate::stdlib::{ use crate::stdlib::{
any::{type_name, TypeId}, any::{type_name, TypeId},
boxed::Box, boxed::Box,
format,
string::{String, ToString}, string::{String, ToString},
sync::Arc, sync::Arc,
vec::Vec, vec::Vec,
@ -45,7 +44,7 @@ impl<'e> Engine<'e> {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #[derive(Clone)] /// #[derive(Debug, Clone, Eq, PartialEq)]
/// struct TestStruct { /// struct TestStruct {
/// field: i64 /// field: i64
/// } /// }
@ -69,8 +68,8 @@ impl<'e> Engine<'e> {
/// engine.register_fn("update", TestStruct::update); /// engine.register_fn("update", TestStruct::update);
/// ///
/// assert_eq!( /// assert_eq!(
/// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?.field, /// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
/// 42 /// TestStruct { field: 42 }
/// ); /// );
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -181,7 +180,7 @@ impl<'e> Engine<'e> {
name: &str, name: &str,
callback: impl Fn(&mut T) -> U + 'static, callback: impl Fn(&mut T) -> U + 'static,
) { ) {
let get_fn_name = format!("{}{}", FUNC_GETTER, name); let get_fn_name = make_getter(name);
self.register_fn(&get_fn_name, callback); self.register_fn(&get_fn_name, callback);
} }
@ -190,7 +189,7 @@ impl<'e> Engine<'e> {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #[derive(Clone)] /// #[derive(Debug, Clone, Eq, PartialEq)]
/// struct TestStruct { /// struct TestStruct {
/// field: i64 /// field: i64
/// } /// }
@ -214,7 +213,10 @@ impl<'e> Engine<'e> {
/// engine.register_set("xyz", TestStruct::set_field); /// engine.register_set("xyz", TestStruct::set_field);
/// ///
/// // Notice that, with a getter, there is no way to get the property value /// // Notice that, with a getter, there is no way to get the property value
/// engine.eval("let a = new_ts(); a.xyz = 42;")?; /// assert_eq!(
/// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
/// TestStruct { field: 42 }
/// );
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
@ -224,7 +226,7 @@ impl<'e> Engine<'e> {
name: &str, name: &str,
callback: impl Fn(&mut T, U) -> () + 'static, callback: impl Fn(&mut T, U) -> () + 'static,
) { ) {
let set_fn_name = format!("{}{}", FUNC_SETTER, name); let set_fn_name = make_setter(name);
self.register_fn(&set_fn_name, callback); self.register_fn(&set_fn_name, callback);
} }

View File

@ -192,6 +192,34 @@ impl Default for Engine<'_> {
} }
} }
/// Make getter function
pub fn make_getter(id: &str) -> String {
format!("{}{}", FUNC_GETTER, id)
}
/// Extract the property name from a getter function name.
fn extract_prop_from_getter(fn_name: &str) -> Option<&str> {
if fn_name.starts_with(FUNC_GETTER) {
Some(&fn_name[FUNC_GETTER.len()..])
} else {
None
}
}
/// Make setter function
pub fn make_setter(id: &str) -> String {
format!("{}{}", FUNC_SETTER, id)
}
/// Extract the property name from a setter function name.
fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
if fn_name.starts_with(FUNC_SETTER) {
Some(&fn_name[FUNC_SETTER.len()..])
} else {
None
}
}
impl Engine<'_> { impl Engine<'_> {
/// Create a new `Engine` /// Create a new `Engine`
pub fn new() -> Self { pub fn new() -> Self {
@ -296,24 +324,18 @@ impl Engine<'_> {
}); });
} }
if fn_name.starts_with(FUNC_GETTER) { if let Some(prop) = extract_prop_from_getter(fn_name) {
// Getter function not found // Getter function not found
return Err(EvalAltResult::ErrorDotExpr( return Err(EvalAltResult::ErrorDotExpr(
format!( format!("- property '{}' unknown or write-only", prop),
"- property '{}' unknown or write-only",
&fn_name[FUNC_GETTER.len()..]
),
pos, pos,
)); ));
} }
if fn_name.starts_with(FUNC_SETTER) { if let Some(prop) = extract_prop_from_setter(fn_name) {
// Setter function not found // Setter function not found
return Err(EvalAltResult::ErrorDotExpr( return Err(EvalAltResult::ErrorDotExpr(
format!( format!("- property '{}' unknown or read-only", prop),
"- property '{}' unknown or read-only",
&fn_name[FUNC_SETTER.len()..]
),
pos, pos,
)); ));
} }
@ -390,7 +412,7 @@ impl Engine<'_> {
// xxx.id // xxx.id
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
let this_ptr = get_this_ptr(scope, src, target); let this_ptr = get_this_ptr(scope, src, target);
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)
} }
@ -401,7 +423,7 @@ impl Engine<'_> {
let (val, _) = match idx_lhs.as_ref() { let (val, _) = match idx_lhs.as_ref() {
// xxx.id[idx_expr] // xxx.id[idx_expr]
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
let this_ptr = get_this_ptr(scope, src, target); let this_ptr = get_this_ptr(scope, src, target);
( (
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)?, self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)?,
@ -431,7 +453,7 @@ impl Engine<'_> {
Expr::Dot(dot_lhs, rhs, _) => match dot_lhs.as_ref() { Expr::Dot(dot_lhs, rhs, _) => match dot_lhs.as_ref() {
// xxx.id.rhs // xxx.id.rhs
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
let this_ptr = get_this_ptr(scope, src, target); let this_ptr = get_this_ptr(scope, src, target);
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)
@ -445,7 +467,7 @@ impl Engine<'_> {
let (val, _) = match idx_lhs.as_ref() { let (val, _) = match idx_lhs.as_ref() {
// xxx.id[idx_expr].rhs // xxx.id[idx_expr].rhs
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
let this_ptr = get_this_ptr(scope, src, target); let this_ptr = get_this_ptr(scope, src, target);
( (
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)?, self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)?,
@ -755,7 +777,7 @@ impl Engine<'_> {
match dot_rhs { match dot_rhs {
// xxx.id // xxx.id
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let set_fn_name = format!("{}{}", FUNC_SETTER, id); let set_fn_name = make_setter(id);
let mut args = [this_ptr, new_val.0.as_mut()]; let mut args = [this_ptr, new_val.0.as_mut()];
self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0)
} }
@ -766,7 +788,7 @@ impl Engine<'_> {
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() { Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
// xxx.id[idx_expr] // xxx.id[idx_expr]
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|v| { .and_then(|v| {
@ -779,7 +801,7 @@ impl Engine<'_> {
) )
}) })
.and_then(|mut v| { .and_then(|mut v| {
let set_fn_name = format!("{}{}", FUNC_SETTER, id); let set_fn_name = make_setter(id);
let mut args = [this_ptr, v.as_mut()]; let mut args = [this_ptr, v.as_mut()];
self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0)
}) })
@ -796,7 +818,7 @@ impl Engine<'_> {
Expr::Dot(lhs, rhs, _) => match lhs.as_ref() { Expr::Dot(lhs, rhs, _) => match lhs.as_ref() {
// xxx.id.rhs // xxx.id.rhs
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|mut v| { .and_then(|mut v| {
@ -804,7 +826,7 @@ impl Engine<'_> {
.map(|_| v) // Discard Ok return value .map(|_| v) // Discard Ok return value
}) })
.and_then(|mut v| { .and_then(|mut v| {
let set_fn_name = format!("{}{}", FUNC_SETTER, id); let set_fn_name = make_setter(id);
let mut args = [this_ptr, v.as_mut()]; let mut args = [this_ptr, v.as_mut()];
self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0)
}) })
@ -816,7 +838,7 @@ impl Engine<'_> {
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() { Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
// xxx.id[idx_expr].rhs // xxx.id[idx_expr].rhs
Expr::Property(id, pos) => { Expr::Property(id, pos) => {
let get_fn_name = format!("{}{}", FUNC_GETTER, id); let get_fn_name = make_getter(id);
self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0) self.call_fn_raw(&get_fn_name, &mut [this_ptr], None, *pos, 0)
.and_then(|v| { .and_then(|v| {
@ -832,7 +854,7 @@ impl Engine<'_> {
Self::update_indexed_value(v, idx as usize, target, val_pos) Self::update_indexed_value(v, idx as usize, target, val_pos)
}) })
.and_then(|mut v| { .and_then(|mut v| {
let set_fn_name = format!("{}{}", FUNC_SETTER, id); let set_fn_name = make_setter(id);
let mut args = [this_ptr, v.as_mut()]; let mut args = [this_ptr, v.as_mut()];
self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0) self.call_fn_raw(&set_fn_name, &mut args, None, *pos, 0)
}) })