2020-03-02 07:28:42 +01:00
|
|
|
use crate::Dynamic;
|
2019-09-18 12:21:07 +02:00
|
|
|
use std::char;
|
2016-02-29 22:43:45 +01:00
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt;
|
|
|
|
use std::iter::Peekable;
|
|
|
|
use std::str::Chars;
|
|
|
|
|
2020-03-03 06:30:46 +01:00
|
|
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
2016-03-02 15:16:36 +01:00
|
|
|
pub enum LexError {
|
2020-02-24 16:25:52 +01:00
|
|
|
UnexpectedChar(char),
|
2020-02-29 14:10:31 +01:00
|
|
|
UnterminatedString,
|
2016-03-02 15:16:36 +01:00
|
|
|
MalformedEscapeSequence,
|
2016-04-14 03:40:06 +02:00
|
|
|
MalformedNumber,
|
2016-04-17 04:32:18 +02:00
|
|
|
MalformedChar,
|
2020-03-03 06:30:46 +01:00
|
|
|
InputError(String),
|
2016-03-02 15:16:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
type LERR = LexError;
|
|
|
|
|
2016-03-02 15:16:36 +01:00
|
|
|
impl Error for LexError {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match *self {
|
2020-02-24 16:25:52 +01:00
|
|
|
LERR::UnexpectedChar(_) => "Unexpected character",
|
2020-02-29 14:10:31 +01:00
|
|
|
LERR::UnterminatedString => "Open string is not terminated",
|
2020-02-24 16:25:52 +01:00
|
|
|
LERR::MalformedEscapeSequence => "Unexpected values in escape sequence",
|
|
|
|
LERR::MalformedNumber => "Unexpected characters in number",
|
|
|
|
LERR::MalformedChar => "Char constant not a single character",
|
2020-03-03 06:30:46 +01:00
|
|
|
LERR::InputError(_) => "Imput error",
|
2016-03-02 15:16:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for LexError {
|
2019-09-18 12:21:07 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-02-24 16:25:52 +01:00
|
|
|
match self {
|
|
|
|
LERR::UnexpectedChar(c) => write!(f, "Unexpected '{}'", c),
|
2020-03-03 06:30:46 +01:00
|
|
|
LERR::InputError(s) => write!(f, "{}", s),
|
2020-02-24 16:25:52 +01:00
|
|
|
_ => write!(f, "{}", self.description()),
|
|
|
|
}
|
2016-03-02 15:16:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum ParseErrorType {
|
|
|
|
BadInput(String),
|
2016-02-29 22:43:45 +01:00
|
|
|
InputPastEndOfFile,
|
|
|
|
UnknownOperator,
|
2020-02-24 16:25:52 +01:00
|
|
|
MissingRightParen,
|
|
|
|
MissingLeftBrace,
|
|
|
|
MissingRightBrace,
|
|
|
|
MissingRightBracket,
|
2016-02-29 22:43:45 +01:00
|
|
|
MalformedCallExpr,
|
2016-03-26 18:46:28 +01:00
|
|
|
MalformedIndexExpr,
|
2020-03-02 15:13:14 +01:00
|
|
|
VarExpectsIdentifier,
|
|
|
|
FnMissingName,
|
2016-04-17 04:32:18 +02:00
|
|
|
FnMissingParams,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
2020-03-01 06:30:22 +01:00
|
|
|
type PERR = ParseErrorType;
|
|
|
|
|
2020-03-03 06:30:46 +01:00
|
|
|
const MAX_LINES: u16 = 65535;
|
|
|
|
const MAX_POS: u16 = 65535;
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
|
2020-02-29 13:12:10 +01:00
|
|
|
pub struct Position {
|
2020-03-03 06:30:46 +01:00
|
|
|
line: u16,
|
|
|
|
pos: u16,
|
2020-02-29 13:12:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Position {
|
2020-03-03 06:30:46 +01:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Self { line: 1, pos: 0 }
|
2020-02-29 13:12:10 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
|
|
|
|
pub fn line(&self) -> u16 {
|
|
|
|
self.line
|
2020-02-29 14:10:31 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
|
|
|
|
pub fn position(&self) -> u16 {
|
|
|
|
self.pos
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn advance(&mut self) -> Result<u16, LexError> {
|
|
|
|
if self.pos >= MAX_POS {
|
|
|
|
Err(LERR::InputError(format!(
|
|
|
|
"cannot advance beyond maximum line length ({})",
|
|
|
|
MAX_POS
|
|
|
|
)))
|
|
|
|
} else {
|
|
|
|
self.pos += 1;
|
|
|
|
Ok(self.pos)
|
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
|
|
|
|
pub(crate) fn rewind(&mut self) -> Result<u16, LexError> {
|
|
|
|
if self.pos == 0 {
|
|
|
|
Err(LERR::InputError("cannot rewind at position 0".into()))
|
|
|
|
} else {
|
|
|
|
self.pos -= 1;
|
|
|
|
Ok(self.pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn new_line(&mut self) -> Result<u16, LexError> {
|
|
|
|
if self.line > MAX_LINES {
|
|
|
|
Err(LERR::InputError(format!(
|
|
|
|
"reached maximum number of lines ({})",
|
|
|
|
MAX_LINES
|
|
|
|
)))
|
|
|
|
} else {
|
|
|
|
self.line += 1;
|
|
|
|
self.pos = 0;
|
|
|
|
|
|
|
|
Ok(self.pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 15:13:14 +01:00
|
|
|
pub fn eof() -> Self {
|
2020-02-29 13:12:10 +01:00
|
|
|
Self { line: 0, pos: 0 }
|
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
|
2020-03-02 15:13:14 +01:00
|
|
|
pub fn is_eof(&self) -> bool {
|
|
|
|
self.line == 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for Position {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
|
2020-03-03 06:30:46 +01:00
|
|
|
if self.is_eof() {
|
|
|
|
write!(f, "EOF")
|
|
|
|
} else {
|
|
|
|
write!(f, "line {}, position {}", self.line, self.pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Position {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
if self.is_eof() {
|
|
|
|
write!(f, "(EOF)")
|
|
|
|
} else {
|
|
|
|
write!(f, "({}:{})", self.line, self.pos)
|
2020-03-02 15:13:14 +01:00
|
|
|
}
|
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2020-03-01 06:30:22 +01:00
|
|
|
pub struct ParseError(PERR, Position);
|
2020-02-24 16:25:52 +01:00
|
|
|
|
|
|
|
impl ParseError {
|
2020-03-01 06:30:22 +01:00
|
|
|
pub fn error_type(&self) -> &PERR {
|
2020-02-24 16:25:52 +01:00
|
|
|
&self.0
|
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
pub fn line(&self) -> u16 {
|
|
|
|
self.1.line()
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
pub fn position(&self) -> u16 {
|
|
|
|
self.1.position()
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
pub fn is_eof(&self) -> bool {
|
|
|
|
self.1.is_eof()
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
impl Error for ParseError {
|
|
|
|
fn description(&self) -> &str {
|
2020-02-24 16:25:52 +01:00
|
|
|
match self.0 {
|
|
|
|
PERR::BadInput(ref p) => p,
|
|
|
|
PERR::InputPastEndOfFile => "Script is incomplete",
|
|
|
|
PERR::UnknownOperator => "Unknown operator",
|
|
|
|
PERR::MissingRightParen => "Expecting ')'",
|
|
|
|
PERR::MissingLeftBrace => "Expecting '{'",
|
|
|
|
PERR::MissingRightBrace => "Expecting '}'",
|
|
|
|
PERR::MissingRightBracket => "Expecting ']'",
|
|
|
|
PERR::MalformedCallExpr => "Invalid expression in function call arguments",
|
|
|
|
PERR::MalformedIndexExpr => "Invalid index in indexing expression",
|
2020-03-02 15:13:14 +01:00
|
|
|
PERR::VarExpectsIdentifier => "Expecting name of a variable",
|
|
|
|
PERR::FnMissingName => "Expecting name in function declaration",
|
2020-02-24 16:25:52 +01:00
|
|
|
PERR::FnMissingParams => "Expecting parameters in function declaration",
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:21:07 +02:00
|
|
|
fn cause(&self) -> Option<&dyn Error> {
|
|
|
|
None
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ParseError {
|
2019-09-18 12:21:07 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-02-24 16:25:52 +01:00
|
|
|
match self.0 {
|
2020-03-02 15:13:14 +01:00
|
|
|
PERR::BadInput(ref s) => write!(f, "{}", s)?,
|
2020-02-24 16:25:52 +01:00
|
|
|
_ => write!(f, "{}", self.description())?,
|
|
|
|
}
|
|
|
|
|
2020-03-02 15:13:14 +01:00
|
|
|
if !self.is_eof() {
|
|
|
|
write!(f, " ({})", self.1)
|
2020-02-24 16:25:52 +01:00
|
|
|
} else {
|
2020-02-29 14:10:31 +01:00
|
|
|
write!(f, " at the end of the script but there is no more input")
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
pub struct AST(pub(crate) Vec<Stmt>, pub(crate) Vec<FnDef>);
|
|
|
|
|
2020-03-02 07:28:42 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-03-01 21:16:10 +01:00
|
|
|
pub struct FnDef {
|
|
|
|
pub name: String,
|
|
|
|
pub params: Vec<String>,
|
2016-04-17 04:32:18 +02:00
|
|
|
pub body: Box<Stmt>,
|
2020-03-02 15:13:14 +01:00
|
|
|
pub pos: Position,
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
2020-03-02 07:28:42 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Stmt {
|
2020-03-02 10:04:56 +01:00
|
|
|
IfElse(Box<Expr>, Box<Stmt>, Option<Box<Stmt>>),
|
2016-04-17 04:32:18 +02:00
|
|
|
While(Box<Expr>, Box<Stmt>),
|
2017-10-30 16:08:44 +01:00
|
|
|
Loop(Box<Stmt>),
|
2020-02-23 15:48:46 +01:00
|
|
|
For(String, Box<Expr>, Box<Stmt>),
|
2020-03-02 15:13:14 +01:00
|
|
|
Let(String, Option<Box<Expr>>, Position),
|
2017-10-02 23:44:45 +02:00
|
|
|
Block(Vec<Stmt>),
|
2016-04-17 04:32:18 +02:00
|
|
|
Expr(Box<Expr>),
|
2020-03-02 15:13:14 +01:00
|
|
|
Break(Position),
|
|
|
|
Return(Position),
|
|
|
|
ReturnWithVal(Box<Expr>, Position),
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2020-03-02 07:28:42 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Expr {
|
2020-03-02 15:13:14 +01:00
|
|
|
IntegerConstant(i64, Position),
|
|
|
|
FloatConstant(f64, Position),
|
|
|
|
Identifier(String, Position),
|
|
|
|
CharConstant(char, Position),
|
|
|
|
StringConstant(String, Position),
|
|
|
|
FunctionCall(String, Vec<Expr>, Option<Dynamic>, Position),
|
2016-04-17 04:32:18 +02:00
|
|
|
Assignment(Box<Expr>, Box<Expr>),
|
|
|
|
Dot(Box<Expr>, Box<Expr>),
|
2020-03-02 15:13:14 +01:00
|
|
|
Index(String, 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>),
|
2020-03-02 15:13:14 +01:00
|
|
|
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)
|
|
|
|
| Expr::Index(_, _, pos)
|
|
|
|
| Expr::Array(_, pos)
|
|
|
|
| Expr::True(pos)
|
|
|
|
| Expr::False(pos)
|
|
|
|
| Expr::Unit(pos) => *pos,
|
|
|
|
|
|
|
|
Expr::Assignment(_, _) | Expr::Dot(_, _) | Expr::And(_, _) | Expr::Or(_, _) => panic!(),
|
|
|
|
}
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Token {
|
2020-02-24 16:25:52 +01:00
|
|
|
IntegerConstant(i64),
|
|
|
|
FloatConstant(f64),
|
2016-04-17 04:32:18 +02:00
|
|
|
Identifier(String),
|
2020-02-24 16:25:52 +01:00
|
|
|
CharConstant(char),
|
2016-04-17 04:32:18 +02:00
|
|
|
StringConst(String),
|
2020-02-24 16:25:52 +01:00
|
|
|
LeftBrace,
|
|
|
|
RightBrace,
|
|
|
|
LeftParen,
|
|
|
|
RightParen,
|
|
|
|
LeftBracket,
|
|
|
|
RightBracket,
|
2016-04-17 04:32:18 +02:00
|
|
|
Plus,
|
2017-10-30 16:08:44 +01:00
|
|
|
UnaryPlus,
|
2016-04-17 04:32:18 +02:00
|
|
|
Minus,
|
2017-10-30 16:08:44 +01:00
|
|
|
UnaryMinus,
|
2016-04-17 04:32:18 +02:00
|
|
|
Multiply,
|
|
|
|
Divide,
|
2020-02-24 16:25:52 +01:00
|
|
|
SemiColon,
|
2016-04-17 04:32:18 +02:00
|
|
|
Colon,
|
|
|
|
Comma,
|
|
|
|
Period,
|
|
|
|
Equals,
|
|
|
|
True,
|
|
|
|
False,
|
2020-02-24 16:25:52 +01:00
|
|
|
Let,
|
2016-04-17 04:32:18 +02:00
|
|
|
If,
|
|
|
|
Else,
|
|
|
|
While,
|
2017-10-30 16:08:44 +01:00
|
|
|
Loop,
|
2016-04-17 04:32:18 +02:00
|
|
|
LessThan,
|
|
|
|
GreaterThan,
|
|
|
|
Bang,
|
2020-02-24 16:25:52 +01:00
|
|
|
LessThanEqualsTo,
|
|
|
|
GreaterThanEqualsTo,
|
|
|
|
EqualsTo,
|
|
|
|
NotEqualsTo,
|
2016-04-17 04:32:18 +02:00
|
|
|
Pipe,
|
|
|
|
Or,
|
|
|
|
Ampersand,
|
|
|
|
And,
|
|
|
|
Fn,
|
|
|
|
Break,
|
|
|
|
Return,
|
2017-12-21 12:32:18 +01:00
|
|
|
PlusAssign,
|
|
|
|
MinusAssign,
|
|
|
|
MultiplyAssign,
|
|
|
|
DivideAssign,
|
|
|
|
LeftShiftAssign,
|
|
|
|
RightShiftAssign,
|
|
|
|
AndAssign,
|
|
|
|
OrAssign,
|
|
|
|
XOrAssign,
|
2017-10-31 06:55:20 +01:00
|
|
|
LeftShift,
|
|
|
|
RightShift,
|
|
|
|
XOr,
|
2017-10-31 23:06:13 +01:00
|
|
|
Modulo,
|
2017-12-21 12:32:18 +01:00
|
|
|
ModuloAssign,
|
2017-11-24 08:56:22 +01:00
|
|
|
PowerOf,
|
2017-12-21 12:32:18 +01:00
|
|
|
PowerOfAssign,
|
2020-02-23 15:48:46 +01:00
|
|
|
For,
|
|
|
|
In,
|
2016-04-17 04:32:18 +02:00
|
|
|
LexErr(LexError),
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
impl Token {
|
|
|
|
// 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 {
|
2020-02-24 16:25:52 +01:00
|
|
|
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 |
|
2020-02-24 16:25:52 +01:00
|
|
|
LessThanEqualsTo |
|
|
|
|
GreaterThanEqualsTo |
|
|
|
|
EqualsTo |
|
|
|
|
NotEqualsTo |
|
2017-10-30 16:08:44 +01:00
|
|
|
Pipe |
|
|
|
|
Or |
|
|
|
|
Ampersand |
|
|
|
|
And |
|
|
|
|
If |
|
|
|
|
While |
|
2017-12-21 12:32:18 +01:00
|
|
|
PlusAssign |
|
|
|
|
MinusAssign |
|
|
|
|
MultiplyAssign |
|
|
|
|
DivideAssign |
|
|
|
|
LeftShiftAssign |
|
|
|
|
RightShiftAssign |
|
|
|
|
AndAssign |
|
|
|
|
OrAssign |
|
|
|
|
XOrAssign |
|
2017-11-01 23:09:07 +01:00
|
|
|
LeftShift |
|
|
|
|
RightShift |
|
|
|
|
XOr |
|
|
|
|
Modulo |
|
2017-12-21 12:32:18 +01:00
|
|
|
ModuloAssign |
|
2017-11-24 08:56:22 +01:00
|
|
|
Return |
|
|
|
|
PowerOf |
|
2020-02-23 15:48:46 +01:00
|
|
|
In |
|
2017-12-21 12:32:18 +01:00
|
|
|
PowerOfAssign => true,
|
2017-10-30 16:08:44 +01:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn is_bin_op(&self) -> bool {
|
|
|
|
use self::Token::*;
|
|
|
|
|
|
|
|
match *self {
|
2020-02-24 16:25:52 +01:00
|
|
|
RightBrace |
|
|
|
|
RightParen |
|
|
|
|
RightBracket |
|
2017-10-30 16:08:44 +01:00
|
|
|
Plus |
|
|
|
|
Minus |
|
|
|
|
Multiply |
|
|
|
|
Divide |
|
|
|
|
Comma |
|
|
|
|
// Period | <- does period count?
|
|
|
|
Equals |
|
|
|
|
LessThan |
|
|
|
|
GreaterThan |
|
2020-02-24 16:25:52 +01:00
|
|
|
LessThanEqualsTo |
|
|
|
|
GreaterThanEqualsTo |
|
|
|
|
EqualsTo |
|
|
|
|
NotEqualsTo |
|
2017-10-30 16:08:44 +01:00
|
|
|
Pipe |
|
|
|
|
Or |
|
|
|
|
Ampersand |
|
2017-11-24 08:56:22 +01:00
|
|
|
And |
|
|
|
|
PowerOf => true,
|
2017-10-30 16:08:44 +01:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub fn is_un_op(&self) -> bool {
|
|
|
|
use self::Token::*;
|
|
|
|
|
|
|
|
match *self {
|
2019-09-18 12:21:07 +02:00
|
|
|
UnaryPlus | UnaryMinus | Equals | Bang | Return => 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,
|
2016-04-17 04:32:18 +02:00
|
|
|
char_stream: Peekable<Chars<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TokenIterator<'a> {
|
2020-03-03 06:30:46 +01:00
|
|
|
fn advance(&mut self) -> Result<u16, (LexError, Position)> {
|
|
|
|
self.pos.advance().map_err(|err| (err, self.pos))
|
|
|
|
}
|
|
|
|
fn rewind(&mut self) -> Result<u16, (LexError, Position)> {
|
|
|
|
self.pos.rewind().map_err(|err| (err, self.pos))
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
fn new_line(&mut self) -> Result<u16, (LexError, Position)> {
|
|
|
|
self.pos.new_line().map_err(|err| (err, self.pos))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn advance_token(&mut self) -> Result<u16, (Token, Position)> {
|
|
|
|
self.advance().map_err(|err| (Token::LexErr(err.0), err.1))
|
2020-02-29 14:10:31 +01:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
fn new_line_token(&mut self) -> Result<u16, (Token, Position)> {
|
|
|
|
self.new_line().map_err(|err| (Token::LexErr(err.0), err.1))
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_string_const(
|
|
|
|
&mut self,
|
|
|
|
enclosing_char: char,
|
2020-02-29 13:12:10 +01:00
|
|
|
) -> Result<String, (LexError, Position)> {
|
2016-04-17 04:32:18 +02:00
|
|
|
let mut result = Vec::new();
|
|
|
|
let mut escape = false;
|
|
|
|
|
2020-02-29 14:10:31 +01:00
|
|
|
loop {
|
|
|
|
let next_char = self.char_stream.next();
|
|
|
|
|
|
|
|
if next_char.is_none() {
|
|
|
|
return Err((LERR::UnterminatedString, Position::eof()));
|
|
|
|
}
|
|
|
|
|
2020-03-03 06:30:46 +01:00
|
|
|
self.advance()?;
|
2020-02-24 16:25:52 +01:00
|
|
|
|
2020-02-29 14:10:31 +01:00
|
|
|
match next_char.unwrap() {
|
2016-04-17 04:32:18 +02:00
|
|
|
'\\' if !escape => escape = true,
|
|
|
|
'\\' if escape => {
|
|
|
|
escape = false;
|
|
|
|
result.push('\\');
|
|
|
|
}
|
|
|
|
't' if escape => {
|
|
|
|
escape = false;
|
|
|
|
result.push('\t');
|
|
|
|
}
|
|
|
|
'n' if escape => {
|
|
|
|
escape = false;
|
|
|
|
result.push('\n');
|
|
|
|
}
|
|
|
|
'r' if escape => {
|
|
|
|
escape = false;
|
|
|
|
result.push('\r');
|
|
|
|
}
|
|
|
|
'x' if escape => {
|
|
|
|
escape = false;
|
|
|
|
let mut out_val: u32 = 0;
|
|
|
|
for _ in 0..2 {
|
|
|
|
if let Some(c) = self.char_stream.next() {
|
|
|
|
if let Some(d1) = c.to_digit(16) {
|
|
|
|
out_val *= 16;
|
|
|
|
out_val += d1;
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
self.advance()?;
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
'u' if escape => {
|
|
|
|
escape = false;
|
|
|
|
let mut out_val: u32 = 0;
|
|
|
|
for _ in 0..4 {
|
|
|
|
if let Some(c) = self.char_stream.next() {
|
|
|
|
if let Some(d1) = c.to_digit(16) {
|
|
|
|
out_val *= 16;
|
|
|
|
out_val += d1;
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
self.advance()?;
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
'U' if escape => {
|
|
|
|
escape = false;
|
|
|
|
let mut out_val: u32 = 0;
|
|
|
|
for _ in 0..8 {
|
|
|
|
if let Some(c) = self.char_stream.next() {
|
|
|
|
if let Some(d1) = c.to_digit(16) {
|
|
|
|
out_val *= 16;
|
|
|
|
out_val += d1;
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
self.advance()?;
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Err((LERR::MalformedEscapeSequence, self.pos));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
x if enclosing_char == x && escape => result.push(x),
|
|
|
|
x if enclosing_char == x && !escape => break,
|
2020-02-29 13:12:10 +01:00
|
|
|
_ if escape => return Err((LERR::MalformedEscapeSequence, self.pos)),
|
2020-02-29 14:10:31 +01:00
|
|
|
'\n' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
self.rewind()?;
|
2020-02-29 14:10:31 +01:00
|
|
|
return Err((LERR::UnterminatedString, self.pos));
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
x => {
|
2016-04-17 04:32:18 +02:00
|
|
|
escape = false;
|
2020-02-24 16:25:52 +01:00
|
|
|
result.push(x);
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let out: String = result.iter().cloned().collect();
|
|
|
|
Ok(out)
|
|
|
|
}
|
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() {
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
|
|
|
|
let pos = self.pos;
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
match c {
|
2020-03-03 06:30:46 +01:00
|
|
|
'\n' => {
|
|
|
|
if let Err(err) = self.new_line_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
}
|
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);
|
|
|
|
|
2020-03-03 06:30:46 +01:00
|
|
|
while let Some(&next_char) = self.char_stream.peek() {
|
|
|
|
match next_char {
|
2019-09-18 12:21:07 +02:00
|
|
|
'0'..='9' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char);
|
2016-04-17 04:32:18 +02:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2017-10-30 04:32:41 +01:00
|
|
|
'.' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char);
|
2017-10-30 04:32:41 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
while let Some(&next_char_in_float) = self.char_stream.peek() {
|
|
|
|
match next_char_in_float {
|
2019-09-18 12:21:07 +02:00
|
|
|
'0'..='9' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char_in_float);
|
2017-10-30 04:32:41 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2017-10-30 04:32:41 +01:00
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-01 06:02:36 +01:00
|
|
|
'x' | 'X' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
while let Some(&next_char_in_hex) = self.char_stream.peek() {
|
|
|
|
match next_char_in_hex {
|
2019-09-18 12:21:07 +02:00
|
|
|
'0'..='9' | 'a'..='f' | 'A'..='F' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char_in_hex);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
'o' | 'O' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
while let Some(&next_char_in_oct) = self.char_stream.peek() {
|
|
|
|
match next_char_in_oct {
|
2019-09-18 12:21:07 +02:00
|
|
|
'0'..='8' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char_in_oct);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
'b' | 'B' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
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' | '_' => {
|
2020-03-03 06:30:46 +01:00
|
|
|
result.push(next_char_in_binary);
|
2017-11-01 06:02:36 +01:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => break,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-01 06:10:46 +01:00
|
|
|
if let Some(radix) = radix_base {
|
2019-09-18 12:21:07 +02:00
|
|
|
let out: String = result
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.skip(2)
|
|
|
|
.filter(|c| c != &'_')
|
|
|
|
.collect();
|
2020-03-03 06:30:46 +01:00
|
|
|
|
2017-11-01 06:10:46 +01:00
|
|
|
if let Ok(val) = i64::from_str_radix(&out, radix) {
|
2020-02-29 13:12:10 +01:00
|
|
|
return Some((Token::IntegerConstant(val), pos));
|
2017-11-01 06:10:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
let out: String = result.iter().cloned().collect();
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2020-02-24 16:25:52 +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::LexErr(LERR::MalformedNumber)
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
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);
|
|
|
|
|
2020-03-03 06:30:46 +01:00
|
|
|
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);
|
2016-04-17 04:32:18 +02:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
_ => break,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
let out: String = result.iter().cloned().collect();
|
2020-02-24 16:25:52 +01:00
|
|
|
|
|
|
|
return Some((
|
2020-03-02 05:08:03 +01:00
|
|
|
match out.as_str() {
|
2020-02-24 16:25:52 +01:00
|
|
|
"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,
|
|
|
|
"fn" => Token::Fn,
|
|
|
|
"for" => Token::For,
|
|
|
|
"in" => Token::In,
|
2020-02-29 13:12:10 +01:00
|
|
|
x => Token::Identifier(x.into()),
|
2020-02-24 16:25:52 +01:00
|
|
|
},
|
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
'"' => {
|
|
|
|
return match self.parse_string_const('"') {
|
2020-02-29 13:12:10 +01:00
|
|
|
Ok(out) => Some((Token::StringConst(out), pos)),
|
|
|
|
Err(e) => Some((Token::LexErr(e.0), e.1)),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
'\'' => match self.parse_string_const('\'') {
|
|
|
|
Ok(result) => {
|
|
|
|
let mut chars = result.chars();
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
return Some((
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Some(first_char) = chars.next() {
|
2020-02-24 16:25:52 +01:00
|
|
|
if chars.count() != 0 {
|
|
|
|
Token::LexErr(LERR::MalformedChar)
|
|
|
|
} else {
|
2020-03-03 06:30:46 +01:00
|
|
|
Token::CharConstant(first_char)
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Token::LexErr(LERR::MalformedChar)
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
));
|
2016-04-14 03:40:06 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Err(e) => return Some((Token::LexErr(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
|
|
|
'+' => {
|
2020-02-24 16:25:52 +01:00
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
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
|
|
|
'-' => {
|
2020-02-24 16:25:52 +01:00
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::MinusAssign
|
|
|
|
}
|
|
|
|
_ if self.last.is_next_unary() => Token::UnaryMinus,
|
|
|
|
_ => Token::Minus,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
'*' => {
|
2020-02-24 16:25:52 +01:00
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::MultiplyAssign
|
|
|
|
}
|
|
|
|
_ => Token::Multiply,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
|
|
|
'/' => match self.char_stream.peek() {
|
|
|
|
Some(&'/') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
while let Some(c) = self.char_stream.next() {
|
2020-03-03 06:30:46 +01:00
|
|
|
match c {
|
|
|
|
'\n' => {
|
|
|
|
if let Err(err) = self.new_line_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
}
|
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();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
while let Some(c) = self.char_stream.next() {
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
|
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
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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
|
|
|
}
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'\n' => {
|
|
|
|
if let Err(err) = self.new_line_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2017-10-30 16:08:44 +01:00
|
|
|
}
|
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();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((Token::LeftShiftAssign, pos))
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
_ => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
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
|
|
|
},
|
2020-02-24 16:25:52 +01:00
|
|
|
'>' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
2019-09-18 12:21:07 +02:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::GreaterThanEqualsTo
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Some(&'>') => {
|
2019-09-18 12:21:07 +02:00
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::RightShiftAssign
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::RightShift
|
|
|
|
}
|
|
|
|
}
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
_ => Token::GreaterThan,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'!' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::NotEqualsTo
|
|
|
|
}
|
|
|
|
_ => Token::Bang,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'|' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'|') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::Or
|
|
|
|
}
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::OrAssign
|
|
|
|
}
|
|
|
|
_ => Token::Pipe,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'&' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'&') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::And
|
|
|
|
}
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::AndAssign
|
|
|
|
}
|
|
|
|
_ => Token::Ampersand,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'^' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::XOrAssign
|
|
|
|
}
|
|
|
|
_ => Token::XOr,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'%' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::ModuloAssign
|
|
|
|
}
|
|
|
|
_ => Token::Modulo,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
'~' => {
|
|
|
|
return Some((
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2020-03-03 06:30:46 +01:00
|
|
|
if let Err(err) = self.advance_token() {
|
|
|
|
return Some(err);
|
|
|
|
}
|
2020-02-24 16:25:52 +01:00
|
|
|
Token::PowerOfAssign
|
|
|
|
}
|
|
|
|
_ => Token::PowerOf,
|
|
|
|
},
|
|
|
|
pos,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
x if x.is_whitespace() => (),
|
2020-02-29 13:12:10 +01:00
|
|
|
x => return Some((Token::LexErr(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> {
|
2020-02-24 16:25:52 +01:00
|
|
|
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-03 06:30:46 +01:00
|
|
|
last: Token::LexErr(LERR::InputError("".into())),
|
2020-02-29 13:12:10 +01:00
|
|
|
pos: Position { line: 1, pos: 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
|
2017-12-21 12:32:18 +01:00
|
|
|
| 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
|
2020-02-24 16:25:52 +01:00
|
|
|
| Token::LessThanEqualsTo
|
2017-10-02 23:44:45 +02:00
|
|
|
| Token::GreaterThan
|
2020-02-24 16:25:52 +01:00
|
|
|
| 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,
|
2017-10-31 23:06:13 +01:00
|
|
|
Token::Modulo => 60,
|
2016-03-07 21:39:02 +01:00
|
|
|
Token::Period => 100,
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => -1,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 15:13:14 +01:00
|
|
|
fn parse_paren_expr<'a>(
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>,
|
|
|
|
begin: Position,
|
|
|
|
) -> Result<Expr, ParseError> {
|
2020-02-24 16:25:52 +01:00
|
|
|
match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((Token::RightParen, _)) => {
|
2020-02-24 16:25:52 +01:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
return Ok(Expr::Unit(begin));
|
2020-02-24 16:25:52 +01:00
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
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),
|
|
|
|
_ => Err(ParseError(PERR::MissingRightParen, 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>>,
|
2020-03-02 15:13:14 +01:00
|
|
|
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();
|
2020-03-02 15:13:14 +01:00
|
|
|
return Ok(Expr::FunctionCall(id, args, None, begin));
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
2020-02-29 14:10:31 +01:00
|
|
|
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, _)) => {
|
2016-03-01 21:16:10 +01:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
return Ok(Expr::FunctionCall(id, args, None, begin));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::Comma, _)) => (),
|
|
|
|
Some(&(_, pos)) => return Err(ParseError(PERR::MalformedCallExpr, pos)),
|
|
|
|
None => return Err(ParseError(PERR::MalformedCallExpr, 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>(
|
|
|
|
id: String,
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>,
|
2020-03-02 15:13:14 +01:00
|
|
|
begin: Position,
|
2019-09-18 12:21:07 +02:00
|
|
|
) -> Result<Expr, ParseError> {
|
2020-02-24 16:25:52 +01:00
|
|
|
match parse_expr(input) {
|
|
|
|
Ok(idx) => match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightBracket, _)) => {
|
2016-03-26 18:46:28 +01:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
return Ok(Expr::Index(id, Box::new(idx), begin));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(_, pos)) => return Err(ParseError(PERR::MalformedIndexExpr, pos)),
|
|
|
|
None => return Err(ParseError(PERR::MalformedIndexExpr, Position::eof())),
|
2020-02-24 16:25:52 +01:00
|
|
|
},
|
|
|
|
Err(mut err) => {
|
|
|
|
err.0 = PERR::MalformedIndexExpr;
|
|
|
|
return Err(err);
|
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>>,
|
2020-03-02 15:13:14 +01:00
|
|
|
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-02 15:13:14 +01:00
|
|
|
Some(&(Token::LeftParen, pos)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
parse_call_expr(id, input, pos)
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
Some(&(Token::LeftBracket, pos)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
parse_index_expr(id, input, pos)
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
Some(_) => Ok(Expr::Identifier(id, begin)),
|
|
|
|
None => Ok(Expr::Identifier(id, Position::eof())),
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 15:13:14 +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();
|
|
|
|
|
|
|
|
let skip_contents = match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightBracket, _)) => true,
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => false,
|
2016-03-26 18:46:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_contents {
|
|
|
|
while let Some(_) = input.peek() {
|
2019-09-18 12:21:07 +02:00
|
|
|
arr.push(parse_expr(input)?);
|
2020-03-02 15:13:14 +01:00
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some(&(Token::Comma, _)) = input.peek() {
|
2017-10-02 23:44:45 +02:00
|
|
|
input.next();
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some(&(Token::RightBracket, _)) = input.peek() {
|
2019-09-18 12:21:07 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
}
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightBracket, _)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
Ok(Expr::Array(arr, begin))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(_, pos)) => Err(ParseError(PERR::MissingRightBracket, pos)),
|
|
|
|
None => Err(ParseError(PERR::MissingRightBracket, 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-02-24 16:25:52 +01:00
|
|
|
match input.next() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((token, pos)) => match token {
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::IntegerConstant(x) => Ok(Expr::IntegerConstant(x, pos)),
|
|
|
|
Token::FloatConstant(x) => Ok(Expr::FloatConstant(x, pos)),
|
|
|
|
Token::StringConst(s) => Ok(Expr::StringConstant(s, pos)),
|
|
|
|
Token::CharConstant(c) => Ok(Expr::CharConstant(c, pos)),
|
|
|
|
Token::Identifier(s) => parse_ident_expr(s, input, pos),
|
|
|
|
Token::LeftParen => parse_paren_expr(input, pos),
|
|
|
|
Token::LeftBracket => parse_array_expr(input, pos),
|
|
|
|
Token::True => Ok(Expr::True(pos)),
|
|
|
|
Token::False => Ok(Expr::False(pos)),
|
2020-02-29 13:12:10 +01:00
|
|
|
Token::LexErr(le) => Err(ParseError(PERR::BadInput(le.to_string()), pos)),
|
2020-02-24 16:25:52 +01:00
|
|
|
_ => Err(ParseError(
|
|
|
|
PERR::BadInput(format!("Unexpected {:?} token", token)),
|
|
|
|
pos,
|
|
|
|
)),
|
|
|
|
},
|
2020-02-29 13:12:10 +01:00
|
|
|
None => Err(ParseError(PERR::InputPastEndOfFile, Position::eof())),
|
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> {
|
2020-03-02 15:13:14 +01:00
|
|
|
let (token, pos) = match input.peek() {
|
|
|
|
Some((tok, tok_pos)) => (tok.clone(), *tok_pos),
|
2020-02-29 13:12:10 +01:00
|
|
|
None => return Err(ParseError(PERR::InputPastEndOfFile, Position::eof())),
|
2017-10-30 16:08:44 +01:00
|
|
|
};
|
2017-10-31 06:55:20 +01:00
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
match token {
|
2019-09-18 12:21:07 +02:00
|
|
|
Token::UnaryMinus => {
|
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
|
2020-03-02 07:28:42 +01:00
|
|
|
Ok(Expr::FunctionCall(
|
|
|
|
"-".into(),
|
|
|
|
vec![parse_primary(input)?],
|
|
|
|
None,
|
2020-03-02 15:13:14 +01:00
|
|
|
pos,
|
2020-03-02 07:28:42 +01:00
|
|
|
))
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
|
|
|
Token::UnaryPlus => {
|
|
|
|
input.next();
|
|
|
|
parse_primary(input)
|
|
|
|
}
|
|
|
|
Token::Bang => {
|
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
|
2020-03-02 07:28:42 +01:00
|
|
|
Ok(Expr::FunctionCall(
|
|
|
|
"!".into(),
|
|
|
|
vec![parse_primary(input)?],
|
|
|
|
Some(Box::new(false)), // NOT operator, when operating on invalid operand, defaults to false
|
2020-03-02 15:13:14 +01:00
|
|
|
pos,
|
2020-03-02 07:28:42 +01:00
|
|
|
))
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
|
|
|
_ => parse_primary(input),
|
2017-10-30 16:08:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:21:07 +02:00
|
|
|
fn parse_binop<'a>(
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>,
|
2020-02-29 14:18:48 +01:00
|
|
|
prec: i8,
|
2019-09-18 12:21:07 +02:00
|
|
|
lhs: Expr,
|
|
|
|
) -> Result<Expr, ParseError> {
|
2016-02-29 22:43:45 +01:00
|
|
|
let mut lhs_curr = lhs;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let mut curr_prec = -1;
|
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some(&(ref curr_op, _)) = input.peek() {
|
2016-02-29 22:43:45 +01:00
|
|
|
curr_prec = get_precedence(curr_op);
|
|
|
|
}
|
|
|
|
|
|
|
|
if curr_prec < prec {
|
|
|
|
return Ok(lhs_curr);
|
|
|
|
}
|
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some((op_token, pos)) = input.next() {
|
2020-03-02 15:13:14 +01:00
|
|
|
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_prec = -1;
|
2016-04-14 03:01:08 +02:00
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some(&(ref next_op, _)) = input.peek() {
|
2016-02-29 22:43:45 +01:00
|
|
|
next_prec = get_precedence(next_op);
|
|
|
|
}
|
|
|
|
|
|
|
|
if curr_prec < next_prec {
|
2019-09-18 12:21:07 +02:00
|
|
|
rhs = parse_binop(input, curr_prec + 1, rhs)?;
|
2016-04-17 04:32:18 +02:00
|
|
|
} else if curr_prec >= 100 {
|
|
|
|
// Always bind right to left for precedence over 100
|
2019-09-18 12:21:07 +02:00
|
|
|
rhs = parse_binop(input, curr_prec, rhs)?;
|
2016-03-07 21:39:02 +01:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
|
|
|
lhs_curr = match op_token {
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::Plus => Expr::FunctionCall("+".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::Minus => Expr::FunctionCall("-".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::Multiply => Expr::FunctionCall("*".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::Divide => Expr::FunctionCall("/".into(), vec![lhs_curr, rhs], None, pos),
|
2020-03-02 07:28:42 +01:00
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
2019-09-18 12:21:07 +02:00
|
|
|
Token::PlusAssign => {
|
2017-10-30 16:08:44 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"+".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-30 16:08:44 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
|
|
|
Token::MinusAssign => {
|
2017-10-30 16:08:44 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"-".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-30 16:08:44 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2016-03-07 21:39:02 +01:00
|
|
|
Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)),
|
2020-03-02 07:28:42 +01:00
|
|
|
|
|
|
|
// Comparison operators default to false when passed invalid operands
|
|
|
|
Token::EqualsTo => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall("==".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
Token::NotEqualsTo => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall("!=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
Token::LessThan => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall("<".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
Token::LessThanEqualsTo => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall("<=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
Token::GreaterThan => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall(">".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
Token::GreaterThanEqualsTo => {
|
2020-03-02 15:13:14 +01:00
|
|
|
Expr::FunctionCall(">=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos)
|
2020-03-02 07:28:42 +01:00
|
|
|
}
|
|
|
|
|
2020-03-02 05:08:03 +01:00
|
|
|
Token::Or => Expr::Or(Box::new(lhs_curr), Box::new(rhs)),
|
|
|
|
Token::And => Expr::And(Box::new(lhs_curr), Box::new(rhs)),
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::XOr => Expr::FunctionCall("^".into(), vec![lhs_curr, rhs], None, pos),
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::OrAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"|".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::AndAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"&".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::XOrAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"^".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::MultiplyAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"*".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::DivideAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"/".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::Pipe => Expr::FunctionCall("|".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::LeftShift => Expr::FunctionCall("<<".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::RightShift => {
|
|
|
|
Expr::FunctionCall(">>".into(), vec![lhs_curr, rhs], None, pos)
|
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::LeftShiftAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"<<".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::RightShiftAssign => {
|
2017-10-31 06:55:20 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
">>".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 06:55:20 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::Ampersand => Expr::FunctionCall("&".into(), vec![lhs_curr, rhs], None, pos),
|
|
|
|
Token::Modulo => Expr::FunctionCall("%".into(), vec![lhs_curr, rhs], None, pos),
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::ModuloAssign => {
|
2017-10-31 23:06:13 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"%".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-10-31 23:06:13 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
Token::PowerOf => Expr::FunctionCall("~".into(), vec![lhs_curr, rhs], None, pos),
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::PowerOfAssign => {
|
2017-11-24 08:56:22 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
2020-03-02 15:13:14 +01:00
|
|
|
Box::new(Expr::FunctionCall(
|
|
|
|
"~".into(),
|
|
|
|
vec![lhs_copy, rhs],
|
|
|
|
None,
|
|
|
|
pos,
|
|
|
|
)),
|
2017-11-24 08:56:22 +01:00
|
|
|
)
|
2019-09-18 12:21:07 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
_ => return Err(ParseError(PERR::UnknownOperator, pos)),
|
2016-02-29 22:43:45 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
2020-02-24 16:25:52 +01:00
|
|
|
let lhs = parse_unary(input)?;
|
|
|
|
parse_binop(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)))
|
|
|
|
}
|
|
|
|
|
2020-02-23 15:48:46 +01:00
|
|
|
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-02 15:13:14 +01:00
|
|
|
Some((_, pos)) => return Err(ParseError(PERR::VarExpectsIdentifier, pos)),
|
|
|
|
None => return Err(ParseError(PERR::VarExpectsIdentifier, Position::eof())),
|
2020-02-23 15:48:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
match input.next() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((Token::In, _)) => {}
|
2020-03-02 15:13:14 +01:00
|
|
|
Some((_, pos)) => return Err(ParseError(PERR::VarExpectsIdentifier, pos)),
|
|
|
|
None => return Err(ParseError(PERR::VarExpectsIdentifier, Position::eof())),
|
2020-02-23 15:48:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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> {
|
2020-03-02 15:13:14 +01:00
|
|
|
let pos = match input.next() {
|
|
|
|
Some((_, tok_pos)) => tok_pos,
|
|
|
|
_ => return Err(ParseError(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-02 15:13:14 +01:00
|
|
|
Some((_, pos)) => return Err(ParseError(PERR::VarExpectsIdentifier, pos)),
|
|
|
|
None => return Err(ParseError(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();
|
2019-09-18 12:21:07 +02:00
|
|
|
let initializer = parse_expr(input)?;
|
2020-03-02 15:13:14 +01:00
|
|
|
Ok(Stmt::Let(name, Some(Box::new(initializer)), pos))
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
2020-03-02 15:13:14 +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, _)) => (),
|
|
|
|
Some(&(_, pos)) => return Err(ParseError(PERR::MissingLeftBrace, pos)),
|
|
|
|
None => return Err(ParseError(PERR::MissingLeftBrace, Position::eof())),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
input.next();
|
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
let mut stmts = Vec::new();
|
|
|
|
|
|
|
|
let skip_body = match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightBrace, _)) => true,
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => false,
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_body {
|
|
|
|
while let Some(_) = input.peek() {
|
2019-09-18 12:21:07 +02:00
|
|
|
stmts.push(parse_stmt(input)?);
|
2016-03-01 21:16:10 +01:00
|
|
|
|
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-03-01 21:16:10 +01:00
|
|
|
}
|
2017-10-02 23:44:45 +02:00
|
|
|
|
2020-02-29 13:12:10 +01:00
|
|
|
if let Some(&(Token::RightBrace, _)) = input.peek() {
|
2019-09-18 12:21:07 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
}
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
|
|
|
match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightBrace, _)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
2017-10-02 23:44:45 +02:00
|
|
|
Ok(Stmt::Block(stmts))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(_, pos)) => Err(ParseError(PERR::MissingRightBrace, pos)),
|
|
|
|
None => Err(ParseError(PERR::MissingRightBrace, Position::eof())),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
2020-02-24 16:25:52 +01:00
|
|
|
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),
|
2020-03-02 15:13:14 +01:00
|
|
|
Some(&(Token::Break, pos)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
2020-03-02 15:13:14 +01:00
|
|
|
Ok(Stmt::Break(pos))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::Return, _)) => {
|
2016-04-14 03:01:08 +02:00
|
|
|
input.next();
|
2016-03-03 15:31:42 +01:00
|
|
|
match input.peek() {
|
2020-03-02 15:13:14 +01:00
|
|
|
Some(&(Token::SemiColon, pos)) => Ok(Stmt::Return(pos)),
|
|
|
|
Some(&(_, pos)) => {
|
2019-09-18 12:21:07 +02:00
|
|
|
let ret = parse_expr(input)?;
|
2020-03-02 15:13:14 +01:00
|
|
|
Ok(Stmt::ReturnWithVal(Box::new(ret), pos))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-03-02 15:13:14 +01:00
|
|
|
_ => parse_expr_stmt(input),
|
2016-03-03 15:31:42 +01:00
|
|
|
}
|
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::LeftBrace, _)) => parse_block(input),
|
|
|
|
Some(&(Token::Let, _)) => parse_var(input),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => parse_expr_stmt(input),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseError> {
|
2020-03-02 15:13:14 +01:00
|
|
|
let pos = match input.next() {
|
|
|
|
Some((_, tok_pos)) => tok_pos,
|
|
|
|
_ => return Err(ParseError(PERR::InputPastEndOfFile, Position::eof())),
|
|
|
|
};
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
let name = match input.next() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((Token::Identifier(s), _)) => s,
|
2020-03-02 15:13:14 +01:00
|
|
|
Some((_, pos)) => return Err(ParseError(PERR::FnMissingName, pos)),
|
|
|
|
None => return Err(ParseError(PERR::FnMissingName, Position::eof())),
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::LeftParen, _)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(_, pos)) => return Err(ParseError(PERR::FnMissingParams, pos)),
|
|
|
|
None => return Err(ParseError(PERR::FnMissingParams, Position::eof())),
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
let skip_params = match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::RightParen, _)) => {
|
2016-04-17 04:32:18 +02:00
|
|
|
input.next();
|
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false,
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_params {
|
|
|
|
loop {
|
|
|
|
match input.next() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((Token::RightParen, _)) => break,
|
|
|
|
Some((Token::Comma, _)) => (),
|
|
|
|
Some((Token::Identifier(s), _)) => {
|
2020-02-29 10:10:51 +01:00
|
|
|
params.push(s);
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2020-02-29 13:12:10 +01:00
|
|
|
Some((_, pos)) => return Err(ParseError(PERR::MalformedCallExpr, pos)),
|
|
|
|
None => return Err(ParseError(PERR::MalformedCallExpr, Position::eof())),
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
2017-12-21 12:28:59 +01:00
|
|
|
let body = parse_block(input)?;
|
2016-03-01 21:16:10 +01:00
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
Ok(FnDef {
|
|
|
|
name: name,
|
|
|
|
params: params,
|
|
|
|
body: Box::new(body),
|
2020-03-02 15:13:14 +01:00
|
|
|
pos: pos,
|
2016-04-17 04:32:18 +02:00
|
|
|
})
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {
|
2016-03-01 21:16:10 +01:00
|
|
|
let mut stmts = Vec::new();
|
|
|
|
let mut fndefs = Vec::new();
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
while let Some(_) = input.peek() {
|
|
|
|
match input.peek() {
|
2020-02-29 13:12:10 +01:00
|
|
|
Some(&(Token::Fn, _)) => fndefs.push(parse_fn(input)?),
|
2019-09-18 12:21:07 +02:00
|
|
|
_ => stmts.push(parse_stmt(input)?),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
Ok(AST(stmts, fndefs))
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
2020-02-24 16:25:52 +01:00
|
|
|
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {
|
2016-03-01 21:16:10 +01:00
|
|
|
parse_top_level(input)
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|