Add lists

This introduces:

* new syntax for list literals, put comma-separated values between
  braces for your new list
* new syntax for indexing, do `foo[index]` to get the value in `foo` at
  `index`. Lists also allow negative indices too. Any type that wants to
  be indexed can include their own __index__ function as well.
* new VM instruction, BuildList. List literals were a lot easier to
  implement using this rather than creating a new list, creating a
  temporary stack value, and then duplicating + pushing to that
  temporary value over and over.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2024-09-30 16:33:58 -07:00
parent 0a21f01ea7
commit dab474a037
9 changed files with 403 additions and 17 deletions

View File

@@ -743,6 +743,16 @@ impl Parser {
.expect("expect name after '.'", TokenKind::Name)?
.clone();
expr = Box::new(GetExpr { expr, name });
} else if self.mat(TokenKind::LBracket)? {
let index = self.expr()?;
let rbracket = self
.expect("expect ']' after index expression", TokenKind::RBracket)?
.clone();
expr = Box::new(IndexExpr {
expr,
index,
rbracket,
})
} else {
break;
}
@@ -801,6 +811,8 @@ impl Parser {
self.expect("expect ')' after expression", TokenKind::RParen)?;
}
Ok(expr)
} else if self.mat(TokenKind::LBracket)? {
self.list()
} else {
Err(self.error(format!("unexpected token {:?}", self.current.kind)))
}
@@ -854,6 +866,32 @@ impl Parser {
params.push((name, ty));
Ok(())
}
fn list(&mut self) -> Result<ExprP> {
let lbracket = self.prev.clone().unwrap();
let mut exprs = Vec::new();
if !self.check(TokenKind::RBracket) {
exprs.push(self.expr()?);
while self.mat(TokenKind::Comma)? {
// allow trailing comma
if self.check(TokenKind::RBracket) {
break;
}
exprs.push(self.expr()?);
}
}
let rbracket = self
.expect("expect ']' after list items", TokenKind::RBracket)?
.clone();
Ok(Box::new(ListExpr {
lbracket,
exprs,
rbracket,
}))
}
}
#[cfg(test)]