FEATURE: Shared cache for all built ucg files.

This commit is contained in:
Jeremy Wall 2018-08-13 23:11:35 -05:00
parent f3e769095d
commit 9370fbe17e
10 changed files with 520 additions and 116 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
target
Cargo.lock
.vscode/settings.json

308
Cargo.lock generated Normal file
View File

@ -0,0 +1,308 @@
[[package]]
name = "ansi_term"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atty"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bencher"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cpuprofiler"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "error-chain"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nom_locate"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_json"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "term_size"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucg"
version = "0.1.5"
dependencies = [
"bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nom_locate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e"
"checksum bencher 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "33f07976bb6821459632d7a18d97ccca005cb5c552f251f822c7c1781c1d7035"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143"
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum nom_locate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49b1c61eff39ab6b91ccedfc62aff196eae066d88355b4fe3e4100c23168f0df"
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95"
"checksum serde_json 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "eb40600c756f02d7ea34943626cefa85732fdae5f95b90b31f9797b3c526d1e6"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

1
examples/shared.ucg Normal file
View File

@ -0,0 +1 @@
let port = 3306;

View File

@ -1,3 +1,5 @@
import "shared.ucg" as shared;
// A few constants.
let dbhost1 = "db1.prod.net";
let dbhost2 = "db2.prod.net";
@ -11,8 +13,8 @@ let mk_db_conn = macro (host, port, db) => {
conn_string = "@:@/@" % (host, port, db)
};
let db_conn1 = mk_db_conn(dbhost1, 3306, dbname);
let db_conn2 = mk_db_conn(dbhost2, 3306, dbname);
let db_conn1 = mk_db_conn(dbhost1, shared.port, dbname);
let db_conn2 = mk_db_conn(dbhost2, shared.port, dbname);
// We have two database connections in a list
let db_conn_list = [db_conn1, db_conn2];

68
src/build/assets.rs Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The asset cache for the ucg compiler.
use std::collections::HashMap;
use std::io;
use std::path::PathBuf;
use std::rc::Rc;
use std::result;
use super::Val;
pub type Result<T> = result::Result<T, io::Error>;
/// Defines the cach interface for a UCG build. It has functions to retrieve
/// An asset for a referenced ucg file if it exists as well as to stash
/// an asset for a built ucg file.
///
/// All methods with a path do path canonicalization. As a result the path
/// is expected to exist on the filesystem. If the path does not exist on
/// the local filesystem then the Cache may return an error.
pub trait Cache {
fn has_path(&self, path: &PathBuf) -> Result<bool>;
fn get(&self, path: &PathBuf) -> Result<Option<Rc<Val>>>;
fn stash(&mut self, path: PathBuf, asset: Rc<Val>) -> Result<()>;
}
pub struct MemoryCache {
map: HashMap<PathBuf, Rc<Val>>,
}
impl MemoryCache {
pub fn new() -> Self {
MemoryCache {
map: HashMap::new(),
}
}
}
impl Cache for MemoryCache {
fn has_path(&self, path: &PathBuf) -> Result<bool> {
let new_path = try!(path.canonicalize());
Ok(self.map.contains_key(&new_path))
}
fn get(&self, path: &PathBuf) -> Result<Option<Rc<Val>>> {
let new_path = try!(path.canonicalize());
Ok(self.map.get(&new_path).map(|v| v.clone()))
}
fn stash(&mut self, path: PathBuf, asset: Rc<Val>) -> Result<()> {
let new_path = try!(path.canonicalize());
self.map.insert(new_path, asset);
Ok(())
}
}

View File

@ -12,10 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::cell::RefCell;
use std::rc::Rc;
use super::assets::MemoryCache;
use super::Builder;
fn assert_build(input: &str) {
let mut b = Builder::new("<Eval>");
let cache = MemoryCache::new();
let mut b = Builder::new("<Eval>", Rc::new(RefCell::new(cache)));
b.enable_validate_mode();
b.eval_string(input).unwrap();
if !b.assert_collector.success {

View File

@ -13,8 +13,9 @@
// limitations under the License.
//! The build stage of the ucg compiler.
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet, VecDeque};
use std::collections::{HashMap, VecDeque};
use std::convert::From;
use std::env;
use std::error::Error;
@ -33,11 +34,14 @@ use format;
use parse::parse;
use tokenizer::Span;
pub mod assets;
impl MacroDef {
/// Expands a ucg Macro using the given arguments into a new Tuple.
pub fn eval(
&self,
root: PathBuf,
cache: Rc<RefCell<assets::Cache>>,
env: Rc<Val>,
mut args: Vec<Rc<Val>>,
) -> Result<Vec<(Positioned<String>, Rc<Val>)>, Box<Error>> {
@ -61,7 +65,7 @@ impl MacroDef {
for (i, arg) in args.drain(0..).enumerate() {
scope.entry(self.argdefs[i].clone()).or_insert(arg.clone());
}
let b = Builder::new_with_env_and_scope(root, scope, env);
let b = Builder::new_with_env_and_scope(root, cache, scope, env);
let mut result: Vec<(Positioned<String>, Rc<Val>)> = Vec::new();
for &(ref key, ref expr) in self.fields.iter() {
// We clone the expressions here because this macro may be consumed
@ -299,13 +303,18 @@ pub struct Builder {
validate_mode: bool,
assert_collector: AssertCollector,
env: Rc<Val>,
/// assets are other parsed files from import statements. They
/// are keyed by the normalized import path. This acts as a cache
// NOTE(jwall): We use interior mutability here because we need
// our asset cache to be shared by multiple different sub-builders.
// We use Rc to handle the reference counting for us and we use
// RefCell to give us interior mutability. This sacrifices our
// compile time memory safety for runtime checks. However it's
// acceptable in this case since I can't figure out a better way to
// handle it.
/// The assets are other parsed files from import statements. They
/// are keyed by the canonicalized import path. This acts as a cache
/// so multiple imports of the same file don't have to be parsed
/// multiple times.
assets: ValueMap,
// List of file paths we have already parsed.
files: HashSet<String>,
assets: Rc<RefCell<assets::Cache>>,
/// build_output is our built output.
build_output: ValueMap,
/// last is the result of the last statement.
@ -377,20 +386,25 @@ impl Builder {
}
/// Constructs a new Builder.
pub fn new<P: Into<PathBuf>>(root: P) -> Self {
Self::new_with_scope(root, HashMap::new())
pub fn new<P: Into<PathBuf>>(root: P, cache: Rc<RefCell<assets::Cache>>) -> Self {
Self::new_with_scope(root, cache, HashMap::new())
}
/// Constructs a new Builder with a provided scope.
pub fn new_with_scope<P: Into<PathBuf>>(root: P, scope: ValueMap) -> Self {
pub fn new_with_scope<P: Into<PathBuf>>(
root: P,
cache: Rc<RefCell<assets::Cache>>,
scope: ValueMap,
) -> Self {
let env_vars: Vec<(Positioned<String>, Rc<Val>)> = env::vars()
.map(|t| (Positioned::new(t.0, 0, 0), Rc::new(t.1.into())))
.collect();
Self::new_with_env_and_scope(root, scope, Rc::new(Val::Tuple(env_vars)))
Self::new_with_env_and_scope(root, cache, scope, Rc::new(Val::Tuple(env_vars)))
}
pub fn new_with_env_and_scope<P: Into<PathBuf>>(
root: P,
cache: Rc<RefCell<assets::Cache>>,
scope: ValueMap,
env: Rc<Val>,
) -> Self {
@ -403,8 +417,7 @@ impl Builder {
failures: String::new(),
},
env: env,
assets: HashMap::new(),
files: HashSet::new(),
assets: cache,
build_output: scope,
out_lock: None,
last: None,
@ -460,6 +473,7 @@ impl Builder {
/// Builds a ucg file at the named path.
pub fn build_file(&mut self, name: &str) -> BuildResult {
eprintln!("building ucg file {}", name);
let mut f = try!(File::open(name));
let mut s = String::new();
try!(f.read_to_string(&mut s));
@ -469,40 +483,23 @@ impl Builder {
fn build_import(&mut self, def: &ImportDef) -> Result<Rc<Val>, Box<Error>> {
let sym = &def.name;
let positioned_sym = sym.into();
let mut normalized = self.root.to_path_buf();
normalized.push(&def.path.fragment);
let key = normalized.to_str().unwrap().to_string();
if !self.files.contains(&key) {
// Only parse the file once on import.
if self.assets.get(&positioned_sym).is_none() {
// FIXME(jwall): We should be sharing our assets collection.
let mut b = Self::new(normalized);
try!(b.build_file(&def.path.fragment));
let fields: Vec<(Positioned<String>, Rc<Val>)> = b.build_output.drain().collect();
let result = Rc::new(Val::Tuple(fields));
self.assets.entry(positioned_sym).or_insert(result.clone());
self.files.insert(def.path.fragment.clone());
return Ok(result);
} else {
return Ok(self.assets.get(&positioned_sym).unwrap().clone());
}
} else {
return match self.assets.get(&positioned_sym) {
None => {
// some kind of error here I think.
Err(Box::new(error::Error::new(
format!(
"Unknown Error processing import in file: {}",
self.root.to_string_lossy()
),
error::ErrorType::Unsupported,
def.name.pos.clone(),
)))
}
Some(val) => Ok(val.clone()),
};
eprintln!("processing import for {}", normalized.to_string_lossy());
// Only parse the file once on import.
let mut shared_assets = self.assets.borrow_mut();
if try!(shared_assets.get(&normalized)).is_some() {
return Ok(try!(shared_assets.get(&normalized)).unwrap().clone());
}
let mut b = Self::new(normalized.clone(), self.assets.clone());
let filepath = normalized.to_str().unwrap().clone();
try!(b.build_file(filepath));
let fields: Vec<(Positioned<String>, Rc<Val>)> = b.build_output.drain().collect();
let result = Rc::new(Val::Tuple(fields));
//eprintln!("storing sym {:?} results {:?} ", sym, result)
self.build_output.insert(sym.into(), result.clone());
try!(shared_assets.stash(normalized.clone(), result.clone()));
return Ok(result);
}
fn build_let(&mut self, def: &LetDef) -> Result<Rc<Val>, Box<Error>> {
@ -512,7 +509,7 @@ impl Builder {
Entry::Occupied(e) => {
return Err(Box::new(error::Error::new(
format!(
"Let binding \
"Binding \
for {:?} already \
exists in file: {}",
e.key(),
@ -560,9 +557,6 @@ impl Builder {
if self.build_output.contains_key(sym) {
return Some(self.build_output[sym].clone());
}
if self.assets.contains_key(sym) {
return Some(self.assets[sym].clone());
}
None
}
@ -822,9 +816,11 @@ impl Builder {
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<Error>> {
Ok(Rc::new(Val::Boolean(try!(
left.equal(right.as_ref(), &self.root.to_string_lossy(), pos.clone())
))))
Ok(Rc::new(Val::Boolean(try!(left.equal(
right.as_ref(),
&self.root.to_string_lossy(),
pos.clone()
)))))
}
fn do_not_deep_equal(
@ -833,9 +829,11 @@ impl Builder {
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<Error>> {
Ok(Rc::new(Val::Boolean(!try!(
left.equal(right.as_ref(), &self.root.to_string_lossy(), pos.clone())
))))
Ok(Rc::new(Val::Boolean(!try!(left.equal(
right.as_ref(),
&self.root.to_string_lossy(),
pos.clone()
)))))
}
fn do_gt(&self, pos: &Position, left: Rc<Val>, right: Rc<Val>) -> Result<Rc<Val>, Box<Error>> {
@ -1064,7 +1062,12 @@ impl Builder {
for arg in args.iter() {
argvals.push(try!(self.eval_expr(arg)));
}
let fields = try!(m.eval(self.root.clone(), self.env.clone(), argvals));
let fields = try!(m.eval(
self.root.clone(),
self.assets.clone(),
self.env.clone(),
argvals
));
return Ok(Rc::new(Val::Tuple(fields)));
}
Err(Box::new(error::Error::new(
@ -1127,7 +1130,12 @@ impl Builder {
let mut out = Vec::new();
for expr in l.iter() {
let argvals = vec![try!(self.eval_expr(expr))];
let fields = try!(macdef.eval(self.root.clone(), self.env.clone(), argvals));
let fields = try!(macdef.eval(
self.root.clone(),
self.assets.clone(),
self.env.clone(),
argvals
));
if let Some(v) = Self::find_in_fieldlist(&def.field, &fields) {
match def.typ {
ListOpType::Map => {

View File

@ -11,10 +11,12 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::assets::MemoryCache;
use super::{Builder, CallDef, MacroDef, SelectDef, Val};
use ast::*;
use std;
use std::cell::RefCell;
use std::rc::Rc;
fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: Builder) {
@ -25,7 +27,8 @@ fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, b: Builder) {
#[test]
fn test_eval_div_expr() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![
(
@ -54,7 +57,8 @@ fn test_eval_div_expr() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_div_expr_fail() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -71,7 +75,8 @@ fn test_eval_div_expr_fail() {
#[test]
fn test_eval_mul_expr() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![
(
@ -100,7 +105,8 @@ fn test_eval_mul_expr() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_mul_expr_fail() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -117,7 +123,8 @@ fn test_eval_mul_expr_fail() {
#[test]
fn test_eval_subtract_expr() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![
(
@ -146,7 +153,8 @@ fn test_eval_subtract_expr() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_subtract_expr_fail() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -163,7 +171,8 @@ fn test_eval_subtract_expr_fail() {
#[test]
fn test_eval_add_expr() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![
(
@ -235,7 +244,8 @@ fn test_eval_add_expr() {
#[test]
#[should_panic(expected = "Expected Float")]
fn test_eval_add_expr_fail() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -327,7 +337,10 @@ fn test_eval_nested_tuple() {
)]),
),
],
Builder::new(std::env::current_dir().unwrap()),
Builder::new(
std::env::current_dir().unwrap(),
Rc::new(RefCell::new(MemoryCache::new())),
),
);
}
@ -362,13 +375,17 @@ fn test_eval_simple_expr() {
)]),
),
],
Builder::new(std::env::current_dir().unwrap()),
Builder::new(
std::env::current_dir().unwrap(),
Rc::new(RefCell::new(MemoryCache::new())),
),
);
}
#[test]
fn test_eval_simple_lookup_expr() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("var1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Int(1)));
@ -383,7 +400,8 @@ fn test_eval_simple_lookup_expr() {
#[test]
fn test_eval_simple_lookup_error() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("var1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Int(1)));
@ -393,7 +411,8 @@ fn test_eval_simple_lookup_error() {
#[test]
fn test_eval_selector_expr() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("var1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Tuple(vec![(
@ -457,7 +476,8 @@ fn test_eval_selector_expr() {
#[test]
fn test_eval_selector_list_expr() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("var1".to_string(), 1, 1))
.or_insert(Rc::new(Val::List(vec![
@ -484,7 +504,8 @@ fn test_eval_selector_list_expr() {
#[test]
#[should_panic(expected = "Unable to find tpl1")]
fn test_expr_copy_no_such_tuple() {
let b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let b = Builder::new(std::env::current_dir().unwrap(), cache);
test_expr_to_val(
vec![(
Expression::Copy(CopyDef {
@ -501,7 +522,8 @@ fn test_expr_copy_no_such_tuple() {
#[test]
#[should_panic(expected = "Expected Tuple got Int(1)")]
fn test_expr_copy_not_a_tuple() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("tpl1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Int(1)));
@ -521,7 +543,8 @@ fn test_expr_copy_not_a_tuple() {
#[test]
#[should_panic(expected = "Expected type Integer for field fld1 but got String")]
fn test_expr_copy_field_type_error() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("tpl1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Tuple(vec![(
@ -549,7 +572,8 @@ fn test_expr_copy_field_type_error() {
#[test]
fn test_expr_copy() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("tpl1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Tuple(vec![(
@ -620,7 +644,8 @@ fn test_expr_copy() {
#[test]
fn test_macro_call() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("tstmac".to_string(), 1, 0))
.or_insert(Rc::new(Val::Macro(MacroDef {
@ -654,7 +679,8 @@ fn test_macro_call() {
#[test]
#[should_panic(expected = "Unable to find arg1")]
fn test_macro_hermetic() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("arg1".to_string(), 1, 0))
.or_insert(Rc::new(Val::Str("bar".to_string())));
@ -690,7 +716,8 @@ fn test_macro_hermetic() {
#[test]
fn test_select_expr() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("foo".to_string(), 1, 0))
.or_insert(Rc::new(Val::Str("bar".to_string())));
@ -752,7 +779,8 @@ fn test_select_expr() {
#[test]
#[should_panic(expected = "Expected String but got Integer in Select expression")]
fn test_select_expr_not_a_string() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.build_output
.entry(value_node!("foo".to_string(), 1, 0))
.or_insert(Rc::new(Val::Int(4)));
@ -785,7 +813,8 @@ fn test_select_expr_not_a_string() {
#[test]
fn test_let_statement() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = MemoryCache::new();
let mut b = Builder::new("<Eval>", Rc::new(RefCell::new(cache)));
let stmt = Statement::Let(LetDef {
name: make_tok!("foo", 1, 1),
value: Expression::Simple(Value::Str(value_node!("bar".to_string(), 1, 1))),
@ -802,35 +831,9 @@ fn test_let_statement() {
#[test]
fn test_build_file_string() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
b.eval_string("let foo = 1;").unwrap();
let key = value_node!("foo".to_string(), 1, 0);
assert!(b.build_output.contains_key(&key));
}
#[test]
fn test_asset_symbol_lookups() {
let mut b = Builder::new(std::env::current_dir().unwrap());
b.assets
.entry(value_node!("foo".to_string(), 1, 0))
.or_insert(Rc::new(Val::Tuple(vec![(
value_node!("bar".to_string(), 1, 0),
Rc::new(Val::Tuple(vec![(
value_node!("quux".to_string(), 1, 0),
Rc::new(Val::Int(1)),
)])),
)])));
test_expr_to_val(
vec![(
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), 1, 1))),
Val::Tuple(vec![(
value_node!("bar".to_string(), 1, 0),
Rc::new(Val::Tuple(vec![(
value_node!("quux".to_string(), 1, 0),
Rc::new(Val::Int(1)),
)])),
)]),
)],
b,
);
}

View File

@ -190,14 +190,18 @@ impl Converter for ExecConverter {
#[cfg(test)]
mod exec_test {
use super::*;
use build::assets::MemoryCache;
use build::Builder;
use convert::traits::Converter;
use std;
use std::cell::RefCell;
use std::io::Cursor;
#[test]
fn convert_just_command_test() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -216,7 +220,8 @@ mod exec_test {
#[test]
fn convert_command_with_env_test() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -242,7 +247,8 @@ mod exec_test {
#[test]
fn convert_command_with_arg_test() {
let mut b = Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
let conv = ExecConverter::new();
b.eval_string(
"let script = {

View File

@ -15,6 +15,7 @@
extern crate clap;
extern crate ucglib;
use std::cell::RefCell;
use std::fs::File;
use std::io;
use std::path::PathBuf;
@ -22,6 +23,7 @@ use std::process;
use std::rc::Rc;
use ucglib::build;
use ucglib::build::assets::MemoryCache;
use ucglib::build::Val;
use ucglib::convert::traits;
use ucglib::convert::ConverterRunner;
@ -63,7 +65,8 @@ fn main() {
let sym = matches.value_of("sym");
let target = matches.value_of("target").unwrap();
let root = PathBuf::from(file);
let mut builder = build::Builder::new(root);
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut builder = build::Builder::new(root.parent().unwrap(), cache);
match ConverterRunner::new(target) {
Ok(converter) => {
let result = builder.build_file(file);
@ -94,7 +97,8 @@ fn main() {
}
} else if let Some(matches) = app.subcommand_matches("validate") {
let file = matches.value_of("INPUT").unwrap();
let mut builder = build::Builder::new(std::env::current_dir().unwrap());
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let mut builder = build::Builder::new(std::env::current_dir().unwrap(), cache);
builder.enable_validate_mode();
builder.build_file(file).unwrap();
println!("File Validates");