mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
Add Boolean types.
This commit is contained in:
parent
eeac1ba599
commit
bfde2c5238
@ -87,6 +87,7 @@ impl Position {
|
|||||||
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
EMPTY,
|
EMPTY,
|
||||||
|
BOOLEAN,
|
||||||
END,
|
END,
|
||||||
WS,
|
WS,
|
||||||
COMMENT,
|
COMMENT,
|
||||||
@ -330,6 +331,7 @@ impl SelectorDef {
|
|||||||
pub enum Value {
|
pub enum Value {
|
||||||
// Constant Values
|
// Constant Values
|
||||||
Empty(Position),
|
Empty(Position),
|
||||||
|
Boolean(Positioned<bool>),
|
||||||
Int(Positioned<i64>),
|
Int(Positioned<i64>),
|
||||||
Float(Positioned<f64>),
|
Float(Positioned<f64>),
|
||||||
String(Positioned<String>),
|
String(Positioned<String>),
|
||||||
@ -345,6 +347,7 @@ impl Value {
|
|||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Value::Empty(_) => "EmptyValue".to_string(),
|
&Value::Empty(_) => "EmptyValue".to_string(),
|
||||||
|
&Value::Boolean(_) => "Boolean".to_string(),
|
||||||
&Value::Int(_) => "Integer".to_string(),
|
&Value::Int(_) => "Integer".to_string(),
|
||||||
&Value::Float(_) => "Float".to_string(),
|
&Value::Float(_) => "Float".to_string(),
|
||||||
&Value::String(_) => "String".to_string(),
|
&Value::String(_) => "String".to_string(),
|
||||||
@ -375,6 +378,7 @@ impl Value {
|
|||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Value::Empty(_) => "EmptyValue".to_string(),
|
&Value::Empty(_) => "EmptyValue".to_string(),
|
||||||
|
&Value::Boolean(ref b) => format!("{}", b.val),
|
||||||
&Value::Int(ref i) => format!("{}", i.val),
|
&Value::Int(ref i) => format!("{}", i.val),
|
||||||
&Value::Float(ref f) => format!("{}", f.val),
|
&Value::Float(ref f) => format!("{}", f.val),
|
||||||
&Value::String(ref s) => format!("{}", s.val),
|
&Value::String(ref s) => format!("{}", s.val),
|
||||||
@ -389,6 +393,7 @@ impl Value {
|
|||||||
pub fn pos(&self) -> &Position {
|
pub fn pos(&self) -> &Position {
|
||||||
match self {
|
match self {
|
||||||
&Value::Empty(ref pos) => pos,
|
&Value::Empty(ref pos) => pos,
|
||||||
|
&Value::Boolean(ref b) => &b.pos,
|
||||||
&Value::Int(ref i) => &i.pos,
|
&Value::Int(ref i) => &i.pos,
|
||||||
&Value::Float(ref f) => &f.pos,
|
&Value::Float(ref f) => &f.pos,
|
||||||
&Value::String(ref s) => &s.pos,
|
&Value::String(ref s) => &s.pos,
|
||||||
@ -405,6 +410,7 @@ impl Value {
|
|||||||
self,
|
self,
|
||||||
target,
|
target,
|
||||||
&Value::Empty(_),
|
&Value::Empty(_),
|
||||||
|
&Value::Boolean(_),
|
||||||
&Value::Int(_),
|
&Value::Int(_),
|
||||||
&Value::Float(_),
|
&Value::Float(_),
|
||||||
&Value::String(_),
|
&Value::String(_),
|
||||||
|
@ -73,6 +73,7 @@ type BuildResult = Result<(), Box<Error>>;
|
|||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub enum Val {
|
pub enum Val {
|
||||||
Empty,
|
Empty,
|
||||||
|
Boolean(bool),
|
||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
String(String),
|
String(String),
|
||||||
@ -86,6 +87,7 @@ impl Val {
|
|||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Val::Empty => "EmptyValue".to_string(),
|
&Val::Empty => "EmptyValue".to_string(),
|
||||||
|
&Val::Boolean(_) => "Boolean".to_string(),
|
||||||
&Val::Int(_) => "Integer".to_string(),
|
&Val::Int(_) => "Integer".to_string(),
|
||||||
&Val::Float(_) => "Float".to_string(),
|
&Val::Float(_) => "Float".to_string(),
|
||||||
&Val::String(_) => "String".to_string(),
|
&Val::String(_) => "String".to_string(),
|
||||||
@ -101,6 +103,7 @@ impl Val {
|
|||||||
self,
|
self,
|
||||||
target,
|
target,
|
||||||
&Val::Empty,
|
&Val::Empty,
|
||||||
|
&Val::Boolean(_),
|
||||||
&Val::Int(_),
|
&Val::Int(_),
|
||||||
&Val::Float(_),
|
&Val::Float(_),
|
||||||
&Val::String(_),
|
&Val::String(_),
|
||||||
@ -172,6 +175,7 @@ impl Val {
|
|||||||
impl Display for Val {
|
impl Display for Val {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
&Val::Boolean(b) => write!(f, "Boolean({})", b),
|
||||||
&Val::Empty => write!(f, "EmptyValue"),
|
&Val::Empty => write!(f, "EmptyValue"),
|
||||||
&Val::Float(ref ff) => write!(f, "Float({})", ff),
|
&Val::Float(ref ff) => write!(f, "Float({})", ff),
|
||||||
&Val::Int(ref i) => write!(f, "Int({})", i),
|
&Val::Int(ref i) => write!(f, "Int({})", i),
|
||||||
@ -267,6 +271,7 @@ impl Builder {
|
|||||||
fn value_to_val(&self, v: &Value) -> Result<Rc<Val>, Box<Error>> {
|
fn value_to_val(&self, v: &Value) -> Result<Rc<Val>, Box<Error>> {
|
||||||
match v {
|
match v {
|
||||||
&Value::Empty(_) => Ok(Rc::new(Val::Empty)),
|
&Value::Empty(_) => Ok(Rc::new(Val::Empty)),
|
||||||
|
&Value::Boolean(ref b) => Ok(Rc::new(Val::Boolean(b.val))),
|
||||||
&Value::Int(ref i) => Ok(Rc::new(Val::Int(i.val))),
|
&Value::Int(ref i) => Ok(Rc::new(Val::Int(i.val))),
|
||||||
&Value::Float(ref f) => Ok(Rc::new(Val::Float(f.val))),
|
&Value::Float(ref f) => Ok(Rc::new(Val::Float(f.val))),
|
||||||
&Value::String(ref s) => Ok(Rc::new(Val::String(s.val.to_string()))),
|
&Value::String(ref s) => Ok(Rc::new(Val::String(s.val.to_string()))),
|
||||||
|
@ -63,6 +63,9 @@ impl EnvConverter {
|
|||||||
// Empty is a noop.
|
// Empty is a noop.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
&Val::Boolean(b) => {
|
||||||
|
try!(write!(w, "{} ", if b { "true" } else { "false" }));
|
||||||
|
}
|
||||||
&Val::Float(ref f) => {
|
&Val::Float(ref f) => {
|
||||||
try!(write!(w, "{} ", f));
|
try!(write!(w, "{} ", f));
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,9 @@ impl FlagConverter {
|
|||||||
// Empty is a noop.
|
// Empty is a noop.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
&Val::Boolean(b) => {
|
||||||
|
try!(write!(w, "{}", if b { "true" } else { "false" }));
|
||||||
|
}
|
||||||
&Val::Float(ref f) => {
|
&Val::Float(ref f) => {
|
||||||
try!(write!(w, "{} ", f));
|
try!(write!(w, "{} ", f));
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ impl JsonConverter {
|
|||||||
|
|
||||||
fn convert_value(&self, v: &Val) -> Result<serde_json::Value> {
|
fn convert_value(&self, v: &Val) -> Result<serde_json::Value> {
|
||||||
let jsn_val = match v {
|
let jsn_val = match v {
|
||||||
|
&Val::Boolean(b) => serde_json::Value::Bool(b),
|
||||||
&Val::Empty => serde_json::Value::Null,
|
&Val::Empty => serde_json::Value::Null,
|
||||||
&Val::Float(f) => {
|
&Val::Float(f) => {
|
||||||
let n = match serde_json::Number::from_f64(f) {
|
let n = match serde_json::Number::from_f64(f) {
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -48,6 +48,8 @@
|
|||||||
//!
|
//!
|
||||||
//! The following words are reserved in ucg and can't be used as named bindings.
|
//! The following words are reserved in ucg and can't be used as named bindings.
|
||||||
//!
|
//!
|
||||||
|
//! * true
|
||||||
|
//! * false
|
||||||
//! * let
|
//! * let
|
||||||
//! * import
|
//! * import
|
||||||
//! * as
|
//! * as
|
||||||
@ -60,7 +62,16 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Primitive types
|
//! ### Primitive types
|
||||||
//!
|
//!
|
||||||
//! ucg has a relatively simple syntax with 3 primitive types, Int, Float, and String.
|
//! ucg has a relatively simple syntax with a few primitive types, Null, Boolean, Int, Float, and String.
|
||||||
|
//!
|
||||||
|
//! ### Boolean
|
||||||
|
//!
|
||||||
|
//! A Boolean is either `true` or `false`.
|
||||||
|
//!
|
||||||
|
//! ```uct
|
||||||
|
//! true;
|
||||||
|
//! false;
|
||||||
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! #### Int
|
//! #### Int
|
||||||
//!
|
//!
|
||||||
|
24
src/parse.rs
24
src/parse.rs
@ -138,6 +138,16 @@ named!(number<TokenIter, Value, ParseError>,
|
|||||||
);
|
);
|
||||||
// trace_macros!(false);
|
// trace_macros!(false);
|
||||||
|
|
||||||
|
named!(boolean_value<TokenIter, Value, ParseError>,
|
||||||
|
do_parse!(
|
||||||
|
b: match_type!(BOOLEAN) >>
|
||||||
|
(Value::Boolean(Positioned{
|
||||||
|
val: b.fragment == "true",
|
||||||
|
pos: b.pos,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
named!(
|
named!(
|
||||||
field_value<TokenIter, (Token, Expression), ParseError>,
|
field_value<TokenIter, (Token, Expression), ParseError>,
|
||||||
do_parse!(
|
do_parse!(
|
||||||
@ -205,6 +215,7 @@ named!(empty_value<TokenIter, Value, ParseError>,
|
|||||||
|
|
||||||
named!(value<TokenIter, Value, ParseError>,
|
named!(value<TokenIter, Value, ParseError>,
|
||||||
alt!(
|
alt!(
|
||||||
|
boolean_value |
|
||||||
empty_value |
|
empty_value |
|
||||||
number |
|
number |
|
||||||
quoted_value |
|
quoted_value |
|
||||||
@ -816,6 +827,19 @@ mod test {
|
|||||||
assert_parse!(empty_value("NULL"), Value::Empty(Position::new(1, 1)));
|
assert_parse!(empty_value("NULL"), Value::Empty(Position::new(1, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boolean_parsing() {
|
||||||
|
assert_parse!(
|
||||||
|
boolean_value("true"),
|
||||||
|
Value::Boolean(Positioned::new(true, 1, 1))
|
||||||
|
);
|
||||||
|
assert_parse!(
|
||||||
|
boolean_value("false"),
|
||||||
|
Value::Boolean(Positioned::new(false, 1, 1))
|
||||||
|
);
|
||||||
|
assert_error!(boolean_value("truth"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_symbol_parsing() {
|
fn test_symbol_parsing() {
|
||||||
assert_parse!(
|
assert_parse!(
|
||||||
|
@ -97,6 +97,21 @@ named!(digittok( Span ) -> Token,
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
named!(booleantok( Span ) -> Token,
|
||||||
|
do_parse!(
|
||||||
|
span: position!() >>
|
||||||
|
b: alt!(
|
||||||
|
tag!("true") |
|
||||||
|
tag!("false")
|
||||||
|
) >>
|
||||||
|
(Token{
|
||||||
|
typ: TokenType::BOOLEAN,
|
||||||
|
pos: Position::from(span),
|
||||||
|
fragment: b.fragment.to_string(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
/// do_tag_tok! is a helper macro to make building a simple tag token
|
/// do_tag_tok! is a helper macro to make building a simple tag token
|
||||||
/// less code.
|
/// less code.
|
||||||
macro_rules! do_tag_tok {
|
macro_rules! do_tag_tok {
|
||||||
@ -299,6 +314,7 @@ named!(token( Span ) -> Token,
|
|||||||
semicolontok |
|
semicolontok |
|
||||||
leftsquarebracket |
|
leftsquarebracket |
|
||||||
rightsquarebracket |
|
rightsquarebracket |
|
||||||
|
booleantok |
|
||||||
lettok |
|
lettok |
|
||||||
selecttok |
|
selecttok |
|
||||||
macrotok |
|
macrotok |
|
||||||
@ -369,6 +385,14 @@ pub fn token_clone(t: &Token) -> Result<Token, ParseError> {
|
|||||||
/// nom macro that matches a Token by type and uses an optional conversion handler
|
/// nom macro that matches a Token by type and uses an optional conversion handler
|
||||||
/// for the matched Token.
|
/// for the matched Token.
|
||||||
macro_rules! match_type {
|
macro_rules! match_type {
|
||||||
|
($i:expr, BOOLEAN => $h:expr) => {
|
||||||
|
match_type!($i, TokenType::BOOLEAN, "Not a Boolean", $h)
|
||||||
|
};
|
||||||
|
|
||||||
|
($i:expr, BOOLEAN) => {
|
||||||
|
match_type!($i, BOOLEAN => token_clone)
|
||||||
|
};
|
||||||
|
|
||||||
($i:expr, COMMENT => $h:expr) => {
|
($i:expr, COMMENT => $h:expr) => {
|
||||||
match_type!($i, TokenType::COMMENT, "Not a Comment", $h)
|
match_type!($i, TokenType::COMMENT, "Not a Comment", $h)
|
||||||
};
|
};
|
||||||
@ -645,19 +669,32 @@ mod tokenizer_test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boolean() {
|
||||||
|
let result = token(LocatedSpan::new("true"));
|
||||||
|
assert!(
|
||||||
|
result.is_done(),
|
||||||
|
format!("result {:?} is not a boolean", result)
|
||||||
|
);
|
||||||
|
if let nom::IResult::Done(_, tok) = result {
|
||||||
|
assert_eq!(tok.fragment, "true");
|
||||||
|
assert_eq!(tok.typ, TokenType::BOOLEAN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tokenize_one_of_each() {
|
fn test_tokenize_one_of_each() {
|
||||||
let result = tokenize(LocatedSpan::new(
|
let result = tokenize(LocatedSpan::new(
|
||||||
"let import macro select as => [ ] { } ; = % / * \
|
"let import macro select as => [ ] { } ; = % / * \
|
||||||
+ - . ( ) , 1 . foo \"bar\" // comment\n ;",
|
+ - . ( ) , 1 . foo \"bar\" // comment\n ; true false",
|
||||||
));
|
));
|
||||||
assert!(result.is_ok(), format!("result {:?} is not ok", result));
|
assert!(result.is_ok(), format!("result {:?} is not ok", result));
|
||||||
let v = result.unwrap();
|
let v = result.unwrap();
|
||||||
for (i, t) in v.iter().enumerate() {
|
for (i, t) in v.iter().enumerate() {
|
||||||
println!("{}: {:?}", i, t);
|
println!("{}: {:?}", i, t);
|
||||||
}
|
}
|
||||||
assert_eq!(v.len(), 27);
|
assert_eq!(v.len(), 29);
|
||||||
assert_eq!(v[26].typ, TokenType::END);
|
assert_eq!(v[28].typ, TokenType::END);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user