Skip to content

Commit

Permalink
rune: Lower to anonymous variables
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jul 29, 2024
1 parent 93e0b57 commit 3c5d19f
Show file tree
Hide file tree
Showing 17 changed files with 387 additions and 479 deletions.
8 changes: 0 additions & 8 deletions crates/rune/src/ast/expr_closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,6 @@ pub enum ExprClosureArgs {
}

impl ExprClosureArgs {
/// The number of arguments the closure takes.
pub(crate) fn len(&self) -> usize {
match self {
Self::Empty { .. } => 0,
Self::List { args, .. } => args.len(),
}
}

/// Get a slice over all arguments.
pub(crate) fn as_slice(&self) -> &[(ast::FnArg, Option<T![,]>)] {
match self {
Expand Down
229 changes: 125 additions & 104 deletions crates/rune/src/compile/compile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::alloc;
use crate::alloc::prelude::*;
use crate::ast;
use crate::ast::{Span, Spanned};
use crate::compile::v1;
use crate::compile::{
Expand All @@ -11,10 +9,11 @@ use crate::hir;
use crate::indexing::FunctionAst;
use crate::macros::Storage;
use crate::parse::Resolve;
use crate::query::{Build, BuildEntry, GenericsParameters, Query, Used};
use crate::query::{Build, BuildEntry, GenericsParameters, Query, SecondaryBuild, Used};
use crate::runtime::unit::UnitEncoder;
use crate::shared::{Consts, Gen};
use crate::worker::{LoadFileKind, Task, Worker};
use crate::{alloc, ast};
use crate::{Diagnostics, Sources};

/// Encode the given object into a collection of asm.
Expand Down Expand Up @@ -149,12 +148,12 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {
entry: BuildEntry,
unit_storage: &mut dyn UnitEncoder,
) -> compile::Result<()> {
use self::v1::assemble;

let BuildEntry { item_meta, build } = entry;

let location = item_meta.location;

let mut asm = self.q.unit.new_assembly(location);

match build {
Build::Query => {
tracing::trace!("query: {}", self.q.pool.item(item_meta.item));
Expand All @@ -179,9 +178,9 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {
}
}
Build::Function(f) => {
tracing::trace!("function: {}", self.q.pool.item(item_meta.item));
let mut asm = self.q.unit.new_assembly(location);

use self::v1::assemble;
tracing::trace!("function: {}", self.q.pool.item(item_meta.item));

// For instance functions, we are required to know the type hash
// of the type it is associated with to perform the proper
Expand Down Expand Up @@ -217,7 +216,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {

let (debug_args, span): (_, &dyn Spanned) = match &f.ast {
FunctionAst::Item(ast) => {
let debug_args = format_fn_args(
let debug_args = format_ast_args(
self.q.sources,
location,
false,
Expand All @@ -229,11 +228,13 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {
};

let arena = hir::Arena::new();
let mut secondary_builds = Vec::new();

let mut cx = hir::lowering::Ctxt::with_query(
&arena,
self.q.borrow(),
item_meta.location.source_id,
&mut secondary_builds,
)?;

let hir = match &f.ast {
Expand Down Expand Up @@ -276,101 +277,86 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {
size,
)?;
}
}
Build::Closure(closure) => {
tracing::trace!("closure: {}", self.q.pool.item(item_meta.item));

use self::v1::assemble;

let debug_args = format_fn_args(
self.q.sources,
location,
true,
closure.ast.args.as_slice().iter().map(|(a, _)| a),
)?;

let captures = self.q.pool.item_type_hash(item_meta.item);

let arena = hir::Arena::new();
let mut cx = hir::lowering::Ctxt::with_query(
&arena,
self.q.borrow(),
item_meta.location.source_id,
)?;

let hir = hir::lowering::expr_closure_secondary(&mut cx, &closure.ast, captures)?;
let mut scopes = self::v1::Scopes::new(location.source_id)?;
let mut c = self.compiler1(location, &closure.ast, &mut asm, &mut scopes)?;
assemble::expr_closure_secondary(&mut c, &hir, &closure.ast)?;
let size = c.scopes.size();

if !c.q.is_used(&item_meta) {
c.q.diagnostics
.not_used(location.source_id, &location.span, None)?;
} else {
let captures =
c.q.get_captures(captures)
.map(|c| c.len())
.filter(|c| *c > 0);

let args = closure
.ast
.args
.len()
.saturating_add(usize::from(captures.is_some()));

self.q.unit.new_function(
location,
self.q.pool.item(item_meta.item),
None,
args,
captures,
asm,
closure.call,
debug_args,
unit_storage,
size,
)?;
}
}
Build::AsyncBlock(b) => {
tracing::trace!("async block: {}", self.q.pool.item(item_meta.item));

use self::v1::assemble;

let captures = self.q.pool.item_type_hash(item_meta.item);

let arena = hir::Arena::new();
let mut cx = hir::lowering::Ctxt::with_query(
&arena,
self.q.borrow(),
item_meta.location.source_id,
)?;
let hir = hir::lowering::async_block_secondary(&mut cx, &b.ast, captures)?;
let mut scopes = self::v1::Scopes::new(location.source_id)?;
let mut c = self.compiler1(location, &b.ast, &mut asm, &mut scopes)?;
assemble::async_block_secondary(&mut c, &hir)?;
let size = c.scopes.size();

if !self.q.is_used(&item_meta) {
self.q
.diagnostics
.not_used(location.source_id, &location.span, None)?;
} else {
let args = hir.captures.len();

self.q.unit.new_function(
location,
self.q.pool.item(item_meta.item),
None,
args,
None,
asm,
b.call,
Default::default(),
unit_storage,
size,
)?;
for build in secondary_builds {
let item_meta = build.item_meta;

let mut asm = self.q.unit.new_assembly(item_meta.location);

match build.build {
SecondaryBuild::Closure(c) => {
tracing::trace!("closure: {}", self.q.pool.item(item_meta.item));

let debug_args =
format_hir_args(self.q.sources, location, true, c.hir.args.iter())?;

let mut scopes = self::v1::Scopes::new(location.source_id)?;
let mut cx = self.compiler1(location, c.hir, &mut asm, &mut scopes)?;
assemble::expr_closure_secondary(&mut cx, c.hir)?;
let size = cx.scopes.size();

if !self.q.is_used(&item_meta) {
self.q.diagnostics.not_used(
location.source_id,
&location.span,
None,
)?;
} else {
let captures =
(!c.hir.captures.is_empty()).then_some(c.hir.captures.len());

let args = c
.hir
.args
.len()
.saturating_add(usize::from(captures.is_some()));

self.q.unit.new_function(
location,
self.q.pool.item(item_meta.item),
None,
args,
captures,
asm,
c.call,
debug_args,
unit_storage,
size,
)?;
}
}
SecondaryBuild::AsyncBlock(b) => {
tracing::trace!("async block: {}", self.q.pool.item(item_meta.item));

let mut scopes = self::v1::Scopes::new(location.source_id)?;
let mut cx = self.compiler1(location, b.hir, &mut asm, &mut scopes)?;
assemble::async_block_secondary(&mut cx, b.hir)?;
let size = cx.scopes.size();

if !self.q.is_used(&item_meta) {
self.q.diagnostics.not_used(
location.source_id,
&location.span,
None,
)?;
} else {
let args = b.hir.captures.len();

self.q.unit.new_function(
location,
self.q.pool.item(item_meta.item),
None,
args,
None,
asm,
b.call,
Default::default(),
unit_storage,
size,
)?;
}
}
}
}
}
Build::Unused => {
Expand Down Expand Up @@ -457,21 +443,52 @@ impl<'arena> CompileBuildEntry<'_, 'arena> {
}
}

fn format_fn_args<'a, I>(
fn format_hir_args<'hir, I>(
sources: &Sources,
location: Location,
environment: bool,
arguments: I,
) -> compile::Result<Box<[Box<str>]>>
where
I: IntoIterator<Item = &'a ast::FnArg>,
I: IntoIterator<Item = &'hir hir::FnArg<'hir>>,
{
let mut args = Vec::new();

for arg in arguments {
match arg {
hir::FnArg::SelfValue(..) => {
args.try_push(Box::try_from("self")?)?;
}
hir::FnArg::Pat(pat) => {
let span = pat.span();

if let Some(s) = sources.source(location.source_id, span) {
args.try_push(Box::try_from(s)?)?;
} else {
args.try_push(Box::try_from("*")?)?;
}
}
}
}

if environment {
args.try_push(Box::try_from("environment")?)?;
}

Ok(args.try_into_boxed_slice()?)
}

fn format_ast_args<'a, I>(
sources: &Sources,
location: Location,
environment: bool,
arguments: I,
) -> compile::Result<Box<[Box<str>]>>
where
I: IntoIterator<Item = &'a ast::FnArg>,
{
let mut args = Vec::new();

for arg in arguments {
match arg {
ast::FnArg::SelfValue(..) => {
Expand All @@ -489,5 +506,9 @@ where
}
}

if environment {
args.try_push(Box::try_from("environment")?)?;
}

Ok(args.try_into_boxed_slice()?)
}
16 changes: 8 additions & 8 deletions crates/rune/src/compile/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ pub(crate) enum ErrorKind {
UnsupportedPatternRest,
UnsupportedMut,
UnsupportedSuffix,
ClosureInConst,
AsyncBlockInConst,
}

impl ErrorKind {
Expand Down Expand Up @@ -1040,6 +1042,12 @@ impl fmt::Display for ErrorKind {
"Unsupported suffix, expected one of `u8`, `i64`, or `f64`"
)?;
}
ErrorKind::ClosureInConst => {
write!(f, "Closures are not supported in constant contexts")?;
}
ErrorKind::AsyncBlockInConst => {
write!(f, "Async blocks are not supported in constant contexts")?;
}
}

Ok(())
Expand Down Expand Up @@ -1230,11 +1238,6 @@ pub(crate) enum IrErrorKind {
/// The field that was missing.
field: Box<str>,
},
/// Missing const or local with the given name.
MissingConst {
/// Name of the missing thing.
name: Box<str>,
},
/// Error raised when trying to use a break outside of a loop.
BreakOutsideOfLoop,
ArgumentCountMismatch {
Expand Down Expand Up @@ -1271,9 +1274,6 @@ impl fmt::Display for IrErrorKind {
IrErrorKind::MissingField { field } => {
write!(f, "Missing field `{field}`",)?;
}
IrErrorKind::MissingConst { name } => {
write!(f, "No constant or local matching `{name}`",)?;
}
IrErrorKind::BreakOutsideOfLoop => {
write!(f, "Break outside of supported loop")?;
}
Expand Down
Loading

0 comments on commit 3c5d19f

Please sign in to comment.