use super::token::{self, Literal, Operator, Token, Word};
use super::{ast::*, Column, Error, LineNumber, MaxValue};
use crate::error;
use std::collections::HashMap;
type Result<T> = std::result::Result<T, Error>;
const FN_RESERVED: &str = "FN RESERVED FOR FUNCTIONS";
const ARRAY_NOT_ALLOWED: &str = "ARRAY NOT ALLOWED";
const EXPECTED_VARIABLE: &str = "EXPECTED VARIABLE";
pub fn parse(line_number: LineNumber, tokens: &[Token]) -> Result<Vec<Statement>> {
match BasicParser::parse(tokens) {
Err(e) => Err(e.in_line_number(line_number)),
Ok(r) => Ok(r),
}
}
struct BasicParser<'a> {
token_stream: std::slice::Iter<'a, Token>,
peeked: Option<&'a Token>,
rem: bool,
col: Column,
}
impl<'a> BasicParser<'a> {
fn parse(tokens: &'a [Token]) -> Result<Vec<Statement>> {
let mut parse = BasicParser {
token_stream: tokens.iter(),
peeked: None,
rem: false,
col: 0..0,
};
match parse.peek() {
Some(Token::Literal(Literal::Integer(_)))
| Some(Token::Literal(Literal::Single(_)))
| Some(Token::Literal(Literal::Double(_))) => {
return Err(error!(UndefinedLine, ..&parse.col; "INVALID LINE NUMBER"));
}
_ => {}
}
parse.expect_statements()
}
fn next(&mut self) -> Option<&'a Token> {
if self.peeked.is_some() {
return self.peeked.take();
}
loop {
self.col.start = self.col.end;
let token = self.token_stream.next()?;
if matches!(token, Token::Word(Word::Rem1) | Token::Word(Word::Rem2)) {
self.rem = true;
}
if self.rem {
continue;
}
self.col.end += token.to_string().chars().count();
match token {
Token::Whitespace(_) => continue,
_ => return Some(token),
}
}
}
fn peek(&mut self) -> Option<&&'a Token> {
if self.peeked.is_none() {
self.peeked = self.next();
}
self.peeked.as_ref()
}
fn expect_statements(&mut self) -> Result<Vec<Statement>> {
let mut statements: Vec<Statement> = vec![];
let mut expect_colon = false;
loop {
match self.peek() {
None | Some(Token::Word(Word::Else)) => return Ok(statements),
Some(Token::Colon) => {
expect_colon = false;
self.next();
continue;
}
Some(_) => {
if expect_colon {
return Err(error!(SyntaxError, ..&self.col; "UNEXPECTED TOKEN"));
}
statements.push(Statement::expect(self)?);
expect_colon = true;
}
}
}
}
fn expect_expression(&mut self) -> Result<Expression> {
self.expect_fn_expression(&HashMap::default())
}
fn expect_expression_list(&mut self) -> Result<Vec<Expression>> {
self.expect_fn_expression_list(&HashMap::default())
}
fn expect_fn_expression(
&mut self,
var_map: &HashMap<token::Ident, Variable>,
) -> Result<Expression> {
Expression::expect(self, var_map)
}
fn expect_fn_expression_list(
&mut self,
var_map: &HashMap<token::Ident, Variable>,
) -> Result<Vec<Expression>> {
let mut expressions: Vec<Expression> = vec![];
loop {
expressions.push(self.expect_fn_expression(var_map)?);
if self.maybe(Token::Comma) {
continue;
}
return Ok(expressions);
}
}
fn expect_print_list(&mut self) -> Result<Vec<Expression>> {
let mut expressions: Vec<Expression> = vec![];
let mut linefeed = true;
loop {
match self.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) => {
let mut column = self.col.clone();
column.start = column.end;
if linefeed {
expressions.push(Expression::String(column, "\n".into()));
}
return Ok(expressions);
}
Some(Token::Semicolon) => {
linefeed = false;
self.next();
}
Some(Token::Comma) => {
linefeed = false;
self.next();
expressions.push(Expression::Variable(Variable::Array(
self.col.clone(),
Ident::String("TAB".into()),
vec![Expression::Integer(self.col.clone(), -14)],
)));
}
_ => {
linefeed = true;
expressions.push(self.expect_expression()?);
}
};
}
}
fn expect_ident(&mut self) -> Result<(Column, token::Ident)> {
let ident = if let Some(Token::Ident(ident)) = self.next() {
ident.clone()
} else {
return Err(error!(SyntaxError, ..&self.col; EXPECTED_VARIABLE));
};
let col = self.col.clone();
if ident.is_user_function() {
return Err(error!(SyntaxError, ..&col; FN_RESERVED));
}
if let Some(Token::LParen) = self.peek() {
return Err(error!(SyntaxError, ..&(col); ARRAY_NOT_ALLOWED));
}
Ok((col, ident))
}
fn expect_ident_list(&mut self) -> Result<Vec<(Column, token::Ident)>> {
let mut idents: Vec<(Column, token::Ident)> = vec![];
let mut expecting = false;
loop {
match self.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) if !expecting => break,
_ => idents.push(self.expect_ident()?),
};
if self.maybe(Token::Comma) {
expecting = true;
} else {
break;
}
}
Ok(idents)
}
fn expect_var(&mut self) -> Result<Variable> {
let ident = if let Some(Token::Ident(ident)) = self.next() {
ident.clone()
} else {
return Err(error!(SyntaxError, ..&self.col; EXPECTED_VARIABLE));
};
let col = self.col.clone();
if ident.is_user_function() {
return Err(error!(SyntaxError, ..&col; FN_RESERVED));
}
match self.peek() {
Some(Token::LParen) => {
self.expect(Token::LParen)?;
let vec_expr = self.expect_expression_list()?;
self.expect(Token::RParen)?;
Ok(Variable::Array(
col.start..self.col.end,
ident.into(),
vec_expr,
))
}
_ => Ok(Variable::Unary(col, ident.into())),
}
}
fn expect_var_list(&mut self) -> Result<Vec<Variable>> {
let mut vec_var: Vec<Variable> = vec![];
loop {
vec_var.push(self.expect_var()?);
if self.maybe(Token::Comma) {
continue;
}
break;
}
Ok(vec_var)
}
fn maybe_line_number(&mut self) -> Result<LineNumber> {
if let Some(str) = match self.peek() {
Some(Token::Literal(Literal::Integer(s))) => Some(s),
Some(Token::Literal(Literal::Single(s))) => Some(s),
Some(Token::Literal(Literal::Double(s))) => Some(s),
_ => None,
} {
self.next();
if let Ok(num) = str.parse::<u16>() {
if num <= LineNumber::max_value() {
return Ok(Some(num));
}
}
return Err(error!(UndefinedLine, ..&self.col; "INVALID LINE NUMBER"));
}
Ok(None)
}
fn expect_line_number(&mut self) -> Result<Expression> {
match self.maybe_line_number()? {
Some(num) => Ok(Expression::Single(self.col.clone(), num as f32)),
None => Err(error!(SyntaxError, ..&self.col; "EXPECTED LINE NUMBER")),
}
}
fn expect_line_number_list(&mut self) -> Result<Vec<Expression>> {
let mut vars: Vec<Expression> = vec![];
let mut expecting = false;
loop {
match self.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) if !expecting => break,
_ => vars.push(self.expect_line_number()?),
};
if self.maybe(Token::Comma) {
expecting = true;
} else {
break;
}
}
Ok(vars)
}
fn expect_line_number_range(&mut self) -> Result<(Expression, Expression)> {
let from;
let from_num;
let to;
let mut to_num;
let col = self.col.clone();
if let Some(num) = self.maybe_line_number()? {
from_num = num as f32;
to_num = from_num;
from = Expression::Single(self.col.clone(), from_num);
} else {
from_num = 0.0;
to_num = LineNumber::max_value() as f32;
from = Expression::Single(self.col.start..self.col.start, from_num);
};
if self.maybe(Token::Operator(Operator::Minus)) {
if let Some(ln) = self.maybe_line_number()? {
to_num = ln as f32;
to = Expression::Single(self.col.clone(), to_num);
} else {
to_num = LineNumber::max_value() as f32;
to = Expression::Single(self.col.start..self.col.start, to_num);
}
} else {
to = Expression::Single(self.col.start..self.col.start, to_num);
}
if from_num > to_num {
return Err(error!(UndefinedLine, ..&(col.start..self.col.end); "INVALID RANGE"));
}
Ok((from, to))
}
fn expect_var_range(&mut self) -> Result<(Variable, Variable)> {
let (from_col, from_ident) = self.expect_ident()?;
let (to_col, to_ident) = if self.maybe(Token::Operator(Operator::Minus)) {
self.expect_ident()?
} else {
(from_col.clone(), from_ident.clone())
};
let from_char = match &from_ident {
token::Ident::Plain(s) if s.len() == 1 => s,
_ => return Err(error!(SyntaxError, ..&from_col)),
};
let to_char = match &to_ident {
token::Ident::Plain(s) if s.len() == 1 => s,
_ => return Err(error!(SyntaxError, ..&to_col)),
};
if from_char > to_char {
return Err(error!(SyntaxError, ..&(from_col.start..to_col.end)));
}
let from = Variable::Unary(from_col, from_ident.into());
let to = Variable::Unary(to_col, to_ident.into());
Ok((from, to))
}
fn maybe(&mut self, token: Token) -> bool {
if let Some(t) = self.peek() {
if **t == token {
self.next();
return true;
}
}
false
}
fn expect(&mut self, token: Token) -> Result<()> {
if let Some(t) = self.next() {
if *t == token {
return Ok(());
}
}
Err(error!(SyntaxError, ..&self.col;
match token {
Token::Unknown(_) | Token::Whitespace(_) => {"EXPECTED THE IMPOSSIBLE"}
Token::Literal(_) => {"EXPECTED LITERAL"}
Token::Word(Word::Then) => {"EXPECTED THEN"}
Token::Word(Word::To) => {"EXPECTED TO"}
Token::Word(_) => {"EXPECTED STATEMENT WORD"}
Token::Operator(Operator::Equal) => {"EXPECTED EQUALS SIGN"}
Token::Operator(_) => {"EXPECTED OPERATOR"}
Token::Ident(_) => {"EXPECTED IDENTIFIER"}
Token::LParen => {"EXPECTED LEFT PARENTHESIS"}
Token::RParen => {"EXPECTED RIGHT PARENTHESIS"}
Token::Comma => {"EXPECTED COMMA"}
Token::Colon => {"EXPECTED COLON"}
Token::Semicolon => {"EXPECTED SEMICOLON"}
}
))
}
}
impl Expression {
fn expect(
parse: &mut BasicParser,
var_map: &HashMap<token::Ident, Variable>,
) -> Result<Expression> {
fn descend(
parse: &mut BasicParser,
var_map: &HashMap<token::Ident, Variable>,
precedence: usize,
) -> Result<Expression> {
let mut lhs = match parse.next() {
Some(Token::LParen) => {
let expr = descend(parse, var_map, 0)?;
parse.expect(Token::RParen)?;
expr
}
Some(Token::Ident(tok_ident)) => {
let ident = tok_ident.clone();
let col = parse.col.clone();
match parse.peek() {
Some(&&Token::LParen) => {
parse.expect(Token::LParen)?;
let mut vec_expr = vec![];
if !parse.maybe(Token::RParen) {
vec_expr = parse.expect_fn_expression_list(var_map)?;
parse.expect(Token::RParen)?;
}
let col = col.start..parse.col.end;
Expression::Variable(Variable::Array(col, ident.into(), vec_expr))
}
_ => {
if ident.is_user_function() {
return Err(error!(SyntaxError, ..&col; FN_RESERVED));
}
match var_map.get(&ident) {
Some(var) => Expression::Variable(var.clone()),
None => Expression::Variable(Variable::Unary(col, ident.into())),
}
}
}
}
Some(Token::Operator(Operator::Plus)) => {
let op_prec = Expression::unary_op_precedence(&Operator::Plus)?;
descend(parse, var_map, op_prec)?
}
Some(Token::Operator(Operator::Minus)) => {
let col = parse.col.clone();
let op_prec = Expression::unary_op_precedence(&Operator::Minus)?;
let expr = descend(parse, var_map, op_prec)?;
Expression::Negation(col, Box::new(expr))
}
Some(Token::Operator(Operator::Not)) => {
let col = parse.col.clone();
let op_prec = Expression::unary_op_precedence(&Operator::Not)?;
let expr = descend(parse, var_map, op_prec)?;
Expression::Not(col, Box::new(expr))
}
Some(Token::Literal(lit)) => Expression::literal(parse.col.clone(), lit)?,
_ => return Err(error!(SyntaxError, ..&parse.col; "EXPECTED EXPRESSION")),
};
let mut rhs;
while let Some(Token::Operator(op)) = parse.peek() {
let op_prec = Expression::binary_op_precedence(op)?;
if op_prec <= precedence {
break;
}
parse.next();
let column = parse.col.clone();
rhs = descend(parse, var_map, op_prec)?;
lhs = Expression::binary_op(column, op, lhs, rhs)?;
}
Ok(lhs)
};
descend(parse, var_map, 0)
}
fn binary_op(
col: Column,
op: &Operator,
lhs: Expression,
rhs: Expression,
) -> Result<Expression> {
use Operator::*;
Ok(match op {
Caret => Expression::Power(col, Box::new(lhs), Box::new(rhs)),
Multiply => Expression::Multiply(col, Box::new(lhs), Box::new(rhs)),
Divide => Expression::Divide(col, Box::new(lhs), Box::new(rhs)),
DivideInt => Expression::DivideInt(col, Box::new(lhs), Box::new(rhs)),
Modulo => Expression::Modulo(col, Box::new(lhs), Box::new(rhs)),
Plus => Expression::Add(col, Box::new(lhs), Box::new(rhs)),
Minus => Expression::Subtract(col, Box::new(lhs), Box::new(rhs)),
Equal => Expression::Equal(col, Box::new(lhs), Box::new(rhs)),
NotEqual => Expression::NotEqual(col, Box::new(lhs), Box::new(rhs)),
Less => Expression::Less(col, Box::new(lhs), Box::new(rhs)),
LessEqual => Expression::LessEqual(col, Box::new(lhs), Box::new(rhs)),
Greater => Expression::Greater(col, Box::new(lhs), Box::new(rhs)),
GreaterEqual => Expression::GreaterEqual(col, Box::new(lhs), Box::new(rhs)),
Not => return Err(error!(InternalError)),
And => Expression::And(col, Box::new(lhs), Box::new(rhs)),
Or => Expression::Or(col, Box::new(lhs), Box::new(rhs)),
Xor => Expression::Xor(col, Box::new(lhs), Box::new(rhs)),
Imp => Expression::Imp(col, Box::new(lhs), Box::new(rhs)),
Eqv => Expression::Eqv(col, Box::new(lhs), Box::new(rhs)),
})
}
fn unary_op_precedence(op: &Operator) -> Result<usize> {
use Operator::*;
Ok(match op {
Plus | Minus => 12,
Not => 6,
_ => 0,
})
}
fn binary_op_precedence(op: &Operator) -> Result<usize> {
use Operator::*;
Ok(match op {
Caret => 13,
Multiply | Divide => 11,
DivideInt => 10,
Modulo => 9,
Plus | Minus => 8,
Equal | NotEqual | Less | LessEqual | Greater | GreaterEqual => 7,
And => 5,
Or => 4,
Xor => 3,
Imp => 2,
Eqv => 1,
_ => 0,
})
}
fn literal(col: Column, lit: &Literal) -> Result<Expression> {
fn parse<T: std::str::FromStr>(col: Column, s: &str) -> Result<T> {
let mut s = String::from(s).replace("D", "E");
match s.chars().last() {
Some('!') | Some('#') | Some('%') => {
s.pop();
}
_ => {}
};
match s.parse() {
Ok(num) => Ok(num),
Err(_) => Err(error!(TypeMismatch, ..&col)),
}
}
fn parse_radix(col: Column, src: &str, radix: u32) -> Result<Expression> {
match i16::from_str_radix(src, radix) {
Ok(num) => Ok(Expression::Integer(col, num)),
Err(_) => Err(error!(Overflow, ..&col)),
}
}
match lit {
Literal::Hex(s) => parse_radix(col, s, 16),
Literal::Octal(s) => parse_radix(col, s, 8),
Literal::Single(s) => Ok(Expression::Single(col.clone(), parse(col, s)?)),
Literal::Double(s) => Ok(Expression::Double(col.clone(), parse(col, s)?)),
Literal::Integer(s) => Ok(Expression::Integer(col.clone(), parse(col, s)?)),
Literal::String(s) => {
if s.chars().count() > 255 {
Err(error!(StringTooLong, ..&col; "MAXIMUM LITERAL LENGTH IS 255"))
} else {
Ok(Expression::String(col, s.clone().into()))
}
}
}
}
}
impl Statement {
#[allow(clippy::cognitive_complexity)]
fn expect(parse: &mut BasicParser) -> Result<Statement> {
match parse.peek() {
Some(Token::Ident(_)) => return Ok(Self::r#let(parse, true)?),
Some(Token::Word(word)) => {
parse.next();
use Word::*;
match word {
Clear => return Ok(Self::r#clear(parse)?),
Cls => return Ok(Self::r#cls(parse)?),
Cont => return Ok(Self::r#cont(parse)?),
Data => return Ok(Self::r#data(parse)?),
Def => return Ok(Self::r#def(parse)?),
Defdbl => return Ok(Self::r#defdbl(parse)?),
Defint => return Ok(Self::r#defint(parse)?),
Defsng => return Ok(Self::r#defsng(parse)?),
Defstr => return Ok(Self::r#defstr(parse)?),
Delete => return Ok(Self::r#delete(parse)?),
Dim => return Ok(Self::r#dim(parse)?),
End => return Ok(Self::r#end(parse)?),
Erase => return Ok(Self::r#erase(parse)?),
For => return Ok(Self::r#for(parse)?),
Gosub => return Ok(Self::r#gosub(parse)?),
Goto => return Ok(Self::r#goto(parse)?),
If => return Ok(Self::r#if(parse)?),
Input => return Ok(Self::r#input(parse)?),
Let => return Ok(Self::r#let(parse, false)?),
List => return Ok(Self::r#list(parse)?),
Load => return Ok(Self::r#load(parse)?),
New => return Ok(Self::r#new(parse)?),
Next => return Ok(Self::r#next(parse)?),
On => return Ok(Self::r#on(parse)?),
Print => return Ok(Self::r#print(parse)?),
Read => return Ok(Self::r#read(parse)?),
Renum => return Ok(Self::r#renum(parse)?),
Restore => return Ok(Self::r#restore(parse)?),
Return => return Ok(Self::r#return(parse)?),
Run => return Ok(Self::r#run(parse)?),
Save => return Ok(Self::r#save(parse)?),
Stop => return Ok(Self::r#stop(parse)?),
Swap => return Ok(Self::r#swap(parse)?),
Troff => return Ok(Self::r#troff(parse)?),
Tron => return Ok(Self::r#tron(parse)?),
Wend => return Ok(Self::r#wend(parse)?),
While => return Ok(Self::r#while(parse)?),
Else | Rem1 | Rem2 | Step | Then | To => {}
}
}
_ => {}
}
Err(error!(SyntaxError, ..&parse.col; "EXPECTED STATEMENT"))
}
fn r#clear(parse: &mut BasicParser) -> Result<Statement> {
let result = Ok(Statement::Clear(parse.col.clone()));
while match parse.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) => false,
_ => true,
} {
parse.next();
}
result
}
fn r#cls(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Cls(parse.col.clone()))
}
fn r#cont(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Cont(parse.col.clone()))
}
fn r#data(parse: &mut BasicParser) -> Result<Statement> {
let vec_expr = parse.expect_expression_list()?;
Ok(Statement::Data(parse.col.clone(), vec_expr))
}
fn r#def(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let fn_ident = if let Some(Token::Ident(ident)) = parse.next() {
ident.clone()
} else {
return Err(error!(SyntaxError, ..&parse.col; EXPECTED_VARIABLE));
};
if !fn_ident.is_user_function() {
return Err(error!(SyntaxError, ..&parse.col; "MUST START WITH FN"));
}
let fn_ident_col = parse.col.clone();
parse.expect(Token::LParen)?;
let mut ident_list = parse.expect_ident_list()?;
parse.expect(Token::RParen)?;
parse.expect(Token::Operator(Operator::Equal))?;
let mut var_map: HashMap<token::Ident, Variable> = HashMap::default();
let var_ident: Vec<Variable> = ident_list
.drain(..)
.map(|(tok_col, tok_ident)| {
let ast_ident = Ident::from((&fn_ident, &tok_ident));
var_map.insert(
tok_ident,
Variable::Unary(tok_col.clone(), ast_ident.clone()),
);
Variable::Unary(tok_col, ast_ident)
})
.collect();
let expr = parse.expect_fn_expression(&var_map)?;
let var = Variable::Unary(fn_ident_col, fn_ident.into());
Ok(Statement::Def(column, var, var_ident, expr))
}
fn r#defdbl(parse: &mut BasicParser) -> Result<Statement> {
let (from, to) = parse.expect_var_range()?;
Ok(Statement::Defdbl(parse.col.clone(), from, to))
}
fn r#defint(parse: &mut BasicParser) -> Result<Statement> {
let (from, to) = parse.expect_var_range()?;
Ok(Statement::Defint(parse.col.clone(), from, to))
}
fn r#defsng(parse: &mut BasicParser) -> Result<Statement> {
let (from, to) = parse.expect_var_range()?;
Ok(Statement::Defsng(parse.col.clone(), from, to))
}
fn r#defstr(parse: &mut BasicParser) -> Result<Statement> {
let (from, to) = parse.expect_var_range()?;
Ok(Statement::Defstr(parse.col.clone(), from, to))
}
fn r#delete(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let (from, to) = parse.expect_line_number_range()?;
Ok(Statement::Delete(column, from, to))
}
fn r#dim(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let var_list = parse.expect_var_list()?;
Ok(Statement::Dim(column, var_list))
}
fn r#end(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::End(parse.col.clone()))
}
fn r#erase(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let mut idents = parse.expect_ident_list()?;
if idents.is_empty() {
return Err(error!(SyntaxError, ..&(column.start..column.start); "EXPECTED VARIABLE"));
}
let vec_var = idents
.drain(..)
.map(|(col, i)| Variable::Unary(col, i.into()))
.collect::<Vec<Variable>>();
Ok(Statement::Erase(column, vec_var))
}
fn r#for(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let (ident_col, ident) = parse.expect_ident()?;
let var = Variable::Unary(ident_col, ident.into());
parse.expect(Token::Operator(Operator::Equal))?;
let expr_from = parse.expect_expression()?;
parse.expect(Token::Word(Word::To))?;
let expr_to = parse.expect_expression()?;
let expr_step = if parse.maybe(Token::Word(Word::Step)) {
parse.expect_expression()?
} else {
Expression::Integer(parse.col.end..parse.col.end, 1)
};
Ok(Statement::For(column, var, expr_from, expr_to, expr_step))
}
fn r#gosub(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Gosub(
parse.col.clone(),
parse.expect_line_number()?,
))
}
fn r#goto(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Goto(
parse.col.clone(),
parse.expect_line_number()?,
))
}
fn r#if(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let predicate = parse.expect_expression()?;
let then_stmt = if parse.maybe(Token::Word(Word::Goto)) {
vec![Statement::Goto(
parse.col.clone(),
parse.expect_line_number()?,
)]
} else {
parse.expect(Token::Word(Word::Then))?;
match parse.maybe_line_number()? {
Some(n) => vec![Statement::Goto(
column.clone(),
Expression::Single(parse.col.clone(), n as f32),
)],
None => parse.expect_statements()?,
}
};
let else_stmt = if parse.maybe(Token::Word(Word::Else)) {
match parse.maybe_line_number()? {
Some(n) => vec![Statement::Goto(
column.clone(),
Expression::Single(parse.col.clone(), n as f32),
)],
None => parse.expect_statements()?,
}
} else {
vec![]
};
Ok(Statement::If(column, predicate, then_stmt, else_stmt))
}
fn r#input(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let mut prompt_col = column.end..column.end;
let caps = if let Some(Token::Comma) = parse.peek() {
parse.next();
Expression::Integer(parse.col.clone(), 0)
} else {
Expression::Integer(parse.col.start..parse.col.start, -1)
};
let prompt = match parse.peek() {
Some(Token::Literal(Literal::String(s))) => {
parse.next();
prompt_col = parse.col.clone();
match parse.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) => {}
Some(Token::Semicolon) => {
parse.next();
}
_ => {
return Err(error!(SyntaxError, ..&parse.col.clone(); "UNEXPECTED TOKEN"));
}
}
s.clone()
}
_ => String::new(),
};
let var_list = parse.expect_var_list()?;
Ok(Statement::Input(
column,
caps,
Expression::String(prompt_col, prompt.into()),
var_list,
))
}
fn r#let(parse: &mut BasicParser, is_shortcut: bool) -> Result<Statement> {
let column = parse.col.clone();
if let Some(Token::Ident(token::Ident::String(s))) = parse.peek() {
if s == "MID$" {
parse.next();
parse.expect(Token::LParen)?;
let var = parse.expect_var()?;
parse.expect(Token::Comma)?;
let pos = parse.expect_expression()?;
let len = if parse.maybe(Token::Comma) {
parse.expect_expression()?
} else {
Expression::Integer(parse.col.start..parse.col.start, i16::max_value())
};
parse.expect(Token::RParen)?;
parse.expect(Token::Operator(Operator::Equal))?;
let expr = parse.expect_expression()?;
return Ok(Statement::Mid(column, var, pos, len, expr));
}
}
let var = parse.expect_var()?;
match parse.next() {
Some(Token::Operator(Operator::Equal)) => {
Ok(Statement::Let(column, var, parse.expect_expression()?))
}
_ => {
if is_shortcut {
Err(error!(SyntaxError, ..&column; "UNKNOWN STATEMENT"))
} else {
Err(error!(SyntaxError, ..&parse.col; "EXPECTED EQUALS SIGN"))
}
}
}
}
fn r#list(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let (from, to) = parse.expect_line_number_range()?;
Ok(Statement::List(column, from, to))
}
fn r#load(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Load(
parse.col.clone(),
parse.expect_expression()?,
))
}
fn r#new(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::New(parse.col.clone()))
}
fn r#next(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let mut idents = parse.expect_ident_list()?;
if idents.is_empty() {
return Ok(Statement::Next(
column,
vec![Variable::Unary(0..0, Ident::Plain("".into()))],
));
}
let vec_var = idents
.drain(..)
.map(|(col, i)| Variable::Unary(col, i.into()))
.collect::<Vec<Variable>>();
Ok(Statement::Next(column, vec_var))
}
fn r#on(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let expr = parse.expect_expression()?;
match parse.next() {
Some(Token::Word(Word::Goto)) => Ok(Statement::OnGoto(
column,
expr,
parse.expect_line_number_list()?,
)),
Some(Token::Word(Word::Gosub)) => Ok(Statement::OnGosub(
column,
expr,
parse.expect_line_number_list()?,
)),
_ => Err(error!(SyntaxError, ..&parse.col; "EXPECTED GOTO OR GOSUB")),
}
}
fn r#print(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
let vec_expr = parse.expect_print_list()?;
Ok(Statement::Print(column, vec_expr))
}
fn r#read(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Read(parse.col.clone(), parse.expect_var_list()?))
}
fn r#renum(parse: &mut BasicParser) -> Result<Statement> {
fn parse_start(parse: &mut BasicParser, default: f32) -> Result<Expression> {
if parse.maybe(Token::Comma) {
Ok(Expression::Single(parse.col.clone(), default))
} else {
match parse.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) => Ok(
Expression::Single(parse.col.start..parse.col.start, default),
),
_ => {
let ln = parse.expect_line_number()?;
parse.maybe(Token::Comma);
Ok(ln)
}
}
}
}
let column = parse.col.clone();
let new_start = parse_start(parse, 10.0)?;
let old_start = parse_start(parse, 0.0)?;
let step = match parse.peek() {
None | Some(Token::Colon) | Some(Token::Word(Word::Else)) => {
Expression::Single(parse.col.start..parse.col.start, 10.0)
}
_ => parse.expect_line_number()?,
};
Ok(Statement::Renum(column, new_start, old_start, step))
}
fn r#restore(parse: &mut BasicParser) -> Result<Statement> {
let num = if let Some(num) = parse.maybe_line_number()? {
num as f32
} else {
-1.0
};
Ok(Statement::Restore(
parse.col.clone(),
Expression::Single(parse.col.clone(), num as f32),
))
}
fn r#return(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Return(parse.col.clone()))
}
fn r#run(parse: &mut BasicParser) -> Result<Statement> {
let column = parse.col.clone();
if let Some(Token::Literal(Literal::String(s))) = parse.peek() {
parse.next();
Ok(Statement::Run(
column,
Expression::String(parse.col.clone(), s.clone().into()),
))
} else if let Some(num) = parse.maybe_line_number()? {
Ok(Statement::Run(
column,
Expression::Single(parse.col.clone(), num as f32),
))
} else {
let empty = parse.col.clone();
let empty = empty.start..empty.start;
Ok(Statement::Run(column, Expression::Single(empty, -1.0)))
}
}
fn r#save(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Save(
parse.col.clone(),
parse.expect_expression()?,
))
}
fn r#stop(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Stop(parse.col.clone()))
}
fn r#swap(parse: &mut BasicParser) -> Result<Statement> {
let col = parse.col.clone();
let mut var_list = parse.expect_var_list()?;
if var_list.len() != 2 {
return Err(
error!(SyntaxError, ..&(col.start..parse.col.end); "EXPECTED TWO VARIABLES" ),
);
}
Ok(Statement::Swap(
col,
var_list.pop().unwrap(),
var_list.pop().unwrap(),
))
}
fn r#troff(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Troff(parse.col.clone()))
}
fn r#tron(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Tron(parse.col.clone()))
}
fn r#wend(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::Wend(parse.col.clone()))
}
fn r#while(parse: &mut BasicParser) -> Result<Statement> {
Ok(Statement::While(
parse.col.clone(),
parse.expect_expression()?,
))
}
}
impl From<token::Ident> for Ident {
fn from(ident: token::Ident) -> Self {
use token::Ident::*;
match ident {
Plain(s) => Ident::Plain(s.into()),
String(s) => Ident::String(s.into()),
Single(s) => Ident::Single(s.into()),
Double(s) => Ident::Double(s.into()),
Integer(s) => Ident::Integer(s.into()),
}
}
}
impl From<(&token::Ident, &token::Ident)> for Ident {
fn from(f: (&token::Ident, &token::Ident)) -> Self {
let mut string = match f.0 {
token::Ident::Plain(s) => s,
token::Ident::String(s) => s,
token::Ident::Single(s) => s,
token::Ident::Double(s) => s,
token::Ident::Integer(s) => s,
}
.to_string();
string.push('.');
match f.1 {
token::Ident::Plain(s) => Ident::Plain({
string.push_str(&s);
string.into()
}),
token::Ident::String(s) => Ident::String({
string.push_str(&s);
string.into()
}),
token::Ident::Single(s) => Ident::Single({
string.push_str(&s);
string.into()
}),
token::Ident::Double(s) => Ident::Double({
string.push_str(&s);
string.into()
}),
token::Ident::Integer(s) => Ident::Integer({
string.push_str(&s);
string.into()
}),
}
}
}
impl token::Ident {
fn is_user_function(&self) -> bool {
use token::Ident::*;
match self {
Plain(s) => s,
String(s) => s,
Single(s) => s,
Double(s) => s,
Integer(s) => s,
}
.starts_with("FN")
}
}