enable imports with arena
This commit is contained in:
parent
cdf394c7e1
commit
9144bc2574
10 changed files with 250 additions and 241 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -1283,6 +1283,11 @@ dependencies = [
|
|||
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.10.0"
|
||||
|
@ -1468,6 +1473,7 @@ dependencies = [
|
|||
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zokrates_embed 0.1.0",
|
||||
"zokrates_field 0.3.3",
|
||||
|
@ -1695,6 +1701,7 @@ dependencies = [
|
|||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f"
|
||||
"checksum typed-arena 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c06a92aef38bb4dc5b0df00d68496fc31307c5344c867bb61678c6e1671ec5"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
|
|
|
@ -16,6 +16,7 @@ libc = "0.2.0"
|
|||
num = {version = "0.1.36", default-features = false}
|
||||
num-bigint = {version = "0.1.36", default-features = false}
|
||||
lazy_static = "0.1.*"
|
||||
typed-arena = "1.4.1"
|
||||
reduce = "0.1.1"
|
||||
# serialization and deserialization
|
||||
serde = "1.0"
|
||||
|
|
|
@ -21,12 +21,11 @@ impl<'ast, T: Field> From<pest::File<'ast>> for absy::Module<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<pest::ImportDirective<'ast>> for absy::ImportNode {
|
||||
impl<'ast> From<pest::ImportDirective<'ast>> for absy::ImportNode<'ast> {
|
||||
fn from(import: pest::ImportDirective<'ast>) -> absy::ImportNode {
|
||||
use absy::NodeValue;
|
||||
|
||||
imports::Import::new(import.source.value)
|
||||
.alias(import.alias.map(|a| a.value))
|
||||
imports::Import::new(import.source.span.as_str())
|
||||
.alias(import.alias.map(|a| a.span.as_str()))
|
||||
.span(import.span)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ type FunctionDeclarationNode<'ast, T> = Node<FunctionDeclaration<'ast, T>>;
|
|||
pub struct Module<'ast, T: Field> {
|
||||
/// Functions of the module
|
||||
pub functions: FunctionDeclarations<'ast, T>,
|
||||
pub imports: Vec<ImportNode>,
|
||||
pub imports: Vec<ImportNode<'ast>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
|
@ -80,7 +80,7 @@ impl<'ast, T: Field> NodeValue for Module<'ast, T> {}
|
|||
impl<'ast> NodeValue for FunctionImport<'ast> {}
|
||||
impl<'ast> NodeValue for Variable<'ast> {}
|
||||
impl<'ast> NodeValue for Parameter<'ast> {}
|
||||
impl NodeValue for Import {}
|
||||
impl<'ast> NodeValue for Import<'ast> {}
|
||||
|
||||
impl<T: NodeValue> std::cmp::PartialEq for Node<T> {
|
||||
fn eq(&self, other: &Node<T>) -> bool {
|
||||
|
|
|
@ -14,6 +14,7 @@ use std::collections::HashMap;
|
|||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
use typed_arena::Arena;
|
||||
use zokrates_field::field::Field;
|
||||
use zokrates_pest_ast as pest;
|
||||
|
||||
|
@ -123,15 +124,21 @@ impl fmt::Display for CompileErrorInner {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Resolve<S, E> = fn(Option<String>, &str) -> Result<(S, String, &str), E>;
|
||||
|
||||
pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
||||
reader: &mut R,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
resolve_option: Option<Resolve<S, E>>,
|
||||
) -> Result<ir::Prog<T>, CompileErrors> {
|
||||
let arena = Arena::new();
|
||||
|
||||
let mut source = String::new();
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let compiled = compile_program(&source, location.clone(), resolve_option)?;
|
||||
let source = arena.alloc(source);
|
||||
|
||||
let compiled = compile_program(source, location.clone(), resolve_option, &arena)?;
|
||||
|
||||
// check semantics
|
||||
let typed_ast = Checker::check(compiled).map_err(|errors| {
|
||||
|
@ -158,11 +165,18 @@ pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
|||
pub fn compile_program<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
|
||||
source: &'ast str,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<Program<T>, CompileErrors> {
|
||||
resolve_option: Option<Resolve<S, E>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<Program<'ast, T>, CompileErrors> {
|
||||
let mut modules = HashMap::new();
|
||||
|
||||
let main = compile_module(&source, location.clone(), resolve_option, &mut modules)?;
|
||||
let main = compile_module(
|
||||
&source,
|
||||
location.clone(),
|
||||
resolve_option,
|
||||
&mut modules,
|
||||
&arena,
|
||||
)?;
|
||||
|
||||
let location = location.unwrap_or("???".to_string());
|
||||
|
||||
|
@ -177,8 +191,9 @@ pub fn compile_program<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
|
|||
pub fn compile_module<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
|
||||
source: &'ast str,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
resolve_option: Option<Resolve<S, E>>,
|
||||
modules: &mut HashMap<ModuleId, Module<'ast, T>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<Module<'ast, T>, CompileErrors> {
|
||||
let ast = pest::generate_ast(&source)
|
||||
.map_err(|e| CompileErrors::from(CompileErrorInner::from(e).with_context(&location)))?;
|
||||
|
@ -189,6 +204,7 @@ pub fn compile_module<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
|
|||
location.clone(),
|
||||
resolve_option,
|
||||
modules,
|
||||
&arena,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
|
||||
use crate::absy::*;
|
||||
use crate::compile::compile_module;
|
||||
use crate::compile::{CompileErrorInner, CompileErrors};
|
||||
use crate::compile::{CompileErrorInner, CompileErrors, Resolve};
|
||||
use crate::parser::Position;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
use typed_arena::Arena;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
|
@ -52,44 +53,44 @@ impl From<io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct Import {
|
||||
source: String,
|
||||
alias: Option<String>,
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub struct Import<'ast> {
|
||||
source: Identifier<'ast>,
|
||||
alias: Option<Identifier<'ast>>,
|
||||
}
|
||||
|
||||
pub type ImportNode = Node<Import>;
|
||||
pub type ImportNode<'ast> = Node<Import<'ast>>;
|
||||
|
||||
impl Import {
|
||||
pub fn new(source: String) -> Import {
|
||||
impl<'ast> Import<'ast> {
|
||||
pub fn new(source: Identifier<'ast>) -> Import<'ast> {
|
||||
Import {
|
||||
source: source,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> &Option<String> {
|
||||
pub fn get_alias(&self) -> &Option<Identifier<'ast>> {
|
||||
&self.alias
|
||||
}
|
||||
|
||||
pub fn new_with_alias(source: String, alias: &String) -> Import {
|
||||
pub fn new_with_alias(source: Identifier<'ast>, alias: Identifier<'ast>) -> Import<'ast> {
|
||||
Import {
|
||||
source: source,
|
||||
alias: Some(alias.clone()),
|
||||
alias: Some(alias),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias(mut self, alias: Option<String>) -> Self {
|
||||
pub fn alias(mut self, alias: Option<Identifier<'ast>>) -> Self {
|
||||
self.alias = alias;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_source(&self) -> &String {
|
||||
pub fn get_source(&self) -> &Identifier<'ast> {
|
||||
&self.source
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Import {
|
||||
impl<'ast> fmt::Display for Import<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(f, "import {} as {}", self.source, alias),
|
||||
|
@ -98,7 +99,7 @@ impl fmt::Display for Import {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Import {
|
||||
impl<'ast> fmt::Debug for Import<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(f, "import(source: {}, alias: {})", self.source, alias),
|
||||
|
@ -114,165 +115,160 @@ impl Importer {
|
|||
Importer {}
|
||||
}
|
||||
|
||||
// Inject dependencies declared for `destination`
|
||||
// The lifetime of the Program before injection outlives the lifetime after
|
||||
pub fn apply_imports<'before, 'after, T: Field, S: BufRead, E: Into<Error>>(
|
||||
pub fn apply_imports<'ast, T: Field, S: BufRead, E: Into<Error>>(
|
||||
&self,
|
||||
destination: Module<'before, T>,
|
||||
destination: Module<'ast, T>,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
modules: &mut HashMap<ModuleId, Module<T>>,
|
||||
) -> Result<Module<'after, T>, CompileErrors>
|
||||
where
|
||||
'before: 'after,
|
||||
{
|
||||
unimplemented!()
|
||||
resolve_option: Option<Resolve<S, E>>,
|
||||
modules: &mut HashMap<ModuleId, Module<'ast, T>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<Module<'ast, T>, CompileErrors> {
|
||||
let mut functions: Vec<_> = vec![];
|
||||
|
||||
for import in destination.imports {
|
||||
let pos = import.pos();
|
||||
let import = import.value;
|
||||
// handle the case of special bellman and packing imports
|
||||
if import.source.starts_with("BELLMAN") {
|
||||
match import.source.as_ref() {
|
||||
"BELLMAN/sha256round" => {
|
||||
use crate::standard::sha_round;
|
||||
|
||||
let compiled = sha_round();
|
||||
|
||||
let alias = match import.alias {
|
||||
Some(alias) => {
|
||||
if alias == "sha256" {
|
||||
alias.clone()
|
||||
} else {
|
||||
return Err(CompileErrorInner::from(Error::new(format!(
|
||||
"Aliasing gadgets is not supported, found alias {}",
|
||||
alias
|
||||
)))
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
None => "sha256",
|
||||
};
|
||||
|
||||
functions.push(
|
||||
FunctionDeclaration {
|
||||
id: &alias,
|
||||
symbol: FunctionSymbol::Flat(compiled),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
s => {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Gadget {} not found", s)).with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
} else if import.source.starts_with("PACKING") {
|
||||
use crate::types::conversions::split;
|
||||
|
||||
match import.source.as_ref() {
|
||||
"PACKING/split" => {
|
||||
let compiled = split();
|
||||
let alias = match import.alias {
|
||||
Some(alias) => {
|
||||
if alias == "split" {
|
||||
alias.clone()
|
||||
} else {
|
||||
return Err(CompileErrorInner::from(Error::new(format!(
|
||||
"Aliasing gadgets is not supported, found alias {}",
|
||||
alias
|
||||
)))
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
None => "split",
|
||||
};
|
||||
|
||||
functions.push(
|
||||
FunctionDeclaration {
|
||||
id: &alias,
|
||||
symbol: FunctionSymbol::Flat(compiled),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
s => {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Packing helper {} not found", s))
|
||||
.with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// to resolve imports, we need a resolver
|
||||
match resolve_option {
|
||||
Some(resolve) => match resolve(location.clone(), &import.source) {
|
||||
Ok((mut reader, location, alias)) => {
|
||||
let mut source = String::new();
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let source = arena.alloc(source);
|
||||
|
||||
let compiled = compile_module(
|
||||
source,
|
||||
Some(location),
|
||||
resolve_option,
|
||||
modules,
|
||||
&arena,
|
||||
)
|
||||
.map_err(|e| e.with_context(Some(import.source.to_string())))?;
|
||||
let alias = import.alias.clone().unwrap_or(alias);
|
||||
|
||||
modules.insert(import.source.to_string(), compiled);
|
||||
|
||||
functions.push(
|
||||
FunctionDeclaration {
|
||||
id: &alias,
|
||||
symbol: FunctionSymbol::There(
|
||||
FunctionImport::with_id_in_module(
|
||||
"main",
|
||||
import.source.clone(),
|
||||
)
|
||||
.start_end(pos.0, pos.1),
|
||||
),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
err.into().with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(CompileErrorInner::from(Error::new(
|
||||
"Can't resolve import without a resolver",
|
||||
))
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
functions.extend(destination.functions);
|
||||
|
||||
Ok(Module {
|
||||
imports: vec![],
|
||||
functions: functions,
|
||||
})
|
||||
}
|
||||
// {
|
||||
// let mut functions: Vec<_> = vec![];
|
||||
|
||||
// for import in destination.imports {
|
||||
// let pos = import.pos();
|
||||
// let import = import.value;
|
||||
// // handle the case of special bellman and packing imports
|
||||
// if import.source.starts_with("BELLMAN") {
|
||||
// match import.source.as_ref() {
|
||||
// "BELLMAN/sha256round" => {
|
||||
// use crate::standard::sha_round;
|
||||
|
||||
// let compiled = sha_round();
|
||||
|
||||
// let alias = match import.alias {
|
||||
// Some(alias) => {
|
||||
// if alias == "sha256" {
|
||||
// alias.clone()
|
||||
// } else {
|
||||
// return Err(CompileErrorInner::from(Error::new(format!(
|
||||
// "Aliasing gadgets is not supported, found alias {}",
|
||||
// alias
|
||||
// )))
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// }
|
||||
// None => String::from("sha256"),
|
||||
// };
|
||||
|
||||
// functions.push(
|
||||
// FunctionDeclaration {
|
||||
// id: &alias,
|
||||
// symbol: FunctionSymbol::Flat(compiled),
|
||||
// }
|
||||
// .start_end(pos.0, pos.1),
|
||||
// );
|
||||
// }
|
||||
// s => {
|
||||
// return Err(CompileErrorInner::ImportError(
|
||||
// Error::new(format!("Gadget {} not found", s)).with_pos(Some(pos)),
|
||||
// )
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// }
|
||||
// } else if import.source.starts_with("PACKING") {
|
||||
// use crate::types::conversions::split;
|
||||
|
||||
// match import.source.as_ref() {
|
||||
// "PACKING/split" => {
|
||||
// let compiled = split();
|
||||
// let alias = match import.alias {
|
||||
// Some(alias) => {
|
||||
// if alias == "split" {
|
||||
// alias.clone()
|
||||
// } else {
|
||||
// return Err(CompileErrorInner::from(Error::new(format!(
|
||||
// "Aliasing gadgets is not supported, found alias {}",
|
||||
// alias
|
||||
// )))
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// }
|
||||
// None => String::from("split"),
|
||||
// };
|
||||
|
||||
// functions.push(
|
||||
// FunctionDeclaration {
|
||||
// id: &alias,
|
||||
// symbol: FunctionSymbol::Flat(compiled),
|
||||
// }
|
||||
// .start_end(pos.0, pos.1),
|
||||
// );
|
||||
// }
|
||||
// s => {
|
||||
// return Err(CompileErrorInner::ImportError(
|
||||
// Error::new(format!("Packing helper {} not found", s))
|
||||
// .with_pos(Some(pos)),
|
||||
// )
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // to resolve imports, we need a resolver
|
||||
// match resolve_option {
|
||||
// Some(resolve) => match resolve(&location, &import.source) {
|
||||
// Ok((mut reader, location, auto_alias)) => {
|
||||
|
||||
// let mut source = String::new();
|
||||
// reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
// let compiled = compile_module(
|
||||
// &source,
|
||||
// Some(location),
|
||||
// resolve_option,
|
||||
// modules,
|
||||
// )
|
||||
// .map_err(|e| e.with_context(Some(import.source.clone())))?;
|
||||
// let alias = import.alias.clone().unwrap_or(auto_alias);
|
||||
|
||||
// modules.insert(import.source.clone(), compiled);
|
||||
|
||||
// functions.push(
|
||||
// FunctionDeclaration {
|
||||
// id: &alias,
|
||||
// symbol: FunctionSymbol::There(
|
||||
// FunctionImport::with_id_in_module(
|
||||
// "main",
|
||||
// import.source.clone(),
|
||||
// )
|
||||
// .start_end(pos.0, pos.1),
|
||||
// ),
|
||||
// }
|
||||
// .start_end(pos.0, pos.1),
|
||||
// );
|
||||
// }
|
||||
// Err(err) => {
|
||||
// return Err(CompileErrorInner::ImportError(
|
||||
// err.into().with_pos(Some(pos)),
|
||||
// )
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// },
|
||||
// None => {
|
||||
// return Err(CompileErrorInner::from(Error::new(
|
||||
// "Can't resolve import without a resolver",
|
||||
// ))
|
||||
// .with_context(&location)
|
||||
// .into());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// functions.extend(destination.functions);
|
||||
|
||||
// Ok(Module {
|
||||
// imports: vec![],
|
||||
// functions: functions,
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -283,9 +279,9 @@ mod tests {
|
|||
#[test]
|
||||
fn create_with_no_alias() {
|
||||
assert_eq!(
|
||||
Import::new("./foo/bar/baz.code".to_string()),
|
||||
Import::new("./foo/bar/baz.code"),
|
||||
Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
source: "./foo/bar/baz.code",
|
||||
alias: None,
|
||||
}
|
||||
);
|
||||
|
@ -294,10 +290,10 @@ mod tests {
|
|||
#[test]
|
||||
fn create_with_alias() {
|
||||
assert_eq!(
|
||||
Import::new_with_alias("./foo/bar/baz.code".to_string(), &"myalias".to_string()),
|
||||
Import::new_with_alias("./foo/bar/baz.code", &"myalias"),
|
||||
Import {
|
||||
source: String::from("./foo/bar/baz.code"),
|
||||
alias: Some("myalias".to_string()),
|
||||
source: "./foo/bar/baz.code",
|
||||
alias: Some("myalias"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ extern crate num_bigint;
|
|||
extern crate reduce; // better reduce function than Iter.fold
|
||||
extern crate serde; // serialization deserialization
|
||||
extern crate serde_json;
|
||||
extern crate typed_arena;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate bellman;
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<'ast, T: Field> fmt::Display for TypedProgram<'ast, T> {
|
|||
pub struct TypedModule<'ast, T: Field> {
|
||||
/// Functions of the program
|
||||
pub functions: TypedFunctionSymbols<'ast, T>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imports: Vec<Import<'ast>>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
use std::path::{Component, PathBuf};
|
||||
|
||||
const ZOKRATES_HOME: &str = &"ZOKRATES_HOME";
|
||||
|
||||
pub fn resolve(
|
||||
location: &Option<String>,
|
||||
source: &String,
|
||||
) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
pub fn resolve<'a>(
|
||||
location: Option<String>,
|
||||
source: &'a str,
|
||||
) -> Result<(BufReader<File>, String, &'a str), io::Error> {
|
||||
// the fs resolver has to be provided a location, as it supports relative paths
|
||||
match location {
|
||||
Some(location) => resolve_with_location(location, source),
|
||||
|
@ -16,11 +17,11 @@ pub fn resolve(
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_with_location(
|
||||
location: &String,
|
||||
source: &String,
|
||||
) -> Result<(BufReader<File>, String, String), io::Error> {
|
||||
let source = PathBuf::from(source);
|
||||
fn resolve_with_location<'a>(
|
||||
location: String,
|
||||
source: &'a str,
|
||||
) -> Result<(BufReader<File>, String, &'a str), io::Error> {
|
||||
let source = Path::new(source);
|
||||
|
||||
// paths starting with `./` or `../` are interpreted relative to the current file
|
||||
// other paths `abc/def.code` are interpreted relative to $ZOKRATES_HOME
|
||||
|
@ -31,25 +32,26 @@ fn resolve_with_location(
|
|||
),
|
||||
};
|
||||
|
||||
let path = base.join(PathBuf::from(source));
|
||||
let path_owned = base.join(PathBuf::from(source));
|
||||
|
||||
if path.is_dir() {
|
||||
if path_owned.is_dir() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Not a file"));
|
||||
}
|
||||
|
||||
let (next_location, alias) = generate_next_parameters(&path)?;
|
||||
let alias = generate_alias(source);
|
||||
let next_location = generate_next_location(&path_owned)?;
|
||||
|
||||
File::open(path).and_then(|f| Ok((BufReader::new(f), next_location, alias)))
|
||||
File::open(path_owned).and_then(|f| Ok((BufReader::new(f), next_location, alias)))
|
||||
}
|
||||
|
||||
fn generate_next_parameters(path: &PathBuf) -> Result<(String, String), io::Error> {
|
||||
match (path.parent(), path.file_stem()) {
|
||||
(Some(parent), Some(stem)) => Ok((
|
||||
parent.to_path_buf().into_os_string().into_string().unwrap(),
|
||||
stem.to_os_string().to_string_lossy().to_string(),
|
||||
)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::Other, "Invalid path")),
|
||||
}
|
||||
fn generate_next_location<'a>(path: &'a PathBuf) -> Result<String, io::Error> {
|
||||
path.parent()
|
||||
.ok_or(io::Error::new(io::ErrorKind::Other, "Invalid path"))
|
||||
.map(|v| v.to_path_buf().into_os_string().into_string().unwrap())
|
||||
}
|
||||
|
||||
fn generate_alias<'a>(path: &'a Path) -> &'a str {
|
||||
path.file_stem().unwrap().to_str().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -58,48 +60,44 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn valid_path_with_location() {
|
||||
let (_, next_location, alias) =
|
||||
resolve(&Some(String::from("./src")), &String::from("./lib.rs")).unwrap();
|
||||
let (_, next_location, alias) = resolve(Some(String::from("./src")), &"./lib.rs").unwrap();
|
||||
assert_eq!(next_location, String::from("./src"));
|
||||
assert_eq!(alias, String::from("lib"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_path_without_location() {
|
||||
let res = resolve(&None, &String::from("./src/lib.rs"));
|
||||
let res = resolve(None, &"./src/lib.rs");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_existing_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from("./rubbish.rs"));
|
||||
let res = resolve(Some(String::from("./src")), &"./rubbish.rs");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_location() {
|
||||
let res = resolve(
|
||||
&Some(String::from(",8!-$2abc")),
|
||||
&String::from("./foo.code"),
|
||||
);
|
||||
let res = resolve(Some(String::from(",8!-$2abc")), &"./foo.code");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_file() {
|
||||
let res = resolve(&Some(String::from("./src")), &String::from(",8!-$2abc"));
|
||||
let res = resolve(Some(String::from("./src")), &",8!-$2abc");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_a_file() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("./src/"));
|
||||
let res = resolve(Some(String::from(".")), &"./src/");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_parent() {
|
||||
let res = resolve(&Some(String::from(".")), &String::from("."));
|
||||
let res = resolve(Some(String::from(".")), &".");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
|
@ -108,7 +106,7 @@ mod tests {
|
|||
fn no_file_name_without_stdlib() {
|
||||
// an empty string is interpreted relative to the HOME folder. If there's none, panic
|
||||
std::env::remove_var(ZOKRATES_HOME);
|
||||
let _res = resolve(&Some(String::from(".")), &String::from(""));
|
||||
let _res = resolve(Some(String::from(".")), &"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -124,7 +122,7 @@ mod tests {
|
|||
// assign HOME folder to ZOKRATES_HOME
|
||||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let res = resolve(&Some(String::from(".")), &String::from(""));
|
||||
let res = resolve(Some(String::from(".")), &"");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
|
@ -149,14 +147,14 @@ mod tests {
|
|||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve(
|
||||
&Some(
|
||||
Some(
|
||||
source_folder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
),
|
||||
&"./bar.code".to_string(),
|
||||
&"./bar.code",
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let mut code = String::new();
|
||||
|
@ -186,14 +184,14 @@ mod tests {
|
|||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve(
|
||||
&Some(
|
||||
Some(
|
||||
source_folder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
),
|
||||
&"bar.code".to_string(),
|
||||
&"bar.code",
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let mut code = String::new();
|
||||
|
@ -215,14 +213,14 @@ mod tests {
|
|||
writeln!(file, "<user code>").unwrap();
|
||||
|
||||
let result = resolve(
|
||||
&Some(
|
||||
Some(
|
||||
source_subfolder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
),
|
||||
&"../bar.code".to_string(),
|
||||
&"../bar.code",
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let mut code = String::new();
|
||||
|
@ -244,20 +242,14 @@ mod tests {
|
|||
// assign HOME folder to ZOKRATES_HOME
|
||||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve(
|
||||
&Some("/path/to/user/folder".to_string()),
|
||||
&"./bar.code".to_string(),
|
||||
);
|
||||
let result = resolve(Some("/path/to/user/folder".to_string()), &"./bar.code");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_if_not_found_in_std() {
|
||||
std::env::set_var(ZOKRATES_HOME, "");
|
||||
let result = resolve(
|
||||
&Some("/path/to/source".to_string()),
|
||||
&"bar.code".to_string(),
|
||||
);
|
||||
let result = resolve(Some("/path/to/source".to_string()), &"bar.code");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
|
@ -265,9 +257,6 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn panic_if_home_not_set() {
|
||||
std::env::remove_var(ZOKRATES_HOME);
|
||||
let _ = resolve(
|
||||
&Some("/path/to/source".to_string()),
|
||||
&"bar.code".to_string(),
|
||||
);
|
||||
let _ = resolve(Some("/path/to/source".to_string()), &"bar.code");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue