Enable dots on numbers to parse as method calls.

This commit is contained in:
Stephen Chung 2020-09-23 22:48:28 +08:00
parent 39433164f2
commit d91d983c74
2 changed files with 42 additions and 3 deletions

View File

@ -731,6 +731,7 @@ pub struct TokenizeState {
/// ///
/// This trait is volatile and may change. /// This trait is volatile and may change.
pub trait InputStream { pub trait InputStream {
fn unread(&mut self, ch: char);
/// Get the next character /// Get the next character
fn get_next(&mut self) -> Option<char>; fn get_next(&mut self) -> Option<char>;
/// Peek the next character /// Peek the next character
@ -1014,8 +1015,21 @@ fn get_next_token_inner(
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
'.' => { '.' => {
result.push(next_char); stream.get_next().unwrap();
eat_next(stream, pos);
// Check if followed by digits (or _)
match stream.peek_next().unwrap_or('\0') {
'0'..='9' | '_' => {
result.push(next_char);
pos.advance()
}
_ => {
// Not a floating-point number
stream.unread(next_char);
break;
}
}
while let Some(next_char_in_float) = stream.peek_next() { while let Some(next_char_in_float) = stream.peek_next() {
match next_char_in_float { match next_char_in_float {
'0'..='9' | '_' => { '0'..='9' | '_' => {
@ -1499,6 +1513,8 @@ fn is_id_continue(x: char) -> bool {
/// A type that implements the `InputStream` trait. /// A type that implements the `InputStream` trait.
/// Multiple character streams are jointed together to form one single stream. /// Multiple character streams are jointed together to form one single stream.
pub struct MultiInputsStream<'a> { pub struct MultiInputsStream<'a> {
/// Buffered character, if any.
buf: Option<char>,
/// The input character streams. /// The input character streams.
streams: StaticVec<Peekable<Chars<'a>>>, streams: StaticVec<Peekable<Chars<'a>>>,
/// The current stream index. /// The current stream index.
@ -1506,8 +1522,16 @@ pub struct MultiInputsStream<'a> {
} }
impl InputStream for MultiInputsStream<'_> { impl InputStream for MultiInputsStream<'_> {
/// Buffer a character.
fn unread(&mut self, ch: char) {
self.buf = Some(ch);
}
/// Get the next character /// Get the next character
fn get_next(&mut self) -> Option<char> { fn get_next(&mut self) -> Option<char> {
if let Some(ch) = self.buf.take() {
return Some(ch);
}
loop { loop {
if self.index >= self.streams.len() { if self.index >= self.streams.len() {
// No more streams // No more streams
@ -1523,6 +1547,10 @@ impl InputStream for MultiInputsStream<'_> {
} }
/// Peek the next character /// Peek the next character
fn peek_next(&mut self) -> Option<char> { fn peek_next(&mut self) -> Option<char> {
if let Some(ch) = self.buf {
return Some(ch);
}
loop { loop {
if self.index >= self.streams.len() { if self.index >= self.streams.len() {
// No more streams // No more streams
@ -1673,6 +1701,7 @@ pub fn lex<'a, 'e>(
}, },
pos: Position::new(1, 0), pos: Position::new(1, 0),
stream: MultiInputsStream { stream: MultiInputsStream {
buf: None,
streams: input.iter().map(|s| s.chars().peekable()).collect(), streams: input.iter().map(|s| s.chars().peekable()).collect(),
index: 0, index: 0,
}, },

View File

@ -4,7 +4,17 @@ use rhai::{Engine, EvalAltResult, INT};
fn test_number_literal() -> Result<(), Box<EvalAltResult>> { fn test_number_literal() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new(); let engine = Engine::new();
assert_eq!(engine.eval::<INT>("65")?, 65); assert_eq!(engine.eval::<INT>("42")?, 42);
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<String>("42.type_of()")?,
if cfg!(feature = "only_i32") {
"i32"
} else {
"i64"
}
);
Ok(()) Ok(())
} }