Skip to content

Commit

Permalink
rune: Lower obvious patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jul 29, 2024
1 parent fc67380 commit 0b6da5d
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 14 deletions.
14 changes: 14 additions & 0 deletions crates/rune/src/compile/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub struct Options {
pub(crate) function_body: bool,
/// When running tests, include std tests.
pub(crate) test_std: bool,
/// Enable lowering optimizations.
pub(crate) lowering: u8,
}

impl Options {
Expand Down Expand Up @@ -88,6 +90,17 @@ impl Options {
"test-std" => {
self.test_std = tail.map_or(true, |s| s == "true");
}
"lowering" => {
self.lowering = match tail {
Some("0") | None => 0,
Some("1") => 1,
_ => {
return Err(ParseOptionError {
option: option.into(),
})
}
};
}
_ => {
return Err(ParseOptionError {
option: option.into(),
Expand Down Expand Up @@ -143,6 +156,7 @@ impl Default for Options {
v2: false,
function_body: false,
test_std: false,
lowering: 0,
}
}
}
103 changes: 89 additions & 14 deletions crates/rune/src/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub(crate) struct Ctxt<'hir, 'a, 'arena> {
needs: Cell<Needs>,
scopes: hir::Scopes<'hir, 'a>,
const_eval: bool,
statement_buffer: Vec<hir::Stmt<'hir>>,
statements: Vec<hir::Stmt<'hir>>,
pattern_bindings: Vec<hir::Variable>,
secondary_builds: Option<&'a mut Vec<SecondaryBuildEntry<'hir>>>,
Expand Down Expand Up @@ -95,6 +96,7 @@ impl<'hir, 'a, 'arena> Ctxt<'hir, 'a, 'arena> {
needs: Cell::new(Needs::default()),
scopes,
const_eval,
statement_buffer: Vec::new(),
statements: Vec::new(),
pattern_bindings: Vec::new(),
secondary_builds,
Expand Down Expand Up @@ -251,19 +253,33 @@ fn statements<'hir>(
let mut value = None;

for ast in statements {
let (last, stmt) = match ast {
ast::Stmt::Local(ast) => (
value.take(),
Some(hir::Stmt::Local(alloc!(local(cx, ast)?))),
),
ast::Stmt::Expr(ast) => (
None,
value.replace(&*alloc!(expr(cx, ast)?)).map(hir::Stmt::Expr),
),
ast::Stmt::Semi(ast) => (
value.take(),
Some(hir::Stmt::Expr(alloc!(expr(cx, &ast.expr)?))),
),
let last = match ast {
ast::Stmt::Local(ast) => {
let depacked = if ast.attributes.is_empty() && cx.q.options.lowering > 0 {
unpack_locals(cx, &ast.pat, &ast.expr)?
} else {
false
};

if !depacked {
let stmt = hir::Stmt::Local(alloc!(local(cx, ast)?));
cx.statement_buffer.try_push(stmt)?;
}

value.take()
}
ast::Stmt::Expr(ast) => {
if let Some(stmt) = value.replace(&*alloc!(expr(cx, ast)?)).map(hir::Stmt::Expr) {
cx.statement_buffer.try_push(stmt)?;
}

None
}
ast::Stmt::Semi(ast) => {
let stmt = hir::Stmt::Expr(alloc!(expr(cx, &ast.expr)?));
cx.statement_buffer.try_push(stmt)?;
value.take()
}
ast::Stmt::Item(..) => continue,
};

Expand All @@ -273,7 +289,7 @@ fn statements<'hir>(
.with_span(span)?;
}

if let Some(stmt) = stmt {
for stmt in cx.statement_buffer.drain(..) {
cx.statements.try_push(stmt).with_span(span)?;
}
}
Expand Down Expand Up @@ -1133,6 +1149,65 @@ fn local<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Local) -> compile::Result
})
}

/// The is a simple locals optimization which unpacks locals from a tuple and
/// assigns them directly to local.
fn unpack_locals(cx: &mut Ctxt<'_, '_, '_>, p: &ast::Pat, e: &ast::Expr) -> compile::Result<bool> {
alloc_with!(cx, p);

match (p, e) {
(p @ ast::Pat::Path(inner), e) => {
let Some(ast::PathKind::Ident(..)) = inner.path.as_kind() else {
return Ok(false);
};

let e = expr(cx, e)?;
let p = pat_binding(cx, p)?;

cx.statement_buffer
.try_push(hir::Stmt::Local(alloc!(hir::Local {
span: p.span().join(e.span()),
pat: p,
expr: e,
})))?;

return Ok(true);
}
(ast::Pat::Tuple(p), ast::Expr::Tuple(e)) => {
if p.items.len() != e.items.len() {
return Ok(false);
}

for ((_, _), (p, _)) in e.items.iter().zip(&p.items) {
if matches!(p, ast::Pat::Rest(..)) {
return Ok(false);
}
}

let mut exprs = Vec::new();

for (e, _) in &e.items {
exprs.try_push(expr(cx, e)?)?;
}

for (e, (p, _)) in exprs.into_iter().zip(&p.items) {
let p = pat_binding(cx, p)?;

cx.statement_buffer
.try_push(hir::Stmt::Local(alloc!(hir::Local {
span: p.span().join(e.span()),
pat: p,
expr: e,
})))?;
}

return Ok(true);
}
_ => {}
};

Ok(false)
}

fn pat_binding<'hir>(
cx: &mut Ctxt<'hir, '_, '_>,
ast: &ast::Pat,
Expand Down
7 changes: 7 additions & 0 deletions crates/rune/tests/assign.rn
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[test]
fn inline_assign() {
let a = 10;
let b = 20;
let (a, b) = (b, a);
assert_eq!(a + b, 30);
}
7 changes: 7 additions & 0 deletions crates/rune/tests/closures.rn
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@ fn test_basic_closure() {
assert_eq!(work(|a, b| n + a + b), 4);
assert_eq!(work(|a, b| n + a * b), 3);
}

#[test]
fn test_lowering() {
let c = 5;
let c = |a| |b| || a + b + c;
assert_eq!(c(1)(2)(), 8);
}

0 comments on commit 0b6da5d

Please sign in to comment.