Merge pull request #565 from Zokrates/fix-import-context
Fix import context
This commit is contained in:
commit
cf8600e608
17 changed files with 607 additions and 510 deletions
|
@ -13,7 +13,7 @@ use std::io::{stdin, BufReader, BufWriter, Read, Write};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::string::String;
|
||||
use zokrates_abi::Encode;
|
||||
use zokrates_core::compile::{compile, CompilationArtifacts};
|
||||
use zokrates_core::compile::{compile, CompilationArtifacts, CompileError};
|
||||
use zokrates_core::ir;
|
||||
use zokrates_core::proof_system::*;
|
||||
use zokrates_core::typed_absy::abi::Abi;
|
||||
|
@ -271,14 +271,6 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
let path = PathBuf::from(sub_matches.value_of("input").unwrap());
|
||||
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let light = sub_matches.occurrences_of("light") > 0;
|
||||
|
||||
let bin_output_path = Path::new(sub_matches.value_of("output").unwrap());
|
||||
|
@ -287,17 +279,36 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
let hr_output_path = bin_output_path.to_path_buf().with_extension("ztf");
|
||||
|
||||
let file = File::open(path.clone()).unwrap();
|
||||
let file = File::open(path.clone())
|
||||
.map_err(|why| format!("Couldn't open input file {}: {}", path.display(), why))?;
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut source = String::new();
|
||||
reader
|
||||
.read_to_string(&mut source)
|
||||
.map_err(|why| format!("couldn't open input file {}: {}", path.display(), why))?;
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let fmt_error = |e: &CompileError| {
|
||||
format!(
|
||||
"{}:{}",
|
||||
e.file()
|
||||
.canonicalize()
|
||||
.unwrap()
|
||||
.strip_prefix(std::env::current_dir().unwrap())
|
||||
.unwrap()
|
||||
.display(),
|
||||
e.value()
|
||||
)
|
||||
};
|
||||
|
||||
let artifacts: CompilationArtifacts<FieldPrime> =
|
||||
compile(source, location, Some(&fs_resolve))
|
||||
.map_err(|e| format!("Compilation failed:\n\n {}", e))?;
|
||||
compile(source, path, Some(&fs_resolve)).map_err(|e| {
|
||||
format!(
|
||||
"Compilation failed:\n\n{}",
|
||||
e.0.iter()
|
||||
.map(|e| fmt_error(e))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
)
|
||||
})?;
|
||||
|
||||
let program_flattened = artifacts.prog();
|
||||
|
||||
|
@ -306,7 +317,7 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
// serialize flattened program and write to binary file
|
||||
let bin_output_file = File::create(&bin_output_path)
|
||||
.map_err(|why| format!("couldn't create {}: {}", bin_output_path.display(), why))?;
|
||||
.map_err(|why| format!("Couldn't create {}: {}", bin_output_path.display(), why))?;
|
||||
|
||||
let mut writer = BufWriter::new(bin_output_file);
|
||||
|
||||
|
@ -315,7 +326,7 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
// serialize ABI spec and write to JSON file
|
||||
let abi_spec_file = File::create(&abi_spec_path)
|
||||
.map_err(|why| format!("couldn't create {}: {}", abi_spec_path.display(), why))?;
|
||||
.map_err(|why| format!("Couldn't create {}: {}", abi_spec_path.display(), why))?;
|
||||
|
||||
let abi = artifacts.abi();
|
||||
|
||||
|
@ -666,19 +677,12 @@ mod tests {
|
|||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let mut source = String::new();
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let _: CompilationArtifacts<FieldPrime> =
|
||||
compile(source, location, Some(&fs_resolve)).unwrap();
|
||||
compile(source, path, Some(&fs_resolve)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -694,20 +698,12 @@ mod tests {
|
|||
|
||||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut source = String::new();
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let artifacts: CompilationArtifacts<FieldPrime> =
|
||||
compile(source, location, Some(&fs_resolve)).unwrap();
|
||||
compile(source, path, Some(&fs_resolve)).unwrap();
|
||||
|
||||
let _ = artifacts
|
||||
.prog()
|
||||
|
@ -729,20 +725,12 @@ mod tests {
|
|||
|
||||
let file = File::open(path.clone()).unwrap();
|
||||
|
||||
let location = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut source = String::new();
|
||||
reader.read_to_string(&mut source).unwrap();
|
||||
|
||||
let artifacts: CompilationArtifacts<FieldPrime> =
|
||||
compile(source, location, Some(&fs_resolve)).unwrap();
|
||||
compile(source, path, Some(&fs_resolve)).unwrap();
|
||||
|
||||
let _ = artifacts
|
||||
.prog()
|
||||
|
|
|
@ -25,13 +25,13 @@ impl<'ast> From<pest::ImportDirective<'ast>> for absy::ImportNode<'ast> {
|
|||
|
||||
match import {
|
||||
pest::ImportDirective::Main(import) => {
|
||||
imports::Import::new(None, import.source.span.as_str())
|
||||
imports::Import::new(None, std::path::Path::new(import.source.span.as_str()))
|
||||
.alias(import.alias.map(|a| a.span.as_str()))
|
||||
.span(import.span)
|
||||
}
|
||||
pest::ImportDirective::From(import) => imports::Import::new(
|
||||
Some(import.symbol.span.as_str()),
|
||||
import.source.span.as_str(),
|
||||
std::path::Path::new(import.source.span.as_str()),
|
||||
)
|
||||
.alias(import.alias.map(|a| a.span.as_str()))
|
||||
.span(import.span),
|
||||
|
|
|
@ -16,6 +16,7 @@ pub use crate::absy::parameter::{Parameter, ParameterNode};
|
|||
use crate::absy::types::{FunctionIdentifier, UnresolvedSignature, UnresolvedType, UserTypeId};
|
||||
pub use crate::absy::variable::{Variable, VariableNode};
|
||||
use embed::FlatEmbed;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::imports::ImportNode;
|
||||
use std::fmt;
|
||||
|
@ -27,7 +28,7 @@ use std::collections::HashMap;
|
|||
pub type Identifier<'ast> = &'ast str;
|
||||
|
||||
/// The identifier of a `Module`, typically a path or uri
|
||||
pub type ModuleId = String;
|
||||
pub type ModuleId = PathBuf;
|
||||
|
||||
/// A collection of `Module`s
|
||||
pub type Modules<'ast, T> = HashMap<ModuleId, Module<'ast, T>>;
|
||||
|
@ -160,7 +161,12 @@ impl<'ast> SymbolImport<'ast> {
|
|||
|
||||
impl<'ast> fmt::Display for SymbolImport<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} from {}", self.symbol_id, self.module_id)
|
||||
write!(
|
||||
f,
|
||||
"{} from {}",
|
||||
self.symbol_id,
|
||||
self.module_id.display().to_string()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use static_analysis::Analyse;
|
|||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use typed_absy::abi::Abi;
|
||||
use typed_arena::Arena;
|
||||
use zokrates_field::field::Field;
|
||||
|
@ -35,7 +36,7 @@ impl<T: Field> CompilationArtifacts<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompileErrors(Vec<CompileError>);
|
||||
pub struct CompileErrors(pub Vec<CompileError>);
|
||||
|
||||
impl From<CompileError> for CompileErrors {
|
||||
fn from(e: CompileError) -> CompileErrors {
|
||||
|
@ -43,50 +44,46 @@ impl From<CompileError> for CompileErrors {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompileErrors {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|e| format!("{}", e))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CompileErrorInner {
|
||||
ParserError(pest::Error),
|
||||
ImportError(imports::Error),
|
||||
SemanticError(semantics::Error),
|
||||
SemanticError(semantics::ErrorInner),
|
||||
ReadError(io::Error),
|
||||
}
|
||||
|
||||
impl CompileErrorInner {
|
||||
pub fn with_context(self, context: &String) -> CompileError {
|
||||
pub fn in_file(self, context: &PathBuf) -> CompileError {
|
||||
CompileError {
|
||||
value: self,
|
||||
context: context.clone(),
|
||||
file: context.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompileError {
|
||||
context: String,
|
||||
file: PathBuf,
|
||||
value: CompileErrorInner,
|
||||
}
|
||||
|
||||
impl CompileError {
|
||||
pub fn file(&self) -> &PathBuf {
|
||||
&self.file
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &CompileErrorInner {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl CompileErrors {
|
||||
pub fn with_context(self, context: String) -> Self {
|
||||
pub fn with_context(self, file: PathBuf) -> Self {
|
||||
CompileErrors(
|
||||
self.0
|
||||
.into_iter()
|
||||
.map(|e| CompileError {
|
||||
context: context.clone(),
|
||||
file: file.clone(),
|
||||
..e
|
||||
})
|
||||
.collect(),
|
||||
|
@ -94,12 +91,6 @@ impl CompileErrors {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompileError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}:{}", self.context, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pest::Error> for CompileErrorInner {
|
||||
fn from(error: pest::Error) -> Self {
|
||||
CompileErrorInner::ParserError(error)
|
||||
|
@ -118,29 +109,34 @@ impl From<io::Error> for CompileErrorInner {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<semantics::Error> for CompileErrorInner {
|
||||
impl From<semantics::Error> for CompileError {
|
||||
fn from(error: semantics::Error) -> Self {
|
||||
CompileErrorInner::SemanticError(error)
|
||||
CompileError {
|
||||
value: CompileErrorInner::SemanticError(error.inner),
|
||||
file: error.module_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompileErrorInner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let res = match *self {
|
||||
CompileErrorInner::ParserError(ref e) => format!("{}", e),
|
||||
CompileErrorInner::SemanticError(ref e) => format!("{}", e),
|
||||
CompileErrorInner::ReadError(ref e) => format!("{}", e),
|
||||
CompileErrorInner::ImportError(ref e) => format!("{}", e),
|
||||
};
|
||||
write!(f, "{}", res)
|
||||
match *self {
|
||||
CompileErrorInner::ParserError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::SemanticError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::ReadError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::ImportError(ref e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Resolve<'a, E> = &'a dyn Fn(String, String) -> Result<(String, String), E>;
|
||||
// See zokrates_fs_resolver for the spec
|
||||
pub type Resolve<'a, E> = &'a dyn Fn(PathBuf, PathBuf) -> Result<(String, PathBuf), E>;
|
||||
|
||||
type FilePath = PathBuf;
|
||||
|
||||
pub fn compile<T: Field, E: Into<imports::Error>>(
|
||||
source: String,
|
||||
location: String,
|
||||
location: FilePath,
|
||||
resolve_option: Option<Resolve<E>>,
|
||||
) -> Result<CompilationArtifacts<T>, CompileErrors> {
|
||||
let arena = Arena::new();
|
||||
|
@ -150,12 +146,7 @@ pub fn compile<T: Field, E: Into<imports::Error>>(
|
|||
|
||||
// check semantics
|
||||
let typed_ast = Checker::check(compiled).map_err(|errors| {
|
||||
CompileErrors(
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|e| CompileErrorInner::from(e).with_context(&location))
|
||||
.collect(),
|
||||
)
|
||||
CompileErrors(errors.into_iter().map(|e| CompileError::from(e)).collect())
|
||||
})?;
|
||||
|
||||
let abi = typed_ast.abi();
|
||||
|
@ -183,7 +174,7 @@ pub fn compile<T: Field, E: Into<imports::Error>>(
|
|||
|
||||
pub fn compile_program<'ast, T: Field, E: Into<imports::Error>>(
|
||||
source: &'ast str,
|
||||
location: String,
|
||||
location: FilePath,
|
||||
resolve_option: Option<Resolve<E>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<Program<'ast, T>, CompileErrors> {
|
||||
|
@ -207,13 +198,13 @@ pub fn compile_program<'ast, T: Field, E: Into<imports::Error>>(
|
|||
|
||||
pub fn compile_module<'ast, T: Field, E: Into<imports::Error>>(
|
||||
source: &'ast str,
|
||||
location: String,
|
||||
location: FilePath,
|
||||
resolve_option: Option<Resolve<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)))?;
|
||||
.map_err(|e| CompileErrors::from(CompileErrorInner::from(e).in_file(&location)))?;
|
||||
let module_without_imports: Module<T> = Module::from(ast);
|
||||
|
||||
Importer::new().apply_imports(
|
||||
|
@ -238,13 +229,10 @@ mod test {
|
|||
return foo()
|
||||
"#
|
||||
.to_string();
|
||||
let res: Result<CompilationArtifacts<FieldPrime>, CompileErrors> = compile(
|
||||
source,
|
||||
String::from("./path/to/file"),
|
||||
None::<Resolve<io::Error>>,
|
||||
);
|
||||
assert!(res
|
||||
.unwrap_err()
|
||||
let res: Result<CompilationArtifacts<FieldPrime>, CompileErrors> =
|
||||
compile(source, "./path/to/file".into(), None::<Resolve<io::Error>>);
|
||||
assert!(res.unwrap_err().0[0]
|
||||
.value()
|
||||
.to_string()
|
||||
.contains(&"Can't resolve import without a resolver"));
|
||||
}
|
||||
|
@ -256,11 +244,8 @@ mod test {
|
|||
return 1
|
||||
"#
|
||||
.to_string();
|
||||
let res: Result<CompilationArtifacts<FieldPrime>, CompileErrors> = compile(
|
||||
source,
|
||||
String::from("./path/to/file"),
|
||||
None::<Resolve<io::Error>>,
|
||||
);
|
||||
let res: Result<CompilationArtifacts<FieldPrime>, CompileErrors> =
|
||||
compile(source, "./path/to/file".into(), None::<Resolve<io::Error>>);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::parser::Position;
|
|||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use typed_arena::Arena;
|
||||
use zokrates_field::field::Field;
|
||||
|
@ -54,9 +55,11 @@ impl From<io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
type ImportPath<'ast> = &'ast Path;
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub struct Import<'ast> {
|
||||
source: Identifier<'ast>,
|
||||
source: ImportPath<'ast>,
|
||||
symbol: Option<Identifier<'ast>>,
|
||||
alias: Option<Identifier<'ast>>,
|
||||
}
|
||||
|
@ -64,7 +67,7 @@ pub struct Import<'ast> {
|
|||
pub type ImportNode<'ast> = Node<Import<'ast>>;
|
||||
|
||||
impl<'ast> Import<'ast> {
|
||||
pub fn new(symbol: Option<Identifier<'ast>>, source: Identifier<'ast>) -> Import<'ast> {
|
||||
pub fn new(symbol: Option<Identifier<'ast>>, source: ImportPath<'ast>) -> Import<'ast> {
|
||||
Import {
|
||||
symbol,
|
||||
source,
|
||||
|
@ -78,7 +81,7 @@ impl<'ast> Import<'ast> {
|
|||
|
||||
pub fn new_with_alias(
|
||||
symbol: Option<Identifier<'ast>>,
|
||||
source: Identifier<'ast>,
|
||||
source: ImportPath<'ast>,
|
||||
alias: Identifier<'ast>,
|
||||
) -> Import<'ast> {
|
||||
Import {
|
||||
|
@ -93,7 +96,7 @@ impl<'ast> Import<'ast> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn get_source(&self) -> &Identifier<'ast> {
|
||||
pub fn get_source(&self) -> &ImportPath<'ast> {
|
||||
&self.source
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +104,8 @@ impl<'ast> Import<'ast> {
|
|||
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),
|
||||
None => write!(f, "import {}", self.source),
|
||||
Some(ref alias) => write!(f, "import {} as {}", self.source.display(), alias),
|
||||
None => write!(f, "import {}", self.source.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,8 +113,13 @@ impl<'ast> fmt::Display for Import<'ast> {
|
|||
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),
|
||||
None => write!(f, "import(source: {})", self.source),
|
||||
Some(ref alias) => write!(
|
||||
f,
|
||||
"import(source: {}, alias: {})",
|
||||
self.source.display(),
|
||||
alias
|
||||
),
|
||||
None => write!(f, "import(source: {})", self.source.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +134,7 @@ impl Importer {
|
|||
pub fn apply_imports<'ast, T: Field, E: Into<Error>>(
|
||||
&self,
|
||||
destination: Module<'ast, T>,
|
||||
location: String,
|
||||
location: PathBuf,
|
||||
resolve_option: Option<Resolve<E>>,
|
||||
modules: &mut HashMap<ModuleId, Module<'ast, T>>,
|
||||
arena: &'ast Arena<String>,
|
||||
|
@ -139,7 +147,7 @@ impl Importer {
|
|||
let alias = import.alias;
|
||||
// handle the case of special bellman and packing imports
|
||||
if import.source.starts_with("EMBED") {
|
||||
match import.source.as_ref() {
|
||||
match import.source.to_str().unwrap() {
|
||||
"EMBED/sha256round" => {
|
||||
let alias = alias.unwrap_or("sha256round");
|
||||
|
||||
|
@ -166,17 +174,15 @@ impl Importer {
|
|||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Embed {} not found. Options are \"EMBED/sha256round\", \"EMBED/unpack\"", s)).with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.in_file(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// to resolve imports, we need a resolver
|
||||
match resolve_option {
|
||||
Some(resolve) => match resolve(location.clone(), import.source.to_string()) {
|
||||
Ok((source, location)) => {
|
||||
let source = arena.alloc(source);
|
||||
|
||||
Some(resolve) => match resolve(location.clone(), import.source.to_path_buf()) {
|
||||
Ok((source, new_location)) => {
|
||||
// generate an alias from the imported path if none was given explicitely
|
||||
let alias = import.alias.unwrap_or(
|
||||
std::path::Path::new(import.source)
|
||||
|
@ -184,19 +190,32 @@ impl Importer {
|
|||
.ok_or(CompileErrors::from(
|
||||
CompileErrorInner::ImportError(Error::new(format!(
|
||||
"Could not determine alias for import {}",
|
||||
import.source
|
||||
import.source.display()
|
||||
)))
|
||||
.with_context(&location),
|
||||
.in_file(&location),
|
||||
))?
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let compiled =
|
||||
compile_module(source, location, resolve_option, modules, &arena)
|
||||
.map_err(|e| e.with_context(import.source.to_string()))?;
|
||||
match modules.get(&new_location) {
|
||||
Some(_) => {}
|
||||
None => {
|
||||
let source = arena.alloc(source);
|
||||
|
||||
modules.insert(import.source.to_string(), compiled);
|
||||
let compiled = compile_module(
|
||||
source,
|
||||
new_location.clone(),
|
||||
resolve_option,
|
||||
modules,
|
||||
&arena,
|
||||
)?;
|
||||
|
||||
assert!(modules
|
||||
.insert(new_location.clone(), compiled)
|
||||
.is_none());
|
||||
}
|
||||
};
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
|
@ -204,7 +223,7 @@ impl Importer {
|
|||
symbol: Symbol::There(
|
||||
SymbolImport::with_id_in_module(
|
||||
import.symbol.unwrap_or("main"),
|
||||
import.source.clone(),
|
||||
new_location.display().to_string(),
|
||||
)
|
||||
.start_end(pos.0, pos.1),
|
||||
),
|
||||
|
@ -216,7 +235,7 @@ impl Importer {
|
|||
return Err(CompileErrorInner::ImportError(
|
||||
err.into().with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.in_file(&location)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
|
@ -224,7 +243,7 @@ impl Importer {
|
|||
return Err(CompileErrorInner::from(Error::new(
|
||||
"Can't resolve import without a resolver",
|
||||
))
|
||||
.with_context(&location)
|
||||
.in_file(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
@ -249,10 +268,10 @@ mod tests {
|
|||
#[test]
|
||||
fn create_with_no_alias() {
|
||||
assert_eq!(
|
||||
Import::new(None, "./foo/bar/baz.zok"),
|
||||
Import::new(None, Path::new("./foo/bar/baz.zok")),
|
||||
Import {
|
||||
symbol: None,
|
||||
source: "./foo/bar/baz.zok",
|
||||
source: Path::new("./foo/bar/baz.zok"),
|
||||
alias: None,
|
||||
}
|
||||
);
|
||||
|
@ -261,10 +280,10 @@ mod tests {
|
|||
#[test]
|
||||
fn create_with_alias() {
|
||||
assert_eq!(
|
||||
Import::new_with_alias(None, "./foo/bar/baz.zok", &"myalias"),
|
||||
Import::new_with_alias(None, Path::new("./foo/bar/baz.zok"), &"myalias"),
|
||||
Import {
|
||||
symbol: None,
|
||||
source: "./foo/bar/baz.zok",
|
||||
source: Path::new("./foo/bar/baz.zok"),
|
||||
alias: Some("myalias"),
|
||||
}
|
||||
);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,8 +27,8 @@ pub struct Inliner<'ast, T: Field> {
|
|||
modules: TypedModules<'ast, T>, // the modules in which to look for functions when inlining
|
||||
module_id: TypedModuleId, // the current module we're visiting
|
||||
statement_buffer: Vec<TypedStatement<'ast, T>>, // a buffer of statements to be added to the inlined statements
|
||||
stack: Vec<(String, FunctionKey<'ast>, usize)>, // the current call stack
|
||||
call_count: HashMap<(String, FunctionKey<'ast>), usize>, // the call count for each function
|
||||
stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>, // the current call stack
|
||||
call_count: HashMap<(TypedModuleId, FunctionKey<'ast>), usize>, // the call count for each function
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Inliner<'ast, T> {
|
||||
|
@ -74,9 +74,9 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
|
||||
// return a program with a single module containing `main`, `_UNPACK`, and `_SHA256_ROUND
|
||||
TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules: vec![(
|
||||
String::from("main"),
|
||||
"main".into(),
|
||||
TypedModule {
|
||||
functions: vec![
|
||||
(unpack_key, TypedFunctionSymbol::Flat(unpack)),
|
||||
|
@ -311,6 +311,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
use typed_absy::types::{FunctionKey, Signature, Type};
|
||||
use zokrates_field::field::FieldPrime;
|
||||
|
||||
|
@ -354,7 +355,7 @@ mod tests {
|
|||
TypedFunctionSymbol::There(
|
||||
FunctionKey::with_id("foo")
|
||||
.signature(Signature::new().outputs(vec![Type::FieldElement])),
|
||||
String::from("foo"),
|
||||
"foo".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -378,12 +379,12 @@ mod tests {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![(String::from("main"), main), (String::from("foo"), foo)]
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
|
@ -393,7 +394,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&String::from("main"))
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(
|
||||
|
@ -469,7 +470,7 @@ mod tests {
|
|||
.inputs(vec![Type::FieldElement])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
),
|
||||
String::from("foo"),
|
||||
"foo".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -500,12 +501,12 @@ mod tests {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![(String::from("main"), main), (String::from("foo"), foo)]
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program: TypedProgram<FieldPrime> = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
|
@ -514,7 +515,7 @@ mod tests {
|
|||
assert_eq!(program.modules.len(), 1);
|
||||
|
||||
let stack = vec![(
|
||||
String::from("foo"),
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(
|
||||
Signature::new()
|
||||
.inputs(vec![Type::FieldElement])
|
||||
|
@ -526,7 +527,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&String::from("main"))
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(
|
||||
|
@ -614,7 +615,7 @@ mod tests {
|
|||
TypedFunctionSymbol::There(
|
||||
FunctionKey::with_id("foo")
|
||||
.signature(Signature::new().outputs(vec![Type::FieldElement])),
|
||||
String::from("foo"),
|
||||
"foo".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -638,12 +639,12 @@ mod tests {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![(String::from("main"), main), (String::from("foo"), foo)]
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
|
@ -653,7 +654,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&String::from("main"))
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(
|
||||
|
@ -733,10 +734,10 @@ mod tests {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![(String::from("main"), main)].into_iter().collect();
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main)].into_iter().collect();
|
||||
|
||||
let program = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
|
@ -746,7 +747,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&String::from("main"))
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(
|
||||
|
@ -832,7 +833,7 @@ mod tests {
|
|||
.inputs(vec![Type::FieldElement])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
),
|
||||
String::from("id"),
|
||||
"id".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
|
@ -861,19 +862,19 @@ mod tests {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
let modules = vec![(String::from("main"), main), (String::from("id"), id)]
|
||||
let modules = vec![("main".into(), main), ("id".into(), id)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program: TypedProgram<FieldPrime> = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
let program = Inliner::inline(program);
|
||||
|
||||
let stack0 = vec![(
|
||||
String::from("id"),
|
||||
"id".into(),
|
||||
FunctionKey::with_id("main").signature(
|
||||
Signature::new()
|
||||
.inputs(vec![Type::FieldElement])
|
||||
|
@ -882,7 +883,7 @@ mod tests {
|
|||
1,
|
||||
)];
|
||||
let stack1 = vec![(
|
||||
String::from("id"),
|
||||
"id".into(),
|
||||
FunctionKey::with_id("main").signature(
|
||||
Signature::new()
|
||||
.inputs(vec![Type::FieldElement])
|
||||
|
@ -895,7 +896,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&String::from("main"))
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(
|
||||
|
|
|
@ -78,7 +78,7 @@ mod tests {
|
|||
|
||||
let p = TypedProgram {
|
||||
modules: vec![(
|
||||
"main".to_string(),
|
||||
"main".into(),
|
||||
TypedModule {
|
||||
functions: vec![(
|
||||
FunctionKey::with_id("main"),
|
||||
|
@ -94,7 +94,7 @@ mod tests {
|
|||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
main: "main".to_string(),
|
||||
main: "main".into(),
|
||||
};
|
||||
|
||||
assert!(PropagatedUnroller::unroll(p).is_err());
|
||||
|
@ -203,7 +203,7 @@ mod tests {
|
|||
|
||||
let p = TypedProgram {
|
||||
modules: vec![(
|
||||
"main".to_string(),
|
||||
"main".into(),
|
||||
TypedModule {
|
||||
functions: vec![(
|
||||
FunctionKey::with_id("main"),
|
||||
|
@ -219,11 +219,12 @@ mod tests {
|
|||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
main: "main".to_string(),
|
||||
main: "main".into(),
|
||||
};
|
||||
|
||||
let statements = match PropagatedUnroller::unroll(p).unwrap().modules["main"].functions
|
||||
[&FunctionKey::with_id("main")]
|
||||
let statements = match PropagatedUnroller::unroll(p).unwrap().modules
|
||||
[std::path::Path::new("main")]
|
||||
.functions[&FunctionKey::with_id("main")]
|
||||
.clone()
|
||||
{
|
||||
TypedFunctionSymbol::Here(f) => f.statements,
|
||||
|
|
|
@ -69,10 +69,10 @@ mod tests {
|
|||
);
|
||||
|
||||
let mut modules = HashMap::new();
|
||||
modules.insert(String::from("main"), TypedModule { functions });
|
||||
modules.insert("main".into(), TypedModule { functions });
|
||||
|
||||
let typed_ast: TypedProgram<FieldPrime> = TypedProgram {
|
||||
main: String::from("main"),
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ mod variable;
|
|||
pub use crate::typed_absy::parameter::Parameter;
|
||||
pub use crate::typed_absy::types::{Signature, Type};
|
||||
pub use crate::typed_absy::variable::Variable;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::typed_absy::types::{FunctionKey, MemberId};
|
||||
use embed::FlatEmbed;
|
||||
|
@ -38,7 +39,7 @@ pub struct Identifier<'ast> {
|
|||
}
|
||||
|
||||
/// An identifier for a `TypedModule`. Typically a path or uri.
|
||||
pub type TypedModuleId = String;
|
||||
pub type TypedModuleId = PathBuf;
|
||||
|
||||
/// A collection of `TypedModule`s
|
||||
pub type TypedModules<'ast, T> = HashMap<TypedModuleId, TypedModule<'ast, T>>;
|
||||
|
@ -90,7 +91,7 @@ impl<'ast, T: Field> fmt::Display for TypedProgram<'ast, T> {
|
|||
writeln!(
|
||||
f,
|
||||
"| {}: |{}",
|
||||
module_id,
|
||||
module_id.display(),
|
||||
if *module_id == self.main {
|
||||
"<---- main"
|
||||
} else {
|
||||
|
@ -123,7 +124,12 @@ impl<'ast> fmt::Display for Identifier<'ast> {
|
|||
"{}_{}_{}",
|
||||
self.stack
|
||||
.iter()
|
||||
.map(|(name, sig, count)| format!("{}_{}_{}", name, sig.to_slug(), count))
|
||||
.map(|(name, sig, count)| format!(
|
||||
"{}_{}_{}",
|
||||
name.display(),
|
||||
sig.to_slug(),
|
||||
count
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
self.id,
|
||||
|
@ -189,7 +195,10 @@ impl<'ast, T: Field> fmt::Display for TypedModule<'ast, T> {
|
|||
TypedFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function),
|
||||
TypedFunctionSymbol::There(ref fun_key, ref module_id) => format!(
|
||||
"import {} from \"{}\" as {} // with signature {}",
|
||||
fun_key.id, module_id, key.id, key.signature
|
||||
fun_key.id,
|
||||
module_id.display(),
|
||||
key.id,
|
||||
key.signature
|
||||
),
|
||||
TypedFunctionSymbol::Flat(ref flat_fun) => {
|
||||
format!("def {}{}:\n\t// hidden", key.id, flat_fun.signature::<T>())
|
||||
|
|
2
zokrates_core_test/tests/tests/import/dep/dep/foo.zok
Normal file
2
zokrates_core_test/tests/tests/import/dep/dep/foo.zok
Normal file
|
@ -0,0 +1,2 @@
|
|||
def foo() -> (field):
|
||||
return 1
|
4
zokrates_core_test/tests/tests/import/dep/foo.zok
Normal file
4
zokrates_core_test/tests/tests/import/dep/foo.zok
Normal file
|
@ -0,0 +1,4 @@
|
|||
from "./dep/foo" import foo as bar
|
||||
|
||||
def foo() -> (field):
|
||||
return 2 + bar()
|
15
zokrates_core_test/tests/tests/import/import.json
Normal file
15
zokrates_core_test/tests/tests/import/import.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/import/import.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["3"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
4
zokrates_core_test/tests/tests/import/import.zok
Normal file
4
zokrates_core_test/tests/tests/import/import.zok
Normal file
|
@ -0,0 +1,4 @@
|
|||
from "./dep/foo" import foo
|
||||
|
||||
def main() -> (field):
|
||||
return foo()
|
|
@ -6,43 +6,72 @@ use std::path::{Component, PathBuf};
|
|||
|
||||
const ZOKRATES_HOME: &str = &"ZOKRATES_HOME";
|
||||
|
||||
type CurrentLocation = String;
|
||||
type ImportLocation<'a> = String;
|
||||
// path to the current file we're importing into
|
||||
type CurrentLocation = PathBuf;
|
||||
// path we're importing from
|
||||
type ImportLocation<'a> = PathBuf;
|
||||
type SourceCode = String;
|
||||
|
||||
/// Returns the source code and the new location from a file path and import path
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `current_location` - Path to the file we're importing into
|
||||
/// * `import_location` - Path to the file we're importing from
|
||||
///
|
||||
/// # Returns
|
||||
/// * The content of the file we're importing from
|
||||
/// * The path to the file we're importing from
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// * `current_location* must point to a file
|
||||
/// * `import_location` and the returned path are both relative to the directory in which `current_location` is, unless it's an absolute
|
||||
/// path, in which case they are relative to the root of the ZoKrates stdlib at `$ZOKRATES_HOME`
|
||||
///
|
||||
pub fn resolve<'a>(
|
||||
current_location: CurrentLocation,
|
||||
import_location: ImportLocation<'a>,
|
||||
) -> Result<(SourceCode, CurrentLocation), io::Error> {
|
||||
let source = Path::new(&import_location);
|
||||
|
||||
if !current_location.is_file() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("{} was expected to be a file", current_location.display()),
|
||||
));
|
||||
}
|
||||
|
||||
// paths starting with `./` or `../` are interpreted relative to the current file
|
||||
// other paths `abc/def` are interpreted relative to $ZOKRATES_HOME
|
||||
let base = match source.components().next() {
|
||||
Some(Component::CurDir) | Some(Component::ParentDir) => PathBuf::from(current_location),
|
||||
_ => PathBuf::from(
|
||||
std::env::var(ZOKRATES_HOME).expect("$ZOKRATES_HOME is not set, please set it"),
|
||||
),
|
||||
};
|
||||
Some(Component::CurDir) | Some(Component::ParentDir) => {
|
||||
Ok(PathBuf::from(current_location).parent().unwrap().into())
|
||||
}
|
||||
_ => std::env::var(ZOKRATES_HOME)
|
||||
.map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"$ZOKRATES_HOME is not set, please set it",
|
||||
)
|
||||
})
|
||||
.map(PathBuf::from),
|
||||
}?;
|
||||
|
||||
let path_owned = base
|
||||
.join(PathBuf::from(import_location))
|
||||
.join(PathBuf::from(import_location.clone()))
|
||||
.with_extension("zok");
|
||||
|
||||
if path_owned.is_dir() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Not a file"));
|
||||
if !path_owned.is_file() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("No file found at {}", import_location.display()),
|
||||
));
|
||||
}
|
||||
|
||||
let next_location = generate_next_location(&path_owned)?;
|
||||
let source = read_to_string(path_owned)?;
|
||||
let source = read_to_string(&path_owned)?;
|
||||
|
||||
Ok((source, next_location))
|
||||
}
|
||||
|
||||
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())
|
||||
Ok((source, path_owned))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -52,39 +81,44 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn valid_path() {
|
||||
use std::io::Write;
|
||||
|
||||
// create a source folder with a zok file
|
||||
let folder = tempfile::tempdir().unwrap();
|
||||
let file_path = folder.path().join("bar.zok");
|
||||
let mut file = File::create(file_path).unwrap();
|
||||
writeln!(file, "some code").unwrap();
|
||||
let (_, next_location) =
|
||||
resolve(folder.path().to_str().unwrap().to_string(), "./bar".into()).unwrap();
|
||||
assert_eq!(next_location, folder.path().to_str().unwrap().to_string());
|
||||
File::create(file_path.clone()).unwrap();
|
||||
let (_, next_location) = resolve(file_path.clone(), "./bar.zok".into()).unwrap();
|
||||
assert_eq!(next_location, file_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_existing_file() {
|
||||
let res = resolve(String::from("./src"), "./rubbish".into());
|
||||
let res = resolve("./source.zok".into(), "./rubbish".into());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_location() {
|
||||
let res = resolve(String::from(",8!-$2abc"), "./foo".into());
|
||||
let res = resolve(",8!-$2abc".into(), "./foo".into());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_a_file() {
|
||||
let res = resolve(String::from("."), "./src/".into());
|
||||
// create a source folder with a zok file
|
||||
let folder = tempfile::tempdir().unwrap();
|
||||
let dir_path = folder.path().join("dir");
|
||||
std::fs::create_dir(dir_path.clone()).unwrap();
|
||||
|
||||
let res = resolve(".".into(), "./dir/".into());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_parent() {
|
||||
let res = resolve(String::from("."), ".".into());
|
||||
// create a source folder with a zok file
|
||||
let folder = tempfile::tempdir().unwrap();
|
||||
let file_path = folder.path().join("foo.zok");
|
||||
File::create(file_path.clone()).unwrap();
|
||||
let res = resolve(file_path, ".".into());
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
|
@ -101,20 +135,13 @@ mod tests {
|
|||
// create a user folder with a code file
|
||||
let source_folder = tempfile::tempdir().unwrap();
|
||||
let file_path = source_folder.path().join("bar.zok");
|
||||
let mut file = File::create(file_path).unwrap();
|
||||
let mut file = File::create(file_path.clone()).unwrap();
|
||||
writeln!(file, "<user code>").unwrap();
|
||||
|
||||
// assign HOME folder to ZOKRATES_HOME
|
||||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve(
|
||||
source_folder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
"./bar.zok".into(),
|
||||
);
|
||||
let result = resolve(file_path, "./bar.zok".into());
|
||||
assert!(result.is_ok());
|
||||
// the imported file should be the user's
|
||||
assert_eq!(result.unwrap().0, String::from("<user code>\n"));
|
||||
|
@ -133,20 +160,13 @@ mod tests {
|
|||
// create a user folder with a code file
|
||||
let source_folder = tempfile::tempdir().unwrap();
|
||||
let file_path = source_folder.path().join("bar.zok");
|
||||
let mut file = File::create(file_path).unwrap();
|
||||
let mut file = File::create(file_path.clone()).unwrap();
|
||||
writeln!(file, "<user code>").unwrap();
|
||||
|
||||
// assign HOME folder to ZOKRATES_HOME
|
||||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve(
|
||||
source_folder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
"bar.zok".into(),
|
||||
);
|
||||
let result = resolve(file_path.clone(), "bar.zok".into());
|
||||
assert!(result.is_ok());
|
||||
// the imported file should be the user's
|
||||
assert_eq!(result.unwrap().0, String::from("<stdlib code>\n"));
|
||||
|
@ -162,13 +182,11 @@ mod tests {
|
|||
let file_path = source_folder.path().join("bar.zok");
|
||||
let mut file = File::create(file_path).unwrap();
|
||||
writeln!(file, "<user code>").unwrap();
|
||||
let origin_path = source_subfolder.path().join("foo.zok");
|
||||
File::create(origin_path).unwrap();
|
||||
|
||||
let result = resolve(
|
||||
source_subfolder
|
||||
.path()
|
||||
.to_path_buf()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
source_subfolder.path().to_path_buf().join("foo.zok"),
|
||||
"../bar.zok".into(),
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
|
@ -189,21 +207,21 @@ mod tests {
|
|||
// assign HOME folder to ZOKRATES_HOME
|
||||
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
|
||||
|
||||
let result = resolve("/path/to/user/folder".to_string(), "./bar.zok".into());
|
||||
let result = resolve("/path/to/source.zok".into(), "./bar.zok".into());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_if_not_found_in_std() {
|
||||
std::env::set_var(ZOKRATES_HOME, "");
|
||||
let result = resolve("/path/to/source".to_string(), "bar.zok".into());
|
||||
let result = resolve("/path/to/source.zok".into(), "bar.zok".into());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn panic_if_home_not_set() {
|
||||
std::env::remove_var(ZOKRATES_HOME);
|
||||
let _ = resolve("/path/to/source".to_string(), "bar.zok".into());
|
||||
let result = resolve("/path/to/source.zok".into(), "bar.zok".into());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use bincode::{deserialize, serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::to_string_pretty;
|
||||
use std::path::PathBuf;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use zokrates_abi::{parse_strict, Encode, Decode, Inputs};
|
||||
use zokrates_core::compile::{compile as core_compile, CompilationArtifacts};
|
||||
use zokrates_core::compile::{compile as core_compile, CompilationArtifacts, CompileError};
|
||||
use zokrates_core::imports::Error;
|
||||
use zokrates_core::ir;
|
||||
use zokrates_core::proof_system::{self, ProofSystem};
|
||||
|
@ -30,8 +31,8 @@ pub struct ComputationResult {
|
|||
}
|
||||
|
||||
impl ResolverResult {
|
||||
fn into_tuple(self) -> (String, String) {
|
||||
(self.source, self.location)
|
||||
fn into_tuple(self) -> (String, PathBuf) {
|
||||
(self.source, PathBuf::from(self.location))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,30 +54,38 @@ pub fn compile(
|
|||
location: JsValue,
|
||||
resolve: &js_sys::Function,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
let closure = |l: String, p: String| {
|
||||
let closure = |l: PathBuf, p: PathBuf| {
|
||||
let value = resolve
|
||||
.call2(&JsValue::UNDEFINED, &l.into(), &p.clone().into())
|
||||
.call2(&JsValue::UNDEFINED, &l.display().to_string().into(), &p.clone().display().to_string().into())
|
||||
.map_err(|_| {
|
||||
Error::new(format!(
|
||||
"Error thrown in callback: Could not resolve `{}`",
|
||||
p
|
||||
p.display()
|
||||
))
|
||||
})?;
|
||||
|
||||
if value.is_null() || value.is_undefined() {
|
||||
Err(Error::new(format!("Could not resolve `{}`", p)))
|
||||
Err(Error::new(format!("Could not resolve `{}`", p.display())))
|
||||
} else {
|
||||
let result: ResolverResult = value.into_serde().unwrap();
|
||||
Ok(result.into_tuple())
|
||||
}
|
||||
};
|
||||
|
||||
let fmt_error = |e: &CompileError| {
|
||||
format!(
|
||||
"{}:{}",
|
||||
e.file().display(),
|
||||
e.value()
|
||||
)
|
||||
};
|
||||
|
||||
let artifacts: CompilationArtifacts<FieldPrime> = core_compile(
|
||||
source.as_string().unwrap(),
|
||||
location.as_string().unwrap(),
|
||||
PathBuf::from(location.as_string().unwrap()),
|
||||
Some(&closure),
|
||||
)
|
||||
.map_err(|ce| JsValue::from_str(&format!("{}", ce)))?;
|
||||
.map_err(|ce| JsValue::from_str(&format!("{}", ce.0.iter().map(|e| fmt_error(e)).collect::<Vec<_>>().join("\n"))))?;
|
||||
|
||||
let result = CompilationResult {
|
||||
program: serialize_program(artifacts.prog())?,
|
||||
|
|
|
@ -77,17 +77,7 @@ pub fn test_inner(test_path: &str) {
|
|||
|
||||
let code = std::fs::read_to_string(&t.entry_point).unwrap();
|
||||
|
||||
let artifacts = compile(
|
||||
code,
|
||||
t.entry_point
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
Some(&resolve),
|
||||
)
|
||||
.unwrap();
|
||||
let artifacts = compile(code, t.entry_point.clone(), Some(&resolve)).unwrap();
|
||||
|
||||
let bin = artifacts.prog();
|
||||
|
||||
|
|
Loading…
Reference in a new issue