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

@@ -106,6 +106,12 @@ impl ExprVisitor for LineNumber {
Ok(())
}
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Result<()> {
expr.expr.accept(self).unwrap();
self.update_end(expr.rbracket.line);
Ok(())
}
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<()> {
self.update_start(expr.token.line);
self.update_end(expr.token.line);
@@ -117,6 +123,12 @@ impl ExprVisitor for LineNumber {
self.update_end(expr.rbrace.line);
Ok(())
}
fn visit_list_expr(&mut self, expr: &ListExpr) -> Result<()> {
self.update_start(expr.lbracket.line);
self.update_end(expr.rbracket.line);
Ok(())
}
}
fn expr_line_number(expr: &dyn Expr) -> LineRange {
@@ -238,6 +250,10 @@ impl ExprVisitor for LocalAssignCollector {
Ok(())
}
fn visit_index_expr(&mut self, _expr: &IndexExpr) -> Result<()> {
Ok(())
}
fn visit_primary_expr(&mut self, _expr: &PrimaryExpr) -> Result<()> {
Ok(())
}
@@ -246,6 +262,11 @@ impl ExprVisitor for LocalAssignCollector {
// don't visit function expr, we're only collecting local assigns
Ok(())
}
fn visit_list_expr(&mut self, _expr: &ListExpr) -> Result<()> {
// there shouldn't be any local assignments inside of a list expression
Ok(())
}
}
#[derive(Default)]
@@ -326,6 +347,12 @@ impl ExprVisitor for LocalNameCollector {
Ok(())
}
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Result<()> {
expr.expr.accept(self)?;
expr.index.accept(self)?;
Ok(())
}
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<()> {
if expr.token.kind == TokenKind::Name {
self.names.insert(expr.token.text.to_string());
@@ -337,6 +364,13 @@ impl ExprVisitor for LocalNameCollector {
// don't visit function expr, we're only collecting local assigns
Ok(())
}
fn visit_list_expr(&mut self, expr: &ListExpr) -> Result<()> {
for expr in &expr.exprs {
expr.accept(self)?;
}
Ok(())
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -863,6 +897,15 @@ impl ExprVisitor for Compiler {
Ok(())
}
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Result<()> {
self.compile_expr(&expr.expr)?;
let constant_id = self.insert_constant(Str::create("__index__"))?;
self.emit(expr_line_number(expr), Op::GetAttr(constant_id));
self.compile_expr(&expr.index)?;
self.emit(expr_line_number(expr), Op::Call(1));
Ok(())
}
fn visit_primary_expr(&mut self, expr: &PrimaryExpr) -> Result<()> {
match expr.token.kind {
TokenKind::Name => {
@@ -990,4 +1033,16 @@ impl ExprVisitor for Compiler {
Ok(())
}
fn visit_list_expr(&mut self, expr: &ListExpr) -> Result<()> {
let line = expr_line_number(expr);
for expr in &expr.exprs {
self.compile_expr(expr)?;
}
self.emit(line, Op::BuildList(expr.exprs.len() as ListLen));
Ok(())
}
}