commit
329942b67f
@ -1180,7 +1180,8 @@ impl Engine {
|
|||||||
Some((index, ScopeEntryType::Normal)) => {
|
Some((index, ScopeEntryType::Normal)) => {
|
||||||
*scope.get_mut(index).0 = rhs_val;
|
*scope.get_mut(index).0 = rhs_val;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
},
|
||||||
|
Some((_, ScopeEntryType::Subscope)) => unreachable!(),
|
||||||
},
|
},
|
||||||
// idx_lhs[idx_expr] = rhs
|
// idx_lhs[idx_expr] = rhs
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -1489,6 +1490,11 @@ impl Engine {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import statement
|
||||||
|
Stmt::Import(_name_expr, _alias) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
// Const statement
|
// Const statement
|
||||||
Stmt::Const(name, expr, _) if expr.is_constant() => {
|
Stmt::Const(name, expr, _) if expr.is_constant() => {
|
||||||
let val = self.eval_expr(scope, state, fn_lib, expr, level)?;
|
let val = self.eval_expr(scope, state, fn_lib, expr, level)?;
|
||||||
|
@ -248,6 +248,8 @@ pub enum Stmt {
|
|||||||
Break(Position),
|
Break(Position),
|
||||||
/// `return`/`throw`
|
/// `return`/`throw`
|
||||||
ReturnWithVal(Option<Box<Expr>>, ReturnType, Position),
|
ReturnWithVal(Option<Box<Expr>>, ReturnType, Position),
|
||||||
|
/// import expr
|
||||||
|
Import(Box<Expr>, Option<String>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stmt {
|
impl Stmt {
|
||||||
@ -261,7 +263,11 @@ impl Stmt {
|
|||||||
| Stmt::Continue(pos)
|
| Stmt::Continue(pos)
|
||||||
| Stmt::Break(pos)
|
| Stmt::Break(pos)
|
||||||
| Stmt::ReturnWithVal(_, _, pos) => *pos,
|
| Stmt::ReturnWithVal(_, _, pos) => *pos,
|
||||||
Stmt::IfThenElse(expr, _, _) | Stmt::Expr(expr) => expr.position(),
|
|
||||||
|
Stmt::IfThenElse(expr, _, _)
|
||||||
|
| Stmt::Expr(expr)
|
||||||
|
| Stmt::Import(expr, _) => expr.position(),
|
||||||
|
|
||||||
Stmt::While(_, stmt) | Stmt::Loop(stmt) | Stmt::For(_, _, stmt) => stmt.position(),
|
Stmt::While(_, stmt) | Stmt::Loop(stmt) | Stmt::For(_, _, stmt) => stmt.position(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,7 +279,8 @@ impl Stmt {
|
|||||||
| Stmt::While(_, _)
|
| Stmt::While(_, _)
|
||||||
| Stmt::Loop(_)
|
| Stmt::Loop(_)
|
||||||
| Stmt::For(_, _, _)
|
| Stmt::For(_, _, _)
|
||||||
| Stmt::Block(_, _) => true,
|
| Stmt::Block(_, _)
|
||||||
|
| Stmt::Import(_, _) => true,
|
||||||
|
|
||||||
// A No-op requires a semicolon in order to know it is an empty statement!
|
// A No-op requires a semicolon in order to know it is an empty statement!
|
||||||
Stmt::Noop(_) => false,
|
Stmt::Noop(_) => false,
|
||||||
@ -303,6 +310,7 @@ impl Stmt {
|
|||||||
Stmt::Let(_, _, _) | Stmt::Const(_, _, _) => false,
|
Stmt::Let(_, _, _) | Stmt::Const(_, _, _) => false,
|
||||||
Stmt::Block(statements, _) => statements.iter().all(Stmt::is_pure),
|
Stmt::Block(statements, _) => statements.iter().all(Stmt::is_pure),
|
||||||
Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_, _, _) => false,
|
Stmt::Continue(_) | Stmt::Break(_) | Stmt::ReturnWithVal(_, _, _) => false,
|
||||||
|
Stmt::Import(_, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,6 +341,16 @@ pub enum Expr {
|
|||||||
Option<Box<Dynamic>>,
|
Option<Box<Dynamic>>,
|
||||||
Position,
|
Position,
|
||||||
),
|
),
|
||||||
|
/// subscope::func(expr, ... )
|
||||||
|
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
||||||
|
/// and the function names are predictable, so no need to allocate a new `String`.
|
||||||
|
SubscopeFnCall(
|
||||||
|
String,
|
||||||
|
Box<Cow<'static, str>>,
|
||||||
|
Box<Vec<Expr>>,
|
||||||
|
Option<Box<Dynamic>>,
|
||||||
|
Position,
|
||||||
|
),
|
||||||
/// expr = expr
|
/// expr = expr
|
||||||
Assignment(Box<Expr>, Box<Expr>, Position),
|
Assignment(Box<Expr>, Box<Expr>, Position),
|
||||||
/// lhs.rhs
|
/// lhs.rhs
|
||||||
@ -430,6 +448,7 @@ impl Expr {
|
|||||||
| Self::Property(_, pos)
|
| Self::Property(_, pos)
|
||||||
| Self::Stmt(_, pos)
|
| Self::Stmt(_, pos)
|
||||||
| Self::FnCall(_, _, _, pos)
|
| Self::FnCall(_, _, _, pos)
|
||||||
|
| Self::SubscopeFnCall(_, _, _, _, pos)
|
||||||
| Self::And(_, _, pos)
|
| Self::And(_, _, pos)
|
||||||
| Self::Or(_, _, pos)
|
| Self::Or(_, _, pos)
|
||||||
| Self::In(_, _, pos)
|
| Self::In(_, _, pos)
|
||||||
@ -456,6 +475,7 @@ impl Expr {
|
|||||||
| Self::Property(_, pos)
|
| Self::Property(_, pos)
|
||||||
| Self::Stmt(_, pos)
|
| Self::Stmt(_, pos)
|
||||||
| Self::FnCall(_, _, _, pos)
|
| Self::FnCall(_, _, _, pos)
|
||||||
|
| Self::SubscopeFnCall(_, _, _, _, pos)
|
||||||
| Self::And(_, _, pos)
|
| Self::And(_, _, pos)
|
||||||
| Self::Or(_, _, pos)
|
| Self::Or(_, _, pos)
|
||||||
| Self::In(_, _, pos)
|
| Self::In(_, _, pos)
|
||||||
@ -533,6 +553,7 @@ impl Expr {
|
|||||||
Self::StringConstant(_, _)
|
Self::StringConstant(_, _)
|
||||||
| Self::Stmt(_, _)
|
| Self::Stmt(_, _)
|
||||||
| Self::FnCall(_, _, _, _)
|
| Self::FnCall(_, _, _, _)
|
||||||
|
| Self::SubscopeFnCall(_, _, _, _, _)
|
||||||
| Self::Assignment(_, _, _)
|
| Self::Assignment(_, _, _)
|
||||||
| Self::Dot(_, _, _)
|
| Self::Dot(_, _, _)
|
||||||
| Self::Index(_, _, _)
|
| Self::Index(_, _, _)
|
||||||
@ -1683,6 +1704,8 @@ fn parse_let<'a>(
|
|||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
Err(PERR::ForbiddenConstantExpr(name).into_err(init_value.position()))
|
Err(PERR::ForbiddenConstantExpr(name).into_err(init_value.position()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopeEntryType::Subscope => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// let name
|
// let name
|
||||||
|
34
src/scope.rs
34
src/scope.rs
@ -13,6 +13,8 @@ pub enum EntryType {
|
|||||||
Normal,
|
Normal,
|
||||||
/// Immutable constant value.
|
/// Immutable constant value.
|
||||||
Constant,
|
Constant,
|
||||||
|
/// Name of a subscope, allowing member access with the :: operator.
|
||||||
|
Subscope,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entry in the Scope.
|
/// An entry in the Scope.
|
||||||
@ -165,6 +167,24 @@ impl<'a> Scope<'a> {
|
|||||||
self.push_dynamic_value(name, EntryType::Normal, value, false);
|
self.push_dynamic_value(name, EntryType::Normal, value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add (push) a new subscope to the Scope.
|
||||||
|
///
|
||||||
|
/// Subscopes are used for access to members in modules and plugins.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Scope;
|
||||||
|
///
|
||||||
|
/// let mut my_scope = Scope::new();
|
||||||
|
///
|
||||||
|
/// my_scope.push_subscope("x".to_string(), "My Plugin".to_string());
|
||||||
|
/// assert_eq!(my_scope.get_subscope("x").unwrap(), "My Plugin");
|
||||||
|
/// ```
|
||||||
|
pub fn push_subscope(&mut self, name: String, value: String) {
|
||||||
|
self.push_dynamic_value(name, EntryType::Subscope, Dynamic::from(value), true);
|
||||||
|
}
|
||||||
|
|
||||||
/// Add (push) a new constant to the Scope.
|
/// Add (push) a new constant to the Scope.
|
||||||
///
|
///
|
||||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||||
@ -297,6 +317,17 @@ impl<'a> Scope<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the subscope of an entry in the Scope, starting from the last.
|
||||||
|
///
|
||||||
|
pub fn get_subscope(&self, name: &str) -> Option<String> {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find(|Entry { name: key, typ, .. }| name == key &&
|
||||||
|
std::mem::discriminant(typ) == std::mem::discriminant(&EntryType::Subscope))
|
||||||
|
.and_then(|Entry { value, .. }| value.downcast_ref::<String>().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the value of an entry in the Scope, starting from the last.
|
/// Get the value of an entry in the Scope, starting from the last.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -344,6 +375,9 @@ impl<'a> Scope<'a> {
|
|||||||
Some((index, EntryType::Normal)) => {
|
Some((index, EntryType::Normal)) => {
|
||||||
self.0.get_mut(index).unwrap().value = Dynamic::from(value)
|
self.0.get_mut(index).unwrap().value = Dynamic::from(value)
|
||||||
}
|
}
|
||||||
|
Some((index, EntryType::Subscope)) => {
|
||||||
|
self.0.get_mut(index).unwrap().value = Dynamic::from(value)
|
||||||
|
}
|
||||||
None => self.push(name, value),
|
None => self.push(name, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,7 @@ pub enum Token {
|
|||||||
RightShift,
|
RightShift,
|
||||||
SemiColon,
|
SemiColon,
|
||||||
Colon,
|
Colon,
|
||||||
|
DoubleColon,
|
||||||
Comma,
|
Comma,
|
||||||
Period,
|
Period,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -230,6 +231,7 @@ impl Token {
|
|||||||
Divide => "/",
|
Divide => "/",
|
||||||
SemiColon => ";",
|
SemiColon => ";",
|
||||||
Colon => ":",
|
Colon => ":",
|
||||||
|
DoubleColon => "::",
|
||||||
Comma => ",",
|
Comma => ",",
|
||||||
Period => ".",
|
Period => ".",
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -874,7 +876,6 @@ impl<'a> TokenIterator<'a> {
|
|||||||
('/', _) => return Some((Token::Divide, pos)),
|
('/', _) => return Some((Token::Divide, pos)),
|
||||||
|
|
||||||
(';', _) => return Some((Token::SemiColon, pos)),
|
(';', _) => return Some((Token::SemiColon, pos)),
|
||||||
(':', _) => return Some((Token::Colon, pos)),
|
|
||||||
(',', _) => return Some((Token::Comma, pos)),
|
(',', _) => return Some((Token::Comma, pos)),
|
||||||
('.', _) => return Some((Token::Period, pos)),
|
('.', _) => return Some((Token::Period, pos)),
|
||||||
|
|
||||||
@ -896,6 +897,12 @@ impl<'a> TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
('=', _) => return Some((Token::Equals, pos)),
|
('=', _) => return Some((Token::Equals, pos)),
|
||||||
|
|
||||||
|
(':', ':') => {
|
||||||
|
self.eat_next();
|
||||||
|
return Some((Token::DoubleColon, pos));
|
||||||
|
}
|
||||||
|
(':', _) => return Some((Token::Colon, pos)),
|
||||||
|
|
||||||
('<', '=') => {
|
('<', '=') => {
|
||||||
self.eat_next();
|
self.eat_next();
|
||||||
return Some((Token::LessThanEqualsTo, pos));
|
return Some((Token::LessThanEqualsTo, pos));
|
||||||
|
Loading…
Reference in New Issue
Block a user