From 059b2cd048780af33d72cd3ae960e8b97d1f26f9 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 14 Apr 2018 11:36:59 +0200 Subject: [PATCH 1/9] Suboptimal but working hash implementation --- dev/playground/src/main.rs | 3 ++ src/mango/ast_full/collect/typ.rs | 35 +++++++++++------ src/mango/ast_full/node/assignment.rs | 2 +- src/mango/ast_full/node/binary_operation.rs | 2 +- src/mango/ast_full/node/unary_operation.rs | 2 +- src/mango/util/mod.rs | 2 + src/mango/util/traitobj/eq.rs | 42 +++++++++++++++++++++ src/mango/util/traitobj/hash.rs | 30 +++++++++++++++ src/mango/util/traitobj/mod.rs | 5 +++ 9 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 src/mango/util/traitobj/eq.rs create mode 100644 src/mango/util/traitobj/hash.rs create mode 100644 src/mango/util/traitobj/mod.rs diff --git a/dev/playground/src/main.rs b/dev/playground/src/main.rs index 4acbdbc9..ae04d569 100644 --- a/dev/playground/src/main.rs +++ b/dev/playground/src/main.rs @@ -1,3 +1,6 @@ + +// https://stackoverflow.com/questions/49711479/how-can-i-create-hashable-trait-objects-trait-objects-with-generic-method-para + use std::collections::HashMap; use std::collections::hash_map::RandomState; use std::hash::Hasher; diff --git a/src/mango/ast_full/collect/typ.rs b/src/mango/ast_full/collect/typ.rs index 6091e43a..31e0baae 100644 --- a/src/mango/ast_full/collect/typ.rs +++ b/src/mango/ast_full/collect/typ.rs @@ -1,6 +1,8 @@ use mango::util::encdec::ToText; use std::any::Any; +use std::collections::hash_map::DefaultHasher; use std::fmt::Debug; +use std::hash::{Hash, Hasher}; /// Trait to be implemented by everything in the full abstract syntax tree. //pub trait BaseAST: ToText + ToObjectNotation { // todo: add ON again later @@ -44,14 +46,25 @@ impl<'a> PartialEq for AST + 'a { } } -// todo: remove? -//// Traits with generic methods cannot be made into trait objects. -//// -//impl<'a> Hash for AST + 'a { -// fn hash(&self, hasher: &mut H) -// where -// H: Hasher, -// { -// self.as_hash(&mut hasher) -// } -//} +/// Create a trait that can be required by traits that +/// 1) can be used as objects, and +/// 2) should be hashable +pub trait HashForTraitObj { + fn my_hash(&self) -> u64; +} + +/// Implement my_hash by delegating to Hash. +// Unfortunately uses `DefaultHasher`, but found no other waIt's a by. +impl HashForTraitObj for T { + fn my_hash(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.hash(&mut hasher); + hasher.finish() + } +} + +impl<'a> Hash for AST + 'a { + fn hash(&self, hasher: &mut H) { + hasher.write_u64(self.my_hash()) + } +} diff --git a/src/mango/ast_full/node/assignment.rs b/src/mango/ast_full/node/assignment.rs index 05f59d99..0bc80745 100644 --- a/src/mango/ast_full/node/assignment.rs +++ b/src/mango/ast_full/node/assignment.rs @@ -4,7 +4,7 @@ use mango::util::encdec::ToText; /// Type for an association, e.g. assignment, parameter binding. //#[derive(Debug, Hash)] -#[derive(Debug)] +#[derive(Debug, Hash)] pub struct AssignmentAST { assignee: Box, value: Box, diff --git a/src/mango/ast_full/node/binary_operation.rs b/src/mango/ast_full/node/binary_operation.rs index 7df9318f..7264cb58 100644 --- a/src/mango/ast_full/node/binary_operation.rs +++ b/src/mango/ast_full/node/binary_operation.rs @@ -4,7 +4,7 @@ use mango::ast_full::terminal::OperatorAST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] -#[derive(Debug)] +#[derive(Debug, Hash)] pub struct BinaryOperationAST { left: Box, operator: OperatorAST, diff --git a/src/mango/ast_full/node/unary_operation.rs b/src/mango/ast_full/node/unary_operation.rs index 9a5e58cc..a11039b7 100644 --- a/src/mango/ast_full/node/unary_operation.rs +++ b/src/mango/ast_full/node/unary_operation.rs @@ -4,7 +4,7 @@ use mango::ast_full::terminal::OperatorAST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] -#[derive(Debug)] +#[derive(Debug, Hash)] pub struct UnaryOperationAST { operator: OperatorAST, subject: Box, diff --git a/src/mango/util/mod.rs b/src/mango/util/mod.rs index 279f8f9a..5cea6ad8 100644 --- a/src/mango/util/mod.rs +++ b/src/mango/util/mod.rs @@ -7,3 +7,5 @@ pub mod format; pub mod encdec; pub mod errors; + +pub mod traitobj; diff --git a/src/mango/util/traitobj/eq.rs b/src/mango/util/traitobj/eq.rs new file mode 100644 index 00000000..30ecbf95 --- /dev/null +++ b/src/mango/util/traitobj/eq.rs @@ -0,0 +1,42 @@ +use std::any::Any; + +// The problem with partialeq trait objects is that `PartialEq` needs +// the concrete type of the struct to be able to delegate equality. +// See https://stackoverflow.com/questions/49466199/ + +// TODO: This wasn't easy to make general after all, so implement for each trait that needs it (like &AST) + +/// Create a trait that can be required by traits that +/// 1) can be used as objects, and +/// 2) should be comparable to the trait object +//pub trait PartialEqForTraitObj { +// /// Should return an &Any so that we can test equality on a casted value. +// fn as_any(&self) -> &Any; +// +// /// Do the equality test. +// fn equals(&self, other: &U) -> bool; +//} +// +//// todo: this implements for too many types I think... I only want &A == &A if A and B implement PartialEqForTraitObj +// +///// Implement PartialEq by downcasting and comparing if types are equal. +//impl PartialEqForTraitObj for T { +// fn as_any(&self) -> &Any { +// self as &Any +// } +// +// fn equals(&self, other: &U) -> bool { +// // Do a type-safe casting. If types are different return false, else test for equality. +// match other.as_any().downcast_ref::() { +// None => false, +// Some(a) => self == a, +// } +// } +//} + +// For the trait that should be hashable, do this: +//impl PartialEq for MyTrait { +// fn eq(&self, other: &MyTrait) -> bool { +// self.equals(other) +// } +//} \ No newline at end of file diff --git a/src/mango/util/traitobj/hash.rs b/src/mango/util/traitobj/hash.rs new file mode 100644 index 00000000..74074c4a --- /dev/null +++ b/src/mango/util/traitobj/hash.rs @@ -0,0 +1,30 @@ +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; + +// The problem with hashable trait objects is that `Hash.hash` is generic, +// so it cannot be made into an object. +// See https://stackoverflow.com/questions/49711479/ + +/// Create a trait that can be required by traits that +/// 1) can be used as objects, and +/// 2) should be hashable +pub trait HashForTraitObj { + fn my_hash(&self) -> u64; +} + +/// Implement my_hash by delegating to Hash. +// Unfortunately uses `DefaultHasher`, but found no other waIt's a by. +impl HashForTraitObj for T { + fn my_hash(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.hash(&mut hasher); + hasher.finish() + } +} + +// For the trait that should be hashable, do this: +//impl Hash for MyTrait { +// fn hash(&self, hasher: &mut H) { +// hasher.write_u64(self.my_hash()) +// } +//} diff --git a/src/mango/util/traitobj/mod.rs b/src/mango/util/traitobj/mod.rs new file mode 100644 index 00000000..8d917ed1 --- /dev/null +++ b/src/mango/util/traitobj/mod.rs @@ -0,0 +1,5 @@ +pub mod hash; +pub use self::hash::HashForTraitObj; + +//pub mod eq; +//pub use self::eq::PartialEqForTraitObj; From d1f7abc6cf1d93a0ed8b6ccfa6ee632f27bbe91a Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 14 Apr 2018 21:57:48 +0200 Subject: [PATCH 2/9] Enum proof of concept + nightly formatting --- Cargo.toml | 1 + README.rst | 6 +- dev/playground/Cargo.toml | 1 + dev/playground/src/enumhash.rs | 27 ++++ dev/playground/src/hashin.rs | 104 +++++++++++++++ dev/playground/src/main.rs | 132 ++++++++------------ src/mango/ast_full/collect/mod.rs | 2 +- src/mango/ast_full/mod.rs | 2 +- src/mango/ast_full/node/assignment.rs | 2 +- src/mango/ast_full/node/binary_operation.rs | 4 +- src/mango/ast_full/node/unary_operation.rs | 4 +- src/mango/util/encdec/mod.rs | 2 +- 12 files changed, 196 insertions(+), 91 deletions(-) create mode 100644 dev/playground/src/enumhash.rs create mode 100644 dev/playground/src/hashin.rs diff --git a/Cargo.toml b/Cargo.toml index 510ce3ed..814d332d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ include = [ regex = "0.2.*" string-interner = "0.6.*" lazy_static = "1.0.*" +cargo-wasm = "0.4.*" diff --git a/README.rst b/README.rst index 94523a89..126002a7 100644 --- a/README.rst +++ b/README.rst @@ -16,9 +16,11 @@ There are dozens of pages of design notes, but the plan still lacks coherence, s How to use ------------------------------- -The compiler is written in Rust. You can run it using: +The compiler is written in Rust for WebAssembly. You can run it using: - cargo run + rustup toolchain install nightly + cargo install cargo-wasm + cargo wasm build This compiles to native code, with WebAssembly to be added later (#34). diff --git a/dev/playground/Cargo.toml b/dev/playground/Cargo.toml index 49091317..66b617b6 100644 --- a/dev/playground/Cargo.toml +++ b/dev/playground/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Mark "] [dependencies] +lazy_static = "1.0.*" diff --git a/dev/playground/src/enumhash.rs b/dev/playground/src/enumhash.rs new file mode 100644 index 00000000..109c1fde --- /dev/null +++ b/dev/playground/src/enumhash.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; + +#[derive(Hash, PartialEq, Eq, Debug)] +struct Alpha { + val: String, +} + +#[derive(Hash, PartialEq, Eq, Debug)] +struct Beta { + nr: i32, + f: u8, +} + +#[derive(Hash, PartialEq, Eq, Debug)] +enum MyEnum { + A(Alpha), + B(Beta), +} + +fn main() { + let a = MyEnum::A(Alpha { val: "Hello World".to_owned() }); + let b = MyEnum::B(Beta { nr: 8, f: 2 }); + let mut m = HashMap::new(); + m.insert(a, 0); + m.insert(b, 0); + println!("{:?}", m); +} diff --git a/dev/playground/src/hashin.rs b/dev/playground/src/hashin.rs new file mode 100644 index 00000000..4acbdbc9 --- /dev/null +++ b/dev/playground/src/hashin.rs @@ -0,0 +1,104 @@ +use std::collections::HashMap; +use std::collections::hash_map::RandomState; +use std::hash::Hasher; +use std::hash::BuildHasher; +use std::hash::Hash; +use std::fmt::Debug; +use std::any::Any; + +#[derive(Hash, Debug)] +struct A(i32); + +#[derive(Hash, Debug)] +struct B { + val: String, +} + +trait MyTrait { + fn as_any(&self) -> &Any; + fn my_hash(&self, hasher: &mut Hasher); +} + +trait AnyHasher { + fn as_any(&self) -> &Any; +} + +impl AnyHasher for H { + fn as_any(&self) -> &Any { + self as &Any + } +} + +// TODO: but now I want this not for everything +impl MyTrait for T { + fn as_any(&self) -> &Any { + self as &Any + } + + fn my_hash(&self, hasher: &mut AnyHasher) { + let h = hasher.as_any().downcast_ref::().unwrap(); + self.as_any().downcast_ref::().unwrap().hash(h) + } +} + +//impl MyTrait for A {} +//impl MyTrait for B {} + +impl Hash for MyTrait { + fn hash(&self, hasher: &mut H) { + self.my_hash(hasher) + } +} + +fn main() { + let s = RandomState::new(); + let mut hasher = s.build_hasher(); + + let x: &MyTrait = &A(1); + x.hash(&mut hasher); +} + + +//trait PreS: Debug {} +// +//trait HasherAsAny { +// fn as_any(&self) -> &Any; +//} +// +//trait PostS { +// fn as_any(&self) -> &Any; +// +// fn _hash(&self, hasher: H); +//} +// +//impl HasherAsAny for T { +// fn as_any(&self) -> &Any { +// self as &Any +// } +//} +// +//impl PostS for T { +// fn as_any(&self) -> &Any { +// self as &Any +// } +// +// fn _hash(&self, hasher: H) { +// self.as_any().downcast_ref::().hash(hasher) +// } +//} +// +//impl PreS for A {} +// +//impl PreS for B {} +// +//impl Hash for PostS { +// fn hash(&self, hasher: &mut HasherAsAny) { +// self._hash(hasher.as_any().downcast_ref::()) +// } +//} +// +//fn main() { +// let x: &PostS = &A(1); +// let m = HashMap::new(); +// m.insert(x, 0); +//} diff --git a/dev/playground/src/main.rs b/dev/playground/src/main.rs index ae04d569..c64f240d 100644 --- a/dev/playground/src/main.rs +++ b/dev/playground/src/main.rs @@ -6,102 +6,72 @@ use std::collections::hash_map::RandomState; use std::hash::Hasher; use std::hash::BuildHasher; use std::hash::Hash; -use std::fmt::Debug; -use std::any::Any; -#[derive(Hash, Debug)] -struct A(i32); - -#[derive(Hash, Debug)] -struct B { - val: String, -} +#[macro_use] +extern crate lazy_static; trait MyTrait { - fn as_any(&self) -> &Any; - fn my_hash(&self, hasher: &mut Hasher); + fn to_text(&self) -> String; } -trait AnyHasher { - fn as_any(&self) -> &Any; +#[derive(Hash, PartialEq, Eq, Debug)] +struct Alpha { + val: String, } -impl AnyHasher for H { - fn as_any(&self) -> &Any { - self as &Any - } +#[derive(Hash, PartialEq, Eq, Debug)] +struct Beta { + nr: i32, + f: u8, } -// TODO: but now I want this not for everything -impl MyTrait for T { - fn as_any(&self) -> &Any { - self as &Any - } - - fn my_hash(&self, hasher: &mut AnyHasher) { - let h = hasher.as_any().downcast_ref::().unwrap(); - self.as_any().downcast_ref::().unwrap().hash(h) - } +impl MyTrait for Alpha { + fn to_text(&self) -> String { + self.val.to_owned() + } } -//impl MyTrait for A {} -//impl MyTrait for B {} +impl MyTrait for Beta { + fn to_text(&self) -> String { + format!("{}, {}", self.nr, self.f) + } +} -impl Hash for MyTrait { - fn hash(&self, hasher: &mut H) { - self.my_hash(hasher) - } +#[derive(Hash, PartialEq, Eq, Debug)] +enum MyEnum { + A(Alpha), + B(Beta), } -fn main() { - let s = RandomState::new(); - let mut hasher = s.build_hasher(); +impl MyTrait for MyEnum { + fn to_text(&self) -> String { + match self { + &MyEnum::A(ref alpha) => alpha.to_text(), + &MyEnum::B(ref beta) => beta.to_text(), + } + } +} - let x: &MyTrait = &A(1); - x.hash(&mut hasher); +lazy_static! { + static ref RANDSTATE: RandomState = RandomState::new(); } +fn get_test_hash(x: &MyEnum) -> u64 { + let mut hasher = RANDSTATE.build_hasher(); + x.hash(&mut hasher); + hasher.finish() +} -//trait PreS: Debug {} -// -//trait HasherAsAny { -// fn as_any(&self) -> &Any; -//} -// -//trait PostS { -// fn as_any(&self) -> &Any; -// -// fn _hash(&self, hasher: H); -//} -// -//impl HasherAsAny for T { -// fn as_any(&self) -> &Any { -// self as &Any -// } -//} -// -//impl PostS for T { -// fn as_any(&self) -> &Any { -// self as &Any -// } -// -// fn _hash(&self, hasher: H) { -// self.as_any().downcast_ref::().hash(hasher) -// } -//} -// -//impl PreS for A {} -// -//impl PreS for B {} -// -//impl Hash for PostS { -// fn hash(&self, hasher: &mut HasherAsAny) { -// self._hash(hasher.as_any().downcast_ref::()) -// } -//} -// -//fn main() { -// let x: &PostS = &A(1); -// let m = HashMap::new(); -// m.insert(x, 0); -//} +fn main() { + let a1: MyEnum = MyEnum::A(Alpha { val: "Hello World".to_owned() }); + let a2: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); + let a3: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); + let b: MyEnum = MyEnum::B(Beta { nr: 8, f: 2 }); + let mut m = HashMap::new(); + println!("{:?} {:?}", a1.to_text(), b.to_text()); + println!("{:?} {:?} {:?}", get_test_hash(&a1), get_test_hash(&a2), get_test_hash(&a3)); + m.insert(a1, 0); + m.insert(a2, 0); + m.insert(b, 0); + println!("{:?}", m); +} diff --git a/src/mango/ast_full/collect/mod.rs b/src/mango/ast_full/collect/mod.rs index 87234cb6..d43d3e61 100644 --- a/src/mango/ast_full/collect/mod.rs +++ b/src/mango/ast_full/collect/mod.rs @@ -2,5 +2,5 @@ mod all; pub use self::all::FullAST; mod typ; -pub use self::typ::AST; pub use self::typ::BaseAST; +pub use self::typ::AST; diff --git a/src/mango/ast_full/mod.rs b/src/mango/ast_full/mod.rs index bc307d13..91e93808 100644 --- a/src/mango/ast_full/mod.rs +++ b/src/mango/ast_full/mod.rs @@ -8,9 +8,9 @@ mod special; pub use self::special::*; mod collect; -pub use self::collect::AST; pub use self::collect::BaseAST; pub use self::collect::FullAST; +pub use self::collect::AST; #[cfg(test)] mod tests; diff --git a/src/mango/ast_full/node/assignment.rs b/src/mango/ast_full/node/assignment.rs index 0bc80745..e731e7fb 100644 --- a/src/mango/ast_full/node/assignment.rs +++ b/src/mango/ast_full/node/assignment.rs @@ -1,5 +1,5 @@ -use mango::ast_full::AST; use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; /// Type for an association, e.g. assignment, parameter binding. diff --git a/src/mango/ast_full/node/binary_operation.rs b/src/mango/ast_full/node/binary_operation.rs index 7264cb58..d169c757 100644 --- a/src/mango/ast_full/node/binary_operation.rs +++ b/src/mango/ast_full/node/binary_operation.rs @@ -1,6 +1,6 @@ -use mango::ast_full::AST; -use mango::ast_full::BaseAST; use mango::ast_full::terminal::OperatorAST; +use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] diff --git a/src/mango/ast_full/node/unary_operation.rs b/src/mango/ast_full/node/unary_operation.rs index a11039b7..947d7216 100644 --- a/src/mango/ast_full/node/unary_operation.rs +++ b/src/mango/ast_full/node/unary_operation.rs @@ -1,6 +1,6 @@ -use mango::ast_full::AST; -use mango::ast_full::BaseAST; use mango::ast_full::terminal::OperatorAST; +use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] diff --git a/src/mango/util/encdec/mod.rs b/src/mango/util/encdec/mod.rs index 96b8e0b6..3058cbf0 100644 --- a/src/mango/util/encdec/mod.rs +++ b/src/mango/util/encdec/mod.rs @@ -1,7 +1,7 @@ #[allow(non_snake_case)] mod to_ON; -pub use self::to_ON::ON; pub use self::to_ON::ToObjectNotation; +pub use self::to_ON::ON; mod to_text; pub use self::to_text::ToText; From b19fc3cb0e79e1893585d8bfac3b83a1cff3cdd3 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 15 Apr 2018 07:24:44 +0200 Subject: [PATCH 3/9] Try to use trait object suggestion from SO --- dev/playground/src/enumhash.rs | 56 ++++++++++++++++++++++-- dev/playground/src/main.rs | 80 ++++++++++------------------------ 2 files changed, 77 insertions(+), 59 deletions(-) diff --git a/dev/playground/src/enumhash.rs b/dev/playground/src/enumhash.rs index 109c1fde..c64f240d 100644 --- a/dev/playground/src/enumhash.rs +++ b/dev/playground/src/enumhash.rs @@ -1,4 +1,18 @@ + +// https://stackoverflow.com/questions/49711479/how-can-i-create-hashable-trait-objects-trait-objects-with-generic-method-para + use std::collections::HashMap; +use std::collections::hash_map::RandomState; +use std::hash::Hasher; +use std::hash::BuildHasher; +use std::hash::Hash; + +#[macro_use] +extern crate lazy_static; + +trait MyTrait { + fn to_text(&self) -> String; +} #[derive(Hash, PartialEq, Eq, Debug)] struct Alpha { @@ -11,17 +25,53 @@ struct Beta { f: u8, } +impl MyTrait for Alpha { + fn to_text(&self) -> String { + self.val.to_owned() + } +} + +impl MyTrait for Beta { + fn to_text(&self) -> String { + format!("{}, {}", self.nr, self.f) + } +} + #[derive(Hash, PartialEq, Eq, Debug)] enum MyEnum { A(Alpha), B(Beta), } +impl MyTrait for MyEnum { + fn to_text(&self) -> String { + match self { + &MyEnum::A(ref alpha) => alpha.to_text(), + &MyEnum::B(ref beta) => beta.to_text(), + } + } +} + +lazy_static! { + static ref RANDSTATE: RandomState = RandomState::new(); +} + +fn get_test_hash(x: &MyEnum) -> u64 { + let mut hasher = RANDSTATE.build_hasher(); + x.hash(&mut hasher); + hasher.finish() +} + fn main() { - let a = MyEnum::A(Alpha { val: "Hello World".to_owned() }); - let b = MyEnum::B(Beta { nr: 8, f: 2 }); + let a1: MyEnum = MyEnum::A(Alpha { val: "Hello World".to_owned() }); + let a2: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); + let a3: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); + let b: MyEnum = MyEnum::B(Beta { nr: 8, f: 2 }); let mut m = HashMap::new(); - m.insert(a, 0); + println!("{:?} {:?}", a1.to_text(), b.to_text()); + println!("{:?} {:?} {:?}", get_test_hash(&a1), get_test_hash(&a2), get_test_hash(&a3)); + m.insert(a1, 0); + m.insert(a2, 0); m.insert(b, 0); println!("{:?}", m); } diff --git a/dev/playground/src/main.rs b/dev/playground/src/main.rs index c64f240d..b2f8c8ce 100644 --- a/dev/playground/src/main.rs +++ b/dev/playground/src/main.rs @@ -1,77 +1,45 @@ - -// https://stackoverflow.com/questions/49711479/how-can-i-create-hashable-trait-objects-trait-objects-with-generic-method-para - -use std::collections::HashMap; +use std::hash::{Hash, Hasher, BuildHasher}; use std::collections::hash_map::RandomState; -use std::hash::Hasher; -use std::hash::BuildHasher; -use std::hash::Hash; - -#[macro_use] -extern crate lazy_static; -trait MyTrait { - fn to_text(&self) -> String; -} +#[derive(Hash)] +struct Foo(i32); -#[derive(Hash, PartialEq, Eq, Debug)] -struct Alpha { - val: String, -} +#[derive(Hash)] +struct Bar(String); -#[derive(Hash, PartialEq, Eq, Debug)] -struct Beta { - nr: i32, - f: u8, +trait MyTrait { + fn my_hash(&self, h: &mut Hasher); } -impl MyTrait for Alpha { - fn to_text(&self) -> String { - self.val.to_owned() +impl MyTrait for Foo { + fn my_hash(&self, mut h: &mut Hasher) { + self.hash(&mut h) } } -impl MyTrait for Beta { - fn to_text(&self) -> String { - format!("{}, {}", self.nr, self.f) +impl MyTrait for Bar { + fn my_hash(&self, mut h: &mut Hasher) { + self.hash(&mut h) } } -#[derive(Hash, PartialEq, Eq, Debug)] -enum MyEnum { - A(Alpha), - B(Beta), -} - -impl MyTrait for MyEnum { - fn to_text(&self) -> String { - match self { - &MyEnum::A(ref alpha) => alpha.to_text(), - &MyEnum::B(ref beta) => beta.to_text(), - } +impl Hash for MyTrait { + fn hash(&self, hasher: &mut H) { + self.my_hash(hasher) } } -lazy_static! { - static ref RANDSTATE: RandomState = RandomState::new(); -} - -fn get_test_hash(x: &MyEnum) -> u64 { - let mut hasher = RANDSTATE.build_hasher(); +fn get_test_hash(x: &MyTrait) -> u64 { + let randstate = RandomState::new(); + let mut hasher = randstate.build_hasher(); x.hash(&mut hasher); hasher.finish() } fn main() { - let a1: MyEnum = MyEnum::A(Alpha { val: "Hello World".to_owned() }); - let a2: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); - let a3: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); - let b: MyEnum = MyEnum::B(Beta { nr: 8, f: 2 }); - let mut m = HashMap::new(); - println!("{:?} {:?}", a1.to_text(), b.to_text()); - println!("{:?} {:?} {:?}", get_test_hash(&a1), get_test_hash(&a2), get_test_hash(&a3)); - m.insert(a1, 0); - m.insert(a2, 0); - m.insert(b, 0); - println!("{:?}", m); + let foo = Foo(42); + let bar = Bar("answer".into()); + + println!("{:?}", get_test_hash(&foo)); + println!("{:?}", get_test_hash(&bar)); } From 7b1f9cbeefe00a4eabdbd14d0d5c24ff02e9a503 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 16 Apr 2018 21:28:48 +0200 Subject: [PATCH 4/9] First derive_new struct --- Cargo.toml | 1 + src/lib.rs | 2 ++ src/mango/ast_full/node/assignment.rs | 9 ++------- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 510ce3ed..fddf3e3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ include = [ regex = "0.2.*" string-interner = "0.6.*" lazy_static = "1.0.*" +derive-new = "0.5.*" diff --git a/src/lib.rs b/src/lib.rs index b05b2184..bfbc141e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ extern crate core; extern crate lazy_static; extern crate regex; extern crate string_interner; +#[macro_use] +extern crate derive_new; pub mod mango { // Utilities diff --git a/src/mango/ast_full/node/assignment.rs b/src/mango/ast_full/node/assignment.rs index 05f59d99..3c29291e 100644 --- a/src/mango/ast_full/node/assignment.rs +++ b/src/mango/ast_full/node/assignment.rs @@ -4,18 +4,13 @@ use mango::util::encdec::ToText; /// Type for an association, e.g. assignment, parameter binding. //#[derive(Debug, Hash)] -#[derive(Debug)] +// todo: use derive(new) everywhere +#[derive(new, Debug)] pub struct AssignmentAST { assignee: Box, value: Box, } -impl AssignmentAST { - pub fn new(assignee: Box, value: Box) -> Self { - return AssignmentAST { assignee, value }; - } -} - impl ToText for AssignmentAST { fn to_text(&self) -> String { return format!( From 20fcc93007df38b5a135d97ea8b5ad6b2f6aa8d9 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 16 Apr 2018 22:53:33 +0200 Subject: [PATCH 5/9] Converting trait objects to enum variants (compiles but fails) --- src/mango/ast_full/collect/all.rs | 15 ++++ src/mango/ast_full/collect/mod.rs | 1 - src/mango/ast_full/collect/typ.rs | 70 +------------------ src/mango/ast_full/mod.rs | 1 - src/mango/ast_full/node/assignment.rs | 23 +++--- src/mango/ast_full/node/binary_operation.rs | 23 +++--- src/mango/ast_full/node/unary_operation.rs | 21 +++--- src/mango/ast_full/special/unparseable.rs | 6 +- .../org/mangolang/fullast/ASTEqualityTest.kt | 56 --------------- src/mango/ast_full/terminal/literal.rs | 9 +-- src/mango/ast_full/terminal/operator.rs | 4 +- src/mango/ast_full/terminal/variable.rs | 4 +- src/mango/ast_full/tests.rs | 29 ++++---- src/mango/token/mod.rs | 33 ++++++--- src/mango/util/mod.rs | 2 - src/mango/util/traitobj/eq.rs | 42 ----------- src/mango/util/traitobj/hash.rs | 30 -------- src/mango/util/traitobj/mod.rs | 5 -- 18 files changed, 95 insertions(+), 279 deletions(-) delete mode 100644 src/mango/ast_full/src/test/kotlin/org/mangolang/fullast/ASTEqualityTest.kt delete mode 100644 src/mango/util/traitobj/eq.rs delete mode 100644 src/mango/util/traitobj/hash.rs delete mode 100644 src/mango/util/traitobj/mod.rs diff --git a/src/mango/ast_full/collect/all.rs b/src/mango/ast_full/collect/all.rs index faa8f446..0740388c 100644 --- a/src/mango/ast_full/collect/all.rs +++ b/src/mango/ast_full/collect/all.rs @@ -5,8 +5,11 @@ use mango::ast_full::special::UnparseableAST; use mango::ast_full::terminal::LiteralAST; use mango::ast_full::terminal::OperatorAST; use mango::ast_full::terminal::VariableAST; +use mango::ast_full::AST; +use mango::util::encdec::ToText; /// Collection of all possible nodes in the full abstract syntax tree. +#[derive(PartialEq, Eq, Hash, Debug)] pub enum FullAST { Operator(OperatorAST), Literal(LiteralAST), @@ -17,3 +20,15 @@ pub enum FullAST { Unparseable(UnparseableAST), } + +impl ToText for FullAST { + // todo: any way to generate this? + fn to_text(&self) -> String { + match self { + FullAST::Operator(operator) => operator.to_text(), + _ => unimplemented!(), // TODO + } + } +} + +impl AST for FullAST {} diff --git a/src/mango/ast_full/collect/mod.rs b/src/mango/ast_full/collect/mod.rs index d43d3e61..8fdb33bd 100644 --- a/src/mango/ast_full/collect/mod.rs +++ b/src/mango/ast_full/collect/mod.rs @@ -2,5 +2,4 @@ mod all; pub use self::all::FullAST; mod typ; -pub use self::typ::BaseAST; pub use self::typ::AST; diff --git a/src/mango/ast_full/collect/typ.rs b/src/mango/ast_full/collect/typ.rs index 31e0baae..ef05b789 100644 --- a/src/mango/ast_full/collect/typ.rs +++ b/src/mango/ast_full/collect/typ.rs @@ -1,70 +1,6 @@ use mango::util::encdec::ToText; -use std::any::Any; -use std::collections::hash_map::DefaultHasher; use std::fmt::Debug; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; -/// Trait to be implemented by everything in the full abstract syntax tree. -//pub trait BaseAST: ToText + ToObjectNotation { // todo: add ON again later -pub trait BaseAST: ToText + Debug {} - -/// AST trait to be used for AST trait objects (implements Eq). -// later: When specialization feature is stable, merge BaseAST and AST: https://stackoverflow.com/questions/49466199/default-trait-method-implementation-for-all-trait-objects -pub trait AST: BaseAST { - /// Should return an &Any so that we can test equality on a casted value. - fn as_any(&self) -> &Any; - - /// Do the equality test. - fn equals(&self, other: &AST) -> bool; - - // /// Create hash, but using a Hasher trait object instead of generic function. - // fn as_hash(&self, state: &mut Hasher); -} - -/// This makes all AST nodes comparable (Eq). -// I *think* that 'static here refers to the type S (not instances). -impl AST for S { - fn as_any(&self) -> &Any { - self as &Any - } - - fn equals(&self, other: &AST) -> bool { - // Do a type-safe casting. If types are differents - // return false, else test for equality. - match other.as_any().downcast_ref::() { - None => false, - Some(a) => self == a, - } - } -} - -/// Actually implement PartialEq to delegate to .equals(...). -// From https://stackoverflow.com/a/49138717/723090 -impl<'a> PartialEq for AST + 'a { - fn eq(&self, other: &AST) -> bool { - self.equals(other) - } -} - -/// Create a trait that can be required by traits that -/// 1) can be used as objects, and -/// 2) should be hashable -pub trait HashForTraitObj { - fn my_hash(&self) -> u64; -} - -/// Implement my_hash by delegating to Hash. -// Unfortunately uses `DefaultHasher`, but found no other waIt's a by. -impl HashForTraitObj for T { - fn my_hash(&self) -> u64 { - let mut hasher = DefaultHasher::new(); - self.hash(&mut hasher); - hasher.finish() - } -} - -impl<'a> Hash for AST + 'a { - fn hash(&self, hasher: &mut H) { - hasher.write_u64(self.my_hash()) - } -} +/// AST trait to be used for AST nodes. +pub trait AST: PartialEq + Eq + Hash + Debug + ToText {} diff --git a/src/mango/ast_full/mod.rs b/src/mango/ast_full/mod.rs index 91e93808..63c89b9d 100644 --- a/src/mango/ast_full/mod.rs +++ b/src/mango/ast_full/mod.rs @@ -8,7 +8,6 @@ mod special; pub use self::special::*; mod collect; -pub use self::collect::BaseAST; pub use self::collect::FullAST; pub use self::collect::AST; diff --git a/src/mango/ast_full/node/assignment.rs b/src/mango/ast_full/node/assignment.rs index e731e7fb..1b5305e0 100644 --- a/src/mango/ast_full/node/assignment.rs +++ b/src/mango/ast_full/node/assignment.rs @@ -1,18 +1,21 @@ -use mango::ast_full::BaseAST; +use mango::ast_full::FullAST; use mango::ast_full::AST; use mango::util::encdec::ToText; /// Type for an association, e.g. assignment, parameter binding. //#[derive(Debug, Hash)] -#[derive(Debug, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct AssignmentAST { - assignee: Box, - value: Box, + assignee: Box, // todo: maybe this could be a subset instead of FullAST + value: Box, } impl AssignmentAST { - pub fn new(assignee: Box, value: Box) -> Self { - return AssignmentAST { assignee, value }; + pub fn new(assignee: FullAST, value: FullAST) -> Self { + return AssignmentAST { + assignee: Box::new(assignee), + value: Box::new(value), + }; } } @@ -26,10 +29,4 @@ impl ToText for AssignmentAST { } } -impl PartialEq for AssignmentAST { - fn eq(&self, other: &AssignmentAST) -> bool { - return &self.assignee == &other.assignee && &self.value == &other.value; - } -} - -impl BaseAST for AssignmentAST {} +impl AST for AssignmentAST {} diff --git a/src/mango/ast_full/node/binary_operation.rs b/src/mango/ast_full/node/binary_operation.rs index d169c757..781c8df7 100644 --- a/src/mango/ast_full/node/binary_operation.rs +++ b/src/mango/ast_full/node/binary_operation.rs @@ -1,22 +1,22 @@ use mango::ast_full::terminal::OperatorAST; -use mango::ast_full::BaseAST; +use mango::ast_full::FullAST; use mango::ast_full::AST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] -#[derive(Debug, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct BinaryOperationAST { - left: Box, + left: Box, operator: OperatorAST, - right: Box, + right: Box, } impl BinaryOperationAST { - pub fn new(left: Box, operator: OperatorAST, right: Box) -> Self { + pub fn new(left: FullAST, operator: OperatorAST, right: FullAST) -> Self { return BinaryOperationAST { - left, + left: Box::new(left), operator, - right, + right: Box::new(right), }; } } @@ -32,11 +32,4 @@ impl ToText for BinaryOperationAST { } } -impl PartialEq for BinaryOperationAST { - fn eq(&self, other: &BinaryOperationAST) -> bool { - return self.operator == other.operator && &self.left == &other.left - && &self.right == &other.right; - } -} - -impl BaseAST for BinaryOperationAST {} +impl AST for BinaryOperationAST {} diff --git a/src/mango/ast_full/node/unary_operation.rs b/src/mango/ast_full/node/unary_operation.rs index 947d7216..b785cd86 100644 --- a/src/mango/ast_full/node/unary_operation.rs +++ b/src/mango/ast_full/node/unary_operation.rs @@ -1,18 +1,21 @@ use mango::ast_full::terminal::OperatorAST; -use mango::ast_full::BaseAST; +use mango::ast_full::FullAST; use mango::ast_full::AST; use mango::util::encdec::ToText; //#[derive(Debug, Hash)] -#[derive(Debug, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct UnaryOperationAST { operator: OperatorAST, - subject: Box, + subject: Box, } impl UnaryOperationAST { - pub fn new(operator: OperatorAST, subject: Box) -> Self { - return UnaryOperationAST { operator, subject }; + pub fn new(operator: OperatorAST, subject: FullAST) -> Self { + return UnaryOperationAST { + operator, + subject: Box::new(subject), + }; } } @@ -26,10 +29,4 @@ impl ToText for UnaryOperationAST { } } -impl PartialEq for UnaryOperationAST { - fn eq(&self, other: &UnaryOperationAST) -> bool { - return self.operator == other.operator && &self.subject == &other.subject; - } -} - -impl BaseAST for UnaryOperationAST {} +impl AST for UnaryOperationAST {} diff --git a/src/mango/ast_full/special/unparseable.rs b/src/mango/ast_full/special/unparseable.rs index ad5ef1db..b5ea9c0f 100644 --- a/src/mango/ast_full/special/unparseable.rs +++ b/src/mango/ast_full/special/unparseable.rs @@ -1,9 +1,9 @@ -use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::token::Token; use mango::util::encdec::ToText; /// Represents an unparseable list of tokens. -#[derive(Debug, PartialEq, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct UnparseableAST { tokens: Vec>, } @@ -27,4 +27,4 @@ impl ToText for UnparseableAST { } } -impl BaseAST for UnparseableAST {} +impl AST for UnparseableAST {} diff --git a/src/mango/ast_full/src/test/kotlin/org/mangolang/fullast/ASTEqualityTest.kt b/src/mango/ast_full/src/test/kotlin/org/mangolang/fullast/ASTEqualityTest.kt deleted file mode 100644 index 8424afb0..00000000 --- a/src/mango/ast_full/src/test/kotlin/org/mangolang/fullast/ASTEqualityTest.kt +++ /dev/null @@ -1,56 +0,0 @@ - -/* Mango compiler (mangolang.org) | Apache 2.0 license, © 2018. */ - -package org.mangolang.fullast - -import org.mangolang.token.IntegerToken -import org.mangolang.token.OperatorToken -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals - -/** - * Test that equals() and hashCode() work for AST nodes. - * - * Note that they should not depend on the [Token], just the actual data. - */ -class ASTEqualityTest { - @Test - fun testASTEquality() { - val twin_one = ConcreteBinaryOperation( - IntegerAST(IntegerToken(7)), - ConcreteBinaryOperator(OperatorToken("*")), - NegateOperationAST(IntegerAST(IntegerToken(3))) - ) - val twin_two = ConcreteBinaryOperation( - IntegerAST(IntegerToken(7)), - ConcreteBinaryOperator(OperatorToken("*")), - NegateOperationAST(IntegerAST(IntegerToken(3))) - ) - assertEquals(twin_one, twin_two) - assertEquals(twin_one.hashCode(), twin_two.hashCode()) - } - - @Test - fun testASTInequality() { - assertNotEquals(IntegerAST(IntegerToken(7)), NegateOperationAST(IntegerAST(IntegerToken(7)))) - assertNotEquals(IntegerAST(IntegerToken(7)), IntegerAST(IntegerToken(8))) - assertNotEquals(NegateOperationAST(IntegerAST(IntegerToken(7))), NegateOperationAST(IntegerAST(IntegerToken(8)))) - assertNotEquals(ConcreteBinaryOperator(OperatorToken("*")), ConcreteBinaryOperator(OperatorToken("/"))) - assertNotEquals( - ConcreteBinaryOperation(IntegerAST(IntegerToken(+7)), ConcreteBinaryOperator(OperatorToken("*")), IntegerAST(IntegerToken(3))), - ConcreteBinaryOperation(IntegerAST(IntegerToken(-7)), ConcreteBinaryOperator(OperatorToken("*")), IntegerAST(IntegerToken(3))) - ) - } - - @Test - fun testUnpareableEquality() { - var up: UnparseableAST - up = UnparseableAST(null) - assertEquals(up, up) - up = UnparseableAST(IntegerToken(7)) - assertEquals(up, up) - assertNotEquals(UnparseableAST(null), UnparseableAST(null)) - assertNotEquals(UnparseableAST(IntegerToken(7)), UnparseableAST(IntegerToken(7))) - } -} diff --git a/src/mango/ast_full/terminal/literal.rs b/src/mango/ast_full/terminal/literal.rs index 4f381ba7..cdefdbc2 100644 --- a/src/mango/ast_full/terminal/literal.rs +++ b/src/mango/ast_full/terminal/literal.rs @@ -1,9 +1,10 @@ -use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; use mango::util::format::to_double_quoted_str; use mango::util::numtype::f64eq; /// Closed collection of literal values +#[derive(Debug, PartialEq, Eq, Hash)] pub enum LiteralAST { Int(IntLiteralAST), Float(FloatLiteralAST), @@ -69,6 +70,6 @@ impl ToText for StringLiteralAST { // TODO: I need to make sure than NaN == NaN to do this legitimately impl Eq for FloatLiteralAST {} -impl BaseAST for IntLiteralAST {} -impl BaseAST for FloatLiteralAST {} -impl BaseAST for StringLiteralAST {} +impl AST for IntLiteralAST {} +impl AST for FloatLiteralAST {} +impl AST for StringLiteralAST {} diff --git a/src/mango/ast_full/terminal/operator.rs b/src/mango/ast_full/terminal/operator.rs index 36c1789a..c50ff366 100644 --- a/src/mango/ast_full/terminal/operator.rs +++ b/src/mango/ast_full/terminal/operator.rs @@ -1,4 +1,4 @@ -use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; use mango::util::strtype::Msg; use mango::util::strtype::StrType; @@ -75,7 +75,7 @@ impl ToText for OperatorAST { } } -impl BaseAST for OperatorAST {} +impl AST for OperatorAST {} //impl ToObjectNotation for OperatorAST { // #[allow(non_snake_case)] diff --git a/src/mango/ast_full/terminal/variable.rs b/src/mango/ast_full/terminal/variable.rs index 0da1f39d..7e7898a3 100644 --- a/src/mango/ast_full/terminal/variable.rs +++ b/src/mango/ast_full/terminal/variable.rs @@ -1,4 +1,4 @@ -use mango::ast_full::BaseAST; +use mango::ast_full::AST; use mango::util::encdec::ToText; use mango::util::strtype::Name; @@ -20,4 +20,4 @@ impl ToText for VariableAST { } } -impl BaseAST for VariableAST {} +impl AST for VariableAST {} diff --git a/src/mango/ast_full/tests.rs b/src/mango/ast_full/tests.rs index 7be8377c..6dd78455 100644 --- a/src/mango/ast_full/tests.rs +++ b/src/mango/ast_full/tests.rs @@ -2,25 +2,27 @@ use mango::ast_full::node::BinaryOperationAST; use mango::ast_full::node::UnaryOperationAST; use mango::ast_full::special::UnparseableAST; use mango::ast_full::terminal::IntLiteralAST; +use mango::ast_full::terminal::LiteralAST; use mango::ast_full::terminal::OperatorAST; use mango::ast_full::terminal::Symbol; +use mango::ast_full::FullAST; #[test] fn test_ast_equality() { let twin_one = BinaryOperationAST::new( - Box::new(IntLiteralAST::new(7)), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(7))), OperatorAST::from_symbol(Symbol::Plus), - Box::new(UnaryOperationAST::new( + FullAST::UnaryOperation(UnaryOperationAST::new( OperatorAST::from_symbol(Symbol::Plus), - Box::new(IntLiteralAST::new(3)), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(7))), )), ); let twin_two = BinaryOperationAST::new( - Box::new(IntLiteralAST::new(7)), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(7))), OperatorAST::from_symbol(Symbol::Plus), - Box::new(UnaryOperationAST::new( + FullAST::UnaryOperation(UnaryOperationAST::new( OperatorAST::from_symbol(Symbol::Plus), - Box::new(IntLiteralAST::new(3)), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(7))), )), ); assert_eq!(twin_one, twin_two); @@ -30,13 +32,14 @@ fn test_ast_equality() { #[test] fn test_ast_inequality() { - // assert_ne!(IntLiteralAST(IntegerToken(7)), UnaryOperationAST(IntLiteralAST(IntegerToken(7)))) - // assert_ne!(IntLiteralAST(IntegerToken(7)), IntLiteralAST(IntegerToken(8))) - // assert_ne!(UnaryOperationAST(IntLiteralAST(IntegerToken(7))), UnaryOperationAST(IntLiteralAST(IntegerToken(8)))) - // assert_ne!(ConcreteBinaryOperator(OperatorAST("*")), ConcreteBinaryOperator(OperatorAST("/"))) - // assert_ne!(BinaryOperationAST(IntLiteralAST(IntegerToken( + 7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))), - // BinaryOperationAST(IntLiteralAST(IntegerToken(-7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))) - // ) + assert_eq!(1, 2); // TODO + // assert_ne!(IntLiteralAST(IntegerToken(7)), UnaryOperationAST(IntLiteralAST(IntegerToken(7)))) + // assert_ne!(IntLiteralAST(IntegerToken(7)), IntLiteralAST(IntegerToken(8))) + // assert_ne!(UnaryOperationAST(IntLiteralAST(IntegerToken(7))), UnaryOperationAST(IntLiteralAST(IntegerToken(8)))) + // assert_ne!(ConcreteBinaryOperator(OperatorAST("*")), ConcreteBinaryOperator(OperatorAST("/"))) + // assert_ne!(BinaryOperationAST(IntLiteralAST(IntegerToken( + 7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))), + // BinaryOperationAST(IntLiteralAST(IntegerToken(-7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))) + // ) } #[test] diff --git a/src/mango/token/mod.rs b/src/mango/token/mod.rs index 983e6207..40178a63 100644 --- a/src/mango/token/mod.rs +++ b/src/mango/token/mod.rs @@ -1,7 +1,6 @@ use mango::util::encdec::ToText; use std::fmt::Debug; use std::hash::Hash; -use std::hash::Hasher; // //pub mod tokens; @@ -10,18 +9,30 @@ use std::hash::Hasher; // //pub mod mock; // -pub trait Token: ToText + Debug {} -impl<'a> PartialEq for Token + 'a { - #[allow(unused_variables)] - fn eq(&self, other: &Token) -> bool { - true // TODO: similar to BaseAST? - } +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum Token { + } -impl<'a> Hash for Token + 'a { - #[allow(unused_variables)] - fn hash(&self, state: &mut H) { - // TODO: similar to BaseAST? +impl ToText for Token { + fn to_text(&self) -> String { + unimplemented!() // todo } } + +pub trait IsToken: PartialEq + Eq + Hash + Debug + ToText {} + +//impl<'a> PartialEq for Token + 'a { +// #[allow(unused_variables)] +// fn eq(&self, other: &Token) -> bool { +// true // TODO: similar to BaseAST? +// } +//} +// +//impl<'a> Hash for Token + 'a { +// #[allow(unused_variables)] +// fn hash(&self, state: &mut H) { +// // TODO: similar to BaseAST? +// } +//} diff --git a/src/mango/util/mod.rs b/src/mango/util/mod.rs index 5cea6ad8..279f8f9a 100644 --- a/src/mango/util/mod.rs +++ b/src/mango/util/mod.rs @@ -7,5 +7,3 @@ pub mod format; pub mod encdec; pub mod errors; - -pub mod traitobj; diff --git a/src/mango/util/traitobj/eq.rs b/src/mango/util/traitobj/eq.rs deleted file mode 100644 index 30ecbf95..00000000 --- a/src/mango/util/traitobj/eq.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::any::Any; - -// The problem with partialeq trait objects is that `PartialEq` needs -// the concrete type of the struct to be able to delegate equality. -// See https://stackoverflow.com/questions/49466199/ - -// TODO: This wasn't easy to make general after all, so implement for each trait that needs it (like &AST) - -/// Create a trait that can be required by traits that -/// 1) can be used as objects, and -/// 2) should be comparable to the trait object -//pub trait PartialEqForTraitObj { -// /// Should return an &Any so that we can test equality on a casted value. -// fn as_any(&self) -> &Any; -// -// /// Do the equality test. -// fn equals(&self, other: &U) -> bool; -//} -// -//// todo: this implements for too many types I think... I only want &A == &A if A and B implement PartialEqForTraitObj -// -///// Implement PartialEq by downcasting and comparing if types are equal. -//impl PartialEqForTraitObj for T { -// fn as_any(&self) -> &Any { -// self as &Any -// } -// -// fn equals(&self, other: &U) -> bool { -// // Do a type-safe casting. If types are different return false, else test for equality. -// match other.as_any().downcast_ref::() { -// None => false, -// Some(a) => self == a, -// } -// } -//} - -// For the trait that should be hashable, do this: -//impl PartialEq for MyTrait { -// fn eq(&self, other: &MyTrait) -> bool { -// self.equals(other) -// } -//} \ No newline at end of file diff --git a/src/mango/util/traitobj/hash.rs b/src/mango/util/traitobj/hash.rs deleted file mode 100644 index 74074c4a..00000000 --- a/src/mango/util/traitobj/hash.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; - -// The problem with hashable trait objects is that `Hash.hash` is generic, -// so it cannot be made into an object. -// See https://stackoverflow.com/questions/49711479/ - -/// Create a trait that can be required by traits that -/// 1) can be used as objects, and -/// 2) should be hashable -pub trait HashForTraitObj { - fn my_hash(&self) -> u64; -} - -/// Implement my_hash by delegating to Hash. -// Unfortunately uses `DefaultHasher`, but found no other waIt's a by. -impl HashForTraitObj for T { - fn my_hash(&self) -> u64 { - let mut hasher = DefaultHasher::new(); - self.hash(&mut hasher); - hasher.finish() - } -} - -// For the trait that should be hashable, do this: -//impl Hash for MyTrait { -// fn hash(&self, hasher: &mut H) { -// hasher.write_u64(self.my_hash()) -// } -//} diff --git a/src/mango/util/traitobj/mod.rs b/src/mango/util/traitobj/mod.rs deleted file mode 100644 index 8d917ed1..00000000 --- a/src/mango/util/traitobj/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod hash; -pub use self::hash::HashForTraitObj; - -//pub mod eq; -//pub use self::eq::PartialEqForTraitObj; From 372c6d501d72d5459cbe2b547ab824e05ca02c11 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 17 Apr 2018 22:20:01 +0200 Subject: [PATCH 6/9] Fixing some full AST tests, secretly on wrong brnach --- dev/playground/src/enumhash.rs | 10 +++++++ src/mango/ast_full/collect/all.rs | 2 +- src/mango/ast_full/tests.rs | 46 ++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/dev/playground/src/enumhash.rs b/dev/playground/src/enumhash.rs index c64f240d..65b56c10 100644 --- a/dev/playground/src/enumhash.rs +++ b/dev/playground/src/enumhash.rs @@ -27,7 +27,11 @@ struct Beta { impl MyTrait for Alpha { fn to_text(&self) -> String { +<<<<<<< Updated upstream self.val.to_owned() +======= + self.val.clone() +>>>>>>> Stashed changes } } @@ -63,9 +67,15 @@ fn get_test_hash(x: &MyEnum) -> u64 { } fn main() { +<<<<<<< Updated upstream let a1: MyEnum = MyEnum::A(Alpha { val: "Hello World".to_owned() }); let a2: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); let a3: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_owned() }); +======= + let a1: MyEnum = MyEnum::A(Alpha { val: "Hello World".to_string() }); + let a2: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_string() }); + let a3: MyEnum = MyEnum::A(Alpha { val: "Bye World".to_string() }); +>>>>>>> Stashed changes let b: MyEnum = MyEnum::B(Beta { nr: 8, f: 2 }); let mut m = HashMap::new(); println!("{:?} {:?}", a1.to_text(), b.to_text()); diff --git a/src/mango/ast_full/collect/all.rs b/src/mango/ast_full/collect/all.rs index 0740388c..c2ea94d4 100644 --- a/src/mango/ast_full/collect/all.rs +++ b/src/mango/ast_full/collect/all.rs @@ -15,8 +15,8 @@ pub enum FullAST { Literal(LiteralAST), UnaryOperation(UnaryOperationAST), BinaryOperation(BinaryOperationAST), - Assignment(AssignmentAST), Variable(VariableAST), + Assignment(AssignmentAST), Unparseable(UnparseableAST), } diff --git a/src/mango/ast_full/tests.rs b/src/mango/ast_full/tests.rs index 6dd78455..85a976d4 100644 --- a/src/mango/ast_full/tests.rs +++ b/src/mango/ast_full/tests.rs @@ -6,9 +6,15 @@ use mango::ast_full::terminal::LiteralAST; use mango::ast_full::terminal::OperatorAST; use mango::ast_full::terminal::Symbol; use mango::ast_full::FullAST; +use mango::ast_full::terminal::FloatLiteralAST; +use mango::ast_full::terminal::StringLiteralAST; +use mango::ast_full::terminal::VariableAST; +use mango::util::strtype::Name; +use mango::ast_full::node::AssignmentAST; +use mango::util::strtype::StrType; #[test] -fn test_ast_equality() { +fn test_nested_ast_eq() { let twin_one = BinaryOperationAST::new( FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(7))), OperatorAST::from_symbol(Symbol::Plus), @@ -31,15 +37,34 @@ fn test_ast_equality() { } #[test] -fn test_ast_inequality() { - assert_eq!(1, 2); // TODO - // assert_ne!(IntLiteralAST(IntegerToken(7)), UnaryOperationAST(IntLiteralAST(IntegerToken(7)))) - // assert_ne!(IntLiteralAST(IntegerToken(7)), IntLiteralAST(IntegerToken(8))) - // assert_ne!(UnaryOperationAST(IntLiteralAST(IntegerToken(7))), UnaryOperationAST(IntLiteralAST(IntegerToken(8)))) - // assert_ne!(ConcreteBinaryOperator(OperatorAST("*")), ConcreteBinaryOperator(OperatorAST("/"))) - // assert_ne!(BinaryOperationAST(IntLiteralAST(IntegerToken( + 7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))), - // BinaryOperationAST(IntLiteralAST(IntegerToken(-7)), ConcreteBinaryOperator(OperatorAST("*")), IntLiteralAST(IntegerToken(3))) - // ) +fn test_simple_ast_eq_ne() { + let nodes = vec![ + FullAST::Operator(OperatorAST::from_symbol(Symbol::Plus)), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))), + FullAST::Literal(LiteralAST::Float(FloatLiteralAST::new(1.))), + FullAST::Literal(LiteralAST::String(StringLiteralAST::new("1".to_string()))), + FullAST::UnaryOperation(UnaryOperationAST::new( + OperatorAST::from_symbol(Symbol::Dash), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))))), + FullAST::BinaryOperation(BinaryOperationAST::new( + FullAST::Literal(LiteralAST::Float(FloatLiteralAST::new(1.))), + OperatorAST::from_symbol(Symbol::Plus), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))))), + FullAST::Variable(VariableAST::new(Name::from_valid("my_var"))), + FullAST::Assignment(AssignmentAST::new( + FullAST::Variable(VariableAST::new(Name::from_valid("my_var"))), + FullAST::Literal(LiteralAST::String(StringLiteralAST::new("1".to_string()))), + )), + ]; + for (i, left) in nodes.iter().enumerate() { + for (j, right) in nodes.iter().enumerate() { + if i == j { + assert_eq!(left, right); + } else { + assert_ne!(left, right); + } + } + } } #[test] @@ -47,6 +72,7 @@ fn test_unparseable_equality() { let unp: UnparseableAST; unp = UnparseableAST::from_tokens(vec![]); assert_eq!(unp, unp); + // todo // let unp = UnparseableAST::from_tokens(vec![IntegerToken()]); // assert_eq!(up, up) // assert_ne!(UnparseableAST(null), UnparseableAST(null)) From 0646cf68ce779d9aa655f879747a2118a9ee3d98 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 16 Apr 2018 21:43:41 +0200 Subject: [PATCH 7/9] Formatting fix --- src/mango/ast_full/tests.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mango/ast_full/tests.rs b/src/mango/ast_full/tests.rs index 85a976d4..f86a5279 100644 --- a/src/mango/ast_full/tests.rs +++ b/src/mango/ast_full/tests.rs @@ -1,16 +1,16 @@ +use mango::ast_full::node::AssignmentAST; use mango::ast_full::node::BinaryOperationAST; use mango::ast_full::node::UnaryOperationAST; use mango::ast_full::special::UnparseableAST; +use mango::ast_full::terminal::FloatLiteralAST; use mango::ast_full::terminal::IntLiteralAST; use mango::ast_full::terminal::LiteralAST; use mango::ast_full::terminal::OperatorAST; -use mango::ast_full::terminal::Symbol; -use mango::ast_full::FullAST; -use mango::ast_full::terminal::FloatLiteralAST; use mango::ast_full::terminal::StringLiteralAST; +use mango::ast_full::terminal::Symbol; use mango::ast_full::terminal::VariableAST; +use mango::ast_full::FullAST; use mango::util::strtype::Name; -use mango::ast_full::node::AssignmentAST; use mango::util::strtype::StrType; #[test] @@ -45,11 +45,13 @@ fn test_simple_ast_eq_ne() { FullAST::Literal(LiteralAST::String(StringLiteralAST::new("1".to_string()))), FullAST::UnaryOperation(UnaryOperationAST::new( OperatorAST::from_symbol(Symbol::Dash), - FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))))), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))), + )), FullAST::BinaryOperation(BinaryOperationAST::new( FullAST::Literal(LiteralAST::Float(FloatLiteralAST::new(1.))), OperatorAST::from_symbol(Symbol::Plus), - FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))))), + FullAST::Literal(LiteralAST::Int(IntLiteralAST::new(1))), + )), FullAST::Variable(VariableAST::new(Name::from_valid("my_var"))), FullAST::Assignment(AssignmentAST::new( FullAST::Variable(VariableAST::new(Name::from_valid("my_var"))), From 59c8fa118fb2516ab66c4a97e9bb8f1cec62c96c Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 16 Apr 2018 21:53:03 +0200 Subject: [PATCH 8/9] Disable format checks (tmp) because travis does not match local --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7666a83..62061d2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,6 @@ before_script: sudo: false cache: cargo script: - - cargo fmt --verbose --all -- --write-mode=diff + - # cargo fmt --verbose --all -- --write-mode=diff - cargo build --verbose --all - cargo test --verbose --all From 1ca830540c58e7ffe7fe870c7427a9cb590c3015 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 17 Apr 2018 07:09:31 +0200 Subject: [PATCH 9/9] Converted applicable cases to derive_new (fewer than expected) --- src/mango/ast_full/node/assignment.rs | 14 +++++++++++--- src/mango/ast_full/node/binary_operation.rs | 2 +- src/mango/ast_full/node/unary_operation.rs | 1 + src/mango/ast_full/terminal/literal.rs | 16 ++-------------- src/mango/ast_full/terminal/variable.rs | 8 +------- src/mango/util/errors/code_problem.rs | 20 +++----------------- src/mango/util/errors/collector.rs | 7 ++----- src/mango/util/numtype/eqfloat.rs | 8 +------- 8 files changed, 22 insertions(+), 54 deletions(-) diff --git a/src/mango/ast_full/node/assignment.rs b/src/mango/ast_full/node/assignment.rs index 96b2d800..558d6d3a 100644 --- a/src/mango/ast_full/node/assignment.rs +++ b/src/mango/ast_full/node/assignment.rs @@ -3,14 +3,22 @@ use mango::ast_full::AST; use mango::util::encdec::ToText; /// Type for an association, e.g. assignment, parameter binding. -//#[derive(Debug, Hash)] -// todo: use derive(new) everywhere -#[derive(new, Debug, PartialEq, Eq, Hash)] +#[derive(Debug, PartialEq, Eq, Hash)] pub struct AssignmentAST { assignee: Box, // todo: maybe this could be a subset instead of FullAST value: Box, } +impl AssignmentAST { + // No derive(new) because of boxing + pub fn new(assignee: FullAST, value: FullAST) -> Self { + return AssignmentAST { + assignee: Box::new(assignee), + value: Box::new(value), + }; + } +} + impl ToText for AssignmentAST { fn to_text(&self) -> String { return format!( diff --git a/src/mango/ast_full/node/binary_operation.rs b/src/mango/ast_full/node/binary_operation.rs index 781c8df7..c3d574e6 100644 --- a/src/mango/ast_full/node/binary_operation.rs +++ b/src/mango/ast_full/node/binary_operation.rs @@ -3,7 +3,6 @@ use mango::ast_full::FullAST; use mango::ast_full::AST; use mango::util::encdec::ToText; -//#[derive(Debug, Hash)] #[derive(Debug, PartialEq, Eq, Hash)] pub struct BinaryOperationAST { left: Box, @@ -12,6 +11,7 @@ pub struct BinaryOperationAST { } impl BinaryOperationAST { + // No derive(new) because of boxing pub fn new(left: FullAST, operator: OperatorAST, right: FullAST) -> Self { return BinaryOperationAST { left: Box::new(left), diff --git a/src/mango/ast_full/node/unary_operation.rs b/src/mango/ast_full/node/unary_operation.rs index b785cd86..751105a3 100644 --- a/src/mango/ast_full/node/unary_operation.rs +++ b/src/mango/ast_full/node/unary_operation.rs @@ -11,6 +11,7 @@ pub struct UnaryOperationAST { } impl UnaryOperationAST { + // No derive(new) because of boxing pub fn new(operator: OperatorAST, subject: FullAST) -> Self { return UnaryOperationAST { operator, diff --git a/src/mango/ast_full/terminal/literal.rs b/src/mango/ast_full/terminal/literal.rs index cdefdbc2..b585461d 100644 --- a/src/mango/ast_full/terminal/literal.rs +++ b/src/mango/ast_full/terminal/literal.rs @@ -12,7 +12,7 @@ pub enum LiteralAST { } /// A literal integer value. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(new, Debug, PartialEq, Eq, Hash)] pub struct IntLiteralAST { value: i64, } @@ -24,17 +24,11 @@ pub struct FloatLiteralAST { } /// A literal text value. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(new, Debug, PartialEq, Eq, Hash)] pub struct StringLiteralAST { value: String, } -impl IntLiteralAST { - pub fn new(value: i64) -> Self { - IntLiteralAST { value } - } -} - impl FloatLiteralAST { pub fn new(value: f64) -> Self { FloatLiteralAST { @@ -43,12 +37,6 @@ impl FloatLiteralAST { } } -impl StringLiteralAST { - pub fn new(value: String) -> Self { - StringLiteralAST { value } - } -} - impl ToText for IntLiteralAST { fn to_text(&self) -> String { format!(" {:} ", self.value) diff --git a/src/mango/ast_full/terminal/variable.rs b/src/mango/ast_full/terminal/variable.rs index 7e7898a3..a49329fb 100644 --- a/src/mango/ast_full/terminal/variable.rs +++ b/src/mango/ast_full/terminal/variable.rs @@ -3,17 +3,11 @@ use mango::util::encdec::ToText; use mango::util::strtype::Name; /// A literal integer value. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(new, Debug, PartialEq, Eq, Hash)] pub struct VariableAST { name: Name, } -impl VariableAST { - pub fn new(name: Name) -> Self { - VariableAST { name } - } -} - impl ToText for VariableAST { fn to_text(&self) -> String { format!("{:}", self.name) diff --git a/src/mango/util/errors/code_problem.rs b/src/mango/util/errors/code_problem.rs index 0e539037..6919824a 100644 --- a/src/mango/util/errors/code_problem.rs +++ b/src/mango/util/errors/code_problem.rs @@ -10,35 +10,21 @@ pub enum Severity { Debug, } -#[derive(Debug, Eq, PartialEq)] +#[derive(new, Debug, Eq, PartialEq)] pub struct Context { code: String, // todo: change this type when there is a specific one } -impl Context { - pub fn new(code: String) -> Context { - Context { code: code } - } -} - -#[derive(Debug, Eq, PartialEq)] +#[derive(new, Debug, Eq, PartialEq)] pub struct CodeProblem { severity: Severity, description: Msg, context: Context, + #[new(value = "vec![]")] hints: Vec, } impl CodeProblem { - pub fn new(severity: Severity, description: Msg, context: Context) -> Self { - CodeProblem { - severity: severity, - description: description, - context: context, - hints: vec![], - } - } - pub fn error(description: Msg, context: Context) -> CodeProblem { Self::new(Severity::Error, description, context) } diff --git a/src/mango/util/errors/collector.rs b/src/mango/util/errors/collector.rs index fef36f55..619ed139 100644 --- a/src/mango/util/errors/collector.rs +++ b/src/mango/util/errors/collector.rs @@ -3,17 +3,14 @@ use mango::util::errors::Context; use mango::util::strtype::Msg; use std::slice; -#[derive(Debug)] +#[derive(new, Debug)] pub struct ProblemCollector { // Note that Vec is already heap-allocated, no need for box. + #[new(value = "vec![]")] problems: Vec, } impl ProblemCollector { - pub fn new() -> Self { - ProblemCollector { problems: vec![] } - } - pub fn error(&mut self, description: Msg, context: Context) -> &mut CodeProblem { let problem = CodeProblem::error(description, context); self.problems.push(problem); diff --git a/src/mango/util/numtype/eqfloat.rs b/src/mango/util/numtype/eqfloat.rs index bb668950..df09318d 100644 --- a/src/mango/util/numtype/eqfloat.rs +++ b/src/mango/util/numtype/eqfloat.rs @@ -7,16 +7,10 @@ use std::hash::Hasher; /// by defining that NAN == NAN. It intentionally can't /// be used for arithmetic, as rounding errors would be bad /// for e.g. HashMap keys. -#[derive(Debug, Clone, Copy)] +#[derive(new, Debug, Clone, Copy)] #[allow(non_camel_case_types)] pub struct f64eq(f64); -impl f64eq { - pub fn new(val: f64) -> Self { - f64eq(val) - } -} - impl fmt::Display for f64eq { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0)