Skip to content

Commit

Permalink
Merge pull request #296 from Marwes/serde_api
Browse files Browse the repository at this point in the history
feat: Add a serializer and deserializer from/to gluon values
  • Loading branch information
Marwes authored Jun 20, 2017
2 parents e7c81b2 + 91e2614 commit 59aeab5
Show file tree
Hide file tree
Showing 19 changed files with 2,115 additions and 334 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ skeptic = { version = "0.6", optional = true }
collect-mac = "0.1.0"
env_logger = "0.3.4"

serde = "1.0.0"
serde_derive = "1.0.0"

hyper = "0.11.0"
curl = "0.4.1"

Expand Down
28 changes: 26 additions & 2 deletions base/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,34 @@ pub fn remove_aliases_cow<'t>(env: &TypeEnv, typ: &'t ArcType) -> Cow<'t, ArcTyp
}
}

pub fn canonical_alias<'t, F>(env: &TypeEnv, typ: &'t ArcType, canonical: F) -> Cow<'t, ArcType>
where
F: Fn(&AliasData<Symbol, ArcType>) -> bool,
{
match peek_alias(env, typ) {
Ok(Some(alias)) if !canonical(alias) => {
type_of_alias(env, alias, typ.unapplied_args())
.map(|typ| {
Cow::Owned(canonical_alias(env, &typ, canonical).into_owned())
})
.unwrap_or(Cow::Borrowed(typ))
}
_ => Cow::Borrowed(typ),
}
}

/// Expand `typ` if it is an alias that can be expanded and return the expanded type.
/// Returns `None` if the type is not an alias or the alias could not be expanded.
pub fn remove_alias(env: &TypeEnv, typ: &ArcType) -> Result<Option<ArcType>, Error> {
Ok(peek_alias(env, typ)?.and_then(|alias| {
type_of_alias(env, alias, typ.unapplied_args())
}))
}

pub fn peek_alias<'t>(
env: &'t TypeEnv,
typ: &'t ArcType,
) -> Result<Option<&'t AliasData<Symbol, ArcType>>, Error> {
let maybe_alias = match **typ {
Type::Alias(ref alias) if alias.args.is_empty() => Some(alias),
Type::App(ref alias, ref args) => {
Expand All @@ -53,8 +78,7 @@ pub fn remove_alias(env: &TypeEnv, typ: &ArcType) -> Result<Option<ArcType>, Err
})?
}
};

Ok(type_of_alias(env, alias, typ.unapplied_args()))
Ok(Some(alias))
}
None => Ok(None),
}
Expand Down
9 changes: 9 additions & 0 deletions base/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,15 @@ where
_ => None,
}
}

pub fn is_non_polymorphic_record(&self) -> bool {
match *self {
Type::Record(ref row) |
Type::ExtendRow { rest: ref row, .. } => row.is_non_polymorphic_record(),
Type::EmptyRow => true,
_ => false,
}
}
}

impl<T> Type<Symbol, T>
Expand Down
5 changes: 2 additions & 3 deletions check/src/completion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Primitive auto completion and type quering on ASTs

use std::borrow::Borrow;
use std::iter::once;
use std::cmp::Ordering;

Expand Down Expand Up @@ -265,7 +264,7 @@ impl<'a> OnFound for GetMetadata<'a> {
}
}

fn pattern(&mut self, pattern: &SpannedPattern<Symbol>) {}
fn pattern(&mut self, _pattern: &SpannedPattern<Symbol>) {}


fn nothing(&mut self) {}
Expand Down Expand Up @@ -313,7 +312,7 @@ impl<'a, E: TypeEnv> OnFound for MetadataSuggest<'a, E> {
}
}

fn pattern(&mut self, pattern: &SpannedPattern<Symbol>) {}
fn pattern(&mut self, _pattern: &SpannedPattern<Symbol>) {}

fn nothing(&mut self) {
self.result = self.suggest
Expand Down
7 changes: 6 additions & 1 deletion check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ pub fn check_signature(env: &TypeEnv, signature: &ArcType, actual: &ArcType) ->
let subs = Substitution::new(Kind::typ());
let state = unify_type::State::new(env, &subs);
let actual = unify_type::instantiate_generic_variables(&mut FnvMap::default(), &subs, actual);
unify_type::merge_signature(&subs, &mut ScopedMap::new(), 0, state, signature, &actual).is_ok()
let result =
unify_type::merge_signature(&subs, &mut ScopedMap::new(), 0, state, signature, &actual);
if let Err(ref err) = result {
debug!("Check signature error: {}", err);
}
result.is_ok()
}

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions examples/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ impl<'vm> Getable<'vm> for Wrap<StatusCode> {
fn from_value(_: &'vm Thread, value: Variants) -> Option<Self> {
use hyper::StatusCode::*;
match value.as_ref() {
ValueRef::Tag(tag) => {
Some(Wrap(match tag {
ValueRef::Data(data) => {
Some(Wrap(match data.tag() {
0 => Ok,
1 => NotFound,
2 => InternalServerError,
Expand Down
188 changes: 188 additions & 0 deletions tests/de.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
extern crate env_logger;
#[macro_use]
extern crate serde_derive;

extern crate gluon;

use gluon::base::types::{ArcType, Field, Type};
use gluon::base::symbol::Symbol;
use gluon::vm::api::{Getable, Hole, OpaqueValue, VmType};
use gluon::vm::api::de::{self, De};
use gluon::vm::thread::Thread;
use gluon::{Compiler, new_vm};

#[test]
fn bool() {
let _ = env_logger::init();

let thread = new_vm();
let (De(b), _) = Compiler::new()
.run_expr::<De<bool>>(&thread, "test", "True")
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(b, true);
}

#[derive(Debug, PartialEq, Deserialize)]
struct Record {
test: i32,
string: String,
}

impl VmType for Record {
type Type = Self;

fn make_type(thread: &Thread) -> ArcType {
Type::poly_record(
vec![],
vec![
Field {
name: Symbol::from("test"),
typ: i32::make_type(thread),
},
Field {
name: Symbol::from("string"),
typ: str::make_type(thread),
},
],
Type::hole(),
)
}
}

#[test]
fn option() {
let _ = env_logger::init();

let thread = new_vm();
let (De(opt), _) = Compiler::new()
.run_expr::<De<Option<f64>>>(&thread, "test", r#" Some 1.0 "#)
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(opt, Some(1.0));
}

#[test]
fn partial_record() {
let _ = env_logger::init();

let thread = new_vm();
let (De(record), _) = Compiler::new()
.run_expr::<De<Record>>(
&thread,
"test",
r#" { test = 1, extra = 1.0, string = "test", } "#,
)
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(
record,
Record {
test: 1,
string: "test".to_string(),
}
);
}


#[derive(Debug, PartialEq, Deserialize)]
struct OptionalFieldRecord {
test: Option<i32>,
}

impl VmType for OptionalFieldRecord {
type Type = Self;

fn make_type(thread: &Thread) -> ArcType {
Type::poly_record(
vec![],
vec![
Field {
name: Symbol::from("test"),
typ: Option::<i32>::make_type(thread),
},
],
Type::hole(),
)
}
}

#[test]
fn optional_field() {
let _ = env_logger::init();

let thread = new_vm();

let (value, _) = Compiler::new()
.run_expr::<OpaqueValue<&Thread, Hole>>(&thread, "test", r#" { } "#)
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(
De::<OptionalFieldRecord>::from_value(&thread, value.get_variants()).map(|x| x.0),
Some(OptionalFieldRecord { test: None })
);

let (value, _) = Compiler::new()
.run_expr::<OpaqueValue<&Thread, Hole>>(&thread, "test", r#" { test = Some 2 } "#)
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(
De::<OptionalFieldRecord>::from_value(&thread, value.get_variants()).map(|x| x.0),
Some(OptionalFieldRecord { test: Some(2) })
);

let (value, _) = Compiler::new()
.run_expr::<OpaqueValue<&Thread, Hole>>(&thread, "test", r#" { test = 1 } "#)
.unwrap_or_else(|err| panic!("{}", err));

let typ = Type::poly_record(
vec![],
vec![
Field {
name: Symbol::from("test"),
typ: i32::make_type(&thread),
},
],
Type::hole(),
);
assert_eq!(
de::from_value(&thread, value.get_variants(), &typ).ok(),
Some(OptionalFieldRecord { test: Some(1) })
);

}

#[derive(Debug, PartialEq, Deserialize)]
enum Enum {
A(i32),
B { string: String, test: f64 },
C(i32, i32),
}

impl VmType for Enum {
type Type = Self;

fn make_type(thread: &Thread) -> ArcType {
thread.find_type_info("test.Enum").unwrap().into_type()
}
}

#[test]
fn enum_() {
let _ = env_logger::init();

let thread = new_vm();
Compiler::new()
.implicit_prelude(false)
.load_script(
&thread,
"test",
r#" type Enum = | A Int | B String Float | C Int Int in { Enum } "#,
)
.unwrap_or_else(|err| panic!("{}", err));

let (De(enum_), _) = Compiler::new()
.implicit_prelude(false)
.run_expr::<De<Enum>>(
&thread,
"test",
r#" let { Enum } = import! "test" in C 0 1 "#,
)
.unwrap_or_else(|err| panic!("{}", err));
assert_eq!(enum_, Enum::C(0, 1));
}
4 changes: 3 additions & 1 deletion vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bitflags = "0.7.0"
itertools = "0.6.0"
futures = "0.1.0"
typed-arena = "1.2.0"
serde = { version = "1.0.0", optional = true }
smallvec = "0.2.1"

gluon_base = { path = "../base", version = "0.4.2" } # GLUON
Expand All @@ -37,6 +38,7 @@ gluon = { path = "..", version = "0.4.2" } # GLUON

lalrpop-util = "0.13.1"
regex = "0.2.0"
serde_derive = "1.0.0"

[features]
test = ["env_logger", "lalrpop", "gluon_parser"]
test = ["env_logger", "lalrpop", "gluon_parser", "serde"]
Loading

0 comments on commit 59aeab5

Please sign in to comment.