Add json as an output type.

* Uses serde_json
* Doesn't handle macro values very well.
* Handles maps and lists just fine.
* doesn't pretty print the values though.
This commit is contained in:
Jeremy Wall 2018-02-04 16:08:30 -06:00
parent 97c97ced55
commit 5fba06d71f
7 changed files with 101 additions and 6 deletions

View File

@ -14,6 +14,7 @@ version = "^3.2"
[dependencies]
nom_locate = "^0.1.1"
clap = "~2.26.0"
serde_json = "~1.0.9"
[lib]
name = "ucglib"

View File

@ -5,11 +5,12 @@
You should be able to ask the compiler to tell you any value or set of values in the
compiled configuration.
## Translation Language (Experiemental)
## Translation Language (Experimental)
For some configuration file formats we need a way to specify a particular
organiztion for a given configuration structure. Some options here could be
* Simple data export (json)
* A Functional Transform similar to xslt or css transforms.
* A Templating language
* Annotations.

View File

@ -25,9 +25,7 @@ impl FlagConverter {
pub fn new() -> Self {
FlagConverter {}
}
}
impl FlagConverter {
fn write(&self, v: &Val, w: &mut Write) -> Result<()> {
match v {
&Val::Float(ref f) => {
@ -45,6 +43,10 @@ impl FlagConverter {
}
&Val::Tuple(ref flds) => {
for &(ref name, ref val) in flds.iter() {
if val.is_tuple() {
eprintln!("Skipping embedded tuple...");
return Ok(());
}
try!(write!(w, "--{} ", name.val));
// TODO(jwall): What if the value is a tuple?
try!(self.write(&val, w));
@ -61,6 +63,6 @@ impl FlagConverter {
impl Converter for FlagConverter {
fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> Result<()> {
return self.write(&v, &mut w);
self.write(&v, &mut w)
}
}

86
src/convert/json.rs Normal file
View File

@ -0,0 +1,86 @@
// 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::rc::Rc;
use std::io::Write;
use std::io::Result;
use serde_json;
use ast;
use build::Val;
use convert::traits::Converter;
pub struct JsonConverter {}
impl JsonConverter {
pub fn new() -> Self {
JsonConverter {}
}
fn convert_list(&self, items: &Vec<Rc<Val>>) -> Result<serde_json::Value> {
let mut v = Vec::new();
for val in items.iter() {
v.push(try!(self.convert_value(val)));
}
Ok(serde_json::Value::Array(v))
}
fn convert_tuple(&self, items: &Vec<(ast::Positioned<String>, Rc<Val>)>) -> Result<serde_json::Value> {
let mut mp = serde_json::Map::new();
for &(ref k, ref v) in items.iter() {
mp.entry(k.val.clone()).or_insert(try!(self.convert_value(v)));
}
Ok(serde_json::Value::Object(mp))
}
fn convert_value(&self, v: &Val) -> Result<serde_json::Value> {
let jsn_val = match v {
&Val::Float(f) => {
let n = match serde_json::Number::from_f64(f) {
Some(n) => n,
// In theory this should never happen. But on the off chance that it does...
None => panic!("Float is too large or Not a Number {}", f),
};
serde_json::Value::Number(n)
},
&Val::Int(i) => {
let n = match serde_json::Number::from_f64(i as f64) {
Some(n) => n,
// In theory this should never happen. But on the off chance that it does...
None => panic!("Float is too large or Not a Number {}", i),
};
serde_json::Value::Number(n)
},
&Val::String(ref s) => serde_json::Value::String(s.clone()),
&Val::Macro(_) => {
// TODO(jwall): We probably want to actually skip this but for now
// we'll use null
eprintln!("Skipping macro encoding as null...");
serde_json::Value::Null
},
&Val::List(ref l) => try!(self.convert_list(l)),
&Val::Tuple(ref t) => try!(self.convert_tuple(t)),
};
Ok(jsn_val)
}
fn write(&self, v: &Val, w: &mut Write) -> Result<()> {
let jsn_val = try!(self.convert_value(v));
try!(serde_json::to_writer(w, &jsn_val));
Ok(())
}
}
impl Converter for JsonConverter {
fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> Result<()> {
self.write(&v, &mut w)
}
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod flags;
pub mod json;
pub mod traits;
use std::io;
@ -29,6 +30,9 @@ impl ConverterRunner {
if typ == "flags" {
return Ok(ConverterRunner { converter: Box::new(flags::FlagConverter::new()) });
}
if typ == "json" {
return Ok(ConverterRunner { converter: Box::new(json::JsonConverter::new()) });
}
return Err(format!("Unknown Target output type: {}", typ));
}

View File

@ -17,6 +17,7 @@
extern crate nom;
#[macro_use]
extern crate nom_locate;
extern crate serde_json;
#[macro_use]
pub mod ast;

View File

@ -34,7 +34,7 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> {
(@subcommand build =>
(about: "Compile a specific ucg file.")
(@arg sym: --sym +takes_value "Specify a specific let binding in the ucg file to output.")
(@arg target: --target -t +required +takes_value "Target output type.")
(@arg target: --target -t +required +takes_value "Target output type. (flags, json)")
(@arg out: --out -o +takes_value "Output file to write to.")
(@arg INPUT: +required "Input ucg file to build.")
)