Skip to content

Commit

Permalink
fix(vm): Correctly assign record field names derive(Pushable)
Browse files Browse the repository at this point in the history
Fixes #591
  • Loading branch information
Marwes committed Jul 24, 2018
1 parent 727e279 commit 4a36d82
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 18 deletions.
25 changes: 21 additions & 4 deletions codegen/src/pushable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn derive_struct(ast: DataStruct, ident: Ident, generics: Generics) -> TokenStre
Fields::Unit => quote!{},
};

let push_impl = gen_push_impl(0, &field_idents, &field_types);
let push_impl = gen_push_impl(None, &field_idents, &field_types);

gen_impl(&ident, generics, quote! { #destructured #push_impl })
}
Expand All @@ -54,7 +54,7 @@ fn derive_enum(ast: DataEnum, ident: Ident, generics: Generics) -> TokenStream {
Fields::Unit => quote! { #ident::#variant_ident },
};

let push_impl = gen_push_impl(tag, &field_idents, &field_types);
let push_impl = gen_push_impl(Some(tag), &field_idents, &field_types);

quote! {
#pattern => {
Expand Down Expand Up @@ -91,7 +91,11 @@ fn gen_impl(ident: &Ident, generics: Generics, push_impl: TokenStream) -> TokenS
}
}

fn gen_push_impl(tag: usize, field_idents: &[Cow<Ident>], field_types: &[&Type]) -> TokenStream {
fn gen_push_impl(
tag: Option<usize>,
field_idents: &[Cow<Ident>],
field_types: &[&Type],
) -> TokenStream {
debug_assert!(field_idents.len() == field_types.len());

// push each field onto the stack
Expand All @@ -111,10 +115,23 @@ fn gen_push_impl(tag: usize, field_idents: &[Cow<Ident>], field_types: &[&Type])
// by popping the stack for each field
let array_init = iter::repeat(quote! { ctx.stack.pop() }).take(field_idents.len());

let new_data = match tag {
Some(tag) => quote!{
ctx.new_data(vm, #tag as ::gluon::vm::types::VmTag, &fields)?
},
None => {
let field_ident_strs = field_idents.iter().map(|i| i.to_string());
quote! { {
let field_names = [#(vm.global_env().intern(#field_ident_strs)?),*];
ctx.new_record(vm, &fields, &field_names)?
} }
}
};

quote! {
#(#stack_pushes)*
let fields = [ #(#array_init),* ];
let val = ctx.new_data(vm, #tag as ::gluon::vm::types::VmTag, &fields)?;
let val = #new_data;
ctx.stack.push(val);
}
}
Expand Down
72 changes: 72 additions & 0 deletions codegen/tests/full.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
extern crate gluon;
#[macro_use]
extern crate gluon_codegen;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gluon_vm;

mod init;

use gluon::vm::{self, ExternModule};
use gluon::{import, Compiler, Thread};
use init::new_vm;

#[derive(Debug, PartialEq, Getable, Pushable, VmType, Serialize, Deserialize)]
#[gluon(vm_type = "types.Struct")]
struct Struct {
string: String,
number: u32,
vec: Vec<f64>,
}

fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
let module = record! {
new_struct => primitive!(1 new_struct),
};

ExternModule::new(vm, module)
}

fn new_struct(_: ()) -> Struct {
Struct {
string: "hello".to_owned(),
number: 1,
vec: vec![1.0, 2.0, 3.0],
}
}

#[test]
fn normal_struct() {
let vm = new_vm();
let mut compiler = Compiler::new();

// must be generated by hand because of bug in make_source (see #542)
let src = r#"
type Struct = { string: String, number: Int, vec: Array Float }
{ Struct }
"#;

compiler.load_script(&vm, "types", &src).unwrap();
import::add_extern_module(&vm, "functions", load_struct_mod);

let script = r#"
let { new_struct } = import! functions
new_struct ()
"#;

let (s, _) = compiler
.run_expr::<Struct>(&vm, "test", script)
.unwrap_or_else(|why| panic!("{}", why));

assert_eq!(
s,
Struct {
string: "hello".into(),
number: 1,
vec: vec![1.0, 2.0, 3.0],
}
);
}
1 change: 0 additions & 1 deletion vm/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ impl<T> Traverseable for Generic<T> {
pub mod generic {
use super::VmType;
use base::types::ArcType;
use thread::ThreadInternal;
use vm::Thread;

macro_rules! make_generics {
Expand Down
2 changes: 1 addition & 1 deletion vm/src/api/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use base::symbol::Symbol;
use base::types::{self, Alias, AliasData, ArcType, Generic, Type};

use super::{Getable, Pushable, ValueRef, VmType};
use thread::{self, Context, ThreadInternal};
use thread::{self, Context};
use types::VmIndex;
use value::{Def, Value, ValueRepr};
use vm::Thread;
Expand Down
2 changes: 1 addition & 1 deletion vm/src/api/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use api::{Pushable, VmType};
use base::types::ArcType;
use interner::InternedStr;
use serde::ser::{self, Serialize};
use thread::{Context, Thread, ThreadInternal};
use thread::{Context, Thread};
use types::{VmIndex, VmTag};
use value::{Def, RecordDef, ValueRepr};
use {Error, Result};
Expand Down
2 changes: 1 addition & 1 deletion vm/src/api/typ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use base::symbol::{Symbol, Symbols};
use base::types::{ArcType, Field, Type, TypeCache};

use api::VmType;
use thread::{Thread, ThreadInternal};
use thread::Thread;
use {Error as VmError, Result};

use serde::de::{
Expand Down
2 changes: 1 addition & 1 deletion vm/src/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::ops::Deref;
use base::resolve;
use base::types::{ArcType, Type};

use thread::{RootedValue, Thread, ThreadInternal, VmRoot};
use thread::{RootedValue, Thread, VmRoot};

#[derive(Debug)]
pub struct FieldIter<'a, T>
Expand Down
1 change: 0 additions & 1 deletion vm/src/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,6 @@ pub mod symbol {
pub mod intern {
use super::*;
use interner::InternedStr;
use thread::ThreadInternal;

use serde::ser::{Serialize, SerializeState, Serializer};
use serde::{Deserialize, Deserializer};
Expand Down
27 changes: 21 additions & 6 deletions vm/src/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use base::types::{self, Alias, ArcType};
use api::{Getable, Pushable, ValueRef, VmType};
use compiler::UpvarInfo;
use gc::{DataDef, Gc, GcPtr, Generation, Move};
use interner::InternedStr;
use macros::MacroEnv;
use source_map::LocalIter;
use stack::{Frame, Lock, Stack, StackFrame, State};
Expand Down Expand Up @@ -716,6 +717,11 @@ impl Thread {
self.interrupt.load(atomic::Ordering::Relaxed)
}

#[doc(hidden)]
pub fn global_env(&self) -> &Arc<GlobalVmState> {
&self.global_state
}

fn current_context(&self) -> OwnedContext {
self.context()
}
Expand Down Expand Up @@ -821,8 +827,6 @@ where

fn resume(&self) -> Result<Async<OwnedContext>>;

fn global_env(&self) -> &Arc<GlobalVmState>;

fn set_global(
&self,
name: Symbol,
Expand Down Expand Up @@ -938,10 +942,6 @@ impl ThreadInternal for Thread {
Ok(Async::Ready(context))
}

fn global_env(&self) -> &Arc<GlobalVmState> {
&self.global_state
}

fn set_global(
&self,
name: Symbol,
Expand Down Expand Up @@ -1173,6 +1173,21 @@ impl Context {
.map(Value::from)
}

pub fn new_record(
&mut self,
thread: &Thread,
fields: &[Value],
field_names: &[InternedStr],
) -> Result<Value> {
Ok(Data(self.alloc_with(
thread,
RecordDef {
elems: fields,
fields: field_names,
},
)?).into())
}

pub fn alloc_with<D>(&mut self, thread: &Thread, data: D) -> Result<GcPtr<D::Value>>
where
D: DataDef + Traverseable,
Expand Down
2 changes: 0 additions & 2 deletions vm/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ impl DataStruct {

impl GcPtr<DataStruct> {
pub(crate) fn get(&self, vm: &Thread, field: &str) -> Result<Option<Variants>> {
use thread::ThreadInternal;

let field = vm.global_env().intern(field)?;
Ok(self.get_field(field))
}
Expand Down

0 comments on commit 4a36d82

Please sign in to comment.