2016-02-29 22:43:45 +01:00
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt;
|
|
|
|
use std::iter::Peekable;
|
|
|
|
use std::str::Chars;
|
2016-03-02 14:37:28 +01:00
|
|
|
use std::char;
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-03-02 15:16:36 +01:00
|
|
|
pub enum LexError {
|
|
|
|
UnexpectedChar,
|
|
|
|
MalformedEscapeSequence,
|
2016-04-14 03:40:06 +02:00
|
|
|
MalformedNumber,
|
2016-04-17 04:32:18 +02:00
|
|
|
MalformedChar,
|
2017-10-30 16:08:44 +01:00
|
|
|
Nothing
|
2016-03-02 15:16:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for LexError {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match *self {
|
|
|
|
LexError::UnexpectedChar => "Unexpected character in input",
|
|
|
|
LexError::MalformedEscapeSequence => "Unexpected values in escape sequence",
|
2016-04-14 03:40:06 +02:00
|
|
|
LexError::MalformedNumber => "Unexpected characters in number",
|
2016-04-17 04:32:18 +02:00
|
|
|
LexError::MalformedChar => "Char constant not a single character",
|
2017-10-30 16:08:44 +01:00
|
|
|
LexError::Nothing => "This error is for internal use only"
|
2016-03-02 15:16:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for LexError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum ParseError {
|
|
|
|
BadInput,
|
|
|
|
InputPastEndOfFile,
|
|
|
|
UnknownOperator,
|
|
|
|
MissingRParen,
|
|
|
|
MissingLCurly,
|
|
|
|
MissingRCurly,
|
2016-03-26 18:46:28 +01:00
|
|
|
MissingRSquare,
|
2016-02-29 22:43:45 +01:00
|
|
|
MalformedCallExpr,
|
2016-03-26 18:46:28 +01:00
|
|
|
MalformedIndexExpr,
|
2016-03-01 21:16:10 +01:00
|
|
|
VarExpectsIdentifier,
|
|
|
|
FnMissingName,
|
2016-04-17 04:32:18 +02:00
|
|
|
FnMissingParams,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for ParseError {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match *self {
|
|
|
|
ParseError::BadInput => "Unparseable characters in the input stream",
|
|
|
|
ParseError::InputPastEndOfFile => "Input past end of file",
|
|
|
|
ParseError::UnknownOperator => "Unknown operator",
|
|
|
|
ParseError::MissingRParen => "Expected ')'",
|
|
|
|
ParseError::MissingLCurly => "Expected '{'",
|
|
|
|
ParseError::MissingRCurly => "Expected '}'",
|
2016-03-26 18:46:28 +01:00
|
|
|
ParseError::MissingRSquare => "Expected ']'",
|
2016-02-29 22:43:45 +01:00
|
|
|
ParseError::MalformedCallExpr => "Call contains bad expression",
|
2016-03-26 18:46:28 +01:00
|
|
|
ParseError::MalformedIndexExpr => "Indexing expression missing correct index",
|
2016-03-01 21:16:10 +01:00
|
|
|
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
|
|
|
|
ParseError::FnMissingName => "Function declaration is missing name",
|
2016-04-17 04:32:18 +02:00
|
|
|
ParseError::FnMissingParams => "Function declaration is missing parameters",
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-14 19:46:22 +02:00
|
|
|
fn cause(&self) -> Option<&Error> { None }
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ParseError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.description())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct FnDef {
|
|
|
|
pub name: String,
|
|
|
|
pub params: Vec<String>,
|
2016-04-17 04:32:18 +02:00
|
|
|
pub body: Box<Stmt>,
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Stmt {
|
|
|
|
If(Box<Expr>, Box<Stmt>),
|
|
|
|
IfElse(Box<Expr>, Box<Stmt>, Box<Stmt>),
|
|
|
|
While(Box<Expr>, Box<Stmt>),
|
2017-10-30 16:08:44 +01:00
|
|
|
Loop(Box<Stmt>),
|
2016-04-17 04:32:18 +02:00
|
|
|
Var(String, Option<Box<Expr>>),
|
2017-10-02 23:44:45 +02:00
|
|
|
Block(Vec<Stmt>),
|
2016-04-17 04:32:18 +02:00
|
|
|
Expr(Box<Expr>),
|
|
|
|
Break,
|
|
|
|
Return,
|
|
|
|
ReturnWithVal(Box<Expr>),
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Expr {
|
|
|
|
IntConst(i64),
|
2017-10-28 05:30:12 +02:00
|
|
|
FloatConst(f64),
|
2016-04-17 04:32:18 +02:00
|
|
|
Identifier(String),
|
|
|
|
CharConst(char),
|
|
|
|
StringConst(String),
|
2017-10-02 23:44:45 +02:00
|
|
|
FnCall(String, Vec<Expr>),
|
2016-04-17 04:32:18 +02:00
|
|
|
Assignment(Box<Expr>, Box<Expr>),
|
|
|
|
Dot(Box<Expr>, Box<Expr>),
|
|
|
|
Index(String, Box<Expr>),
|
2017-10-02 23:44:45 +02:00
|
|
|
Array(Vec<Expr>),
|
2016-04-17 04:32:18 +02:00
|
|
|
True,
|
|
|
|
False,
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2016-04-17 04:32:18 +02:00
|
|
|
pub enum Token {
|
|
|
|
IntConst(i64),
|
2017-10-28 05:30:12 +02:00
|
|
|
FloatConst(f64),
|
2016-04-17 04:32:18 +02:00
|
|
|
Identifier(String),
|
|
|
|
CharConst(char),
|
|
|
|
StringConst(String),
|
|
|
|
LCurly,
|
|
|
|
RCurly,
|
|
|
|
LParen,
|
|
|
|
RParen,
|
|
|
|
LSquare,
|
|
|
|
RSquare,
|
|
|
|
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,
|
|
|
|
Semicolon,
|
|
|
|
Colon,
|
|
|
|
Comma,
|
|
|
|
Period,
|
|
|
|
Equals,
|
|
|
|
True,
|
|
|
|
False,
|
|
|
|
Var,
|
|
|
|
If,
|
|
|
|
Else,
|
|
|
|
While,
|
2017-10-30 16:08:44 +01:00
|
|
|
Loop,
|
2016-04-17 04:32:18 +02:00
|
|
|
LessThan,
|
|
|
|
GreaterThan,
|
|
|
|
Bang,
|
|
|
|
LessThanEqual,
|
|
|
|
GreaterThanEqual,
|
|
|
|
EqualTo,
|
|
|
|
NotEqualTo,
|
|
|
|
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,
|
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 {
|
|
|
|
LCurly | // (+expr) - is unary
|
|
|
|
// RCurly | {expr} - expr not unary & is closing
|
|
|
|
LParen | // {-expr} - is unary
|
|
|
|
// RParen | (expr) - expr not unary & is closing
|
|
|
|
LSquare | // [-expr] - is unary
|
|
|
|
// RSquare | [expr] - expr not unary & is closing
|
|
|
|
Plus |
|
|
|
|
UnaryPlus |
|
|
|
|
Minus |
|
|
|
|
UnaryMinus |
|
|
|
|
Multiply |
|
|
|
|
Divide |
|
|
|
|
Colon |
|
|
|
|
Comma |
|
|
|
|
Period |
|
|
|
|
Equals |
|
|
|
|
LessThan |
|
|
|
|
GreaterThan |
|
|
|
|
Bang |
|
|
|
|
LessThanEqual |
|
|
|
|
GreaterThanEqual |
|
|
|
|
EqualTo |
|
|
|
|
NotEqualTo |
|
|
|
|
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 |
|
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 {
|
|
|
|
RCurly |
|
|
|
|
RParen |
|
|
|
|
RSquare |
|
|
|
|
Plus |
|
|
|
|
Minus |
|
|
|
|
Multiply |
|
|
|
|
Divide |
|
|
|
|
Comma |
|
|
|
|
// Period | <- does period count?
|
|
|
|
Equals |
|
|
|
|
LessThan |
|
|
|
|
GreaterThan |
|
|
|
|
LessThanEqual |
|
|
|
|
GreaterThanEqual |
|
|
|
|
EqualTo |
|
|
|
|
NotEqualTo |
|
|
|
|
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 {
|
|
|
|
UnaryPlus |
|
|
|
|
UnaryMinus |
|
|
|
|
Equals |
|
|
|
|
Bang |
|
|
|
|
Return => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
pub struct TokenIterator<'a> {
|
2017-10-30 16:08:44 +01:00
|
|
|
last: Token,
|
2016-04-17 04:32:18 +02:00
|
|
|
char_stream: Peekable<Chars<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TokenIterator<'a> {
|
|
|
|
pub fn parse_string_const(&mut self, enclosing_char: char) -> Result<String, LexError> {
|
|
|
|
let mut result = Vec::new();
|
|
|
|
let mut escape = false;
|
|
|
|
|
|
|
|
while let Some(nxt) = self.char_stream.next() {
|
|
|
|
match nxt {
|
|
|
|
'\\' 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 {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'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 {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'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 {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(r) = char::from_u32(out_val) {
|
|
|
|
result.push(r);
|
|
|
|
} else {
|
|
|
|
return Err(LexError::MalformedEscapeSequence);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x if enclosing_char == x && escape => result.push(x),
|
|
|
|
x if enclosing_char == x && !escape => break,
|
|
|
|
_ if escape => return Err(LexError::MalformedEscapeSequence),
|
|
|
|
_ => {
|
|
|
|
escape = false;
|
|
|
|
result.push(nxt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let out: String = result.iter().cloned().collect();
|
|
|
|
Ok(out)
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
fn inner_next(&mut self) -> Option<Token> {
|
2016-02-29 22:43:45 +01:00
|
|
|
while let Some(c) = self.char_stream.next() {
|
|
|
|
match c {
|
|
|
|
'0'...'9' => {
|
|
|
|
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(&nxt) = self.char_stream.peek() {
|
|
|
|
match nxt {
|
2016-04-17 04:32:18 +02:00
|
|
|
'0'...'9' => {
|
|
|
|
result.push(nxt);
|
|
|
|
self.char_stream.next();
|
|
|
|
}
|
2017-10-30 04:32:41 +01:00
|
|
|
'.' => {
|
|
|
|
result.push(nxt);
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(&nxt_float) = self.char_stream.peek() {
|
|
|
|
match nxt_float {
|
|
|
|
'0'...'9' => {
|
|
|
|
result.push(nxt_float);
|
|
|
|
self.char_stream.next();
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-01 06:02:36 +01:00
|
|
|
'x' | 'X' => {
|
|
|
|
result.push(nxt);
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(&nxt_hex) = self.char_stream.peek() {
|
|
|
|
match nxt_hex {
|
|
|
|
'0'...'9' | 'a'...'f' | 'A'...'F' => {
|
|
|
|
result.push(nxt_hex);
|
|
|
|
self.char_stream.next();
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
2017-11-01 06:10:46 +01:00
|
|
|
radix_base = Some(16);
|
2017-11-01 06:02:36 +01:00
|
|
|
}
|
|
|
|
'o' | 'O' => {
|
|
|
|
result.push(nxt);
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(&nxt_oct) = self.char_stream.peek() {
|
|
|
|
match nxt_oct {
|
|
|
|
'0'...'8' => {
|
|
|
|
result.push(nxt_oct);
|
|
|
|
self.char_stream.next();
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
2017-11-01 06:10:46 +01:00
|
|
|
radix_base = Some(8);
|
2017-11-01 06:02:36 +01:00
|
|
|
}
|
|
|
|
'b' | 'B' => {
|
|
|
|
result.push(nxt);
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(&nxt_bin) = self.char_stream.peek() {
|
|
|
|
match nxt_bin {
|
|
|
|
'0' | '1' | '_' => {
|
|
|
|
result.push(nxt_bin);
|
|
|
|
self.char_stream.next();
|
|
|
|
}
|
|
|
|
_ => 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 {
|
|
|
|
let out: String = result.iter().cloned().skip(2).filter(|c| c != &'_').collect();
|
|
|
|
if let Ok(val) = i64::from_str_radix(&out, radix) {
|
|
|
|
return Some(Token::IntConst(val));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
let out: String = result.iter().cloned().collect();
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2016-04-13 04:52:27 +02:00
|
|
|
if let Ok(val) = out.parse::<i64>() {
|
2016-03-02 14:37:28 +01:00
|
|
|
return Some(Token::IntConst(val));
|
2017-10-30 04:32:41 +01:00
|
|
|
} else if let Ok(val) = out.parse::<f64>() {
|
|
|
|
return Some(Token::FloatConst(val));
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
2016-03-02 15:16:36 +01:00
|
|
|
return Some(Token::LexErr(LexError::MalformedNumber));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
'A'...'Z' | 'a'...'z' | '_' => {
|
|
|
|
let mut result = Vec::new();
|
|
|
|
result.push(c);
|
|
|
|
|
|
|
|
while let Some(&nxt) = self.char_stream.peek() {
|
|
|
|
match nxt {
|
2017-10-14 19:46:22 +02:00
|
|
|
x if x.is_alphanumeric() || x == '_' => {
|
|
|
|
result.push(x);
|
2016-04-17 04:32:18 +02:00
|
|
|
self.char_stream.next();
|
|
|
|
}
|
|
|
|
_ => break,
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
let out: String = result.iter().cloned().collect();
|
2017-10-14 19:46:22 +02:00
|
|
|
match out.as_ref() {
|
|
|
|
"true" => return Some(Token::True),
|
|
|
|
"false" => return Some(Token::False),
|
|
|
|
"let" => return Some(Token::Var),
|
|
|
|
"if" => return Some(Token::If),
|
|
|
|
"else" => return Some(Token::Else),
|
|
|
|
"while" => return Some(Token::While),
|
2017-10-30 16:08:44 +01:00
|
|
|
"loop" => return Some(Token::Loop),
|
2017-10-14 19:46:22 +02:00
|
|
|
"break" => return Some(Token::Break),
|
|
|
|
"return" => return Some(Token::Return),
|
|
|
|
"fn" => return Some(Token::Fn),
|
2017-10-30 04:32:41 +01:00
|
|
|
x => return Some(Token::Identifier(x.to_string())),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-03-02 14:37:28 +01:00
|
|
|
'"' => {
|
2016-04-17 04:32:18 +02:00
|
|
|
match self.parse_string_const('"') {
|
|
|
|
Ok(out) => return Some(Token::StringConst(out)),
|
|
|
|
Err(e) => return Some(Token::LexErr(e)),
|
2016-03-02 14:37:28 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-14 03:40:06 +02:00
|
|
|
'\'' => {
|
2016-04-17 04:32:18 +02:00
|
|
|
match self.parse_string_const('\'') {
|
|
|
|
Ok(result) => {
|
|
|
|
let mut chars = result.chars();
|
|
|
|
|
|
|
|
if let Some(out) = chars.next() {
|
|
|
|
println!("result: {}", result);
|
|
|
|
if chars.count() != 0 {
|
|
|
|
return Some(Token::LexErr(LexError::MalformedChar));
|
2016-04-14 03:40:06 +02:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
return Some(Token::CharConst(out));
|
|
|
|
} else {
|
|
|
|
return Some(Token::LexErr(LexError::MalformedChar));
|
2016-04-14 03:40:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
Err(e) => return Some(Token::LexErr(e)),
|
2016-04-14 03:40:06 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
'{' => return Some(Token::LCurly),
|
|
|
|
'}' => return Some(Token::RCurly),
|
|
|
|
'(' => return Some(Token::LParen),
|
|
|
|
')' => return Some(Token::RParen),
|
|
|
|
'[' => return Some(Token::LSquare),
|
|
|
|
']' => return Some(Token::RSquare),
|
2017-10-30 16:08:44 +01:00
|
|
|
'+' => {
|
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
Some(Token::PlusAssign)
|
2017-10-30 16:08:44 +01:00
|
|
|
},
|
|
|
|
_ if self.last.is_next_unary() => Some(Token::UnaryPlus),
|
|
|
|
_ => Some(Token::Plus),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'-' => {
|
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
Some(Token::MinusAssign)
|
2017-10-30 16:08:44 +01:00
|
|
|
},
|
|
|
|
_ if self.last.is_next_unary() => Some(Token::UnaryMinus),
|
|
|
|
_ => Some(Token::Minus),
|
|
|
|
}
|
|
|
|
},
|
2017-10-31 06:55:20 +01:00
|
|
|
'*' => {
|
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
Some(Token::MultiplyAssign)
|
2017-10-31 06:55:20 +01:00
|
|
|
},
|
|
|
|
_ => Some(Token::Multiply)
|
|
|
|
}
|
|
|
|
},
|
2017-10-30 16:08:44 +01:00
|
|
|
'/' => {
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'/') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(c) = self.char_stream.next() {
|
|
|
|
if c == '\n' { break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(&'*') => {
|
|
|
|
let mut level = 1;
|
|
|
|
self.char_stream.next();
|
|
|
|
while let Some(c) = self.char_stream.next() {
|
|
|
|
match c {
|
|
|
|
'/' => if let Some('*') = self.char_stream.next() {
|
|
|
|
level+=1;
|
|
|
|
}
|
|
|
|
'*' => if let Some('/') = self.char_stream.next() {
|
|
|
|
level-=1;
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
if level == 0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::DivideAssign);
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
2017-10-30 16:08:44 +01:00
|
|
|
_ => return Some(Token::Divide),
|
|
|
|
}
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
';' => return Some(Token::Semicolon),
|
|
|
|
':' => return Some(Token::Colon),
|
|
|
|
',' => return Some(Token::Comma),
|
|
|
|
'.' => return Some(Token::Period),
|
2016-04-14 03:01:08 +02:00
|
|
|
'=' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::EqualTo);
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::Equals),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
'<' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::LessThanEqual);
|
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
Some(&'<') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
Some(Token::LeftShiftAssign)
|
2017-10-31 06:55:20 +01:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
self.char_stream.next();
|
|
|
|
Some(Token::LeftShift)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::LessThan),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
'>' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::GreaterThanEqual);
|
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
Some(&'>') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
Some(Token::RightShiftAssign)
|
2017-10-31 06:55:20 +01:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
self.char_stream.next();
|
|
|
|
Some(Token::RightShift)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::GreaterThan),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
'!' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::NotEqualTo);
|
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::Bang),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
'|' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'|') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::Or);
|
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::OrAssign);
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::Pipe),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-04-14 03:01:08 +02:00
|
|
|
'&' => {
|
2016-03-01 15:40:48 +01:00
|
|
|
match self.char_stream.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&'&') => {
|
|
|
|
self.char_stream.next();
|
|
|
|
return Some(Token::And);
|
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::AndAssign);
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
2017-10-14 19:46:22 +02:00
|
|
|
_ => return Some(Token::Ampersand),
|
2016-03-01 15:40:48 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2017-10-31 06:55:20 +01:00
|
|
|
'^' => {
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::XOrAssign);
|
2017-10-31 06:55:20 +01:00
|
|
|
}
|
|
|
|
_ => return Some(Token::XOr)
|
|
|
|
}
|
2017-10-31 23:06:13 +01:00
|
|
|
},
|
|
|
|
'%' => {
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::ModuloAssign);
|
2017-10-31 23:06:13 +01:00
|
|
|
}
|
|
|
|
_ => return Some(Token::Modulo)
|
|
|
|
}
|
2017-11-24 08:56:22 +01:00
|
|
|
},
|
|
|
|
'~' => {
|
|
|
|
match self.char_stream.peek() {
|
|
|
|
Some(&'=') => {
|
|
|
|
self.char_stream.next();
|
2017-12-21 12:32:18 +01:00
|
|
|
return Some(Token::PowerOfAssign);
|
2017-11-24 08:56:22 +01:00
|
|
|
}
|
|
|
|
_ => return Some(Token::PowerOf)
|
|
|
|
}
|
|
|
|
},
|
2017-10-02 08:33:47 +02:00
|
|
|
_x if _x.is_whitespace() => (),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => return Some(Token::LexErr(LexError::UnexpectedChar)),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
impl<'a> Iterator for TokenIterator<'a> {
|
|
|
|
type Item = Token;
|
|
|
|
|
|
|
|
// TODO - perhaps this could be optimized?
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.last = match self.inner_next() {
|
|
|
|
Some(c) => c,
|
|
|
|
None => return None,
|
|
|
|
};
|
|
|
|
Some(self.last.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-02 23:44:45 +02:00
|
|
|
pub fn lex(input: &str) -> TokenIterator {
|
2017-10-30 16:08:44 +01:00
|
|
|
TokenIterator { last: Token::LexErr(LexError::Nothing), char_stream: input.chars().peekable() }
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_precedence(token: &Token) -> i32 {
|
|
|
|
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,
|
2017-10-31 06:55:20 +01:00
|
|
|
Token::Or
|
|
|
|
| Token::XOr
|
|
|
|
| Token::Pipe => 11,
|
2017-10-31 23:06:13 +01:00
|
|
|
Token::And
|
|
|
|
| Token::Ampersand => 12,
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::LessThan
|
|
|
|
| Token::LessThanEqual
|
|
|
|
| Token::GreaterThan
|
|
|
|
| Token::GreaterThanEqual
|
|
|
|
| Token::EqualTo
|
|
|
|
| Token::NotEqualTo => 15,
|
|
|
|
Token::Plus
|
|
|
|
| Token::Minus => 20,
|
|
|
|
Token::Divide
|
2017-11-24 08:56:22 +01:00
|
|
|
| Token::Multiply
|
|
|
|
| Token::PowerOf => 40,
|
2017-10-31 06:55:20 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
|
|
|
let expr = try!(parse_expr(input));
|
|
|
|
|
|
|
|
match input.next() {
|
|
|
|
Some(Token::RParen) => Ok(expr),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => Err(ParseError::MissingRParen),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
fn parse_call_expr<'a>(id: String,
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>)
|
|
|
|
-> Result<Expr, ParseError> {
|
2016-02-29 22:43:45 +01:00
|
|
|
let mut args = Vec::new();
|
2017-10-28 05:30:12 +02:00
|
|
|
|
2017-10-02 23:44:45 +02:00
|
|
|
if let Some(&Token::RParen) = input.peek() {
|
|
|
|
input.next();
|
|
|
|
return Ok(Expr::FnCall(id, args));
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if let Ok(arg) = parse_expr(input) {
|
|
|
|
args.push(arg);
|
2016-04-17 04:32:18 +02:00
|
|
|
} else {
|
2016-02-29 22:43:45 +01:00
|
|
|
return Err(ParseError::MalformedCallExpr);
|
|
|
|
}
|
|
|
|
|
|
|
|
match input.peek() {
|
2016-03-01 21:16:10 +01:00
|
|
|
Some(&Token::RParen) => {
|
|
|
|
input.next();
|
2017-10-02 23:44:45 +02:00
|
|
|
return Ok(Expr::FnCall(id, args));
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
Some(&Token::Comma) => (),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => return Err(ParseError::MalformedCallExpr),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
input.next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
fn parse_index_expr<'a>(id: String,
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>)
|
|
|
|
-> Result<Expr, ParseError> {
|
2016-03-26 18:46:28 +01:00
|
|
|
if let Ok(idx) = parse_expr(input) {
|
|
|
|
match input.peek() {
|
|
|
|
Some(&Token::RSquare) => {
|
|
|
|
input.next();
|
2016-04-17 04:32:18 +02:00
|
|
|
return Ok(Expr::Index(id, Box::new(idx)));
|
|
|
|
}
|
|
|
|
_ => return Err(ParseError::MalformedIndexExpr),
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
} else {
|
2016-03-26 18:46:28 +01:00
|
|
|
return Err(ParseError::MalformedIndexExpr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
fn parse_ident_expr<'a>(id: String,
|
|
|
|
input: &mut Peekable<TokenIterator<'a>>)
|
|
|
|
-> Result<Expr, ParseError> {
|
2016-03-26 18:46:28 +01:00
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::LParen) => {
|
|
|
|
input.next();
|
|
|
|
parse_call_expr(id, input)
|
|
|
|
}
|
|
|
|
Some(&Token::LSquare) => {
|
|
|
|
input.next();
|
|
|
|
parse_index_expr(id, input)
|
|
|
|
}
|
2017-10-02 23:44:45 +02:00
|
|
|
_ => Ok(Expr::Identifier(id)),
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_array_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
|
|
|
let mut arr = Vec::new();
|
|
|
|
|
|
|
|
let skip_contents = match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::RSquare) => true,
|
|
|
|
_ => false,
|
2016-03-26 18:46:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_contents {
|
|
|
|
while let Some(_) = input.peek() {
|
|
|
|
arr.push(try!(parse_expr(input)));
|
2017-10-02 23:44:45 +02:00
|
|
|
if let Some(&Token::Comma) = input.peek() {
|
|
|
|
input.next();
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
|
2017-10-02 23:44:45 +02:00
|
|
|
if let Some(&Token::RSquare) = input.peek() { break }
|
2016-04-14 03:01:08 +02:00
|
|
|
}
|
2016-03-26 18:46:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::RSquare) => {
|
|
|
|
input.next();
|
2017-10-02 23:44:45 +02:00
|
|
|
Ok(Expr::Array(arr))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
_ => Err(ParseError::MissingRSquare),
|
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> {
|
|
|
|
if let Some(token) = input.next() {
|
|
|
|
match token {
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::IntConst(ref x) => Ok(Expr::IntConst(*x)),
|
2017-10-28 05:30:12 +02:00
|
|
|
Token::FloatConst(ref x) => Ok(Expr::FloatConst(*x)),
|
2016-04-17 04:32:18 +02:00
|
|
|
Token::StringConst(ref s) => Ok(Expr::StringConst(s.clone())),
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::CharConst(ref c) => Ok(Expr::CharConst(*c)),
|
2016-04-17 04:32:18 +02:00
|
|
|
Token::Identifier(ref s) => parse_ident_expr(s.clone(), input),
|
|
|
|
Token::LParen => parse_paren_expr(input),
|
|
|
|
Token::LSquare => parse_array_expr(input),
|
|
|
|
Token::True => Ok(Expr::True),
|
|
|
|
Token::False => Ok(Expr::False),
|
|
|
|
Token::LexErr(le) => {
|
|
|
|
println!("Error: {}", le);
|
|
|
|
Err(ParseError::BadInput)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
println!("Can't parse: {:?}", token);
|
|
|
|
Err(ParseError::BadInput)
|
|
|
|
}
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
} else {
|
2016-02-29 22:43:45 +01:00
|
|
|
Err(ParseError::InputPastEndOfFile)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
|
|
|
let tok = match input.peek() {
|
|
|
|
Some(tok) => tok.clone(),
|
|
|
|
None => return Err(ParseError::InputPastEndOfFile),
|
|
|
|
};
|
2017-10-31 06:55:20 +01:00
|
|
|
|
2017-10-30 16:08:44 +01:00
|
|
|
match tok {
|
|
|
|
Token::UnaryMinus => { input.next(); Ok(Expr::FnCall("-".to_string(), vec![parse_primary(input)?])) }
|
|
|
|
Token::UnaryPlus => { input.next(); parse_primary(input) }
|
|
|
|
Token::Bang => { input.next(); Ok(Expr::FnCall("!".to_string(), vec![parse_primary(input)?])) }
|
|
|
|
_ => parse_primary(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>,
|
|
|
|
prec: i32,
|
|
|
|
lhs: Expr)
|
|
|
|
-> Result<Expr, ParseError> {
|
2016-02-29 22:43:45 +01:00
|
|
|
let mut lhs_curr = lhs;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let mut curr_prec = -1;
|
|
|
|
|
2016-04-14 03:01:08 +02:00
|
|
|
if let Some(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(op_token) = input.next() {
|
2017-10-30 16:08:44 +01:00
|
|
|
let mut rhs = try!(parse_unary(input));
|
2016-02-29 22:43:45 +01:00
|
|
|
|
|
|
|
let mut next_prec = -1;
|
2016-04-14 03:01:08 +02:00
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
if let Some(next_op) = input.peek() {
|
|
|
|
next_prec = get_precedence(next_op);
|
|
|
|
}
|
|
|
|
|
|
|
|
if curr_prec < next_prec {
|
2016-04-17 04:32:18 +02:00
|
|
|
rhs = try!(parse_binop(input, curr_prec + 1, rhs));
|
|
|
|
} else if curr_prec >= 100 {
|
|
|
|
// Always bind right to left for precedence over 100
|
2016-04-14 03:01:08 +02:00
|
|
|
rhs = try!(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 {
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::Plus => Expr::FnCall("+".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::Minus => Expr::FnCall("-".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::Multiply => Expr::FnCall("*".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::Divide => Expr::FnCall("/".to_string(), vec![lhs_curr, rhs]),
|
2016-02-29 22:43:45 +01:00
|
|
|
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::PlusAssign => {
|
2017-10-30 16:08:44 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
|
|
|
Box::new(Expr::FnCall("+".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
2017-12-21 12:32:18 +01:00
|
|
|
Token::MinusAssign => {
|
2017-10-30 16:08:44 +01:00
|
|
|
let lhs_copy = lhs_curr.clone();
|
|
|
|
Expr::Assignment(
|
|
|
|
Box::new(lhs_curr),
|
|
|
|
Box::new(Expr::FnCall("-".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
2016-03-07 21:39:02 +01:00
|
|
|
Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)),
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::EqualTo => Expr::FnCall("==".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::NotEqualTo => Expr::FnCall("!=".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::LessThan => Expr::FnCall("<".to_string(), vec![lhs_curr, rhs]),
|
2016-04-17 04:32:18 +02:00
|
|
|
Token::LessThanEqual => {
|
2017-10-02 23:44:45 +02:00
|
|
|
Expr::FnCall("<=".to_string(), vec![lhs_curr, rhs])
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::GreaterThan => Expr::FnCall(">".to_string(), vec![lhs_curr, rhs]),
|
2016-04-17 04:32:18 +02:00
|
|
|
Token::GreaterThanEqual => {
|
2017-10-02 23:44:45 +02:00
|
|
|
Expr::FnCall(">=".to_string(), vec![lhs_curr, rhs])
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
2017-10-02 23:44:45 +02:00
|
|
|
Token::Or => Expr::FnCall("||".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::And => Expr::FnCall("&&".to_string(), vec![lhs_curr, rhs]),
|
2017-10-31 06:55:20 +01:00
|
|
|
Token::XOr => Expr::FnCall("^".to_string(), vec![lhs_curr, rhs]),
|
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),
|
|
|
|
Box::new(Expr::FnCall("|".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
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),
|
|
|
|
Box::new(Expr::FnCall("&".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
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),
|
|
|
|
Box::new(Expr::FnCall("^".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
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),
|
|
|
|
Box::new(Expr::FnCall("*".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
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),
|
|
|
|
Box::new(Expr::FnCall("/".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
|
|
|
Token::Pipe => {
|
|
|
|
Expr::FnCall("|".to_string(), vec![lhs_curr, rhs])
|
|
|
|
},
|
|
|
|
Token::LeftShift => Expr::FnCall("<<".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::RightShift => Expr::FnCall(">>".to_string(), vec![lhs_curr, rhs]),
|
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),
|
|
|
|
Box::new(Expr::FnCall("<<".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
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),
|
|
|
|
Box::new(Expr::FnCall(">>".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
2017-10-31 23:06:13 +01:00
|
|
|
Token::Ampersand => Expr::FnCall("&".to_string(), vec![lhs_curr, rhs]),
|
|
|
|
Token::Modulo => Expr::FnCall("%".to_string(), vec![lhs_curr, rhs]),
|
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),
|
|
|
|
Box::new(Expr::FnCall("%".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
2017-11-24 08:56:22 +01:00
|
|
|
},
|
|
|
|
Token::PowerOf => Expr::FnCall("~".to_string(), vec![lhs_curr, rhs]),
|
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),
|
|
|
|
Box::new(Expr::FnCall("~".to_string(), vec![lhs_copy, rhs]))
|
|
|
|
)
|
|
|
|
},
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => return Err(ParseError::UnknownOperator),
|
2016-02-29 22:43:45 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
|
2017-10-30 16:08:44 +01:00
|
|
|
let lhs = try!(parse_unary(input));
|
2016-02-29 22:43:45 +01:00
|
|
|
|
|
|
|
parse_binop(input, 0, lhs)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
|
|
|
input.next();
|
|
|
|
|
|
|
|
let guard = try!(parse_expr(input));
|
|
|
|
let body = try!(parse_block(input));
|
|
|
|
|
2016-03-03 14:20:55 +01:00
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::Else) => {
|
2016-03-03 14:20:55 +01:00
|
|
|
input.next();
|
|
|
|
let else_body = try!(parse_block(input));
|
|
|
|
Ok(Stmt::IfElse(Box::new(guard), Box::new(body), Box::new(else_body)))
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => Ok(Stmt::If(Box::new(guard), Box::new(body))),
|
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();
|
|
|
|
|
|
|
|
let guard = try!(parse_expr(input));
|
|
|
|
let body = try!(parse_block(input));
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
let body = try!(parse_block(input));
|
|
|
|
|
|
|
|
Ok(Stmt::Loop(Box::new(body)))
|
|
|
|
}
|
|
|
|
|
2016-02-29 22:43:45 +01:00
|
|
|
fn parse_var<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
|
|
|
input.next();
|
|
|
|
|
|
|
|
let name = match input.next() {
|
2016-03-02 14:37:28 +01:00
|
|
|
Some(Token::Identifier(ref s)) => s.clone(),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => return Err(ParseError::VarExpectsIdentifier),
|
2016-02-29 22:43:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
match input.peek() {
|
|
|
|
Some(&Token::Equals) => {
|
|
|
|
input.next();
|
|
|
|
let initializer = try!(parse_expr(input));
|
|
|
|
Ok(Stmt::Var(name, Some(Box::new(initializer))))
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => Ok(Stmt::Var(name, None)),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::LCurly) => (),
|
|
|
|
_ => return Err(ParseError::MissingLCurly),
|
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() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::RCurly) => true,
|
|
|
|
_ => false,
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_body {
|
|
|
|
while let Some(_) = input.peek() {
|
|
|
|
stmts.push(try!(parse_stmt(input)));
|
|
|
|
|
2017-10-02 23:44:45 +02:00
|
|
|
if let Some(&Token::Semicolon) = input.peek() {
|
|
|
|
input.next();
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
2017-10-02 23:44:45 +02:00
|
|
|
|
|
|
|
if let Some(&Token::RCurly) = input.peek() { 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() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::RCurly) => {
|
|
|
|
input.next();
|
2017-10-02 23:44:45 +02:00
|
|
|
Ok(Stmt::Block(stmts))
|
2016-04-17 04:32:18 +02:00
|
|
|
}
|
|
|
|
_ => Err(ParseError::MissingRCurly),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_expr_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
2016-04-14 03:01:08 +02:00
|
|
|
let expr = try!(parse_expr(input));
|
2016-02-29 22:43:45 +01:00
|
|
|
Ok(Stmt::Expr(Box::new(expr)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
|
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::If) => parse_if(input),
|
|
|
|
Some(&Token::While) => parse_while(input),
|
2017-10-30 16:08:44 +01:00
|
|
|
Some(&Token::Loop) => parse_loop(input),
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::Break) => {
|
|
|
|
input.next();
|
|
|
|
Ok(Stmt::Break)
|
|
|
|
}
|
|
|
|
Some(&Token::Return) => {
|
2016-04-14 03:01:08 +02:00
|
|
|
input.next();
|
2016-03-03 15:31:42 +01:00
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::Semicolon) => Ok(Stmt::Return),
|
|
|
|
_ => {
|
|
|
|
let ret = try!(parse_expr(input));
|
|
|
|
Ok(Stmt::ReturnWithVal(Box::new(ret)))
|
|
|
|
}
|
2016-03-03 15:31:42 +01:00
|
|
|
}
|
|
|
|
}
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::LCurly) => parse_block(input),
|
|
|
|
Some(&Token::Var) => parse_var(input),
|
|
|
|
_ => 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> {
|
|
|
|
input.next();
|
2016-02-29 22:43:45 +01:00
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
let name = match input.next() {
|
2016-03-02 14:37:28 +01:00
|
|
|
Some(Token::Identifier(ref s)) => s.clone(),
|
2016-04-17 04:32:18 +02:00
|
|
|
_ => return Err(ParseError::FnMissingName),
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::LParen) => {
|
|
|
|
input.next();
|
|
|
|
}
|
|
|
|
_ => return Err(ParseError::FnMissingParams),
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut params = Vec::new();
|
|
|
|
|
|
|
|
let skip_params = match input.peek() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::RParen) => {
|
|
|
|
input.next();
|
|
|
|
true
|
|
|
|
}
|
|
|
|
_ => false,
|
2016-03-01 21:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if !skip_params {
|
|
|
|
loop {
|
|
|
|
match input.next() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(Token::RParen) => break,
|
2016-03-01 21:16:10 +01:00
|
|
|
Some(Token::Comma) => (),
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(Token::Identifier(ref s)) => {
|
|
|
|
params.push(s.clone());
|
|
|
|
}
|
|
|
|
_ => return Err(ParseError::MalformedCallExpr),
|
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),
|
|
|
|
})
|
2016-03-01 21:16:10 +01:00
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>)
|
|
|
|
-> Result<(Vec<Stmt>, Vec<FnDef>), 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() {
|
2016-04-17 04:32:18 +02:00
|
|
|
Some(&Token::Fn) => fndefs.push(try!(parse_fn(input))),
|
|
|
|
_ => stmts.push(try!(parse_stmt(input))),
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
2017-10-02 23:44:45 +02:00
|
|
|
if let Some(&Token::Semicolon) = input.peek() {
|
|
|
|
input.next();
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 21:16:10 +01:00
|
|
|
Ok((stmts, fndefs))
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|
|
|
|
|
2016-04-17 04:32:18 +02:00
|
|
|
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>)
|
|
|
|
-> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
|
2016-03-01 21:16:10 +01:00
|
|
|
parse_top_level(input)
|
2016-02-29 22:43:45 +01:00
|
|
|
}
|