rhai/src/parser.rs

1747 lines
58 KiB
Rust
Raw Normal View History

2020-03-08 12:54:02 +01:00
//! Main module defining the lexer and parser.
2020-03-04 15:00:01 +01:00
use crate::any::Dynamic;
use crate::error::{LexError, ParseError, ParseErrorType};
use std::{borrow::Cow, char, fmt, iter::Peekable, str::Chars, usize};
2016-02-29 22:43:45 +01:00
type LERR = LexError;
2020-03-01 06:30:22 +01:00
type PERR = ParseErrorType;
2020-03-04 15:00:01 +01:00
/// A location (line number + character position) in the input script.
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
2020-02-29 13:12:10 +01:00
pub struct Position {
line: usize,
pos: usize,
2020-02-29 13:12:10 +01:00
}
impl Position {
2020-03-04 15:00:01 +01:00
/// Create a new `Position`.
pub fn new(line: usize, position: usize) -> Self {
if line == 0 || (line == usize::MAX && position == usize::MAX) {
panic!("invalid position: ({}, {})", line, position);
}
2020-03-04 15:00:01 +01:00
Self {
line,
pos: position,
}
2020-02-29 13:12:10 +01:00
}
/// Get the line number (1-based), or `None` if no position or EOF.
2020-03-04 15:00:01 +01:00
pub fn line(&self) -> Option<usize> {
if self.is_none() || self.is_eof() {
None
} else {
Some(self.line)
2020-03-04 15:00:01 +01:00
}
}
2020-03-04 15:00:01 +01:00
/// Get the character position (1-based), or `None` if at beginning of a line.
pub fn position(&self) -> Option<usize> {
if self.is_none() || self.is_eof() {
None
} else if self.pos == 0 {
None
} else {
Some(self.pos)
2020-03-04 15:00:01 +01:00
}
}
2020-03-04 15:00:01 +01:00
/// Advance by one character position.
pub(crate) fn advance(&mut self) {
self.pos += 1;
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Go backwards by one character position.
///
/// # Panics
///
/// Panics if already at beginning of a line - cannot rewind to a previous line.
///
pub(crate) fn rewind(&mut self) {
2020-03-04 16:06:05 +01:00
assert!(self.pos > 0, "cannot rewind at position 0");
self.pos -= 1;
}
2020-03-04 15:00:01 +01:00
/// Advance to the next line.
pub(crate) fn new_line(&mut self) {
self.line += 1;
self.pos = 0;
}
/// Create a `Position` representing no position.
pub(crate) fn none() -> Self {
Self { line: 0, pos: 0 }
}
2020-03-04 15:00:01 +01:00
/// Create a `Position` at EOF.
pub(crate) fn eof() -> Self {
Self {
line: usize::MAX,
pos: usize::MAX,
}
}
/// Is there no `Position`?
pub fn is_none(&self) -> bool {
self.line == 0 && self.pos == 0
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Is the `Position` at EOF?
pub fn is_eof(&self) -> bool {
self.line == usize::MAX && self.pos == usize::MAX
}
}
2020-03-04 15:00:01 +01:00
impl Default for Position {
fn default() -> Self {
Self::new(1, 0)
}
}
2020-03-08 12:54:02 +01:00
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_eof() {
write!(f, "EOF")
} else if self.is_none() {
write!(f, "none")
} else {
write!(f, "line {}, position {}", self.line, self.pos)
}
}
}
2020-03-08 12:54:02 +01:00
impl fmt::Debug for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_eof() {
write!(f, "(EOF)")
} else {
write!(f, "({}:{})", self.line, self.pos)
}
}
2020-02-29 13:12:10 +01:00
}
2020-03-04 15:00:01 +01:00
/// Compiled AST (abstract syntax tree) of a Rhai script.
2020-03-07 03:15:42 +01:00
pub struct AST(pub(crate) Vec<Stmt>, pub(crate) Vec<FnDef<'static>>);
#[derive(Debug, Clone)]
2020-03-07 03:15:42 +01:00
pub struct FnDef<'a> {
pub name: Cow<'a, str>,
pub params: Vec<Cow<'a, str>>,
pub body: Box<Stmt>,
pub pos: Position,
}
#[derive(Debug, Clone)]
pub enum Stmt {
2020-03-02 10:04:56 +01:00
IfElse(Box<Expr>, Box<Stmt>, Option<Box<Stmt>>),
While(Box<Expr>, Box<Stmt>),
2017-10-30 16:08:44 +01:00
Loop(Box<Stmt>),
For(String, Box<Expr>, Box<Stmt>),
Let(String, Option<Box<Expr>>, Position),
2017-10-02 23:44:45 +02:00
Block(Vec<Stmt>),
Expr(Box<Expr>),
Break(Position),
2020-03-03 11:15:20 +01:00
ReturnWithVal(Option<Box<Expr>>, bool, Position),
}
2016-02-29 22:43:45 +01:00
#[derive(Debug, Clone)]
pub enum Expr {
IntegerConstant(i64, Position),
FloatConstant(f64, Position),
Identifier(String, Position),
CharConstant(char, Position),
StringConstant(String, Position),
2020-03-07 03:39:00 +01:00
Block(Box<Stmt>, Position),
FunctionCall(String, Vec<Expr>, Option<Dynamic>, Position),
Assignment(Box<Expr>, Box<Expr>, Position),
Dot(Box<Expr>, Box<Expr>, Position),
Index(Box<Expr>, Box<Expr>, Position),
Array(Vec<Expr>, Position),
2020-03-02 05:08:03 +01:00
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
True(Position),
False(Position),
Unit(Position),
}
impl Expr {
pub fn position(&self) -> Position {
match self {
Expr::IntegerConstant(_, pos)
| Expr::FloatConstant(_, pos)
| Expr::Identifier(_, pos)
| Expr::CharConstant(_, pos)
| Expr::StringConstant(_, pos)
| Expr::FunctionCall(_, _, _, pos)
2020-03-07 03:39:00 +01:00
| Expr::Block(_, pos)
| Expr::Array(_, pos)
| Expr::True(pos)
| Expr::False(pos)
| Expr::Unit(pos) => *pos,
Expr::Index(e, _, _)
| Expr::Assignment(e, _, _)
| Expr::Dot(e, _, _)
2020-03-05 13:28:03 +01:00
| Expr::And(e, _)
| Expr::Or(e, _) => e.position(),
}
}
}
2016-02-29 22:43:45 +01:00
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
IntegerConstant(i64),
FloatConstant(f64),
Identifier(String),
CharConstant(char),
StringConst(String),
LeftBrace,
RightBrace,
LeftParen,
RightParen,
LeftBracket,
RightBracket,
Plus,
2017-10-30 16:08:44 +01:00
UnaryPlus,
Minus,
2017-10-30 16:08:44 +01:00
UnaryMinus,
Multiply,
Divide,
SemiColon,
Colon,
Comma,
Period,
Equals,
True,
False,
Let,
If,
Else,
While,
2017-10-30 16:08:44 +01:00
Loop,
LessThan,
GreaterThan,
Bang,
LessThanEqualsTo,
GreaterThanEqualsTo,
EqualsTo,
NotEqualsTo,
Pipe,
Or,
Ampersand,
And,
Fn,
Break,
Return,
2020-03-03 11:15:20 +01:00
Throw,
PlusAssign,
MinusAssign,
MultiplyAssign,
DivideAssign,
LeftShiftAssign,
RightShiftAssign,
AndAssign,
OrAssign,
XOrAssign,
LeftShift,
RightShift,
XOr,
Modulo,
ModuloAssign,
2017-11-24 08:56:22 +01:00
PowerOf,
PowerOfAssign,
For,
In,
2020-03-04 15:00:01 +01:00
LexError(LexError),
}
2016-02-29 22:43:45 +01:00
2017-10-30 16:08:44 +01:00
impl Token {
2020-03-07 03:15:42 +01:00
pub fn syntax<'a>(&'a self) -> Cow<'a, str> {
use self::Token::*;
match *self {
2020-03-07 03:15:42 +01:00
IntegerConstant(ref i) => i.to_string().into(),
FloatConstant(ref f) => f.to_string().into(),
Identifier(ref s) => s.into(),
CharConstant(ref c) => c.to_string().into(),
2020-03-04 15:00:01 +01:00
LexError(ref err) => err.to_string().into(),
ref token => (match token {
StringConst(_) => "string",
LeftBrace => "{",
RightBrace => "}",
LeftParen => "(",
RightParen => ")",
LeftBracket => "[",
RightBracket => "]",
Plus => "+",
UnaryPlus => "+",
Minus => "-",
UnaryMinus => "-",
Multiply => "*",
Divide => "/",
SemiColon => ";",
Colon => ":",
Comma => ",",
Period => ".",
Equals => "=",
True => "true",
False => "false",
Let => "let",
If => "if",
Else => "else",
While => "while",
Loop => "loop",
LessThan => "<",
GreaterThan => ">",
Bang => "!",
LessThanEqualsTo => "<=",
GreaterThanEqualsTo => ">=",
EqualsTo => "==",
NotEqualsTo => "!=",
Pipe => "|",
Or => "||",
Ampersand => "&",
And => "&&",
Fn => "fn",
Break => "break",
Return => "return",
2020-03-03 11:15:20 +01:00
Throw => "throw",
PlusAssign => "+=",
MinusAssign => "-=",
MultiplyAssign => "*=",
DivideAssign => "/=",
LeftShiftAssign => "<<=",
RightShiftAssign => ">>=",
AndAssign => "&=",
OrAssign => "|=",
XOrAssign => "^=",
LeftShift => "<<",
RightShift => ">>",
XOr => "^",
Modulo => "%",
ModuloAssign => "%=",
PowerOf => "~",
PowerOfAssign => "~=",
For => "for",
In => "in",
2020-03-07 03:15:42 +01:00
_ => panic!("operator should be match in outer scope"),
})
.into(),
}
}
2017-10-30 16:08:44 +01:00
// if another operator is after these, it's probably an unary operator
// not sure about fn's name
pub fn is_next_unary(&self) -> bool {
use self::Token::*;
match *self {
LeftBrace | // (+expr) - is unary
// RightBrace | {expr} - expr not unary & is closing
LeftParen | // {-expr} - is unary
// RightParen | (expr) - expr not unary & is closing
LeftBracket | // [-expr] - is unary
// RightBracket | [expr] - expr not unary & is closing
2017-10-30 16:08:44 +01:00
Plus |
UnaryPlus |
Minus |
UnaryMinus |
Multiply |
Divide |
Colon |
Comma |
Period |
Equals |
LessThan |
GreaterThan |
Bang |
LessThanEqualsTo |
GreaterThanEqualsTo |
EqualsTo |
NotEqualsTo |
2017-10-30 16:08:44 +01:00
Pipe |
Or |
Ampersand |
And |
If |
While |
PlusAssign |
MinusAssign |
MultiplyAssign |
DivideAssign |
LeftShiftAssign |
RightShiftAssign |
AndAssign |
OrAssign |
XOrAssign |
LeftShift |
RightShift |
XOr |
Modulo |
ModuloAssign |
2017-11-24 08:56:22 +01:00
Return |
2020-03-03 11:15:20 +01:00
Throw |
2017-11-24 08:56:22 +01:00
PowerOf |
In |
PowerOfAssign => true,
2017-10-30 16:08:44 +01:00
_ => false,
}
}
#[allow(dead_code)]
2020-03-04 15:00:01 +01:00
pub fn is_binary_op(&self) -> bool {
2017-10-30 16:08:44 +01:00
use self::Token::*;
match *self {
2020-03-04 15:00:01 +01:00
RightBrace | RightParen | RightBracket | Plus | Minus | Multiply | Divide | Comma
| Equals | LessThan | GreaterThan | LessThanEqualsTo | GreaterThanEqualsTo
| EqualsTo | NotEqualsTo | Pipe | Or | Ampersand | And | PowerOf => true,
2017-10-30 16:08:44 +01:00
_ => false,
}
}
#[allow(dead_code)]
2020-03-04 15:00:01 +01:00
pub fn is_unary_op(&self) -> bool {
2017-10-30 16:08:44 +01:00
use self::Token::*;
match *self {
2020-03-03 11:15:20 +01:00
UnaryPlus | UnaryMinus | Equals | Bang | Return | Throw => true,
2017-10-30 16:08:44 +01:00
_ => false,
}
}
}
2016-02-29 22:43:45 +01:00
pub struct TokenIterator<'a> {
2017-10-30 16:08:44 +01:00
last: Token,
2020-02-29 13:12:10 +01:00
pos: Position,
char_stream: Peekable<Chars<'a>>,
}
impl<'a> TokenIterator<'a> {
fn advance(&mut self) {
self.pos.advance();
}
fn rewind(&mut self) {
self.pos.rewind();
}
fn new_line(&mut self) {
self.pos.new_line()
}
pub fn parse_string_const(
&mut self,
enclosing_char: char,
2020-02-29 13:12:10 +01:00
) -> Result<String, (LexError, Position)> {
let mut result = Vec::new();
2020-03-03 14:39:25 +01:00
let mut escape = String::with_capacity(12);
loop {
let next_char = self.char_stream.next();
if next_char.is_none() {
return Err((LERR::UnterminatedString, Position::eof()));
}
self.advance();
match next_char.unwrap() {
2020-03-03 14:39:25 +01:00
'\\' if escape.is_empty() => {
escape.push('\\');
}
'\\' if !escape.is_empty() => {
escape.clear();
result.push('\\');
}
2020-03-03 14:39:25 +01:00
't' if !escape.is_empty() => {
escape.clear();
result.push('\t');
}
2020-03-03 14:39:25 +01:00
'n' if !escape.is_empty() => {
escape.clear();
result.push('\n');
}
2020-03-03 14:39:25 +01:00
'r' if !escape.is_empty() => {
escape.clear();
result.push('\r');
}
2020-03-03 14:39:25 +01:00
'x' if !escape.is_empty() => {
let mut seq = escape.clone();
seq.push('x');
escape.clear();
let mut out_val: u32 = 0;
for _ in 0..2 {
if let Some(c) = self.char_stream.next() {
2020-03-03 14:39:25 +01:00
seq.push(c);
self.advance();
2020-03-03 14:39:25 +01:00
if let Some(d1) = c.to_digit(16) {
out_val *= 16;
out_val += d1;
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
if let Some(r) = char::from_u32(out_val) {
result.push(r);
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
2020-03-03 14:39:25 +01:00
'u' if !escape.is_empty() => {
let mut seq = escape.clone();
seq.push('u');
escape.clear();
let mut out_val: u32 = 0;
for _ in 0..4 {
if let Some(c) = self.char_stream.next() {
2020-03-03 14:39:25 +01:00
seq.push(c);
self.advance();
2020-03-03 14:39:25 +01:00
if let Some(d1) = c.to_digit(16) {
out_val *= 16;
out_val += d1;
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
if let Some(r) = char::from_u32(out_val) {
result.push(r);
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
2020-03-03 14:39:25 +01:00
'U' if !escape.is_empty() => {
let mut seq = escape.clone();
seq.push('U');
escape.clear();
let mut out_val: u32 = 0;
for _ in 0..8 {
if let Some(c) = self.char_stream.next() {
2020-03-03 14:39:25 +01:00
seq.push(c);
self.advance();
2020-03-03 14:39:25 +01:00
if let Some(d1) = c.to_digit(16) {
out_val *= 16;
out_val += d1;
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
if let Some(r) = char::from_u32(out_val) {
result.push(r);
} else {
2020-03-03 14:39:25 +01:00
return Err((LERR::MalformedEscapeSequence(seq), self.pos));
}
}
2020-03-03 14:39:25 +01:00
x if enclosing_char == x && !escape.is_empty() => result.push(x),
x if enclosing_char == x && escape.is_empty() => break,
_ if !escape.is_empty() => {
return Err((LERR::MalformedEscapeSequence(escape), self.pos))
}
'\n' => {
self.rewind();
return Err((LERR::UnterminatedString, self.pos));
}
x => {
2020-03-03 14:39:25 +01:00
escape.clear();
result.push(x);
}
}
}
2020-03-07 03:15:42 +01:00
Ok(result.iter().collect())
}
2016-02-29 22:43:45 +01:00
2020-02-29 13:12:10 +01:00
fn inner_next(&mut self) -> Option<(Token, Position)> {
2016-02-29 22:43:45 +01:00
while let Some(c) = self.char_stream.next() {
self.advance();
let pos = self.pos;
2016-02-29 22:43:45 +01:00
match c {
'\n' => self.new_line(),
2019-09-18 12:21:07 +02:00
'0'..='9' => {
2016-02-29 22:43:45 +01:00
let mut result = Vec::new();
2017-11-01 06:10:46 +01:00
let mut radix_base: Option<u32> = None;
2016-02-29 22:43:45 +01:00
result.push(c);
while let Some(&next_char) = self.char_stream.peek() {
match next_char {
2020-03-03 14:39:25 +01:00
'0'..='9' | '_' => {
result.push(next_char);
self.char_stream.next();
self.advance();
}
'.' => {
result.push(next_char);
self.char_stream.next();
self.advance();
while let Some(&next_char_in_float) = self.char_stream.peek() {
match next_char_in_float {
2020-03-03 14:39:25 +01:00
'0'..='9' | '_' => {
result.push(next_char_in_float);
self.char_stream.next();
self.advance();
}
_ => break,
}
}
}
2020-03-03 14:39:25 +01:00
'x' | 'X' if c == '0' => {
result.push(next_char);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
while let Some(&next_char_in_hex) = self.char_stream.peek() {
match next_char_in_hex {
2020-03-03 14:39:25 +01:00
'0'..='9' | 'a'..='f' | 'A'..='F' | '_' => {
result.push(next_char_in_hex);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
2017-11-01 06:02:36 +01:00
}
_ => break,
}
}
2017-11-01 06:10:46 +01:00
radix_base = Some(16);
2017-11-01 06:02:36 +01:00
}
2020-03-03 14:39:25 +01:00
'o' | 'O' if c == '0' => {
result.push(next_char);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
while let Some(&next_char_in_oct) = self.char_stream.peek() {
match next_char_in_oct {
2020-03-03 14:39:25 +01:00
'0'..='8' | '_' => {
result.push(next_char_in_oct);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
2017-11-01 06:02:36 +01:00
}
_ => break,
}
}
2017-11-01 06:10:46 +01:00
radix_base = Some(8);
2017-11-01 06:02:36 +01:00
}
2020-03-03 14:39:25 +01:00
'b' | 'B' if c == '0' => {
result.push(next_char);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
while let Some(&next_char_in_binary) = self.char_stream.peek() {
match next_char_in_binary {
2017-11-01 06:02:36 +01:00
'0' | '1' | '_' => {
result.push(next_char_in_binary);
2017-11-01 06:02:36 +01:00
self.char_stream.next();
self.advance();
2017-11-01 06:02:36 +01:00
}
_ => break,
}
}
2017-11-01 06:10:46 +01:00
radix_base = Some(2);
2017-11-01 06:02:36 +01:00
}
_ => break,
2016-02-29 22:43:45 +01:00
}
}
2017-11-01 06:10:46 +01:00
if let Some(radix) = radix_base {
2020-03-03 14:39:25 +01:00
let out: String = result.iter().skip(2).filter(|&&c| c != '_').collect();
return Some((
if let Ok(val) = i64::from_str_radix(&out, radix) {
Token::IntegerConstant(val)
} else {
2020-03-04 15:00:01 +01:00
Token::LexError(LERR::MalformedNumber(result.iter().collect()))
2020-03-03 14:39:25 +01:00
},
pos,
));
2020-03-07 03:15:42 +01:00
} else {
let out: String = result.iter().filter(|&&c| c != '_').collect();
2016-02-29 22:43:45 +01:00
2020-03-07 03:15:42 +01:00
return Some((
if let Ok(val) = out.parse::<i64>() {
Token::IntegerConstant(val)
} else if let Ok(val) = out.parse::<f64>() {
Token::FloatConstant(val)
} else {
Token::LexError(LERR::MalformedNumber(result.iter().collect()))
},
pos,
));
}
}
2019-09-18 12:21:07 +02:00
'A'..='Z' | 'a'..='z' | '_' => {
2016-02-29 22:43:45 +01:00
let mut result = Vec::new();
result.push(c);
while let Some(&next_char) = self.char_stream.peek() {
match next_char {
x if x.is_ascii_alphanumeric() || x == '_' => {
2017-10-14 19:46:22 +02:00
result.push(x);
self.char_stream.next();
self.advance();
}
_ => break,
2016-02-29 22:43:45 +01:00
}
}
2020-03-03 14:39:25 +01:00
let out: String = result.iter().collect();
return Some((
2020-03-02 05:08:03 +01:00
match out.as_str() {
"true" => Token::True,
"false" => Token::False,
"let" => Token::Let,
"if" => Token::If,
"else" => Token::Else,
"while" => Token::While,
"loop" => Token::Loop,
"break" => Token::Break,
"return" => Token::Return,
2020-03-03 11:15:20 +01:00
"throw" => Token::Throw,
"fn" => Token::Fn,
"for" => Token::For,
"in" => Token::In,
2020-03-07 03:15:42 +01:00
_ => Token::Identifier(out),
},
pos,
));
}
'"' => {
return match self.parse_string_const('"') {
2020-02-29 13:12:10 +01:00
Ok(out) => Some((Token::StringConst(out), pos)),
2020-03-04 15:00:01 +01:00
Err(e) => Some((Token::LexError(e.0), e.1)),
2016-02-29 22:43:45 +01:00
}
}
2019-09-18 12:21:07 +02:00
'\'' => match self.parse_string_const('\'') {
Ok(result) => {
let mut chars = result.chars();
return Some((
if let Some(first_char) = chars.next() {
if chars.count() != 0 {
2020-03-04 15:00:01 +01:00
Token::LexError(LERR::MalformedChar(format!("'{}'", result)))
} else {
Token::CharConstant(first_char)
}
} else {
2020-03-04 15:00:01 +01:00
Token::LexError(LERR::MalformedChar(format!("'{}'", result)))
},
pos,
));
2016-04-14 03:40:06 +02:00
}
2020-03-04 15:00:01 +01:00
Err(e) => return Some((Token::LexError(e.0), e.1)),
2019-09-18 12:21:07 +02:00
},
2020-02-29 13:12:10 +01:00
'{' => return Some((Token::LeftBrace, pos)),
'}' => return Some((Token::RightBrace, pos)),
'(' => return Some((Token::LeftParen, pos)),
')' => return Some((Token::RightParen, pos)),
'[' => return Some((Token::LeftBracket, pos)),
']' => return Some((Token::RightBracket, pos)),
2017-10-30 16:08:44 +01:00
'+' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::PlusAssign
}
_ if self.last.is_next_unary() => Token::UnaryPlus,
_ => Token::Plus,
},
pos,
))
2019-09-18 12:21:07 +02:00
}
2017-10-30 16:08:44 +01:00
'-' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::MinusAssign
}
_ if self.last.is_next_unary() => Token::UnaryMinus,
_ => Token::Minus,
},
pos,
))
2019-09-18 12:21:07 +02:00
}
'*' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::MultiplyAssign
}
_ => Token::Multiply,
},
pos,
))
2019-09-18 12:21:07 +02:00
}
'/' => match self.char_stream.peek() {
Some(&'/') => {
self.char_stream.next();
self.advance();
2019-09-18 12:21:07 +02:00
while let Some(c) = self.char_stream.next() {
match c {
'\n' => {
2020-03-04 15:00:01 +01:00
self.new_line();
break;
}
_ => self.advance(),
2017-10-30 16:08:44 +01:00
}
}
2019-09-18 12:21:07 +02:00
}
Some(&'*') => {
let mut level = 1;
self.char_stream.next();
self.advance();
2019-09-18 12:21:07 +02:00
while let Some(c) = self.char_stream.next() {
self.advance();
2019-09-18 12:21:07 +02:00
match c {
'/' => {
if let Some('*') = self.char_stream.next() {
level += 1;
2017-10-30 16:08:44 +01:00
}
self.advance();
2019-09-18 12:21:07 +02:00
}
'*' => {
if let Some('/') = self.char_stream.next() {
level -= 1;
2017-10-30 16:08:44 +01:00
}
self.advance();
2017-10-30 16:08:44 +01:00
}
2020-03-04 15:00:01 +01:00
'\n' => self.new_line(),
2019-09-18 12:21:07 +02:00
_ => (),
}
2017-10-30 16:08:44 +01:00
2019-09-18 12:21:07 +02:00
if level == 0 {
break;
2017-10-30 16:08:44 +01:00
}
}
}
2019-09-18 12:21:07 +02:00
Some(&'=') => {
self.char_stream.next();
self.advance();
2020-02-29 13:12:10 +01:00
return Some((Token::DivideAssign, pos));
2019-09-18 12:21:07 +02:00
}
2020-02-29 13:12:10 +01:00
_ => return Some((Token::Divide, pos)),
2019-09-18 12:21:07 +02:00
},
2020-02-29 13:12:10 +01:00
';' => return Some((Token::SemiColon, pos)),
':' => return Some((Token::Colon, pos)),
',' => return Some((Token::Comma, pos)),
'.' => return Some((Token::Period, pos)),
2019-09-18 12:21:07 +02:00
'=' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
2020-02-29 13:12:10 +01:00
return Some((Token::EqualsTo, pos));
2016-03-01 15:40:48 +01:00
}
2020-02-29 13:12:10 +01:00
_ => return Some((Token::Equals, pos)),
2019-09-18 12:21:07 +02:00
},
'<' => match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
2020-02-29 13:12:10 +01:00
return Some((Token::LessThanEqualsTo, pos));
2019-09-18 12:21:07 +02:00
}
Some(&'<') => {
self.char_stream.next();
self.advance();
2019-09-18 12:21:07 +02:00
return match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
2020-02-29 13:12:10 +01:00
Some((Token::LeftShiftAssign, pos))
}
2019-09-18 12:21:07 +02:00
_ => {
self.char_stream.next();
self.advance();
2020-02-29 13:12:10 +01:00
Some((Token::LeftShift, pos))
2019-09-18 12:21:07 +02:00
}
};
2016-03-01 15:40:48 +01:00
}
2020-02-29 13:12:10 +01:00
_ => return Some((Token::LessThan, pos)),
2019-09-18 12:21:07 +02:00
},
'>' => {
return Some((
match self.char_stream.peek() {
2019-09-18 12:21:07 +02:00
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::GreaterThanEqualsTo
}
Some(&'>') => {
2019-09-18 12:21:07 +02:00
self.char_stream.next();
self.advance();
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::RightShiftAssign
}
_ => {
self.char_stream.next();
self.advance();
Token::RightShift
}
}
2019-09-18 12:21:07 +02:00
}
_ => Token::GreaterThan,
},
pos,
))
}
'!' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::NotEqualsTo
}
_ => Token::Bang,
},
pos,
))
}
'|' => {
return Some((
match self.char_stream.peek() {
Some(&'|') => {
self.char_stream.next();
self.advance();
Token::Or
}
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::OrAssign
}
_ => Token::Pipe,
},
pos,
))
}
'&' => {
return Some((
match self.char_stream.peek() {
Some(&'&') => {
self.char_stream.next();
self.advance();
Token::And
}
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::AndAssign
}
_ => Token::Ampersand,
},
pos,
))
}
'^' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::XOrAssign
}
_ => Token::XOr,
},
pos,
))
}
'%' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::ModuloAssign
}
_ => Token::Modulo,
},
pos,
))
}
'~' => {
return Some((
match self.char_stream.peek() {
Some(&'=') => {
self.char_stream.next();
self.advance();
Token::PowerOfAssign
}
_ => Token::PowerOf,
},
pos,
))
}
x if x.is_whitespace() => (),
2020-03-04 15:00:01 +01:00
x => return Some((Token::LexError(LERR::UnexpectedChar(x)), pos)),
2016-02-29 22:43:45 +01:00
}
}
None
}
}
2017-10-30 16:08:44 +01:00
impl<'a> Iterator for TokenIterator<'a> {
2020-02-29 13:12:10 +01:00
type Item = (Token, Position);
2017-10-30 16:08:44 +01:00
// TODO - perhaps this could be optimized?
fn next(&mut self) -> Option<Self::Item> {
self.inner_next().map(|x| {
self.last = x.0.clone();
x
})
2017-10-30 16:08:44 +01:00
}
}
2019-09-18 12:21:07 +02:00
pub fn lex(input: &str) -> TokenIterator<'_> {
TokenIterator {
2020-03-04 15:00:01 +01:00
last: Token::LexError(LERR::InputError("".into())),
pos: Position::new(1, 0),
2019-09-18 12:21:07 +02:00
char_stream: input.chars().peekable(),
}
2016-02-29 22:43:45 +01:00
}
2020-02-29 14:18:48 +01:00
fn get_precedence(token: &Token) -> i8 {
2016-02-29 22:43:45 +01:00
match *token {
2017-10-30 16:08:44 +01:00
Token::Equals
| Token::PlusAssign
| Token::MinusAssign
| Token::MultiplyAssign
| Token::DivideAssign
| Token::LeftShiftAssign
| Token::RightShiftAssign
| Token::AndAssign
| Token::OrAssign
| Token::XOrAssign
| Token::ModuloAssign
| Token::PowerOfAssign => 10,
2019-09-18 12:21:07 +02:00
Token::Or | Token::XOr | Token::Pipe => 11,
Token::And | Token::Ampersand => 12,
2017-10-02 23:44:45 +02:00
Token::LessThan
| Token::LessThanEqualsTo
2017-10-02 23:44:45 +02:00
| Token::GreaterThan
| Token::GreaterThanEqualsTo
| Token::EqualsTo
| Token::NotEqualsTo => 15,
2019-09-18 12:21:07 +02:00
Token::Plus | Token::Minus => 20,
Token::Divide | Token::Multiply | Token::PowerOf => 40,
Token::LeftShift | Token::RightShift => 50,
Token::Modulo => 60,
Token::Period => 100,
_ => -1,
2016-02-29 22:43:45 +01:00
}
}
fn parse_paren_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
) -> Result<Expr, ParseError> {
match input.peek() {
2020-02-29 13:12:10 +01:00
Some((Token::RightParen, _)) => {
input.next();
return Ok(Expr::Unit(begin));
}
_ => (),
}
2019-09-18 12:21:07 +02:00
let expr = parse_expr(input)?;
2016-02-29 22:43:45 +01:00
match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::RightParen, _)) => Ok(expr),
Some((_, pos)) => {
return Err(ParseError::new(
PERR::MissingRightParen("a matching ( in the expression".into()),
pos,
))
}
None => Err(ParseError::new(
PERR::MissingRightParen("a matching ( in the expression".into()),
Position::eof(),
)),
2016-02-29 22:43:45 +01:00
}
}
2019-09-18 12:21:07 +02:00
fn parse_call_expr<'a>(
id: String,
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
2016-02-29 22:43:45 +01:00
let mut args = Vec::new();
2017-10-28 05:30:12 +02:00
2020-02-29 13:12:10 +01:00
if let Some(&(Token::RightParen, _)) = input.peek() {
2017-10-02 23:44:45 +02:00
input.next();
return Ok(Expr::FunctionCall(id, args, None, begin));
2016-02-29 22:43:45 +01:00
}
loop {
args.push(parse_expr(input)?);
2016-02-29 22:43:45 +01:00
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::RightParen, _)) => {
input.next();
return Ok(Expr::FunctionCall(id, args, None, begin));
}
2020-02-29 13:12:10 +01:00
Some(&(Token::Comma, _)) => (),
Some(&(_, pos)) => {
return Err(ParseError::new(
PERR::MissingRightParen(format!(
"closing the arguments list to function call of '{}'",
id
)),
pos,
))
}
None => {
return Err(ParseError::new(
PERR::MissingRightParen(format!(
"closing the arguments list to function call of '{}'",
id
)),
Position::eof(),
))
}
2016-02-29 22:43:45 +01:00
}
input.next();
}
}
2019-09-18 12:21:07 +02:00
fn parse_index_expr<'a>(
2020-03-05 13:28:03 +01:00
lhs: Box<Expr>,
2019-09-18 12:21:07 +02:00
input: &mut Peekable<TokenIterator<'a>>,
pos: Position,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
parse_expr(input).and_then(|idx_expr| match input.peek() {
Some(&(Token::RightBracket, _)) => {
input.next();
return Ok(Expr::Index(lhs, Box::new(idx_expr), pos));
}
Some(&(_, pos)) => {
return Err(ParseError::new(
PERR::MissingRightBracket("index expression".into()),
pos,
))
}
None => {
return Err(ParseError::new(
PERR::MissingRightBracket("index expression".into()),
Position::eof(),
))
}
})
2016-03-26 18:46:28 +01:00
}
2019-09-18 12:21:07 +02:00
fn parse_ident_expr<'a>(
id: String,
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
2019-09-18 12:21:07 +02:00
) -> Result<Expr, ParseError> {
2016-03-26 18:46:28 +01:00
match input.peek() {
2020-03-04 15:00:01 +01:00
Some(&(Token::LeftParen, _)) => {
input.next();
2020-03-04 15:00:01 +01:00
parse_call_expr(id, input, begin)
}
Some(&(Token::LeftBracket, pos)) => {
input.next();
parse_index_expr(Box::new(Expr::Identifier(id, begin)), input, pos)
}
Some(_) => Ok(Expr::Identifier(id, begin)),
None => Ok(Expr::Identifier(id, Position::eof())),
2016-03-26 18:46:28 +01:00
}
}
fn parse_array_expr<'a>(
input: &mut Peekable<TokenIterator<'a>>,
begin: Position,
) -> Result<Expr, ParseError> {
2016-03-26 18:46:28 +01:00
let mut arr = Vec::new();
match input.peek() {
Some(&(Token::RightBracket, _)) => (),
2016-03-26 18:46:28 +01:00
_ => {
while input.peek().is_some() {
arr.push(parse_expr(input)?);
if let Some(&(Token::Comma, _)) = input.peek() {
input.next();
}
2016-03-26 18:46:28 +01:00
if let Some(&(Token::RightBracket, _)) = input.peek() {
break;
}
2019-09-18 12:21:07 +02:00
}
}
2016-03-26 18:46:28 +01:00
}
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::RightBracket, _)) => {
input.next();
Ok(Expr::Array(arr, begin))
}
Some(&(_, pos)) => Err(ParseError::new(
PERR::MissingRightBracket("the end of array literal".into()),
pos,
)),
None => Err(ParseError::new(
PERR::MissingRightBracket("the end of array literal".into()),
Position::eof(),
)),
2016-03-26 18:46:28 +01:00
}
}
2016-02-29 22:43:45 +01:00
fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
2020-03-07 03:39:00 +01:00
// Block statement as expression
match input.peek() {
Some(&(Token::LeftBrace, pos)) => {
return parse_block(input).map(|block| Expr::Block(Box::new(block), pos))
}
_ => (),
}
2020-03-05 13:28:03 +01:00
let token = input.next();
let mut follow_on = false;
let mut root_expr = match token {
Some((Token::IntegerConstant(x), pos)) => Ok(Expr::IntegerConstant(x, pos)),
Some((Token::FloatConstant(x), pos)) => Ok(Expr::FloatConstant(x, pos)),
Some((Token::CharConstant(c), pos)) => Ok(Expr::CharConstant(c, pos)),
2020-03-05 13:28:03 +01:00
Some((Token::StringConst(s), pos)) => {
follow_on = true;
Ok(Expr::StringConstant(s, pos))
}
Some((Token::Identifier(s), pos)) => {
follow_on = true;
parse_ident_expr(s, input, pos)
}
Some((Token::LeftParen, pos)) => {
follow_on = true;
parse_paren_expr(input, pos)
}
Some((Token::LeftBracket, pos)) => {
follow_on = true;
parse_array_expr(input, pos)
}
Some((Token::True, pos)) => Ok(Expr::True(pos)),
Some((Token::False, pos)) => Ok(Expr::False(pos)),
2020-03-04 15:00:01 +01:00
Some((Token::LexError(le), pos)) => {
Err(ParseError::new(PERR::BadInput(le.to_string()), pos))
}
Some((token, pos)) => Err(ParseError::new(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())),
pos,
)),
2020-03-04 15:00:01 +01:00
None => Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())),
2020-03-05 13:28:03 +01:00
}?;
if !follow_on {
return Ok(root_expr);
2020-03-05 13:28:03 +01:00
}
// Tail processing all possible indexing
while let Some(&(Token::LeftBracket, pos)) = input.peek() {
input.next();
root_expr = parse_index_expr(Box::new(root_expr), input, pos)?;
2016-02-29 22:43:45 +01:00
}
Ok(root_expr)
2016-02-29 22:43:45 +01:00
}
2017-10-30 16:08:44 +01:00
fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
match input.peek() {
Some(&(Token::UnaryMinus, pos)) => {
2019-09-18 12:21:07 +02:00
input.next();
Ok(Expr::FunctionCall(
"-".into(),
vec![parse_primary(input)?],
None,
pos,
))
2019-09-18 12:21:07 +02:00
}
Some(&(Token::UnaryPlus, _)) => {
2019-09-18 12:21:07 +02:00
input.next();
parse_primary(input)
}
Some(&(Token::Bang, pos)) => {
2019-09-18 12:21:07 +02:00
input.next();
Ok(Expr::FunctionCall(
"!".into(),
vec![parse_primary(input)?],
Some(Box::new(false)), // NOT operator, when operating on invalid operand, defaults to false
pos,
))
2019-09-18 12:21:07 +02:00
}
_ => parse_primary(input),
2017-10-30 16:08:44 +01:00
}
}
fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result<Expr, ParseError> {
fn valid_assignment_chain(expr: &Expr) -> (bool, Position) {
match expr {
Expr::Identifier(_, pos) => (true, *pos),
Expr::Index(idx_lhs, _, _) => match idx_lhs.as_ref() {
Expr::Identifier(_, _) => (true, idx_lhs.position()),
_ => (false, idx_lhs.position()),
},
Expr::Dot(dot_lhs, dot_rhs, _) => match dot_lhs.as_ref() {
Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs),
Expr::Index(idx_lhs, _, _) => match idx_lhs.as_ref() {
Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs),
_ => (false, idx_lhs.position()),
},
_ => (false, dot_lhs.position()),
},
_ => (false, expr.position()),
2020-03-07 03:15:42 +01:00
}
}
2020-03-07 03:15:42 +01:00
//println!("{:?} = {:?}", lhs, rhs);
match valid_assignment_chain(&lhs) {
(true, _) => Ok(Expr::Assignment(Box::new(lhs), Box::new(rhs), pos)),
(false, pos) => Err(ParseError::new(PERR::AssignmentToInvalidLHS, pos)),
}
2020-03-07 03:15:42 +01:00
}
2020-03-07 06:39:28 +01:00
fn parse_op_assignment(
function: &str,
lhs: Expr,
rhs: Expr,
pos: Position,
) -> Result<Expr, ParseError> {
let lhs_copy = lhs.clone();
parse_assignment(
lhs,
Expr::FunctionCall(function.into(), vec![lhs_copy, rhs], None, pos),
pos,
)
/*
const LHS_VALUE: &'static str = "@LHS_VALUE@";
let lhs_pos = lhs.position();
Ok(Expr::Block(
Box::new(Stmt::Block(vec![
Stmt::Let(LHS_VALUE.to_string(), Some(Box::new(lhs)), lhs_pos),
Stmt::Expr(Box::new(parse_assignment(
lhs,
Expr::FunctionCall(
function.into(),
vec![Expr::Identifier(LHS_VALUE.to_string(), lhs_pos), rhs],
None,
pos,
),
pos,
)?)),
])),
pos,
))
*/
}
fn parse_binary_op<'a>(
2019-09-18 12:21:07 +02:00
input: &mut Peekable<TokenIterator<'a>>,
precedence: i8,
2019-09-18 12:21:07 +02:00
lhs: Expr,
) -> Result<Expr, ParseError> {
let mut current_lhs = lhs;
2016-02-29 22:43:45 +01:00
loop {
let mut current_precedence = -1;
2016-02-29 22:43:45 +01:00
if let Some(&(ref current_op, _)) = input.peek() {
current_precedence = get_precedence(current_op);
2016-02-29 22:43:45 +01:00
}
if current_precedence < precedence {
return Ok(current_lhs);
2016-02-29 22:43:45 +01:00
}
2020-02-29 13:12:10 +01:00
if let Some((op_token, pos)) = input.next() {
input.peek();
2019-09-18 12:21:07 +02:00
let mut rhs = parse_unary(input)?;
2016-02-29 22:43:45 +01:00
let mut next_precedence = -1;
2020-02-29 13:12:10 +01:00
if let Some(&(ref next_op, _)) = input.peek() {
next_precedence = get_precedence(next_op);
2016-02-29 22:43:45 +01:00
}
if current_precedence < next_precedence {
rhs = parse_binary_op(input, current_precedence + 1, rhs)?;
} else if current_precedence >= 100 {
// Always bind right to left for precedence over 100
rhs = parse_binary_op(input, current_precedence, rhs)?;
}
2016-02-29 22:43:45 +01:00
current_lhs = match op_token {
Token::Plus => Expr::FunctionCall("+".into(), vec![current_lhs, rhs], None, pos),
Token::Minus => Expr::FunctionCall("-".into(), vec![current_lhs, rhs], None, pos),
Token::Multiply => {
Expr::FunctionCall("*".into(), vec![current_lhs, rhs], None, pos)
}
Token::Divide => Expr::FunctionCall("/".into(), vec![current_lhs, rhs], None, pos),
Token::Equals => parse_assignment(current_lhs, rhs, pos)?,
2020-03-07 06:39:28 +01:00
Token::PlusAssign => parse_op_assignment("+", current_lhs, rhs, pos)?,
Token::MinusAssign => parse_op_assignment("-", current_lhs, rhs, pos)?,
Token::Period => Expr::Dot(Box::new(current_lhs), Box::new(rhs), pos),
// Comparison operators default to false when passed invalid operands
Token::EqualsTo => Expr::FunctionCall(
"==".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::NotEqualsTo => Expr::FunctionCall(
"!=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::LessThan => Expr::FunctionCall(
"<".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::LessThanEqualsTo => Expr::FunctionCall(
"<=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThan => Expr::FunctionCall(
">".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThanEqualsTo => Expr::FunctionCall(
">=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::Or => Expr::Or(Box::new(current_lhs), Box::new(rhs)),
Token::And => Expr::And(Box::new(current_lhs), Box::new(rhs)),
Token::XOr => Expr::FunctionCall("^".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::OrAssign => parse_op_assignment("|", current_lhs, rhs, pos)?,
Token::AndAssign => parse_op_assignment("&", current_lhs, rhs, pos)?,
Token::XOrAssign => parse_op_assignment("^", current_lhs, rhs, pos)?,
Token::MultiplyAssign => parse_op_assignment("*", current_lhs, rhs, pos)?,
Token::DivideAssign => parse_op_assignment("/", current_lhs, rhs, pos)?,
Token::Pipe => Expr::FunctionCall("|".into(), vec![current_lhs, rhs], None, pos),
Token::LeftShift => {
Expr::FunctionCall("<<".into(), vec![current_lhs, rhs], None, pos)
}
Token::RightShift => {
Expr::FunctionCall(">>".into(), vec![current_lhs, rhs], None, pos)
}
2020-03-07 06:39:28 +01:00
Token::LeftShiftAssign => parse_op_assignment("<<", current_lhs, rhs, pos)?,
Token::RightShiftAssign => parse_op_assignment(">>", current_lhs, rhs, pos)?,
Token::Ampersand => {
Expr::FunctionCall("&".into(), vec![current_lhs, rhs], None, pos)
}
Token::Modulo => Expr::FunctionCall("%".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::ModuloAssign => parse_op_assignment("%", current_lhs, rhs, pos)?,
Token::PowerOf => Expr::FunctionCall("~".into(), vec![current_lhs, rhs], None, pos),
2020-03-07 06:39:28 +01:00
Token::PowerOfAssign => parse_op_assignment("~", current_lhs, rhs, pos)?,
2020-03-03 16:31:29 +01:00
token => {
2020-03-04 15:00:01 +01:00
return Err(ParseError::new(
PERR::UnknownOperator(token.syntax().into()),
2020-03-03 16:31:29 +01:00
pos,
))
}
2016-02-29 22:43:45 +01:00
};
}
}
}
fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let lhs = parse_unary(input)?;
parse_binary_op(input, 0, lhs)
2016-02-29 22:43:45 +01:00
}
fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next();
2019-09-18 12:21:07 +02:00
let guard = parse_expr(input)?;
let body = parse_block(input)?;
2016-02-29 22:43:45 +01:00
2016-03-03 14:20:55 +01:00
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::Else, _)) => {
2016-03-03 14:20:55 +01:00
input.next();
2020-03-02 10:04:56 +01:00
let else_body = match input.peek() {
Some(&(Token::If, _)) => parse_if(input)?,
_ => parse_block(input)?,
};
2019-09-18 12:21:07 +02:00
Ok(Stmt::IfElse(
Box::new(guard),
Box::new(body),
2020-03-02 10:04:56 +01:00
Some(Box::new(else_body)),
2019-09-18 12:21:07 +02:00
))
2016-03-03 14:20:55 +01:00
}
2020-03-02 10:04:56 +01:00
_ => Ok(Stmt::IfElse(Box::new(guard), Box::new(body), None)),
2016-03-03 14:20:55 +01:00
}
2016-02-29 22:43:45 +01:00
}
fn parse_while<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next();
2019-09-18 12:21:07 +02:00
let guard = parse_expr(input)?;
let body = parse_block(input)?;
2016-02-29 22:43:45 +01:00
Ok(Stmt::While(Box::new(guard), Box::new(body)))
}
2017-10-30 16:08:44 +01:00
fn parse_loop<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next();
2019-09-18 12:21:07 +02:00
let body = parse_block(input)?;
2017-10-30 16:08:44 +01:00
Ok(Stmt::Loop(Box::new(body)))
}
fn parse_for<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
input.next();
let name = match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::Identifier(s), _)) => s,
2020-03-04 15:00:01 +01:00
Some((_, pos)) => return Err(ParseError::new(PERR::VarExpectsIdentifier, pos)),
None => return Err(ParseError::new(PERR::VarExpectsIdentifier, Position::eof())),
};
match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::In, _)) => {}
2020-03-04 15:00:01 +01:00
Some((_, pos)) => return Err(ParseError::new(PERR::VarExpectsIdentifier, pos)),
None => return Err(ParseError::new(PERR::VarExpectsIdentifier, Position::eof())),
}
let expr = parse_expr(input)?;
let body = parse_block(input)?;
Ok(Stmt::For(name, Box::new(expr), Box::new(body)))
}
2016-02-29 22:43:45 +01:00
fn parse_var<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
let pos = match input.next() {
Some((_, tok_pos)) => tok_pos,
2020-03-04 15:00:01 +01:00
_ => return Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())),
};
2016-02-29 22:43:45 +01:00
let name = match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::Identifier(s), _)) => s,
2020-03-04 15:00:01 +01:00
Some((_, pos)) => return Err(ParseError::new(PERR::VarExpectsIdentifier, pos)),
None => return Err(ParseError::new(PERR::VarExpectsIdentifier, Position::eof())),
2016-02-29 22:43:45 +01:00
};
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::Equals, _)) => {
2016-02-29 22:43:45 +01:00
input.next();
let init_value = parse_expr(input)?;
Ok(Stmt::Let(name, Some(Box::new(init_value)), pos))
2016-02-29 22:43:45 +01:00
}
_ => Ok(Stmt::Let(name, None, pos)),
2016-02-29 22:43:45 +01:00
}
}
fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::LeftBrace, _)) => (),
2020-03-04 15:00:01 +01:00
Some(&(_, pos)) => return Err(ParseError::new(PERR::MissingLeftBrace, pos)),
None => return Err(ParseError::new(PERR::MissingLeftBrace, Position::eof())),
2016-02-29 22:43:45 +01:00
}
input.next();
let mut statements = Vec::new();
match input.peek() {
Some(&(Token::RightBrace, _)) => (), // empty block
2020-03-04 15:00:01 +01:00
Some(&(Token::Fn, pos)) => return Err(ParseError::new(PERR::WrongFnDefinition, pos)),
_ => {
while input.peek().is_some() {
// Parse statements inside the block
statements.push(parse_stmt(input)?);
2020-03-03 11:15:20 +01:00
// Notice semicolons are optional
if let Some(&(Token::SemiColon, _)) = input.peek() {
input.next();
}
2017-10-02 23:44:45 +02:00
if let Some(&(Token::RightBrace, _)) = input.peek() {
break;
}
2019-09-18 12:21:07 +02:00
}
}
}
2016-02-29 22:43:45 +01:00
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::RightBrace, _)) => {
input.next();
Ok(Stmt::Block(statements))
}
Some(&(_, pos)) => Err(ParseError::new(
PERR::MissingRightBrace("end of block".into()),
pos,
)),
None => Err(ParseError::new(
PERR::MissingRightBrace("end of block".into()),
Position::eof(),
)),
2016-02-29 22:43:45 +01:00
}
}
fn parse_expr_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
Ok(Stmt::Expr(Box::new(parse_expr(input)?)))
2016-02-29 22:43:45 +01:00
}
fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::If, _)) => parse_if(input),
Some(&(Token::While, _)) => parse_while(input),
Some(&(Token::Loop, _)) => parse_loop(input),
Some(&(Token::For, _)) => parse_for(input),
Some(&(Token::Break, pos)) => {
input.next();
Ok(Stmt::Break(pos))
}
2020-03-03 11:15:20 +01:00
Some(&(ref token @ Token::Return, _)) | Some(&(ref token @ Token::Throw, _)) => {
let is_return = match token {
Token::Return => true,
Token::Throw => false,
_ => panic!(),
};
input.next();
2020-03-03 11:15:20 +01:00
match input.peek() {
2020-03-03 11:15:20 +01:00
// return; or throw;
Some(&(Token::SemiColon, pos)) => Ok(Stmt::ReturnWithVal(None, is_return, pos)),
// Just a return/throw without anything at the end of script
None => Ok(Stmt::ReturnWithVal(None, is_return, Position::eof())),
// return or throw with expression
Some(&(_, pos)) => {
2019-09-18 12:21:07 +02:00
let ret = parse_expr(input)?;
2020-03-03 11:15:20 +01:00
Ok(Stmt::ReturnWithVal(Some(Box::new(ret)), is_return, pos))
}
}
}
2020-02-29 13:12:10 +01:00
Some(&(Token::LeftBrace, _)) => parse_block(input),
Some(&(Token::Let, _)) => parse_var(input),
_ => parse_expr_stmt(input),
2016-02-29 22:43:45 +01:00
}
}
2020-03-07 03:15:42 +01:00
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef<'static>, ParseError> {
let pos = match input.next() {
Some((_, tok_pos)) => tok_pos,
2020-03-04 15:00:01 +01:00
_ => return Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())),
};
2016-02-29 22:43:45 +01:00
let name = match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::Identifier(s), _)) => s,
2020-03-04 15:00:01 +01:00
Some((_, pos)) => return Err(ParseError::new(PERR::FnMissingName, pos)),
None => return Err(ParseError::new(PERR::FnMissingName, Position::eof())),
};
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::LeftParen, _)) => {
input.next();
}
2020-03-04 15:00:01 +01:00
Some(&(_, pos)) => return Err(ParseError::new(PERR::FnMissingParams(name), pos)),
None => {
return Err(ParseError::new(
PERR::FnMissingParams(name),
Position::eof(),
))
}
}
let mut params = Vec::new();
2020-03-03 16:31:29 +01:00
match input.peek() {
2020-02-29 13:12:10 +01:00
Some(&(Token::RightParen, _)) => {
input.next();
}
2020-03-03 16:31:29 +01:00
_ => loop {
match input.next() {
2020-02-29 13:12:10 +01:00
Some((Token::RightParen, _)) => break,
Some((Token::Comma, _)) => (),
Some((Token::Identifier(s), _)) => {
2020-03-07 03:15:42 +01:00
params.push(s.into());
}
2020-03-04 15:00:01 +01:00
Some((_, pos)) => return Err(ParseError::new(PERR::MalformedCallExpr, pos)),
None => return Err(ParseError::new(PERR::MalformedCallExpr, Position::eof())),
}
2020-03-03 16:31:29 +01:00
},
2016-02-29 22:43:45 +01:00
}
2017-12-21 12:28:59 +01:00
let body = parse_block(input)?;
Ok(FnDef {
2020-03-07 03:15:42 +01:00
name: name.into(),
params: params,
body: Box::new(body),
pos: pos,
})
}
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {
let mut statements = Vec::new();
let mut functions = Vec::new();
while input.peek().is_some() {
2016-02-29 22:43:45 +01:00
match input.peek() {
Some(&(Token::Fn, _)) => functions.push(parse_fn(input)?),
_ => statements.push(parse_stmt(input)?),
2016-02-29 22:43:45 +01:00
}
2020-03-03 11:15:20 +01:00
// Notice semicolons are optional
2020-02-29 13:12:10 +01:00
if let Some(&(Token::SemiColon, _)) = input.peek() {
2017-10-02 23:44:45 +02:00
input.next();
2016-02-29 22:43:45 +01:00
}
}
Ok(AST(statements, functions))
2016-02-29 22:43:45 +01:00
}
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {
parse_top_level(input)
2016-02-29 22:43:45 +01:00
}