Enable custom syntax without internals.

This commit is contained in:
Stephen Chung
2020-07-22 17:05:13 +08:00
parent 35374f5b3b
commit abf66850f6
8 changed files with 98 additions and 131 deletions

View File

@@ -11,15 +11,13 @@ use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, St
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::{CustomSyntax, EvalContext, Expression};
use crate::token::Position;
use crate::utils::StaticVec;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
#[cfg(feature = "internals")]
use crate::syntax::{CustomSyntax, EvalContext};
use crate::stdlib::{
any::{type_name, TypeId},
borrow::Cow,
@@ -88,45 +86,10 @@ pub const FN_SET: &str = "set$";
pub const FN_IDX_GET: &str = "index$get$";
pub const FN_IDX_SET: &str = "index$set$";
pub const FN_ANONYMOUS: &str = "anon$";
#[cfg(feature = "internals")]
pub const MARKER_EXPR: &str = "$expr$";
#[cfg(feature = "internals")]
pub const MARKER_BLOCK: &str = "$block$";
#[cfg(feature = "internals")]
pub const MARKER_IDENT: &str = "$ident$";
#[cfg(feature = "internals")]
#[derive(Debug, Clone, Hash)]
pub struct Expression<'a>(&'a Expr);
#[cfg(feature = "internals")]
impl<'a> From<&'a Expr> for Expression<'a> {
fn from(expr: &'a Expr) -> Self {
Self(expr)
}
}
#[cfg(feature = "internals")]
impl Expression<'_> {
/// If this expression is a variable name, return it. Otherwise `None`.
#[cfg(feature = "internals")]
pub fn get_variable_name(&self) -> Option<&str> {
match self.0 {
Expr::Variable(x) => Some((x.0).0.as_str()),
_ => None,
}
}
/// Get the expression.
pub(crate) fn expr(&self) -> &Expr {
&self.0
}
/// Get the position of this expression.
pub fn position(&self) -> Position {
self.0.position()
}
}
/// A type specifying the method of chaining.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum ChainType {
@@ -316,7 +279,6 @@ pub struct Engine {
/// A hashset containing custom keywords and precedence to recognize.
pub(crate) custom_keywords: Option<HashMap<String, u8>>,
/// Custom syntax.
#[cfg(feature = "internals")]
pub(crate) custom_syntax: Option<HashMap<String, CustomSyntax>>,
/// Callback closure for implementing the `print` command.
@@ -376,8 +338,6 @@ impl Default for Engine {
type_names: None,
disabled_symbols: None,
custom_keywords: None,
#[cfg(feature = "internals")]
custom_syntax: None,
// default print/debug implementations
@@ -605,8 +565,6 @@ impl Engine {
type_names: None,
disabled_symbols: None,
custom_keywords: None,
#[cfg(feature = "internals")]
custom_syntax: None,
print: Box::new(|_| {}),
@@ -1734,8 +1692,6 @@ impl Engine {
/// ## WARNING - Low Level API
///
/// This function is very low level. It evaluates an expression from an AST.
#[cfg(feature = "internals")]
#[deprecated(note = "this method is volatile and may change")]
pub fn eval_expression_tree(
&self,
context: &mut EvalContext,
@@ -2215,7 +2171,6 @@ impl Engine {
Expr::False(_) => Ok(false.into()),
Expr::Unit(_) => Ok(().into()),
#[cfg(feature = "internals")]
Expr::Custom(x) => {
let func = (x.0).1.as_ref();
let ep: StaticVec<_> = (x.0).0.iter().map(|e| e.into()).collect();

View File

@@ -91,7 +91,6 @@ mod scope;
mod serde;
mod settings;
mod stdlib;
#[cfg(feature = "internals")]
mod syntax;
mod token;
mod r#unsafe;
@@ -106,6 +105,7 @@ pub use module::Module;
pub use parser::{ImmutableString, AST, INT};
pub use result::EvalAltResult;
pub use scope::Scope;
pub use syntax::{EvalContext, Expression};
pub use token::Position;
pub use utils::calc_fn_spec as calc_fn_hash;
@@ -169,11 +169,7 @@ pub use parser::{CustomExpr, Expr, ReturnType, ScriptFnDef, Stmt};
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]
pub use engine::{Expression, Imports, State as EvalState};
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]
pub use syntax::EvalContext;
pub use engine::{Imports, State as EvalState};
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]

View File

@@ -2,23 +2,19 @@
use crate::any::{Dynamic, Union};
use crate::calc_fn_hash;
use crate::engine::{make_getter, make_setter, Engine, FN_ANONYMOUS, KEYWORD_THIS};
use crate::engine::{
make_getter, make_setter, Engine, FN_ANONYMOUS, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR,
MARKER_IDENT,
};
use crate::error::{LexError, ParseError, ParseErrorType};
use crate::fn_native::Shared;
use crate::module::{Module, ModuleRef};
use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::FnCustomSyntaxEval;
use crate::token::{is_valid_identifier, Position, Token, TokenStream};
use crate::utils::{StaticVec, StraightHasherBuilder};
#[cfg(feature = "internals")]
use crate::engine::{MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
#[cfg(feature = "internals")]
use crate::fn_native::Shared;
#[cfg(feature = "internals")]
use crate::syntax::FnCustomSyntaxEval;
use crate::stdlib::{
borrow::Cow,
boxed::Box,
@@ -587,17 +583,14 @@ impl Stmt {
}
#[derive(Clone)]
#[cfg(feature = "internals")]
pub struct CustomExpr(pub StaticVec<Expr>, pub Shared<FnCustomSyntaxEval>);
#[cfg(feature = "internals")]
impl fmt::Debug for CustomExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
#[cfg(feature = "internals")]
impl Hash for CustomExpr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
@@ -683,7 +676,6 @@ pub enum Expr {
/// ()
Unit(Position),
/// Custom syntax
#[cfg(feature = "internals")]
Custom(Box<(CustomExpr, Position)>),
}
@@ -781,7 +773,6 @@ impl Expr {
Self::Dot(x) | Self::Index(x) => x.0.position(),
#[cfg(feature = "internals")]
Self::Custom(x) => x.1,
}
}
@@ -816,8 +807,6 @@ impl Expr {
Self::Assignment(x) => x.3 = new_pos,
Self::Dot(x) => x.2 = new_pos,
Self::Index(x) => x.2 = new_pos,
#[cfg(feature = "internals")]
Self::Custom(x) => x.1 = new_pos,
}
@@ -925,7 +914,6 @@ impl Expr {
_ => false,
},
#[cfg(feature = "internals")]
Self::Custom(_) => false,
}
}
@@ -2148,7 +2136,6 @@ fn parse_expr(
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// Check if it is a custom syntax.
#[cfg(feature = "internals")]
if let Some(ref custom) = state.engine.custom_syntax {
let (token, pos) = input.peek().unwrap();
let token_pos = *pos;

View File

@@ -1,14 +1,13 @@
//! Module containing implementation for custom syntax.
#![cfg(feature = "internals")]
use crate::any::Dynamic;
use crate::engine::{Engine, Expression, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
use crate::error::LexError;
use crate::engine::{Engine, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
use crate::error::{LexError, ParseError, ParseErrorType};
use crate::fn_native::{SendSync, Shared};
use crate::module::Module;
use crate::parser::Expr;
use crate::result::EvalAltResult;
use crate::scope::Scope;
use crate::token::{is_valid_identifier, Token};
use crate::token::{is_valid_identifier, Position, Token};
use crate::utils::StaticVec;
use crate::stdlib::{
@@ -32,6 +31,33 @@ pub type FnCustomSyntaxEval = dyn Fn(&Engine, &mut EvalContext, &mut Scope, &[Ex
+ Send
+ Sync;
#[derive(Debug, Clone, Hash)]
pub struct Expression<'a>(&'a Expr);
impl<'a> From<&'a Expr> for Expression<'a> {
fn from(expr: &'a Expr) -> Self {
Self(expr)
}
}
impl Expression<'_> {
/// If this expression is a variable name, return it. Otherwise `None`.
pub fn get_variable_name(&self) -> Option<&str> {
match self.0 {
Expr::Variable(x) => Some((x.0).0.as_str()),
_ => None,
}
}
/// Get the expression.
pub(crate) fn expr(&self) -> &Expr {
&self.0
}
/// Get the position of this expression.
pub fn position(&self) -> Position {
self.0.position()
}
}
#[derive(Clone)]
pub struct CustomSyntax {
pub segments: StaticVec<String>,
@@ -45,6 +71,7 @@ impl fmt::Debug for CustomSyntax {
}
}
#[derive(Debug)]
pub struct EvalContext<'a, 'b: 'a, 's, 'm, 't, 'd: 't> {
pub(crate) mods: &'a mut Imports<'b>,
pub(crate) state: &'s mut State,
@@ -56,7 +83,7 @@ pub struct EvalContext<'a, 'b: 'a, 's, 'm, 't, 'd: 't> {
impl Engine {
pub fn register_custom_syntax<S: AsRef<str> + ToString>(
&mut self,
value: &[S],
keywords: &[S],
scope_delta: isize,
func: impl Fn(
&Engine,
@@ -66,15 +93,18 @@ impl Engine {
) -> Result<Dynamic, Box<EvalAltResult>>
+ SendSync
+ 'static,
) -> Result<&mut Self, Box<LexError>> {
if value.is_empty() {
return Err(Box::new(LexError::ImproperSymbol("".to_string())));
}
) -> Result<&mut Self, Box<ParseError>> {
let mut segments: StaticVec<_> = Default::default();
for s in value {
let seg = match s.as_ref() {
for s in keywords {
let s = s.as_ref().trim();
// skip empty keywords
if s.is_empty() {
continue;
}
let seg = match s {
// Markers not in first position
MARKER_EXPR | MARKER_BLOCK | MARKER_IDENT if !segments.is_empty() => s.to_string(),
// Standard symbols not in first position
@@ -115,12 +145,25 @@ impl Engine {
s.into()
}
// Anything else is an error
_ => return Err(Box::new(LexError::ImproperSymbol(s.to_string()))),
_ => {
return Err(LexError::ImproperSymbol(format!(
"Improper symbol for custom syntax: '{}'",
s
))
.into_err(Position::none())
.into());
}
};
segments.push(seg);
}
// If the syntax has no keywords, just ignore the registration
if segments.is_empty() {
return Ok(self);
}
// Remove the first keyword as the discriminator
let key = segments.remove(0);
let syntax = CustomSyntax {