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 {
|
||||
TokenType::PlusEqual => &l + &r,
|
||||
TokenType::MinusEqual => &l - &r,
|
||||
TokenType::StarEqual => &l * &r,
|
||||
TokenType::SlashEqual => &l / &r,
|
||||
TokenType::PercentEqual => &l % &r,
|
||||
TokenType::CaretEqual => l.pow(&r),
|
||||
TokenType::DoubleSlashEqual => l.fracdiv(&r),
|
||||
TokenType::PlusEqual => l + r,
|
||||
TokenType::MinusEqual => l - r,
|
||||
TokenType::StarEqual => l * r,
|
||||
TokenType::SlashEqual => l / r,
|
||||
TokenType::PercentEqual => l % r,
|
||||
TokenType::CaretEqual => l.pow(r),
|
||||
TokenType::DoubleSlashEqual => l.fracdiv(r),
|
||||
_ => todo!() // TODO more operations
|
||||
}.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()))?;
|
||||
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()
|
||||
.set(name, result.clone()).expect("unreachable");
|
||||
Ok(result)
|
||||
env.borrow_mut().set(name, result.clone()).expect("unreachable");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
},
|
||||
Expr::Index { lhs, index, pos } => {
|
||||
|
@ -321,18 +320,28 @@ pub fn eval_assignment(lhs: &Expr, rhs: &Expr, op: &Token, env: EnvRef) -> Resul
|
|||
} else {
|
||||
let prev_value = l.index(&idx).map_err(|e| RuntimeError::new(e, pos.clone()))?;
|
||||
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()))?;
|
||||
Ok(result)
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
},
|
||||
Expr::FieldAccess { target, name, pos } => {
|
||||
let target = eval_expr(target, env.clone())?;
|
||||
let r = eval_expr(rhs, env)?;
|
||||
if let Value::Struct(s) = target {
|
||||
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());
|
||||
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 {
|
||||
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> {
|
||||
if !req_semicolon {
|
||||
if self.at_end() {
|
||||
if req_semicolon {
|
||||
self.err_on_eof()?;
|
||||
} else{
|
||||
return Ok(stmt)
|
||||
}
|
||||
if self.at_end() {
|
||||
self.err_on_eof()?;
|
||||
}
|
||||
|
||||
match self.expect(TokenType::Semicolon) {
|
||||
(true, _) => Ok(stmt),
|
||||
(false, _) => Err(self.mk_error("Missing semicolon after statement"))
|
||||
match self.expect(TokenType::Semicolon).0 {
|
||||
true => Ok(stmt),
|
||||
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)?;
|
||||
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) })
|
||||
} else {
|
||||
Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body"))
|
||||
}
|
||||
}
|
||||
|
||||
fn block(&mut self) -> Result<Stmt, ParserError> {
|
||||
|
@ -415,15 +432,14 @@ impl Parser {
|
|||
|
||||
// dot notation for field access
|
||||
fn fieldaccess(&mut self) -> Result<Expr, ParserError> {
|
||||
let target = self.suffix()?;
|
||||
if !self.at_end() && self.peek().ty == TokenType::Dot {
|
||||
let mut target = self.suffix()?;
|
||||
while !self.at_end() && self.peek().ty == TokenType::Dot {
|
||||
let pos = self.next().pos;
|
||||
self.err_on_eof()?;
|
||||
let name = self.ident()?.ty.as_ident().unwrap();
|
||||
Ok(Expr::FieldAccess { target: Box::new(target), name, pos })
|
||||
} else {
|
||||
Ok(target)
|
||||
target = Expr::FieldAccess { target: Box::new(target), name, pos }
|
||||
}
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
// function calls, array access, struct initializaiton
|
||||
|
@ -531,8 +547,23 @@ impl Parser {
|
|||
}
|
||||
let args = self.commalist(TokenType::RParen, Self::ident)?;
|
||||
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) })
|
||||
} else {
|
||||
Err(self.mk_error("Expected '(' or '{' after function arguments list to begin body"))
|
||||
}
|
||||
} else {
|
||||
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue