This commit is contained in:
TriMill 2022-09-22 09:56:44 -04:00
parent 350f775b6c
commit d9b1f08bbf
2 changed files with 74 additions and 34 deletions

View File

@ -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()) {
s.data.borrow_mut().insert(name.to_string(), r.clone());
Ok(r)
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()))
}

View File

@ -155,16 +155,18 @@ impl Parser {
}
fn terminate_stmt(&mut self, stmt: Stmt, req_semicolon: bool) -> Result<Stmt, ParserError> {
if !req_semicolon {
return Ok(stmt)
}
if self.at_end() {
self.err_on_eof()?;
if req_semicolon {
self.err_on_eof()?;
} else{
return Ok(stmt)
}
}
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)?;
Ok(Stmt::Fn { name, args, body: Box::new(body) })
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)?;
Ok(Expr::Fn { args, body: Box::new(body) })
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)))
}