Skip to content

Commit

Permalink
More working HIR lowering
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jun 8, 2023
1 parent 64278a2 commit 2750b3e
Show file tree
Hide file tree
Showing 22 changed files with 479 additions and 481 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
resolver = "2"
members = [
"crates/*",
"examples",
Expand Down
40 changes: 8 additions & 32 deletions crates/rune-macros/src/instrument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ use syn::Token;
/// An internal call to the macro.
#[derive(Default)]
pub struct Attr {
skip_span: bool,
leaving: bool,
span: Option<syn::Ident>,
span: Option<syn::Expr>,
}

impl syn::parse::Parse for Attr {
Expand All @@ -18,11 +16,7 @@ impl syn::parse::Parse for Attr {
while !input.is_empty() {
let ident = input.parse::<syn::Ident>()?;

if ident == "skip_span" {
attr.skip_span = true;
} else if ident == "leaving" {
attr.leaving = true;
} else if ident == "span" {
if ident == "span" {
input.parse::<Token![=]>()?;
attr.span = Some(input.parse()?);
} else {
Expand Down Expand Up @@ -71,45 +65,27 @@ impl Expander {
_ => None,
};

let second = match it.next() {
Some(syn::FnArg::Typed(ty)) => match &*ty.pat {
syn::Pat::Ident(ident) => Some(&ident.ident),
_ => None,
},
_ => None,
};

let ident = &self.sig.ident;

let log = match (first, second) {
(Some(a), Some(b)) => {
let log = match first {
Some(a) => {
let ident = syn::LitStr::new(&ident.to_string(), ident.span());

let enter = match (attr.skip_span, &attr.span) {
(false, None) => Some(quote! {
let _instrument_span = ::tracing::span!(::tracing::Level::TRACE, #ident);
let _instrument_enter = _instrument_span.enter();

if let Some(source) = #b.q.sources.source(#b.source_id, #a.span()) {
::tracing::trace!("{:?}", source);
}
}),
(_, Some(span)) => Some(quote! {
match &attr.span {
Some(span) => Some(quote! {
let _instrument_span = ::tracing::span!(::tracing::Level::TRACE, #ident);
let _instrument_enter = _instrument_span.enter();

if let Some(source) = #a.q.sources.source(#a.source_id, Spanned::span(&#span)) {
::tracing::trace!("{:?}", source);
}
}),
_ => Some(quote! {
None => Some(quote! {
let _instrument_span = ::tracing::span!(::tracing::Level::TRACE, #ident);
let _instrument_enter = _instrument_span.enter();
::tracing::trace!("entering");
}),
};

enter
}
}
_ => None,
};
Expand Down
4 changes: 2 additions & 2 deletions crates/rune/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ bench = []
workspace = ["std", "toml", "semver", "relative-path", "serde-hashkey", "linked-hash-map"]
doc = ["std", "rust-embed", "handlebars", "pulldown-cmark", "syntect", "sha2", "base64", "rune-core/doc", "relative-path"]
cli = ["std", "emit", "doc", "bincode", "atty", "tracing-subscriber", "clap", "webbrowser", "capture-io", "disable-io", "languageserver", "fmt", "similar", "rand"]
languageserver = ["std", "lsp", "ropey", "percent-encoding", "url", "serde_json", "tokio", "tokio/macros", "tokio/io-std", "workspace", "doc"]
languageserver = ["std", "lsp", "ropey", "percent-encoding", "url", "serde_json", "tokio", "workspace", "doc"]
byte-code = ["alloc", "musli-storage"]
capture-io = ["alloc", "parking_lot"]
disable-io = ["alloc"]
Expand Down Expand Up @@ -61,7 +61,7 @@ semver = { version = "1.0.17", optional = true, features = ["serde"] }
serde-hashkey = { version = "0.4.5", optional = true }
syntect = { version = "5.0.0", optional = true }
thiserror = { version = "1.0.40", optional = true }
tokio = { version = "1.28.1", features = ["rt-multi-thread", "fs"], optional = true }
tokio = { version = "1.28.1", features = ["rt-multi-thread", "fs", "macros", "sync", "io-std", "io-util"], optional = true }
toml = { version = "0.7.3", optional = true, features = ["parse"] }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"], optional = true }
webbrowser = { version = "0.8.9", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,10 @@ impl<'a, S> Build<'a, S> {
self.sources,
&mut pool,
context,
options,
visitors,
diagnostics,
source_loader,
options,
&mut unit_storage,
);

Expand Down
15 changes: 8 additions & 7 deletions crates/rune/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ mod prelude;
pub(crate) use self::prelude::Prelude;

pub(crate) mod ir;
pub use self::ir::IrValue;
pub(crate) use self::ir::{IrBudget, IrCompiler, IrEvalContext, IrEvalOutcome, IrInterpreter};
pub use self::ir::{IrEval, IrValue};

pub use rune_core::{Component, ComponentRef, IntoComponent, Item, ItemBuf};

mod source_loader;
pub use self::source_loader::{FileSourceLoader, SourceLoader};
pub use self::source_loader::{FileSourceLoader, NoopSourceLoader, SourceLoader};

mod unit_builder;
pub use self::unit_builder::LinkerError;
Expand Down Expand Up @@ -96,10 +96,10 @@ pub(crate) fn compile(
sources: &mut Sources,
pool: &mut Pool,
context: &Context,
options: &Options,
visitor: &mut dyn CompileVisitor,
diagnostics: &mut Diagnostics,
source_loader: &mut dyn SourceLoader,
options: &Options,
unit_storage: &mut dyn UnitEncoder,
) -> Result<(), ()> {
// Shared id generator.
Expand All @@ -117,13 +117,15 @@ pub(crate) fn compile(
pool,
visitor,
diagnostics,
source_loader,
options,
&gen,
context,
&mut inner,
);

// The worker queue.
let mut worker = Worker::new(options, source_loader, q);
let mut worker = Worker::new(q);

// Queue up the initial sources to be loaded.
for source_id in worker.q.sources.source_ids() {
Expand Down Expand Up @@ -376,10 +378,9 @@ impl CompileBuildEntry<'_> {
self.q.borrow(),
item_meta.location.source_id,
);
let hir = hir::lowering::block(&mut ctx, &b.ast)?;

let hir = hir::lowering::async_block(&mut ctx, &b.ast, &b.captures)?;
let mut c = self.compiler1(location, span, &mut asm);
assemble::closure_from_block(&hir, &mut c, &b.captures)?;
assemble::async_block(&mut c, &hir)?;

if used.is_unused() {
self.q
Expand Down
2 changes: 0 additions & 2 deletions crates/rune/src/compile/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,6 @@ pub(crate) enum IrErrorKind {
/// Error raised when trying to use a break outside of a loop.
#[error("Break outside of supported loop")]
BreakOutsideOfLoop,
#[error("Function not found")]
FnNotFound,
#[error("Argument count mismatch, got {actual} but expected {expected}")]
ArgumentCountMismatch { actual: usize, expected: usize },
}
Expand Down
43 changes: 31 additions & 12 deletions crates/rune/src/compile/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,44 @@ use crate::compile::ir;
use crate::compile::ir::eval::IrEvalBreak;
use crate::compile::{self, ItemMeta, WithSpan};
use crate::hir;
use crate::indexing::index;
use crate::indexing::{IndexScopes, Indexer};
use crate::parse::NonZeroId;
use crate::query::Used;
use crate::shared::Items;

/// Context used for [IrEval].
pub struct IrEvalContext<'a> {
pub(crate) c: IrCompiler<'a>,
pub(crate) item: &'a ItemMeta,
}

/// The trait for a type that can be compiled into intermediate representation.
///
/// This is primarily used through [MacroContext::eval][crate::macros::MacroContext::eval].
pub trait IrEval {
/// Evaluate the current value as a constant expression and return its value
/// through its intermediate representation [IrValue].
fn eval(&self, ctx: &mut IrEvalContext<'_>) -> compile::Result<IrValue>;
}
impl ast::Expr {
pub(crate) fn eval(&self, ctx: &mut IrEvalContext<'_>) -> compile::Result<IrValue> {
let Some(id) = ctx.item.id.get() else {
return Err(compile::Error::msg(self, "Missing id for constant eval"));
};

let item = ctx.c.q.pool.item(ctx.item.item);
let items = Items::new(item, id, ctx.c.q.gen);

let mut idx = Indexer {
q: ctx.c.q.borrow(),
source_id: ctx.c.source_id,
items,
scopes: IndexScopes::new(),
mod_item: ctx.item.module,
impl_item: Default::default(),
nested_item: None,
macro_depth: 0,
root: None,
loaded: None,
queue: None,
};

let mut expr = self.clone();
index::expr(&mut idx, &mut expr, index::IS_USED)?;

impl IrEval for ast::Expr {
fn eval(&self, ctx: &mut IrEvalContext<'_>) -> compile::Result<IrValue> {
let ir = {
// TODO: avoid this arena?
let arena = crate::hir::Arena::new();
Expand All @@ -53,7 +72,7 @@ impl IrEval for ast::Expr {
ctx.c.q.borrow(),
ctx.item.location.source_id,
);
let hir = crate::hir::lowering::expr(&mut hir_ctx, self)?;
let hir = crate::hir::lowering::expr(&mut hir_ctx, &expr)?;
compiler::expr(&hir, &mut ctx.c)?
};

Expand Down Expand Up @@ -477,7 +496,7 @@ pub struct IrCall {
#[rune(span)]
pub(crate) span: Span,
/// The target of the call.
pub(crate) target: Box<str>,
pub(crate) id: NonZeroId,
/// Arguments to the call.
pub(crate) args: Vec<Ir>,
}
Expand Down
58 changes: 34 additions & 24 deletions crates/rune/src/compile/ir/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,11 @@ impl IrCompiler<'_> {
/// Resolve an ir target from an expression.
fn ir_target(&self, expr: &hir::Expr<'_>) -> compile::Result<ir::IrTarget> {
match expr.kind {
hir::ExprKind::Path(path) => {
if let Some(ident) = path.try_as_ident() {
let name = self.resolve(ident)?;

return Ok(ir::IrTarget {
span: expr.span(),
kind: ir::IrTargetKind::Name(name.into()),
});
}
hir::ExprKind::Variable(_, name) => {
return Ok(ir::IrTarget {
span: expr.span(),
kind: ir::IrTargetKind::Name(name.into()),
});
}
hir::ExprKind::FieldAccess(expr_field_access) => {
let target = self.ir_target(expr_field_access.expr)?;
Expand Down Expand Up @@ -72,7 +68,7 @@ impl IrCompiler<'_> {
_ => (),
}

Err(compile::Error::msg(expr, "not supported as a target"))
Err(compile::Error::msg(expr, "Not supported as a target"))
}
}

Expand All @@ -82,15 +78,15 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut IrCompiler<'_>) -> compile::Resu

Ok(match hir.kind {
hir::ExprKind::Vec(hir) => ir::Ir::new(span, expr_vec(span, c, hir)?),
hir::ExprKind::Tuple(hir) => expr_tuple(span, c, hir)?,
hir::ExprKind::Tuple(hir) => expr_tuple(c, span, hir)?,
hir::ExprKind::Object(hir) => ir::Ir::new(span, expr_object(span, c, hir)?),
hir::ExprKind::Group(hir) => expr(hir, c)?,
hir::ExprKind::Binary(hir) => expr_binary(span, c, hir)?,
hir::ExprKind::Assign(hir) => expr_assign(span, c, hir)?,
hir::ExprKind::Call(hir) => ir::Ir::new(span, expr_call(span, c, hir)?),
hir::ExprKind::If(hir) => ir::Ir::new(span, expr_if(span, c, hir)?),
hir::ExprKind::Loop(hir) => ir::Ir::new(span, expr_loop(span, c, hir)?),
hir::ExprKind::Lit(hir) => lit(span, c, hir)?,
hir::ExprKind::Lit(hir) => lit(c, span, hir)?,
hir::ExprKind::Block(hir) => ir::Ir::new(span, block(hir, c)?),
hir::ExprKind::Path(hir) => path(hir, c)?,
hir::ExprKind::FieldAccess(..) => ir::Ir::new(span, c.ir_target(hir)?),
Expand All @@ -99,7 +95,22 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut IrCompiler<'_>) -> compile::Resu
let ir_template = builtin_template(template, c)?;
ir::Ir::new(hir.span(), ir_template)
}
_ => return Err(compile::Error::msg(hir, "not supported yet")),
hir::ExprKind::Const(hash) => {
let Some(value) = c.q.get_const_value(hash) else {
return Err(compile::Error::msg(hir, format_args!("Missing constant for hash {hash}")));
};

ir::Ir::new(span, ir::IrValue::from_const(value))
}
hir::ExprKind::Variable(_, name) => {
return Ok(ir::Ir::new(span, <Box<str>>::from(name)));
}
_ => {
return Err(compile::Error::msg(
hir,
"Expression kind not supported yet in constant contexts",
))
}
})
}

Expand Down Expand Up @@ -133,15 +144,14 @@ fn expr_call(
args.push(expr(e, c)?);
}

if let hir::Call::Var { name, .. } = hir.call {
return Ok(ir::IrCall {
span,
target: name.into(),
args,
});
if let hir::Call::ConstFn { id, .. } = hir.call {
return Ok(ir::IrCall { span, id, args });
}

Err(compile::Error::msg(span, "call not supported"))
Err(compile::Error::msg(
span,
"Call not supported in constant contexts",
))
}

#[instrument]
Expand Down Expand Up @@ -203,8 +213,8 @@ fn expr_binary(
))
}

#[instrument]
fn lit(span: Span, c: &mut IrCompiler<'_>, hir: hir::Lit<'_>) -> compile::Result<ir::Ir> {
#[instrument(span = span)]
fn lit(c: &mut IrCompiler<'_>, span: Span, hir: hir::Lit<'_>) -> compile::Result<ir::Ir> {
Ok(match hir {
hir::Lit::Bool(boolean) => ir::Ir::new(span, IrValue::Bool(boolean)),
hir::Lit::Str(string) => ir::Ir::new(span, IrValue::String(Shared::new(string.to_owned()))),
Expand All @@ -219,10 +229,10 @@ fn lit(span: Span, c: &mut IrCompiler<'_>, hir: hir::Lit<'_>) -> compile::Result
})
}

#[instrument]
#[instrument(span = span)]
fn expr_tuple(
span: Span,
c: &mut IrCompiler<'_>,
span: Span,
hir: &hir::ExprSeq<'_>,
) -> compile::Result<ir::Ir> {
if hir.items.is_empty() {
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/compile/ir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ fn eval_ir_call(
args.push(eval_ir(arg, interp, used)?);
}

Ok(interp.call_const_fn(ir, &ir.target, args, used)?)
Ok(interp.call_const_fn(ir, ir.id, args, used)?)
}

fn eval_ir_condition(
Expand Down
Loading

0 comments on commit 2750b3e

Please sign in to comment.