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 { 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()))
} }

View file

@ -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)))
} }