Skip to content

Ergotree proc-macro #634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --verbose --release --tests
args: --verbose --tests
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --verbose --release
args: --verbose

test_coverage:
name: Code coverage in tests
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"ergoscript-compiler",
"ergotree-ir",
"ergotree-interpreter",
"ergotree-macro",
"ergo-lib",
"ergo-p2p",
"ergo-chain-generation",
Expand Down
1 change: 1 addition & 0 deletions ergotree-interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ ergotree-ir = { version = "^0.20.0", path = "../ergotree-ir", features = ["arbit
ergoscript-compiler = { version = "^0.16.0", path = "../ergoscript-compiler" }
proptest = "1.0.0"
sigma-test-util = { version = "^0.3.0", path = "../sigma-test-util" }
ergotree-macro = { version = "0.20", path = "../ergotree-macro"}

4 changes: 4 additions & 0 deletions ergotree-ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ strum_macros = "0.21"
indexmap = "1.3.2"
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", features = ["arbitrary_precision"], optional = true }
syn = { version = "1", features = ["parsing"], optional = true }
quote = { version = "1", optional = true }
proc-macro2 = { version = "1", optional = true }

[dependencies.proptest]
# wasm support, via https://altsysrq.github.io/proptest-book/proptest/wasm.html
Expand All @@ -59,6 +62,7 @@ optional = true
default = ["json"]
arbitrary = ["proptest", "proptest-derive", "ergo-chain-types/arbitrary"]
json = ["serde", "serde_json", "serde_with", "bounded-vec/serde"]
ergotree-proc-macro = ["syn", "quote", "proc-macro2"]

[dev-dependencies]
sigma-test-util = { version = "^0.3.0", path = "../sigma-test-util" }
Expand Down
264 changes: 264 additions & 0 deletions ergotree-ir/src/ergotree_proc_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
//! Utility code to support `ergo_tree!` procedural-macro

use syn::{ext::IdentExt, Ident};

use crate::types::stype::SType;

/// A representation of the type T extracted from `_.typed[T]` on scala side.
#[derive(Debug)]
pub enum ExtractedType {
/// Fully specified `SType`
FullySpecified(SType),
/// `SCollection[_]]` in scala representation.
SCollection(Box<ExtractedType>),
/// `SOption[_]]` in scala representation.
SOption(Box<ExtractedType>),
/// `STuple` in scala representation
STuple,
}

impl From<SType> for ExtractedType {
fn from(s: SType) -> Self {
ExtractedType::FullySpecified(s)
}
}

/// Extracts T within `_.typed[T]`.
/// Note that scala uses some type aliases: e.g. `BoolValue` is short for `Value[SBoolean.type]`
pub fn extract_tpe_from_dot_typed(
buf: syn::parse::ParseStream,
) -> Result<ExtractedType, syn::Error> {
let ident: syn::Ident = buf.parse()?;
match &*ident.to_string() {
"BoolValue" => Ok(SType::SBoolean.into()),
"IntValue" => Ok(SType::SInt.into()),
"ShortValue" => Ok(SType::SShort.into()),
"LongValue" => Ok(SType::SLong.into()),
"BigIntValue" => Ok(SType::SBigInt.into()),
"ByteValue" => Ok(SType::SByte.into()),
"SigmaPropValue" => Ok(SType::SSigmaProp.into()),
"STuple" => Ok(ExtractedType::STuple),
"SByte" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SByte))
}
"SGroupElement" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SGroupElement))
}
"SInt" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SInt))
}
"SLong" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SLong))
}
"SBigInt" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBigInt))
}
"SBoolean" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBoolean))
}
"SAvlTree" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SAvlTree))
}
"SBox" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBox))
}
"SSigmaProp" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SSigmaProp))
}
"SHeader" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SHeader))
}
"SOption" => {
let content_nested;
let _bracketed = syn::bracketed!(content_nested in buf);
Ok(ExtractedType::SOption(Box::new(
extract_tpe_from_dot_typed(&content_nested)?,
)))
}
"SCollection" => {
let content_nested;
let _bracketed = syn::bracketed!(content_nested in buf);

//let _ident: syn::Ident = content_nested.parse()?;
//handle_dot_type(&content_nested)?;
Ok(ExtractedType::SCollection(Box::new(
extract_tpe_from_dot_typed(&content_nested)?,
)))
}
"Value" => {
let content;
let _bracketed = syn::bracketed!(content in buf);
let next_ident: syn::Ident = content.parse()?;
match &*next_ident.to_string() {
"STuple" => Ok(ExtractedType::STuple),
"SByte" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SByte))
}
"SGroupElement" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SGroupElement))
}
"SInt" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SInt))
}
"SLong" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SLong))
}
"SBigInt" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBigInt))
}
"SBoolean" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBoolean))
}
"SAvlTree" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SAvlTree))
}
"SBox" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SBox))
}
"SSigmaProp" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SSigmaProp))
}
"SHeader" => {
handle_dot_type(buf)?;
Ok(ExtractedType::FullySpecified(SType::SHeader))
}
"SOption" => {
let content_nested;
let _bracketed = syn::bracketed!(content_nested in content);
Ok(ExtractedType::SOption(Box::new(
extract_tpe_from_dot_typed(&content_nested)?,
)))
}
"SCollection" => {
let content_nested;
let _bracketed = syn::bracketed!(content_nested in content);

Ok(ExtractedType::SCollection(Box::new(
extract_tpe_from_dot_typed(&content_nested)?,
)))
}
t => {
unreachable!("unknown ident T in _.typed[Value[T]]: T = {}", t)
}
}
}
t => unreachable!("unknown ident T in _.typed[T]: T = {}", t),
}
}

//pub fn extract_tpe_from_dot_typed(
// buf: syn::parse::ParseStream,
//) -> Result<ExtractedType, syn::Error> {
// let ident: syn::Ident = buf.parse()?;
// match &*ident.to_string() {
// "BoolValue" => Ok(SType::SBoolean.into()),
// "IntValue" => Ok(SType::SInt.into()),
// "ShortValue" => Ok(SType::SShort.into()),
// "LongValue" => Ok(SType::SLong.into()),
// "BigIntValue" => Ok(SType::SBigInt.into()),
// "ByteValue" => Ok(SType::SByte.into()),
// "SigmaPropValue" => Ok(SType::SSigmaProp.into()),
// "SByte" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SByte))
// }
// "Value" => {
// let content;
// let _bracketed = syn::bracketed!(content in buf);
// let next_ident: syn::Ident = content.parse()?;
// match &*next_ident.to_string() {
// "STuple" => Ok(ExtractedType::STuple),
// "SByte" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SByte))
// }
// "SGroupElement" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SGroupElement))
// }
// "SInt" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SInt))
// }
// "SLong" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SLong))
// }
// "SBigInt" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SBigInt))
// }
// "SBoolean" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SBoolean))
// }
// "SAvlTree" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SAvlTree))
// }
// "SBox" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SBox))
// }
// "SSigmaProp" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SSigmaProp))
// }
// "SHeader" => {
// handle_dot_type(buf)?;
// Ok(ExtractedType::FullySpecified(SType::SHeader))
// }
// "SOption" => {
// let content_nested;
// let _bracketed = syn::bracketed!(content_nested in content);
// Ok(ExtractedType::SOption(Box::new(
// extract_tpe_from_dot_typed(&content_nested)?,
// )))
// }
// "SCollection" => {
// let content_nested;
// let _bracketed = syn::bracketed!(content_nested in content);
//
// //let _ident: syn::Ident = content_nested.parse()?;
// //handle_dot_type(&content_nested)?;
// Ok(ExtractedType::SCollection(Box::new(
// extract_tpe_from_dot_typed(&content_nested)?,
// )))
// }
// t => {
// unreachable!("unknown ident T in _.typed[Value[T]]: T = {}", t)
// }
// }
// }
// t => unreachable!("unknown ident T in _.typed[T]: T = {}", t),
// }
//}

/// Parses `.type` from the buffered token stream
pub fn handle_dot_type(buf: syn::parse::ParseStream) -> Result<(), syn::Error> {
let _dot: syn::Token![.] = buf.parse()?;
let ident: syn::Ident = buf.call(Ident::parse_any)?; //buf.parse()?;
if ident != "type" {
return Err(syn::Error::new_spanned(ident, ""));
}
Ok(())
}
5 changes: 4 additions & 1 deletion ergotree-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::todo)]
//#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::panic)]

Expand All @@ -30,3 +30,6 @@ pub mod sigma_protocol;
pub mod type_check;
pub mod types;
pub mod util;

#[cfg(feature = "ergotree-proc-macro")]
pub mod ergotree_proc_macro;
Loading