Skip to content

Commit

Permalink
Rewrite Rune to use a slot-based virtual machine
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jul 15, 2024
1 parent 953927a commit b069126
Show file tree
Hide file tree
Showing 105 changed files with 7,536 additions and 3,839 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ jobs:
- run: cargo test --doc
- run: cargo run --bin rune -- check --recursive --experimental scripts
- run: cargo run --bin rune -- test --recursive --experimental scripts --opt include-std
- run: cargo run --bin rune -- test
1 change: 1 addition & 0 deletions Rune.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
members = [
"benches",
"examples",
"crates/rune",
]
1 change: 1 addition & 0 deletions crates/rune-alloc/src/btree/map/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::ifs_same_cond)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::useless_vec)]
#![allow(unused_must_use)]

use core::fmt::Debug;
use core::sync::atomic::{AtomicUsize, Ordering::SeqCst};
Expand Down
1 change: 1 addition & 0 deletions crates/rune-alloc/src/btree/set/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![allow(clippy::needless_borrow)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::useless_vec)]
#![allow(unused_must_use)]

use core::ops::Bound::{Excluded, Included};

Expand Down
2 changes: 1 addition & 1 deletion crates/rune-alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// # Ok::<_, rune::alloc::Error>(())
/// ```
#[inline]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.len
}

Expand Down
17 changes: 15 additions & 2 deletions crates/rune-core/src/item/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,28 @@ impl Item {
#[inline]
pub const fn new() -> &'static Self {
// SAFETY: an empty slice is a valid bit pattern for the root.
unsafe { Self::from_raw(&[]) }
unsafe { Self::from_bytes(&[]) }
}

/// Construct an [Item] from an [ItemBuf].
///
/// # Safety
///
/// Caller must ensure that content has a valid [ItemBuf] representation.
pub(super) const unsafe fn from_raw(content: &[u8]) -> &Self {
/// The easiest way to accomplish this is to use the `rune::item!` macro.
///
/// # Examples
///
/// ```
/// use rune::compile::{Item, ItemBuf};
///
/// let item = ItemBuf::with_item(["foo", "bar"])?;
///
/// // SAFETY: item is constructed from a valid buffer.
/// let item = unsafe { Item::from_bytes(item.as_bytes()) };
/// # Ok::<_, rune::alloc::Error>(())
/// ```
pub const unsafe fn from_bytes(content: &[u8]) -> &Self {
&*(content as *const _ as *const _)
}

Expand Down
4 changes: 2 additions & 2 deletions crates/rune-core/src/item/item_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub struct ItemBuf<A: Allocator = Global> {

impl<A: Allocator> ItemBuf<A> {
/// Construct a new item buffer inside of the given allocator.
pub(crate) fn new_in(alloc: A) -> Self {
pub(crate) const fn new_in(alloc: A) -> Self {
Self {
content: Vec::new_in(alloc),
}
Expand Down Expand Up @@ -320,7 +320,7 @@ impl<A: Allocator> Deref for ItemBuf<A> {

fn deref(&self) -> &Self::Target {
// SAFETY: Item ensures that content is valid.
unsafe { Item::from_raw(self.content.as_ref()) }
unsafe { Item::from_bytes(self.content.as_ref()) }
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/rune-core/src/item/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ impl<'a> Iter<'a> {
#[inline]
pub fn as_item(&self) -> &Item {
// SAFETY: Iterator ensures that content is valid.
unsafe { Item::from_raw(self.content) }
unsafe { Item::from_bytes(self.content) }
}

/// Coerce the iterator into an item with the lifetime of the iterator.
#[inline]
pub fn into_item(self) -> &'a Item {
// SAFETY: Iterator ensures that content is valid.
unsafe { Item::from_raw(self.content) }
unsafe { Item::from_bytes(self.content) }
}

/// Get the next component as a string.
Expand Down
56 changes: 56 additions & 0 deletions crates/rune-macros/src/item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use core::mem::take;

use proc_macro2::Span;
use rune_core::{ComponentRef, ItemBuf};

/// Construct a static item from a path.
pub(crate) fn build_item(path: &syn::Path) -> syn::Result<syn::ExprArray> {
let mut buf = ItemBuf::new();
let mut first = path.leading_colon.is_some();

for s in &path.segments {
let ident = s.ident.to_string();

let c = if take(&mut first) {
ComponentRef::Crate(&ident)
} else {
ComponentRef::Str(&ident)
};

buf.push(c)
.map_err(|error| syn::Error::new_spanned(s, error))?;

match &s.arguments {
syn::PathArguments::None => {}
syn::PathArguments::AngleBracketed(generics) => {
return Err(syn::Error::new_spanned(
generics,
"Generic arguments are not supported",
));
}
syn::PathArguments::Parenthesized(generics) => {
return Err(syn::Error::new_spanned(
generics,
"Generic arguments are not supported",
));
}
}
}

let mut elems = syn::punctuated::Punctuated::new();

for &byte in buf.as_bytes() {
let byte = syn::LitByte::new(byte, Span::call_site());

elems.push(syn::Expr::Lit(syn::ExprLit {
attrs: Vec::new(),
lit: syn::Lit::Byte(byte),
}));
}

Ok(syn::ExprArray {
attrs: Vec::new(),
bracket_token: syn::token::Bracket::default(),
elems,
})
}
39 changes: 35 additions & 4 deletions crates/rune-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod hash;
mod inst_display;
mod instrument;
mod internals;
mod item;
mod macro_;
mod module;
mod opaque;
Expand Down Expand Up @@ -191,14 +192,14 @@ pub fn any(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
builder.expand().into()
}

/// Calculate a type hash.
/// Calculate a type hash at compile time.
///
/// # Examples
///
/// ```
/// use rune_core::Hash;
/// use rune::Hash;
///
/// let hash: Hash = rune_macros::hash!(::std::ops::Generator);
/// let hash: Hash = rune::hash!(::std::ops::Generator);
/// ```
#[proc_macro]
pub fn hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
Expand All @@ -207,7 +208,37 @@ pub fn hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let stream = match self::hash::build_type_hash(&path) {
Ok(hash) => {
let hash = hash.into_inner();
::quote::quote!(Hash::new(#hash))
::quote::quote!(rune::Hash::new(#hash))
}
Err(error) => to_compile_errors([error]),
};

stream.into()
}

/// Calculate an item reference at compile time.
///
/// # Examples
///
/// ```
/// use rune::{Item, ItemBuf};
///
/// static ITEM: &Item = rune::item!(::std::ops::Generator);
///
/// let mut item = ItemBuf::with_crate("std")?;
/// item.push("ops")?;
/// item.push("Generator")?;
///
/// assert_eq!(item, ITEM);
/// # Ok::<_, rune::alloc::Error>(())
/// ```
#[proc_macro]
pub fn item(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let path = syn::parse_macro_input!(input as syn::Path);

let stream = match self::item::build_item(&path) {
Ok(hash) => {
::quote::quote!(unsafe { rune::Item::from_bytes(&#hash) })
}
Err(error) => to_compile_errors([error]),
};
Expand Down
3 changes: 3 additions & 0 deletions crates/rune-shim/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ pub mod support {
pub use anyhow::Error;
pub use anyhow::Result;
}

#[cfg(feature = "rune-core")]
pub use rune_core::{Item, ItemBuf};
1 change: 1 addition & 0 deletions crates/rune-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ async fn inner_compile(
let start = WasmPosition::from(
source.pos_to_utf8_linecol(inst.span.start.into_usize()),
);

let end = WasmPosition::from(
source.pos_to_utf8_linecol(inst.span.end.into_usize()),
);
Expand Down
3 changes: 3 additions & 0 deletions crates/rune/Rune.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "rune"
version = "0.0.0"
2 changes: 1 addition & 1 deletion crates/rune/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ pub use self::expr_match::{ExprMatch, ExprMatchBranch};
pub use self::expr_object::{ExprObject, FieldAssign, ObjectIdent, ObjectKey};
pub use self::expr_range::{ExprRange, ExprRangeLimits};
pub use self::expr_return::ExprReturn;
pub use self::expr_select::{ExprSelect, ExprSelectBranch, ExprSelectPatBranch};
pub use self::expr_select::{ExprDefaultBranch, ExprSelect, ExprSelectBranch, ExprSelectPatBranch};
pub use self::expr_try::ExprTry;
pub use self::expr_tuple::ExprTuple;
pub use self::expr_unary::{ExprUnary, UnOp};
Expand Down
18 changes: 0 additions & 18 deletions crates/rune/src/ast/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,24 +152,6 @@ impl Parse for AttrStyle {
}
}

/// Helper struct to only parse inner attributes.
#[allow(unused)]
pub(crate) struct InnerAttribute(pub(crate) Attribute);

impl Parse for InnerAttribute {
fn parse(p: &mut Parser) -> Result<Self> {
let attribute: Attribute = p.parse()?;

match attribute.style {
AttrStyle::Inner => Ok(Self(attribute)),
_ => Err(compile::Error::expected(
attribute,
"inner attribute like `#![allow(unused)]`",
)),
}
}
}

/// Tag struct to assist peeking for an outer `#![...]` attributes at the top of
/// a module/file
#[non_exhaustive]
Expand Down
15 changes: 8 additions & 7 deletions crates/rune/src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,14 @@ fn base(
K!['['] => Expr::Vec(ast::ExprVec::parse_with_meta(p, take(attributes))?),
ast::Kind::Open(ast::Delimiter::Empty) => empty_group(p, take(attributes))?,
K!['('] => paren_group(p, take(attributes))?,
K!['{'] => Expr::Block(ast::ExprBlock::parse_with_meta(
p,
take(attributes),
take(&mut async_token),
take(&mut const_token),
take(&mut move_token),
)?),
K!['{'] => Expr::Block(ast::ExprBlock {
attributes: take(attributes),
async_token: take(&mut async_token),
const_token: take(&mut const_token),
move_token: take(&mut move_token),
label: take(&mut label),
block: p.parse()?,
}),
K![break] => Expr::Break(ast::ExprBreak::parse_with_meta(p, take(attributes))?),
K![continue] => Expr::Continue(ast::ExprContinue::parse_with_meta(p, take(attributes))?),
K![yield] => Expr::Yield(ast::ExprYield::parse_with_meta(p, take(attributes))?),
Expand Down
10 changes: 8 additions & 2 deletions crates/rune/src/ast/expr_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ fn ast_parse() {
let expr = rt::<ast::ExprBlock>("async { 42 }");
assert_eq!(expr.block.statements.len(), 1);

let expr = rt::<ast::ExprBlock>("'foo: { 42 }");
assert_eq!(expr.block.statements.len(), 1);
assert!(expr.label.is_some());

let expr = rt::<ast::ExprBlock>("#[retry] async { 42 }");
assert_eq!(expr.block.statements.len(), 1);
assert_eq!(expr.attributes.len(), 1);
Expand All @@ -26,8 +30,7 @@ fn ast_parse() {
/// * `<block>`.
/// * `async <block>`.
/// * `const <block>`.
#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)]
#[rune(parse = "meta_only")]
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct ExprBlock {
/// The attributes for the block.
Expand All @@ -42,6 +45,9 @@ pub struct ExprBlock {
/// The optional move token.
#[rune(iter, meta)]
pub move_token: Option<T![move]>,
/// An optional label for the block.
#[rune(iter)]
pub label: Option<(ast::Label, T![:])>,
/// The close brace.
pub block: ast::Block,
}
Expand Down
2 changes: 1 addition & 1 deletion crates/rune/src/ast/expr_for.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl ExprFor {
binding: parser.parse()?,
in_: parser.parse()?,
iter: Box::try_new(ast::Expr::parse_without_eager_brace(parser)?)?,
body: parser.parse()?,
body: Box::try_new(parser.parse()?)?,
})
}
}
Expand Down
Loading

0 comments on commit b069126

Please sign in to comment.