Skip to content

Commit

Permalink
feat(codegen): Add the newtype attribute
Browse files Browse the repository at this point in the history
Adding `#[gluon(newtype)]` when deriving `VmType` defines the type as an
alias of the content of the type instead of the plain type

```
struct Test {
   x: i32,
}
// Without : { x : Int }
// With : type Test = { x : Int }; Test
```
  • Loading branch information
Marwes committed Apr 21, 2019
1 parent a2daace commit 4085463
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 6 deletions.
7 changes: 7 additions & 0 deletions codegen/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub enum CrateName {
pub struct Container {
pub crate_name: CrateName,
pub vm_type: Option<String>,
pub newtype: bool,
}

impl Container {
Expand All @@ -35,6 +36,7 @@ impl Container {

let mut crate_name = CrateName::None;
let mut vm_type = None;
let mut newtype = false;

for meta_items in item.attrs.iter().filter_map(get_gluon_meta_items) {
for meta_item in meta_items {
Expand All @@ -51,6 +53,10 @@ impl Container {
crate_name = CrateName::GluonVm;
}

Meta(Word(ref w)) if w == "newtype" => {
newtype = true;
}

Meta(NameValue(ref m)) if m.ident == "vm_type" => {
vm_type = Some(get_lit_str(&m.ident, &m.ident, &m.lit).unwrap().value())
}
Expand All @@ -63,6 +69,7 @@ impl Container {
Container {
crate_name,
vm_type,
newtype,
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions codegen/src/vm_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,32 @@ fn gen_impl(container: &Container, ident: Ident, generics: Generics, data: &Data

let dummy_const = Ident::new(&format!("_IMPL_VM_TYPE_FOR_{}", ident), Span::call_site());

let make_type_impl = if container.newtype {
let type_application = gen_type_application(&generics);
let generic_params = map_type_params(&generics, |param| {
let lower_param = param.to_string().to_ascii_lowercase();
quote! {
vm.global_env().get_generic(#lower_param)
}
});

quote! {
let ty = if let Ok(ty) = vm.find_type_info(stringify!(#ident)) {
ty.into_type()
} else {
let ty = _gluon_base::types::Alias::new(
_gluon_base::symbol::Symbol::from(stringify!(#ident)),
vec![#(#generic_params),*],
#make_type_impl,
);
vm.cache_alias(ty)
};
#type_application
}
} else {
make_type_impl
};

quote! {
#[allow(non_upper_case_globals)]
const #dummy_const: () = {
Expand Down
3 changes: 2 additions & 1 deletion codegen/tests/derive_userdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use gluon::{import, Compiler, Thread};
use init::new_vm;
use std::sync::Arc;

#[derive(Userdata, Debug)]
#[derive(Userdata, Debug, VmType)]
#[gluon(vm_type = "WindowHandle")]
struct WindowHandle {
id: Arc<u64>,
metadata: Arc<str>,
Expand Down
29 changes: 25 additions & 4 deletions codegen/tests/derive_vm_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate gluon;

mod init;

use gluon::vm::api::VmType;
use gluon::{base::types::Type, vm::api::VmType};
use init::new_vm;

#[derive(VmType)]
Expand Down Expand Up @@ -45,14 +45,35 @@ fn enum_() {

#[derive(VmType)]
#[allow(unused)]
struct Newtype(Struct);
struct NewtypeInner(Struct);

#[test]
fn newtype() {
fn newtype_inner() {
let vm = new_vm();

assert_eq!(
Newtype::make_type(&vm).to_string(),
NewtypeInner::make_type(&vm).to_string(),
Struct::make_type(&vm).to_string(),
);
}

#[derive(VmType)]
#[gluon(newtype)]
#[allow(unused)]
struct Newtype(Struct);

#[test]
fn newtype() {
let vm = new_vm();

match &*Newtype::make_type(&vm) {
Type::Alias(alias) => {
assert_eq!(alias.name.declared_name(), "Newtype");
assert_eq!(
alias.unresolved_type().to_string(),
Struct::make_type(&vm).to_string()
);
}
_ => panic!(),
}
}
8 changes: 7 additions & 1 deletion vm/src/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,10 @@ impl Thread {
self.global_env().register_type_as(name, alias, id)
}

pub fn cache_alias(&self, alias: Alias<Symbol, ArcType>) -> ArcType {
self.global_env().cache_alias(alias)
}

/// Locks and retrieves the global environment of the vm
pub fn get_env<'b>(&'b self) -> RwLockReadGuard<'b, VmEnv> {
self.global_env().get_env()
Expand Down Expand Up @@ -1484,7 +1488,9 @@ impl<'b> OwnedContext<'b> {

maybe_context = match state {
State::Unknown => return Ok(Async::Ready(Some(context))),
State::Extern(ref ext) if ext.is_locked() => return Ok(Async::Ready(Some(context))),
State::Extern(ref ext) if ext.is_locked() => {
return Ok(Async::Ready(Some(context)))
}

State::Extern(mut ext) => {
// We are currently in the poll call of this extern function.
Expand Down
10 changes: 10 additions & 0 deletions vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,16 @@ impl GlobalVmState {
}
}

pub fn cache_alias(&self, alias: Alias<Symbol, ArcType>) -> ArcType {
let mut env = self.env.write().unwrap();
let type_infos = &mut env.type_infos;
let t = alias.clone().into_type();
type_infos
.id_to_type
.insert(alias.name.definition_name().into(), alias);
t
}

pub fn get_macros(&self) -> &MacroEnv {
&self.macros
}
Expand Down

0 comments on commit 4085463

Please sign in to comment.