bugfixes
This commit is contained in:
parent
350f775b6c
commit
d9b1f08bbf
2 changed files with 74 additions and 34 deletions
|
@ -273,15 +273,15 @@ pub fn eval_ident(token: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compound_assignment_inner(l: Value, r: Value, op: &Token) -> Result<Value, RuntimeError> {
|
fn compound_assignment_inner(l: &Value, r: &Value, op: &Token) -> Result<Value, RuntimeError> {
|
||||||
match op.ty {
|
match op.ty {
|
||||||
TokenType::PlusEqual => &l + &r,
|
TokenType::PlusEqual => l + r,
|
||||||
TokenType::MinusEqual => &l - &r,
|
TokenType::MinusEqual => l - r,
|
||||||
TokenType::StarEqual => &l * &r,
|
TokenType::StarEqual => l * r,
|
||||||
TokenType::SlashEqual => &l / &r,
|
TokenType::SlashEqual => l / r,
|
||||||
TokenType::PercentEqual => &l % &r,
|
TokenType::PercentEqual => l % r,
|
||||||
TokenType::CaretEqual => l.pow(&r),
|
TokenType::CaretEqual => l.pow(r),
|
||||||
TokenType::DoubleSlashEqual => l.fracdiv(&r),
|
TokenType::DoubleSlashEqual => l.fracdiv(r),
|
||||||
_ => todo!() // TODO more operations
|
_ => todo!() // TODO more operations
|
||||||
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
}.map_err(|e| RuntimeError::new(e, op.pos.clone()))
|
||||||
}
|
}
|
||||||
|
@ -304,11 +304,10 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul
|
||||||
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?;
|
.ok_or_else(|| RuntimeError::new("Variable not defined in scope", op.pos.clone()))?;
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
|
|
||||||
let result = compound_assignment_inner(prev_value, r, op)?;
|
let result = compound_assignment_inner(&prev_value, &r, op)?;
|
||||||
|
|
||||||
env.borrow_mut()
|
env.borrow_mut().set(name, result.clone()).expect("unreachable");
|
||||||
.set(name, result.clone()).expect("unreachable");
|
Ok(Value::Nil)
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::Index { lhs, index, pos } => {
|
Expr::Index { lhs, index, pos } => {
|
||||||
|
@ -321,18 +320,28 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul
|
||||||
} else {
|
} else {
|
||||||
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||||
let r = eval_expr(rhs, env)?;
|
let r = eval_expr(rhs, env)?;
|
||||||
let result = compound_assignment_inner(prev_value, r, op)?;
|
let result = compound_assignment_inner(&prev_value, &r, op)?;
|
||||||
l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
l.assign_index(&idx, result.clone()).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||||
Ok(result)
|
Ok(Value::Nil)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::FieldAccess { target, name, pos } => {
|
Expr::FieldAccess { target, name, pos } => {
|
||||||
let target = eval_expr(target, env.clone())?;
|
let target = eval_expr(target, env.clone())?;
|
||||||
let r = eval_expr(rhs, env)?;
|
|
||||||
if let Value::Struct(s) = target {
|
if let Value::Struct(s) = target {
|
||||||
if s.data.borrow().contains_key(name.as_ref()) {
|
if s.data.borrow().contains_key(name.as_ref()) {
|
||||||
|
if op.ty == TokenType::Equal {
|
||||||
|
let r = eval_expr(rhs, env)?;
|
||||||
s.data.borrow_mut().insert(name.to_string(), r.clone());
|
s.data.borrow_mut().insert(name.to_string(), r.clone());
|
||||||
Ok(r)
|
Ok(r)
|
||||||
|
} else {
|
||||||
|
let result = {
|
||||||
|
let prev_value = &s.data.borrow()[name.as_ref()];
|
||||||
|
let r = eval_expr(rhs, env)?;
|
||||||
|
compound_assignment_inner(prev_value, &r, op)?
|
||||||
|
};
|
||||||
|
s.data.borrow_mut().insert(name.to_string(), result);
|
||||||
|
Ok(Value::Nil)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::new(format!("Struct {} does not have field {}", Value::Struct(s).repr(), name), pos.clone()))
|
Err(RuntimeError::new(format!("Struct {} does not have field {}", Value::Struct(s).repr(), name), pos.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,16 +155,18 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result<Stmt, ParserError> {
|
fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result<Stmt, ParserError> {
|
||||||
if !req_semicolon {
|
if self.at_end() {
|
||||||
|
if req_semicolon {
|
||||||
|
self.err_on_eof()?;
|
||||||
|
} else{
|
||||||
return Ok(stmt)
|
return Ok(stmt)
|
||||||
}
|
}
|
||||||
if self.at_end() {
|
|
||||||
self.err_on_eof()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.expect(TokenType::Semicolon) {
|
match self.expect(TokenType::Semicolon).0 {
|
||||||
(true, _) => Ok(stmt),
|
true => Ok(stmt),
|
||||||
(false, _) => Err(self.mk_error("Missing semicolon after statement"))
|
false if !req_semicolon => Ok(stmt),
|
||||||
|
false => Err(self.mk_error("Missing semicolon after statement"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -249,8 +251,23 @@ impl Parser {
|
||||||
}
|
}
|
||||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let body = self.statement(false)?;
|
if self.peek().ty == TokenType::LParen {
|
||||||
|
self.next();
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let body = self.assignment()?;
|
||||||
|
self.err_on_eof()?;
|
||||||
|
if !self.expect(TokenType::RParen).0 {
|
||||||
|
return Err(self.mk_error("Expected right parenthesis to close function body"))
|
||||||
|
}
|
||||||
|
Ok(Stmt::Fn { name, args, body: Box::new(Stmt::Expr {expr: body }) })
|
||||||
|
} else if self.peek().ty == TokenType::LBrace {
|
||||||
|
self.next();
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let body = self.block()?;
|
||||||
Ok(Stmt::Fn { name, args, body: Box::new(body) })
|
Ok(Stmt::Fn { name, args, body: Box::new(body) })
|
||||||
|
} else {
|
||||||
|
Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&mut self) -> Result<Stmt, ParserError> {
|
fn block(&mut self) -> Result<Stmt, ParserError> {
|
||||||
|
@ -415,15 +432,14 @@ impl Parser {
|
||||||
|
|
||||||
// dot notation for field access
|
// dot notation for field access
|
||||||
fn fieldaccess(&mut self) -> Result<Expr, ParserError> {
|
fn fieldaccess(&mut self) -> Result<Expr, ParserError> {
|
||||||
let target = self.suffix()?;
|
let mut target = self.suffix()?;
|
||||||
if !self.at_end() && self.peek().ty == TokenType::Dot {
|
while !self.at_end() && self.peek().ty == TokenType::Dot {
|
||||||
let pos = self.next().pos;
|
let pos = self.next().pos;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let name = self.ident()?.ty.as_ident().unwrap();
|
let name = self.ident()?.ty.as_ident().unwrap();
|
||||||
Ok(Expr::FieldAccess { target: Box::new(target), name, pos })
|
target = Expr::FieldAccess { target: Box::new(target), name, pos }
|
||||||
} else {
|
|
||||||
Ok(target)
|
|
||||||
}
|
}
|
||||||
|
Ok(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// function calls, array access, struct initializaiton
|
// function calls, array access, struct initializaiton
|
||||||
|
@ -531,8 +547,23 @@ impl Parser {
|
||||||
}
|
}
|
||||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||||
self.err_on_eof()?;
|
self.err_on_eof()?;
|
||||||
let body = self.statement(false)?;
|
if self.peek().ty == TokenType::LParen {
|
||||||
|
self.next();
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let body = self.assignment()?;
|
||||||
|
self.err_on_eof()?;
|
||||||
|
if !self.expect(TokenType::RParen).0 {
|
||||||
|
return Err(self.mk_error("Expected right parenthesis to close function body"))
|
||||||
|
}
|
||||||
|
Ok(Expr::Fn { args, body: Box::new(Stmt::Expr {expr: body }) })
|
||||||
|
} else if self.peek().ty == TokenType::LBrace {
|
||||||
|
self.next();
|
||||||
|
self.err_on_eof()?;
|
||||||
|
let body = self.block()?;
|
||||||
Ok(Expr::Fn { args, body: Box::new(body) })
|
Ok(Expr::Fn { args, body: Box::new(body) })
|
||||||
|
} else {
|
||||||
|
Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue