Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions implants/lib/eldritchv2/eldritch-core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,20 +609,20 @@ pub enum ExprKind {
FString(Vec<FStringSegment>),
ListComp {
body: Box<Expr>,
var: String,
vars: Vec<String>,
iterable: Box<Expr>,
cond: Option<Box<Expr>>,
},
DictComp {
key: Box<Expr>,
value: Box<Expr>,
var: String,
vars: Vec<String>,
iterable: Box<Expr>,
cond: Option<Box<Expr>>,
},
SetComp {
body: Box<Expr>,
var: String,
vars: Vec<String>,
iterable: Box<Expr>,
cond: Option<Box<Expr>>,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use spin::RwLock;
pub(crate) fn evaluate_list_comp(
interp: &mut Interpreter,
body: &Expr,
var: &str,
vars: &[alloc::string::String],
iterable: &Expr,
cond: &Option<Box<Expr>>,
) -> Result<Value, EldritchError> {
let mut results = Vec::new();
evaluate_comprehension_generic(interp, var, iterable, cond, |i| {
evaluate_comprehension_generic(interp, vars, iterable, cond, |i| {
results.push(evaluate(i, body)?);
Ok(())
})?;
Expand All @@ -28,12 +28,12 @@ pub(crate) fn evaluate_dict_comp(
interp: &mut Interpreter,
key_expr: &Expr,
val_expr: &Expr,
var: &str,
vars: &[alloc::string::String],
iterable: &Expr,
cond: &Option<Box<Expr>>,
) -> Result<Value, EldritchError> {
let mut results = BTreeMap::new();
evaluate_comprehension_generic(interp, var, iterable, cond, |i| {
evaluate_comprehension_generic(interp, vars, iterable, cond, |i| {
let k = evaluate(i, key_expr)?;
let v = evaluate(i, val_expr)?;
results.insert(k, v);
Expand All @@ -45,13 +45,13 @@ pub(crate) fn evaluate_dict_comp(
pub(crate) fn evaluate_set_comp(
interp: &mut Interpreter,
body: &Expr,
var: &str,
vars: &[alloc::string::String],
iterable: &Expr,
cond: &Option<Box<Expr>>,
) -> Result<Value, EldritchError> {
#[allow(clippy::mutable_key_type)]
let mut results = BTreeSet::new();
evaluate_comprehension_generic(interp, var, iterable, cond, |i| {
evaluate_comprehension_generic(interp, vars, iterable, cond, |i| {
results.insert(evaluate(i, body)?);
Ok(())
})?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,23 @@ pub fn evaluate(interp: &mut Interpreter, expr: &Expr) -> Result<Value, Eldritch
ExprKind::FString(segments) => evaluate_fstring(interp, segments),
ExprKind::ListComp {
body,
var,
vars,
iterable,
cond,
} => evaluate_list_comp(interp, body, var, iterable, cond),
} => evaluate_list_comp(interp, body, vars, iterable, cond),
ExprKind::DictComp {
key,
value,
var,
vars,
iterable,
cond,
} => evaluate_dict_comp(interp, key, value, var, iterable, cond),
} => evaluate_dict_comp(interp, key, value, vars, iterable, cond),
ExprKind::SetComp {
body,
var,
vars,
iterable,
cond,
} => evaluate_set_comp(interp, body, var, iterable, cond),
} => evaluate_set_comp(interp, body, vars, iterable, cond),
ExprKind::Lambda { params, body } => evaluate_lambda(interp, params, body),
ExprKind::If {
cond,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::ast::{Environment, Expr};
use crate::interpreter::core::Interpreter;
use crate::interpreter::error::EldritchError;
use crate::interpreter::error::{EldritchError, EldritchErrorKind};
use crate::interpreter::eval::evaluate;
use crate::interpreter::introspection::is_truthy;
use alloc::boxed::Box;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::sync::Arc;
use spin::RwLock;

use crate::ast::Value;

pub(crate) fn evaluate_comprehension_generic<F>(
interp: &mut Interpreter,
var: &str,
vars: &[alloc::string::String],
iterable: &Expr,
cond: &Option<Box<Expr>>,
mut insert_fn: F,
Expand All @@ -33,13 +35,51 @@ where
interp.env = comp_env;

for item in items {
interp.define_variable(var, item);
if vars.len() == 1 {
interp.define_variable(&vars[0], item);
} else {
// Unpack
let elements = match item {
Value::List(l) => l.read().clone(),
Value::Tuple(t) => t.clone(),
Value::Set(s) => s.read().iter().cloned().collect(),
_ => {
interp.env = original_env;
return interp.error(
EldritchErrorKind::TypeError,
&alloc::format!("Cannot unpack non-iterable object of type {}", item),
iterable.span,
);
}
};

if elements.len() != vars.len() {
interp.env = original_env;
return interp.error(
EldritchErrorKind::ValueError,
&alloc::format!(
"Too many (or not enough) values to unpack (expected {}, got {})",
vars.len(),
elements.len()
),
iterable.span,
);
}

for (var, val) in vars.iter().zip(elements.into_iter()) {
interp.define_variable(var, val);
}
}

let include = match cond {
Some(c) => is_truthy(&evaluate(interp, c)?),
None => true,
};
if include {
insert_fn(interp)?;
if let Err(e) = insert_fn(interp) {
interp.env = original_env;
return Err(e);
}
}
}
interp.env = original_env;
Expand Down
54 changes: 33 additions & 21 deletions implants/lib/eldritchv2/eldritch-core/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,18 +638,22 @@ impl Parser {
// If first expression is valid, check for comprehension
if let Ok(first_expr) = first_expr_res {
if self.match_token(&[TokenKind::For]) {
let (var, _) = {
let mut vars = Vec::new();
loop {
let t = self.consume(
|t| matches!(t, TokenKind::Identifier(_)),
"Expected iteration variable.",
)?;
let v = if let TokenKind::Identifier(s) = &t.kind {
s.clone()
if let TokenKind::Identifier(s) = &t.kind {
vars.push(s.clone());
} else {
unreachable!()
};
(v, t.span)
};
}

if !self.match_token(&[TokenKind::Comma]) {
break;
}
}

self.consume(|t| matches!(t, TokenKind::In), "Expected 'in'.")?;
let iterable = self.logic_or()?;
Expand All @@ -663,7 +667,7 @@ impl Parser {
return Ok(self.make_expr(
ExprKind::ListComp {
body: Box::new(first_expr),
var,
vars,
iterable: Box::new(iterable),
cond,
},
Expand Down Expand Up @@ -775,18 +779,22 @@ impl Parser {
let val_expr = self.expression()?;

if self.match_token(&[TokenKind::For]) {
let (var, _) = {
let mut vars = Vec::new();
loop {
let t = self.consume(
|t| matches!(t, TokenKind::Identifier(_)),
"Expected iteration variable.",
)?;
let v = if let TokenKind::Identifier(s) = &t.kind {
s.clone()
if let TokenKind::Identifier(s) = &t.kind {
vars.push(s.clone());
} else {
unreachable!()
};
(v, t.span)
};
}

if !self.match_token(&[TokenKind::Comma]) {
break;
}
}

self.consume(|t| matches!(t, TokenKind::In), "Expected 'in'.")?;
// Use logic_or to avoid consuming the 'if' of the comprehension
Expand All @@ -802,7 +810,7 @@ impl Parser {
ExprKind::DictComp {
key: Box::new(first_expr),
value: Box::new(val_expr),
var,
vars,
iterable: Box::new(iterable),
cond,
},
Expand Down Expand Up @@ -836,18 +844,22 @@ impl Parser {
} else {
// Set or SetComp
if self.match_token(&[TokenKind::For]) {
let (var, _) = {
let mut vars = Vec::new();
loop {
let t = self.consume(
|t| matches!(t, TokenKind::Identifier(_)),
"Expected iteration variable.",
)?;
let v = if let TokenKind::Identifier(s) = &t.kind {
s.clone()
if let TokenKind::Identifier(s) = &t.kind {
vars.push(s.clone());
} else {
unreachable!()
};
(v, t.span)
};
}

if !self.match_token(&[TokenKind::Comma]) {
break;
}
}

self.consume(|t| matches!(t, TokenKind::In), "Expected 'in'.")?;
let iterable = self.logic_or()?;
Expand All @@ -861,7 +873,7 @@ impl Parser {
return Ok(self.make_expr(
ExprKind::SetComp {
body: Box::new(first_expr),
var,
vars,
iterable: Box::new(iterable),
cond,
},
Expand Down
Loading
Loading