diff --git a/Cargo.lock b/Cargo.lock index b18a13c..d445bb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,6 +224,14 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ucg" version = "0.2.3" @@ -235,6 +243,7 @@ dependencies = [ "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "simple-error 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -316,6 +325,7 @@ dependencies = [ "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 toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" "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" diff --git a/Cargo.toml b/Cargo.toml index dd2fc2d..4bc48b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ clap = "~2.26.0" serde_json = "~1.0.9" simple-error = "0.1" serde_yaml = "~0.8.1" +toml = "~0.4.8" [dev-dependencies] bencher = "~0.1.5" diff --git a/examples/test_toml.ucg b/examples/test_toml.ucg new file mode 100644 index 0000000..1a50e64 --- /dev/null +++ b/examples/test_toml.ucg @@ -0,0 +1,12 @@ +let config = { + format = "toml", + app = { + name = "app", + version = "v0.0.0", + }, + metadata = { + tags = ["foo", "bar"], + }, +}; + +out toml config; \ No newline at end of file diff --git a/src/convert/mod.rs b/src/convert/mod.rs index 96837d4..259f1a8 100644 --- a/src/convert/mod.rs +++ b/src/convert/mod.rs @@ -17,6 +17,7 @@ pub mod env; pub mod exec; pub mod flags; pub mod json; +pub mod toml; pub mod traits; pub mod yaml; @@ -47,6 +48,7 @@ impl ConverterRegistry { registry.register("flags", Box::new(flags::FlagConverter::new())); registry.register("exec", Box::new(exec::ExecConverter::new())); registry.register("yaml", Box::new(yaml::YamlConverter::new())); + registry.register("toml", Box::new(toml::TomlConverter::new())); registry } diff --git a/src/convert/toml.rs b/src/convert/toml.rs new file mode 100644 index 0000000..c15b8cb --- /dev/null +++ b/src/convert/toml.rs @@ -0,0 +1,94 @@ +// Copyright 2018 Jeremy Wall +// +// 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. + +use std; +use std::error; +use std::io::Write; +use std::rc::Rc; + +use simple_error::SimpleError; +use toml; + +use ast; +use build::Val; +use convert::traits::{Converter, Result}; + +pub struct TomlConverter {} + +type ConvertResult = std::result::Result>; + +impl TomlConverter { + pub fn new() -> Self { + TomlConverter {} + } + + fn convert_list(&self, items: &Vec>) -> ConvertResult { + let mut v = Vec::new(); + for val in items.iter() { + v.push(try!(self.convert_value(val))); + } + Ok(toml::Value::Array(v)) + } + + fn convert_tuple(&self, items: &Vec<(ast::PositionedItem, Rc)>) -> ConvertResult { + let mut mp = toml::value::Table::new(); + for &(ref k, ref v) in items.iter() { + mp.entry(k.val.clone()) + .or_insert(try!(self.convert_value(v))); + } + Ok(toml::Value::Table(mp)) + } + + fn convert_value(&self, v: &Val) -> ConvertResult { + let toml_val = match v { + &Val::Boolean(b) => toml::Value::Boolean(b), + // TODO(jwall): This is an error apparently + &Val::Empty => { + let err = SimpleError::new("Nulls are not allowed in Toml Conversions!"); + return Err(Box::new(err)); + } + &Val::Float(f) => toml::Value::Float(f), + &Val::Int(i) => toml::Value::Integer(i), + &Val::Str(ref s) => toml::Value::String(s.clone()), + &Val::Macro(_) => { + let err = SimpleError::new("Macros are not allowed in Toml Conversions!"); + return Err(Box::new(err)); + } + &Val::List(ref l) => try!(self.convert_list(l)), + &Val::Tuple(ref t) => try!(self.convert_tuple(t)), + }; + Ok(toml_val) + } + + fn write(&self, v: &Val, w: &mut Write) -> Result { + let toml_val = try!(self.convert_value(v)); + let toml_bytes = try!(toml::ser::to_string_pretty(&toml_val)); + try!(write!(w, "{}", toml_bytes)); + Ok(()) + } +} + +impl Converter for TomlConverter { + fn convert(&self, v: Rc, mut w: &mut Write) -> Result { + self.write(&v, &mut w) + } + + fn file_ext(&self) -> String { + String::from("toml") + } + + fn description(&self) -> String { + "Convert ucg Vals into valid ucg.".to_string() + } +} diff --git a/src/lib.rs b/src/lib.rs index 33b9d4f..8e2d698 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ //! //! ## Syntax //! -//! A valid ucg file is composesed of a series of statements. Stataments start with an +//! A valid ucg file is composed of a series of statements. Statements start with an //! optional keyword and terminate with a semicolon. //! //! ### Reserved words @@ -488,6 +488,7 @@ extern crate abortable_parser; extern crate serde_json; extern crate serde_yaml; extern crate simple_error; +extern crate toml; #[macro_use] pub mod ast;