bitwise operators, hex/bin/seximal literals, changed infix boxing notation, fixed semicolons in repl
This commit is contained in:
parent
443262f711
commit
7be878b97a
10 changed files with 180 additions and 69 deletions
|
@ -229,6 +229,10 @@ let add7 = add(7);
|
||||||
println(add7(3)); # prints 10
|
println(add7(3)); # prints 10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Boxed infix operators
|
||||||
|
|
||||||
|
Some infix operators can be converted to functions by prefixing them with a backslash `\`. For example, `\+` is a function that computes the sum of its two arguments (the same as `fn(x, y) (x + y)`). This can be done for arithmetic, comparison, and bitwise operators only.
|
||||||
|
|
||||||
## Iterators
|
## Iterators
|
||||||
|
|
||||||
An iterator is simply a function with the following properties:
|
An iterator is simply a function with the following properties:
|
||||||
|
|
|
@ -144,7 +144,9 @@ pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
Some(OpType::Additive)
|
Some(OpType::Additive)
|
||||||
| Some(OpType::Multiplicative)
|
| Some(OpType::Multiplicative)
|
||||||
| Some(OpType::Exponential)
|
| Some(OpType::Exponential)
|
||||||
| Some(OpType::Comparison) => {
|
| Some(OpType::Comparison)
|
||||||
|
| Some(OpType::BitwiseAnd)
|
||||||
|
| Some(OpType::BitwiseOr) => {
|
||||||
let l = eval_expr(lhs, env.clone())?;
|
let l = eval_expr(lhs, env.clone())?;
|
||||||
let r = eval_expr(rhs, env)?;
|
let r = eval_expr(rhs, env)?;
|
||||||
eval_standard_binary(l, r, &op.ty, &op.pos)
|
eval_standard_binary(l, r, &op.ty, &op.pos)
|
||||||
|
@ -361,6 +363,8 @@ pub fn eval_standard_binary(l: Value, r: Value, opty: &TokenType, pos: &Position
|
||||||
TokenType::Star => &l * &r,
|
TokenType::Star => &l * &r,
|
||||||
TokenType::Slash => &l / &r,
|
TokenType::Slash => &l / &r,
|
||||||
TokenType::Percent => &l % &r,
|
TokenType::Percent => &l % &r,
|
||||||
|
TokenType::Amper => &l & &r,
|
||||||
|
TokenType::Pipe => &l | &r,
|
||||||
TokenType::Caret => l.pow(&r),
|
TokenType::Caret => l.pow(&r),
|
||||||
TokenType::DoubleSlash => l.fracdiv(&r),
|
TokenType::DoubleSlash => l.fracdiv(&r),
|
||||||
TokenType::DoubleEqual => Ok(Value::Bool(l == r)),
|
TokenType::DoubleEqual => Ok(Value::Bool(l == r)),
|
||||||
|
@ -511,8 +515,9 @@ pub fn eval_ternary(arg1: &Expr, arg2: &Expr, arg3: &Expr, op: &Token, env: EnvR
|
||||||
pub fn eval_unary(arg: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
pub fn eval_unary(arg: &Expr, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
let a = eval_expr(arg, env)?;
|
let a = eval_expr(arg, env)?;
|
||||||
match op.ty {
|
match op.ty {
|
||||||
TokenType::Minus => -a,
|
TokenType::Minus => -&a,
|
||||||
TokenType::Bang => Ok(Value::Bool(!a.truthy())),
|
TokenType::Bang => Ok(Value::Bool(!a.truthy())),
|
||||||
|
TokenType::Tilde => !&a,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,8 @@ pub fn interpret(src: &str, fname: Option<String>, env: Option<EnvRef>, repl: bo
|
||||||
let ctx_name = if repl { "<interactive input>" } else { fname.as_ref().map(|s| s.as_ref()).unwrap_or("<unknown>") };
|
let ctx_name = if repl { "<interactive input>" } else { fname.as_ref().map(|s| s.as_ref()).unwrap_or("<unknown>") };
|
||||||
let mut lexer = Lexer::new(src, fname.clone());
|
let mut lexer = Lexer::new(src, fname.clone());
|
||||||
lexer.lex()?;
|
lexer.lex()?;
|
||||||
let mut parser = Parser::new(lexer.into_tokens(), repl);
|
let tokens = lexer.into_tokens();
|
||||||
|
let mut parser = Parser::new(tokens);
|
||||||
let ast = parser.parse()?;
|
let ast = parser.parse()?;
|
||||||
let environ;
|
let environ;
|
||||||
if let Some(env) = env {
|
if let Some(env) = env {
|
||||||
|
|
|
@ -2,6 +2,19 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{ParserError, Position, token::{Token, TokenType}};
|
use crate::{ParserError, Position, token::{Token, TokenType}};
|
||||||
|
|
||||||
|
fn is_in_base(c: char, base: u32) -> bool {
|
||||||
|
match (c, base) {
|
||||||
|
('0' | '1', 2) => true,
|
||||||
|
('0'..='5', 6) => true,
|
||||||
|
('0'..='7', 8) => true,
|
||||||
|
('0'..='9', 10) => true,
|
||||||
|
('0'..='9' | 'a' | 'b' | 'A' | 'B', 12) => true,
|
||||||
|
('0'..='9' | 'a'..='f' | 'A'..='F', 16) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct Lexer {
|
pub struct Lexer {
|
||||||
// name of file being lexed
|
// name of file being lexed
|
||||||
filename: Option<Rc<str>>,
|
filename: Option<Rc<str>>,
|
||||||
|
@ -220,6 +233,7 @@ impl Lexer {
|
||||||
_ => self.add_token(TokenType::Pipe, "|"),
|
_ => self.add_token(TokenType::Pipe, "|"),
|
||||||
},
|
},
|
||||||
'~' => self.add_token(TokenType::Tilde, "~"),
|
'~' => self.add_token(TokenType::Tilde, "~"),
|
||||||
|
'\\' => self.add_token(TokenType::Backslash, "\\"),
|
||||||
',' => self.add_token(TokenType::Comma, ","),
|
',' => self.add_token(TokenType::Comma, ","),
|
||||||
';' => self.add_token(TokenType::Semicolon, ";"),
|
';' => self.add_token(TokenType::Semicolon, ";"),
|
||||||
':' => self.add_token(TokenType::Colon, ":"),
|
':' => self.add_token(TokenType::Colon, ":"),
|
||||||
|
@ -256,7 +270,15 @@ impl Lexer {
|
||||||
'"' => self.string()?,
|
'"' => self.string()?,
|
||||||
'\'' => self.char()?,
|
'\'' => self.char()?,
|
||||||
' ' | '\t' | '\r' | '\n' => (),
|
' ' | '\t' | '\r' | '\n' => (),
|
||||||
'0'..='9' => self.number()?,
|
'0' => match self.expect(&['b', 's', 'o', 'd', 'x']) {
|
||||||
|
Some('b') => self.number(2)?,
|
||||||
|
Some('s') => self.number(6)?,
|
||||||
|
Some('o') => self.number(8)?,
|
||||||
|
Some('d') => self.number(12)?,
|
||||||
|
Some('x') => self.number(16)?,
|
||||||
|
_ => self.number(10)?,
|
||||||
|
},
|
||||||
|
'0'..='9' => self.number(10)?,
|
||||||
'a'..='z' | 'A'..='Z' | '_' => self.ident()?,
|
'a'..='z' | 'A'..='Z' | '_' => self.ident()?,
|
||||||
c => return Err(self.mk_error(format!("Unexpected character: {}", c)))
|
c => return Err(self.mk_error(format!("Unexpected character: {}", c)))
|
||||||
}
|
}
|
||||||
|
@ -306,9 +328,9 @@ impl Lexer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(&mut self) -> Result<(), ParserError> {
|
fn number(&mut self, base: u32) -> Result<(), ParserError> {
|
||||||
let mut has_dot = false;
|
let mut has_dot = false;
|
||||||
while !self.at_end() && (self.peek().is_numeric() || self.peek() == '.') {
|
while !self.at_end() && (is_in_base(self.peek(), base) || self.peek() == '.') {
|
||||||
if self.peek() == '.' {
|
if self.peek() == '.' {
|
||||||
if has_dot {
|
if has_dot {
|
||||||
break;
|
break;
|
||||||
|
@ -316,6 +338,9 @@ impl Lexer {
|
||||||
if self.peek_ahead(1) == Some('.') {
|
if self.peek_ahead(1) == Some('.') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if base != 10 {
|
||||||
|
return Err(self.mk_error("Numeric literals using bases other than 10 must be integers."))
|
||||||
|
}
|
||||||
has_dot = true;
|
has_dot = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,10 +359,16 @@ impl Lexer {
|
||||||
Ok(num) => self.add_token(TokenType::Float(num), literal),
|
Ok(num) => self.add_token(TokenType::Float(num), literal),
|
||||||
Err(e) => return Err(self.mk_error(format!("Error parsing float: {}", e)))
|
Err(e) => return Err(self.mk_error(format!("Error parsing float: {}", e)))
|
||||||
}
|
}
|
||||||
|
} else if base != 10 {
|
||||||
|
match i64::from_str_radix(&literal[2..literal.len()], base) {
|
||||||
|
Ok(num) => self.add_token(TokenType::Int(num), literal),
|
||||||
|
Err(e) => return Err(self.mk_error(format!("Error parsing integer: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
match literal.parse::<i64>() {
|
match literal.parse::<i64>() {
|
||||||
Ok(num) => self.add_token(TokenType::Int(num), literal),
|
Ok(num) => self.add_token(TokenType::Int(num), literal),
|
||||||
Err(e) => return Err(self.mk_error(format!("Error parsing float: {}", e)))
|
Err(e) => return Err(self.mk_error(format!("Error parsing integer: {}", e)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -4,19 +4,18 @@ use crate::{token::{Token, TokenType, OpType}, ParserError, expr::{Stmt, Expr},
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
repl: bool,
|
|
||||||
idx: usize
|
idx: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn new(tokens: Vec<Token>, repl: bool) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
Self { tokens, repl, idx: 0 }
|
Self { tokens, idx: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Vec<Stmt>, ParserError> {
|
pub fn parse(&mut self) -> Result<Vec<Stmt>, ParserError> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
while !self.at_end() {
|
while !self.at_end() {
|
||||||
stmts.push(self.statement(!self.repl)?);
|
stmts.push(self.statement()?);
|
||||||
}
|
}
|
||||||
Ok(stmts)
|
Ok(stmts)
|
||||||
}
|
}
|
||||||
|
@ -96,14 +95,19 @@ impl Parser {
|
||||||
// //
|
// //
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
fn statement(&mut self, req_semicolon: bool) -> Result<Stmt, ParserError> {
|
fn statement(&mut self) -> Result<Stmt, ParserError> {
|
||||||
let next_ty = &self.peek().ty;
|
let next_ty = &self.peek().ty;
|
||||||
|
|
||||||
match next_ty {
|
match next_ty {
|
||||||
|
TokenType::Semicolon => {
|
||||||
|
// skip lonely semicolon
|
||||||
|
self.next();
|
||||||
|
self.statement()
|
||||||
|
}
|
||||||
TokenType::Let => {
|
TokenType::Let => {
|
||||||
// let statement
|
// let statement
|
||||||
self.next();
|
self.next();
|
||||||
self.letstmt(req_semicolon)
|
self.letstmt()
|
||||||
},
|
},
|
||||||
TokenType::LBrace => {
|
TokenType::LBrace => {
|
||||||
// block
|
// block
|
||||||
|
@ -127,16 +131,16 @@ impl Parser {
|
||||||
},
|
},
|
||||||
TokenType::Break => {
|
TokenType::Break => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
self.terminate_stmt(Stmt::Break{ pos: tok.pos }, req_semicolon)
|
self.terminate_stmt(Stmt::Break{ pos: tok.pos })
|
||||||
},
|
},
|
||||||
TokenType::Continue => {
|
TokenType::Continue => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
self.terminate_stmt(Stmt::Continue{ pos: tok.pos }, req_semicolon)
|
self.terminate_stmt(Stmt::Continue{ pos: tok.pos })
|
||||||
},
|
},
|
||||||
TokenType::Return => {
|
TokenType::Return => {
|
||||||
let tok = self.next();
|
let tok = self.next();
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.terminate_stmt(Stmt::Return{ pos: tok.pos, expr }, req_semicolon)
|
self.terminate_stmt(Stmt::Return{ pos: tok.pos, expr })
|
||||||
},
|
},
|
||||||
TokenType::Fn => {
|
TokenType::Fn => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -149,39 +153,34 @@ impl Parser {
|
||||||
_ => {
|
_ => {
|
||||||
// fallback to an expression terminated with a semicolon
|
// fallback to an expression terminated with a semicolon
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.terminate_stmt(Stmt::Expr{ expr }, req_semicolon)
|
self.terminate_stmt(Stmt::Expr{ expr })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result<Stmt, ParserError> {
|
fn terminate_stmt(&mut self, stmt: Stmt) -> Result<Stmt, ParserError> {
|
||||||
if self.at_end() {
|
if self.at_end() {
|
||||||
if req_semicolon {
|
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
} else{
|
|
||||||
return Ok(stmt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.expect(TokenType::Semicolon).0 {
|
match self.expect(TokenType::Semicolon).0 {
|
||||||
true => Ok(stmt),
|
true => Ok(stmt),
|
||||||
false if !req_semicolon => Ok(stmt),
|
|
||||||
false => Err(self.mk_error("Missing semicolon after statement"))
|
false => Err(self.mk_error("Missing semicolon after statement"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn letstmt(&mut self, req_semicolon: bool) -> Result<Stmt, ParserError> {
|
fn letstmt(&mut self) -> Result<Stmt, ParserError> {
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
// must be followed by an assignment expression
|
// must be followed by an assignment expression
|
||||||
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
||||||
if let Expr::Ident{value: tok} = *lhs {
|
if let Expr::Ident{value: tok} = *lhs {
|
||||||
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: Some(*rhs)}, req_semicolon)
|
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: Some(*rhs)})
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
}
|
}
|
||||||
} else if let Expr::Ident{value: tok} = expr {
|
} else if let Expr::Ident{value: tok} = expr {
|
||||||
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: None}, req_semicolon)
|
self.terminate_stmt(Stmt::Let{lhs: tok, rhs: None})
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
}
|
}
|
||||||
|
@ -192,7 +191,7 @@ impl Parser {
|
||||||
let mut ec = false;
|
let mut ec = false;
|
||||||
loop {
|
loop {
|
||||||
let condition = self.assignment()?;
|
let condition = self.assignment()?;
|
||||||
let body = self.statement(true)?;
|
let body = self.statement()?;
|
||||||
if_clauses.push((condition, body));
|
if_clauses.push((condition, body));
|
||||||
match self.peek().ty {
|
match self.peek().ty {
|
||||||
TokenType::Elif => { self.next(); continue },
|
TokenType::Elif => { self.next(); continue },
|
||||||
|
@ -201,7 +200,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let else_clause = if ec {
|
let else_clause = if ec {
|
||||||
Some(Box::new(self.statement(true)?))
|
Some(Box::new(self.statement()?))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -222,7 +221,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let stmt = self.statement(true)?;
|
let stmt = self.statement()?;
|
||||||
Ok(Stmt::For{ var, expr, stmt: Box::new(stmt), iter_pos: colon.pos })
|
Ok(Stmt::For{ var, expr, stmt: Box::new(stmt), iter_pos: colon.pos })
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error("Expected identifier after for"))
|
Err(self.mk_error("Expected identifier after for"))
|
||||||
|
@ -233,7 +232,7 @@ impl Parser {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let stmt = self.statement(true)?;
|
let stmt = self.statement()?;
|
||||||
Ok(Stmt::While{ expr, stmt: Box::new(stmt) })
|
Ok(Stmt::While{ expr, stmt: Box::new(stmt) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +272,7 @@ impl Parser {
|
||||||
fn block(&mut self) -> Result<Stmt, ParserError> {
|
fn block(&mut self) -> Result<Stmt, ParserError> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
while !self.at_end() && self.peek().ty != TokenType::RBrace {
|
while !self.at_end() && self.peek().ty != TokenType::RBrace {
|
||||||
stmts.push(self.statement(true)?)
|
stmts.push(self.statement()?)
|
||||||
}
|
}
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -357,7 +356,15 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> Result<Expr, ParserError> {
|
fn comparison(&mut self) -> Result<Expr, ParserError> {
|
||||||
self.expr(OpType::Comparison, Self::additive)
|
self.expr(OpType::Comparison, Self::bitwise_or)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bitwise_or(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
self.expr(OpType::BitwiseOr, Self::bitwise_and)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bitwise_and(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
self.expr(OpType::BitwiseAnd, Self::additive)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn additive(&mut self) -> Result<Expr, ParserError> {
|
fn additive(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
@ -422,9 +429,9 @@ impl Parser {
|
||||||
// unary: !x, -x
|
// unary: !x, -x
|
||||||
fn unary(&mut self) -> Result<Expr, ParserError> {
|
fn unary(&mut self) -> Result<Expr, ParserError> {
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
if matches!(self.peek().ty, TokenType::Bang | TokenType::Minus) {
|
if matches!(self.peek().ty, TokenType::Minus | TokenType::Bang | TokenType::Tilde) {
|
||||||
let op = self.next();
|
let op = self.next();
|
||||||
Ok(Expr::Unary { arg: Box::new(self.fieldaccess()?), op })
|
Ok(Expr::Unary { arg: Box::new(self.unary()?), op })
|
||||||
} else {
|
} else {
|
||||||
self.fieldaccess()
|
self.fieldaccess()
|
||||||
}
|
}
|
||||||
|
@ -511,29 +518,26 @@ impl Parser {
|
||||||
// An identifier
|
// An identifier
|
||||||
Ok(Expr::Ident { value: next })
|
Ok(Expr::Ident { value: next })
|
||||||
} else if next.ty == TokenType::LParen {
|
} else if next.ty == TokenType::LParen {
|
||||||
// Special case for "boxed infix operators"
|
// Grouping with parentheses
|
||||||
if !self.at_end() && self.peek().ty.is_infix_op() {
|
|
||||||
let op = self.next();
|
|
||||||
self.err_on_eof()?;
|
|
||||||
if self.peek().ty != TokenType::RParen {
|
|
||||||
return Err(self.mk_error("Expected right parenthesis after enclosed operator"))
|
|
||||||
}
|
|
||||||
self.next();
|
|
||||||
let func = Func::BuiltinClosure {
|
|
||||||
arg_count: 2,
|
|
||||||
func: Rc::new(move |args| {
|
|
||||||
eval_standard_binary(args[0].clone(), args[1].clone(), &op.ty, &op.pos)
|
|
||||||
})
|
|
||||||
};
|
|
||||||
return Ok(Expr::BoxedInfix { func })
|
|
||||||
}
|
|
||||||
// general case: parentheses as grouping symbols
|
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
if self.at_end() || TokenType::RParen != self.next().ty {
|
if self.at_end() || TokenType::RParen != self.next().ty {
|
||||||
Err(self.mk_error("Left parenthesis never closed"))
|
Err(self.mk_error("Left parenthesis never closed"))
|
||||||
} else {
|
} else {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
} else if next.ty == TokenType::Backslash {
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let op = self.next();
|
||||||
|
if !op.ty.is_infix_op() {
|
||||||
|
return Err(self.mk_error("Expected infix operator after backslash"))
|
||||||
|
}
|
||||||
|
let func = Func::BuiltinClosure {
|
||||||
|
arg_count: 2,
|
||||||
|
func: Rc::new(move |args| {
|
||||||
|
eval_standard_binary(args[0].clone(), args[1].clone(), &op.ty, &op.pos)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
Ok(Expr::BoxedInfix { func })
|
||||||
} else if next.ty == TokenType::LBrack {
|
} else if next.ty == TokenType::LBrack {
|
||||||
// list literal
|
// list literal
|
||||||
let items = self.commalist(TokenType::RBrack, Self::assignment)?;
|
let items = self.commalist(TokenType::RBrack, Self::assignment)?;
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub enum TokenType {
|
||||||
|
|
||||||
PipeColon, PipePoint, PipeQuestion, PipeAmper,
|
PipeColon, PipePoint, PipeQuestion, PipeAmper,
|
||||||
PipeSlash, PipeBackslash, PipeDoubleSlash, PipeDoubleBackslash,
|
PipeSlash, PipeBackslash, PipeDoubleSlash, PipeDoubleBackslash,
|
||||||
|
Backslash,
|
||||||
|
|
||||||
Comma, Semicolon, Colon,
|
Comma, Semicolon, Colon,
|
||||||
|
|
||||||
|
@ -63,6 +64,9 @@ impl TokenType {
|
||||||
| Self::StarEqual | Self::SlashEqual | Self::DoubleSlashEqual
|
| Self::StarEqual | Self::SlashEqual | Self::DoubleSlashEqual
|
||||||
| Self::CaretEqual | Self::PercentEqual => Some(OpType::Assignment),
|
| Self::CaretEqual | Self::PercentEqual => Some(OpType::Assignment),
|
||||||
|
|
||||||
|
Self::Amper => Some(OpType::BitwiseAnd),
|
||||||
|
Self::Pipe => Some(OpType::BitwiseOr),
|
||||||
|
|
||||||
Self::DoubleAmper => Some(OpType::LogicalAnd),
|
Self::DoubleAmper => Some(OpType::LogicalAnd),
|
||||||
Self::DoublePipe => Some(OpType::LogicalOr),
|
Self::DoublePipe => Some(OpType::LogicalOr),
|
||||||
|
|
||||||
|
@ -83,6 +87,8 @@ impl TokenType {
|
||||||
| OpType::Multiplicative
|
| OpType::Multiplicative
|
||||||
| OpType::Exponential
|
| OpType::Exponential
|
||||||
| OpType::Comparison
|
| OpType::Comparison
|
||||||
|
| OpType::BitwiseAnd
|
||||||
|
| OpType::BitwiseOr
|
||||||
// TODO | OpType::Pipeline
|
// TODO | OpType::Pipeline
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -90,7 +96,10 @@ impl TokenType {
|
||||||
|
|
||||||
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
|
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
|
||||||
pub enum OpType {
|
pub enum OpType {
|
||||||
Assignment, Comparison, Pipeline, Additive, Multiplicative, Exponential, LogicalAnd, LogicalOr
|
Assignment, Comparison, Pipeline,
|
||||||
|
Additive, Multiplicative, Exponential,
|
||||||
|
LogicalAnd, LogicalOr,
|
||||||
|
BitwiseAnd, BitwiseOr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpType {
|
impl OpType {
|
||||||
|
|
|
@ -480,7 +480,7 @@ value_from!(Map, RefCell<HashMap<Value,Value>>);
|
||||||
|
|
||||||
|
|
||||||
macro_rules! impl_numeric_op {
|
macro_rules! impl_numeric_op {
|
||||||
($optrait:ty, $fnname:ident, { $($bonus:tt)* }) => {
|
($optrait:ty, $fnname:ident, $op:literal, { $($bonus:tt)* }) => {
|
||||||
impl $optrait for &Value {
|
impl $optrait for &Value {
|
||||||
type Output = Result<Value, String>;
|
type Output = Result<Value, String>;
|
||||||
fn $fnname(self, other: Self) -> Self::Output {
|
fn $fnname(self, other: Self) -> Self::Output {
|
||||||
|
@ -504,14 +504,14 @@ macro_rules! impl_numeric_op {
|
||||||
(Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).$fnname(b).into()),
|
(Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).$fnname(b).into()),
|
||||||
(Complex(a), Rational(b)) => Ok(a.$fnname(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()),
|
(Complex(a), Rational(b)) => Ok(a.$fnname(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()),
|
||||||
(Complex(a), Complex(b)) => Ok(a.$fnname(b).into()),
|
(Complex(a), Complex(b)) => Ok(a.$fnname(b).into()),
|
||||||
(lhs, rhs) => Err(format!("Unsupported operation '{}' between {} and {}", stringify!($fnname), lhs.repr(), rhs.repr()))
|
(lhs, rhs) => Err(format!("Unsupported operation '{}' between {} and {}", $op, lhs.repr(), rhs.repr()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Neg for Value {
|
impl Neg for &Value {
|
||||||
type Output = Result<Value, String>;
|
type Output = Result<Value, String>;
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
|
@ -524,7 +524,7 @@ impl Neg for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_numeric_op!(Add, add, {
|
impl_numeric_op!(Add, add, "+", {
|
||||||
(String(a), String(b)) => Ok(((**a).to_owned() + b).into()),
|
(String(a), String(b)) => Ok(((**a).to_owned() + b).into()),
|
||||||
(String(a), Char(c)) => {
|
(String(a), Char(c)) => {
|
||||||
let mut s = (**a).to_owned();
|
let mut s = (**a).to_owned();
|
||||||
|
@ -543,20 +543,20 @@ impl_numeric_op!(Add, add, {
|
||||||
Ok(a.into())
|
Ok(a.into())
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
impl_numeric_op!(Sub, sub, {});
|
impl_numeric_op!(Sub, sub, "-", {});
|
||||||
impl_numeric_op!(Mul, mul, {
|
impl_numeric_op!(Mul, mul, "*", {
|
||||||
(String(a), Int(b)) | (Int(b), String(a))
|
(String(a), Int(b)) | (Int(b), String(a))
|
||||||
=> Ok(Value::from(a.chars().cycle().take(a.chars().count()*(*b as usize)).collect::<std::string::String>())),
|
=> Ok(Value::from(a.chars().cycle().take(a.chars().count()*(*b as usize)).collect::<std::string::String>())),
|
||||||
(List(a), Int(b)) | (Int(b), List(a))
|
(List(a), Int(b)) | (Int(b), List(a))
|
||||||
=> Ok(Value::from(a.borrow().iter().cycle().take(a.borrow().len()*(*b as usize)).cloned().collect::<Vec<Value>>())),
|
=> Ok(Value::from(a.borrow().iter().cycle().take(a.borrow().len()*(*b as usize)).cloned().collect::<Vec<Value>>())),
|
||||||
});
|
});
|
||||||
impl_numeric_op!(Div, div, {
|
impl_numeric_op!(Div, div, "/", {
|
||||||
(Int(_), Int(b)) if *b == 0 => Err("Integer division by zero".into()),
|
(Int(_), Int(b)) if *b == 0 => Err("Integer division by zero".into()),
|
||||||
(Rational(_), Int(b)) if *b == 0 => Err("Rational division by zero".into()),
|
(Rational(_), Int(b)) if *b == 0 => Err("Rational division by zero".into()),
|
||||||
(Int(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()),
|
(Int(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()),
|
||||||
(Rational(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()),
|
(Rational(_), Rational(b)) if b.is_zero() => Err("Rational division by zero".into()),
|
||||||
});
|
});
|
||||||
impl_numeric_op!(Rem, rem, {
|
impl_numeric_op!(Rem, rem, "%", {
|
||||||
(Int(_), Int(b)) if *b == 0 => Err("Integer modulo by zero".into()),
|
(Int(_), Int(b)) if *b == 0 => Err("Integer modulo by zero".into()),
|
||||||
(Rational(_), Int(b)) if *b == 0 => Err("Rational modulo by zero".into()),
|
(Rational(_), Int(b)) if *b == 0 => Err("Rational modulo by zero".into()),
|
||||||
(Int(_), Rational(b)) if b.is_zero() => Err("Rational modulo by zero".into()),
|
(Int(_), Rational(b)) if b.is_zero() => Err("Rational modulo by zero".into()),
|
||||||
|
@ -594,7 +594,46 @@ impl Pow<&Value> for &Value {
|
||||||
(Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).pow(b).into()),
|
(Rational(a), Complex(b)) => Ok(self::Complex::from(a.to_f64().ok_or(RATIO_CAST_FAIL)?).pow(b).into()),
|
||||||
(Complex(a), Rational(b)) => Ok(a.pow(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()),
|
(Complex(a), Rational(b)) => Ok(a.pow(self::Complex::from(b.to_f64().ok_or(RATIO_CAST_FAIL)?)).into()),
|
||||||
(Complex(a), Complex(b)) => Ok(a.pow(b).into()),
|
(Complex(a), Complex(b)) => Ok(a.pow(b).into()),
|
||||||
(lhs, rhs) => Err(format!("Unsupported operation 'pow' between {} and {}", lhs.repr(), rhs.repr()))
|
(lhs, rhs) => Err(format!("Unsupported operation '^' between {} and {}", lhs.repr(), rhs.repr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd for &Value {
|
||||||
|
type Output = Result<Value, String>;
|
||||||
|
|
||||||
|
fn bitand(self, other: Self) -> Self::Output {
|
||||||
|
use Value::*;
|
||||||
|
match (self, other) {
|
||||||
|
(Int(a), Int(b)) => Ok(Int(a & b)),
|
||||||
|
(Bool(a), Bool(b)) => Ok(Bool(a & b)),
|
||||||
|
_ => Err(format!("Unsupported operation '&' between {} and {}", self.repr(), other.repr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for &Value {
|
||||||
|
type Output = Result<Value, String>;
|
||||||
|
|
||||||
|
fn bitor(self, other: Self) -> Self::Output {
|
||||||
|
use Value::*;
|
||||||
|
match (self, other) {
|
||||||
|
(Int(a), Int(b)) => Ok(Int(a | b)),
|
||||||
|
(Bool(a), Bool(b)) => Ok(Bool(a | b)),
|
||||||
|
_ => Err(format!("Unsupported operation '|' between {} and {}", self.repr(), other.repr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for &Value {
|
||||||
|
type Output = Result<Value, String>;
|
||||||
|
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
use Value::*;
|
||||||
|
match self {
|
||||||
|
Int(a) => Ok(Int(!a)),
|
||||||
|
Bool(a) => Ok(Bool(!a)),
|
||||||
|
_ => Err(format!("Unsupported operation '~' for {}", self.repr())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
while true {
|
while true {
|
||||||
print(input());
|
println(input());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,29 @@
|
||||||
fn factorial(n) {
|
fn fact_recursive(n) {
|
||||||
if n <= 1 {
|
if n <= 1 {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
|
||||||
return n * factorial(n-1);
|
|
||||||
}
|
}
|
||||||
|
return n * fact_recursive(n-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for n: 0..10 {
|
fn fact_imperative(n) {
|
||||||
println(factorial(n));
|
if n <= 1 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
let res = 1;
|
||||||
|
for i: 1..=n {
|
||||||
|
res *= i;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fact_pipeline(n) {
|
||||||
|
if n <= 1 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1..=n |// \*;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 10*9*8*7*6*5*4*3*2*1 = 10
|
||||||
|
println(fact_recursive(10));
|
||||||
|
println(fact_imperative(10));
|
||||||
|
println(fact_pipeline(10));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# compute the primorial of n - the product of all primes <= n
|
# compute the primorial of n - the product of all primes <= n
|
||||||
fn primorial(n) {
|
fn primorial(n) {
|
||||||
return 2..(n+1) |? is_prime |// fn(x,y) { return x*y; };
|
return 2..(n+1) |? is_prime |// \*;
|
||||||
}
|
}
|
||||||
|
|
||||||
println(primorial(10)); # 2*3*5*7 = 210
|
println(primorial(10)); # 2*3*5*7 = 210
|
||||||
|
|
Loading…
Reference in a new issue