mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
cleanup: fix some selector vs symbol parsing issues
Add test coverage of selector parsing.
This commit is contained in:
parent
3ab5d27fc7
commit
e975dea201
@ -2,13 +2,13 @@ let dbhost = "localhost";
|
|||||||
let dbname = "testdb";
|
let dbname = "testdb";
|
||||||
|
|
||||||
let mk_db_conn = macro (host, port, db) => {
|
let mk_db_conn = macro (host, port, db) => {
|
||||||
conn_string = "@:@/@" % (host, port, db)
|
|
||||||
host = host,
|
host = host,
|
||||||
port = port,
|
port = port,
|
||||||
db = db,
|
db = db,
|
||||||
|
conn_string = "@:@/@" % (host, port, db)
|
||||||
};
|
};
|
||||||
|
|
||||||
let db_conn = mk_db_conn(host, 3306, dbame);
|
let db_conn = mk_db_conn(dbhost, 3306, dbname);
|
||||||
|
|
||||||
let server_config = {
|
let server_config = {
|
||||||
dbconn = db_conn.conn_string,
|
dbconn = db_conn.conn_string,
|
||||||
|
13
src/ast.rs
13
src/ast.rs
@ -241,24 +241,29 @@ impl MacroDef {
|
|||||||
-> HashSet<String> {
|
-> HashSet<String> {
|
||||||
let mut bad_symbols = HashSet::new();
|
let mut bad_symbols = HashSet::new();
|
||||||
if let &Value::Symbol(ref name) = val {
|
if let &Value::Symbol(ref name) = val {
|
||||||
let mut ok = true;
|
let mut ok = false;
|
||||||
for arg in self.argdefs.iter() {
|
for arg in self.argdefs.iter() {
|
||||||
ok &= arg.val == name.val
|
if arg.val == name.val {
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
bad_symbols.insert(name.val.clone());
|
bad_symbols.insert(name.val.clone());
|
||||||
}
|
}
|
||||||
} else if let &Value::Selector(ref sel_node) = val {
|
} else if let &Value::Selector(ref sel_node) = val {
|
||||||
let list = &sel_node.val;
|
let list = &sel_node.val;
|
||||||
let mut ok = true;
|
let mut ok = false;
|
||||||
if list.len() > 0 {
|
if list.len() > 0 {
|
||||||
// We only look to see if the first selector item exists.
|
// We only look to see if the first selector item exists.
|
||||||
// This is because only the first one is a symbol all of the
|
// This is because only the first one is a symbol all of the
|
||||||
// rest of the items in the selector are fields in a tuple.
|
// rest of the items in the selector are fields in a tuple.
|
||||||
// But we don't know at this time of the value passed into
|
// But we don't know at this time of the value passed into
|
||||||
// this macro is a tuple since this isn't a callsite.
|
// this macro is a tuple since this isn't a callsite.
|
||||||
|
println!("checking selector head {}", list[0].fragment);
|
||||||
for arg in self.argdefs.iter() {
|
for arg in self.argdefs.iter() {
|
||||||
ok &= arg.val == list[0].fragment
|
if arg.val == list[0].fragment {
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
bad_symbols.insert(list[0].fragment.to_string());
|
bad_symbols.insert(list[0].fragment.to_string());
|
||||||
|
28
src/build.rs
28
src/build.rs
@ -231,7 +231,7 @@ pub struct Builder {
|
|||||||
/// out is our built output.
|
/// out is our built output.
|
||||||
out: ValueMap,
|
out: ValueMap,
|
||||||
/// last is the result of the last statement.
|
/// last is the result of the last statement.
|
||||||
last: Option<Rc<Val>>,
|
pub last: Option<Rc<Val>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! eval_binary_expr {
|
macro_rules! eval_binary_expr {
|
||||||
@ -294,6 +294,17 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
||||||
|
let key = Positioned {
|
||||||
|
pos: Position {
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
},
|
||||||
|
val: name.to_string(),
|
||||||
|
};
|
||||||
|
self.lookup_sym(&key)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(&mut self, ast: &Vec<Statement>) -> BuildResult {
|
pub fn build(&mut self, ast: &Vec<Statement>) -> BuildResult {
|
||||||
for stmt in ast.iter() {
|
for stmt in ast.iter() {
|
||||||
try!(self.build_stmt(stmt));
|
try!(self.build_stmt(stmt));
|
||||||
@ -303,7 +314,7 @@ impl Builder {
|
|||||||
|
|
||||||
pub fn build_file_string(&mut self, name: &str, input: String) -> BuildResult {
|
pub fn build_file_string(&mut self, name: &str, input: String) -> BuildResult {
|
||||||
match parse(Span::new(&input)) {
|
match parse(Span::new(&input)) {
|
||||||
nom::IResult::Done(_, stmts) => {
|
nom::IResult::Done(_span, stmts) => {
|
||||||
for stmt in stmts.iter() {
|
for stmt in stmts.iter() {
|
||||||
try!(self.build_stmt(stmt));
|
try!(self.build_stmt(stmt));
|
||||||
}
|
}
|
||||||
@ -324,6 +335,7 @@ impl Builder {
|
|||||||
// TODO(jwall): It would be nice to be able to do this with streaming
|
// TODO(jwall): It would be nice to be able to do this with streaming
|
||||||
try!(f.read_to_string(&mut s));
|
try!(f.read_to_string(&mut s));
|
||||||
self.build_file_string(name, s)
|
self.build_file_string(name, s)
|
||||||
|
// TODO(jwall): Call an output converter.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
|
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
|
||||||
@ -923,8 +935,16 @@ mod test {
|
|||||||
}))
|
}))
|
||||||
.or_insert(Rc::new(Val::Int(2)));
|
.or_insert(Rc::new(Val::Int(2)));
|
||||||
b.out
|
b.out
|
||||||
.entry(Positioned::new("var3".to_string(), Position{line: 1, column: 0}))
|
.entry(Positioned::new("var3".to_string(),
|
||||||
.or_insert(Rc::new(Val::Tuple(vec![(Positioned::new("lvl1".to_string(), Position{line: 1, column: 0}),
|
Position {
|
||||||
|
line: 1,
|
||||||
|
column: 0,
|
||||||
|
}))
|
||||||
|
.or_insert(Rc::new(Val::Tuple(vec![(Positioned::new("lvl1".to_string(),
|
||||||
|
Position {
|
||||||
|
line: 1,
|
||||||
|
column: 0,
|
||||||
|
}),
|
||||||
Rc::new(Val::Int(4)))])));
|
Rc::new(Val::Int(4)))])));
|
||||||
test_expr_to_val(vec![
|
test_expr_to_val(vec![
|
||||||
(Expression::Simple(Value::Selector(make_value_node(vec![Token::new("var1", Position{line: 1, column: 1})], 1, 1))), Val::Tuple(
|
(Expression::Simple(Value::Selector(make_value_node(vec![Token::new("var1", Position{line: 1, column: 1})], 1, 1))), Val::Tuple(
|
||||||
|
@ -24,6 +24,7 @@ pub mod ast;
|
|||||||
pub mod tokenizer;
|
pub mod tokenizer;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod build;
|
pub mod build;
|
||||||
|
pub mod convert;
|
||||||
mod format;
|
mod format;
|
||||||
|
|
||||||
pub use ast::Value;
|
pub use ast::Value;
|
||||||
|
54
src/main.rs
54
src/main.rs
@ -13,11 +13,19 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
|
||||||
extern crate ucglib;
|
extern crate ucglib;
|
||||||
|
|
||||||
use ucglib::build;
|
use std::fs::File;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::io;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
use ucglib::build::Val;
|
||||||
|
use ucglib::build;
|
||||||
|
//use ucglib::convert::get_converter;
|
||||||
|
use ucglib::convert::ConverterRunner;
|
||||||
|
|
||||||
|
// TODO(jwall): List the target output types automatically.
|
||||||
fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
||||||
clap_app!(
|
clap_app!(
|
||||||
ucg =>
|
ucg =>
|
||||||
@ -26,6 +34,9 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
|||||||
(about: "Universal Configuration Grammar compiler.")
|
(about: "Universal Configuration Grammar compiler.")
|
||||||
(@subcommand build =>
|
(@subcommand build =>
|
||||||
(about: "Compile a specific ucg file.")
|
(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 out: --out -o +takes_value "Output file to write to.")
|
||||||
(@arg INPUT: +required "Input ucg file to build.")
|
(@arg INPUT: +required "Input ucg file to build.")
|
||||||
)
|
)
|
||||||
(@subcommand validate =>
|
(@subcommand validate =>
|
||||||
@ -36,18 +47,53 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
|||||||
.get_matches()
|
.get_matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_converter(c: ConverterRunner, v: Rc<Val>, f: &str) -> io::Result<()> {
|
||||||
|
let file = File::create(f);
|
||||||
|
c.convert(v, Box::new(file.unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO(jwall): Read and build an actual file.
|
// TODO(jwall): Read and build an actual file.
|
||||||
let app = do_flags();
|
let app = do_flags();
|
||||||
if let Some(matches) = app.subcommand_matches("build") {
|
if let Some(matches) = app.subcommand_matches("build") {
|
||||||
let file = matches.value_of("INPUT").unwrap();
|
let file = matches.value_of("INPUT").unwrap();
|
||||||
|
let out = matches.value_of("out").unwrap();
|
||||||
|
let sym = matches.value_of("sym");
|
||||||
|
let target = matches.value_of("target").unwrap();
|
||||||
let mut builder = build::Builder::new();
|
let mut builder = build::Builder::new();
|
||||||
builder.build_file(file).unwrap();
|
match ConverterRunner::new(target) {
|
||||||
println!("Build successful");
|
Ok(converter) => {
|
||||||
|
let result = builder.build_file(file);
|
||||||
|
if !result.is_ok() {
|
||||||
|
eprintln!("{:?}", result.err());
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
let val = match sym {
|
||||||
|
Some(sym_name) => builder.get_out_by_name(sym_name),
|
||||||
|
None => builder.last,
|
||||||
|
};
|
||||||
|
match val {
|
||||||
|
Some(value) => {
|
||||||
|
run_converter(converter, value, out).unwrap();
|
||||||
|
println!("Build successful");
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
eprintln!("Build results in no value.");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(msg) => {
|
||||||
|
eprintln!("{}", msg);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if let Some(matches) = app.subcommand_matches("validate") {
|
} else if let Some(matches) = app.subcommand_matches("validate") {
|
||||||
let file = matches.value_of("INPUT").unwrap();
|
let file = matches.value_of("INPUT").unwrap();
|
||||||
let mut builder = build::Builder::new();
|
let mut builder = build::Builder::new();
|
||||||
builder.build_file(file).unwrap();
|
builder.build_file(file).unwrap();
|
||||||
println!("File Validates");
|
println!("File Validates");
|
||||||
|
process::exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
143
src/parse.rs
143
src/parse.rs
@ -15,6 +15,9 @@ use std::str::FromStr;
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
|
use nom::IResult;
|
||||||
|
use nom::InputLength;
|
||||||
|
|
||||||
use ast::*;
|
use ast::*;
|
||||||
use tokenizer::*;
|
use tokenizer::*;
|
||||||
|
|
||||||
@ -163,7 +166,27 @@ named!(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
named!(value( Span ) -> Value, alt!(number | quoted_value | symbol | tuple));
|
pub fn selector_or_symbol(input: Span) -> IResult<Span, Value> {
|
||||||
|
let sym = do_parse!(input,
|
||||||
|
sym: symbol >>
|
||||||
|
not!(dottok) >>
|
||||||
|
(sym)
|
||||||
|
);
|
||||||
|
match sym {
|
||||||
|
IResult::Incomplete(i) => {
|
||||||
|
return IResult::Incomplete(i);
|
||||||
|
},
|
||||||
|
IResult::Error(_) => {
|
||||||
|
// TODO(jwall): Maybe be smarter about the error reporting here?
|
||||||
|
return ws!(input, selector_value);
|
||||||
|
},
|
||||||
|
IResult::Done(rest, val) => {
|
||||||
|
return IResult::Done(rest, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
named!(value( Span ) -> Value, alt!(number | quoted_value | tuple | selector_or_symbol ));
|
||||||
|
|
||||||
fn value_to_expression(v: Value) -> ParseResult<Expression> {
|
fn value_to_expression(v: Value) -> ParseResult<Expression> {
|
||||||
Ok(Expression::Simple(v))
|
Ok(Expression::Simple(v))
|
||||||
@ -504,19 +527,90 @@ named!(statement( Span ) -> Statement,
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
named!(pub parse( Span ) -> Vec<Statement>, many1!(ws!(statement)));
|
pub fn parse(input: Span) -> IResult<Span, Vec<Statement>> {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
let mut i = input;
|
||||||
|
loop {
|
||||||
|
match ws!(i, statement) {
|
||||||
|
IResult::Error(e) => {
|
||||||
|
return IResult::Error(e);
|
||||||
|
},
|
||||||
|
IResult::Incomplete(i) => {
|
||||||
|
return IResult::Incomplete(i);
|
||||||
|
},
|
||||||
|
IResult::Done(rest, stmt) => {
|
||||||
|
out.push(stmt);
|
||||||
|
i = rest;
|
||||||
|
if i.input_len() == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IResult::Done(i, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
//named!(pub parse( Span ) -> Vec<Statement>, many1!());
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef};
|
use super::{Statement, Expression, Value, MacroDef, SelectDef, CallDef};
|
||||||
use super::{number, symbol, parse, field_value, tuple, grouped_expression};
|
use super::{number, symbol, parse, field_value, selector_value, selector_or_symbol, tuple, grouped_expression};
|
||||||
use super::{copy_expression, macro_expression, select_expression};
|
use super::{copy_expression, macro_expression, select_expression};
|
||||||
use super::{format_expression, call_expression, expression};
|
use super::{format_expression, call_expression, expression};
|
||||||
use super::{expression_statement, let_statement, import_statement, statement};
|
use super::{expression_statement, let_statement, import_statement, statement};
|
||||||
use ast::*;
|
use ast::*;
|
||||||
use nom_locate::LocatedSpan;
|
use nom_locate::LocatedSpan;
|
||||||
|
|
||||||
use nom::IResult;
|
use nom::{Needed, IResult};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_symbol_parsing() {
|
||||||
|
assert_eq!(symbol(LocatedSpan::new("foo")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 3, line: 1},
|
||||||
|
Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 1}))) );
|
||||||
|
assert_eq!(symbol(LocatedSpan::new("foo-bar")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
|
||||||
|
Value::Symbol(value_node!("foo-bar".to_string(), Position{line: 1, column: 1}))) );
|
||||||
|
assert_eq!(symbol(LocatedSpan::new("foo_bar")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
|
||||||
|
Value::Symbol(value_node!("foo_bar".to_string(), Position{line: 1, column: 1}))) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_selector_parsing() {
|
||||||
|
assert_eq!(selector_value(LocatedSpan::new("foo.")),
|
||||||
|
IResult::Incomplete(Needed::Unknown)
|
||||||
|
);
|
||||||
|
assert_eq!(selector_value(LocatedSpan::new("foo.bar ")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1},
|
||||||
|
Value::Selector(value_node!(vec![Token{fragment:"foo".to_string(), pos: Position{line: 1, column: 1}},
|
||||||
|
Token{fragment:"bar".to_string(), pos: Position{line: 1, column: 5}}],
|
||||||
|
Position{line: 1, column: 0})))
|
||||||
|
);
|
||||||
|
assert_eq!(selector_value(LocatedSpan::new("foo.bar;")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: ";", offset: 7, line: 1},
|
||||||
|
Value::Selector(value_node!(vec![Token{fragment:"foo".to_string(), pos: Position{line: 1, column: 1}},
|
||||||
|
Token{fragment:"bar".to_string(), pos: Position{line: 1, column: 5}}],
|
||||||
|
Position{line: 1, column: 0})))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_selector_or_symbol_parsing() {
|
||||||
|
assert_eq!(selector_or_symbol(LocatedSpan::new("foo.")),
|
||||||
|
IResult::Incomplete(Needed::Unknown)
|
||||||
|
);
|
||||||
|
assert_eq!(selector_or_symbol(LocatedSpan::new("foo")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 3, line: 1},
|
||||||
|
Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 1}))) );
|
||||||
|
assert_eq!(selector_or_symbol(LocatedSpan::new("foo.bar ")),
|
||||||
|
IResult::Done(LocatedSpan{fragment: "", offset: 8, line: 1},
|
||||||
|
Value::Selector(value_node!(vec![Token{fragment:"foo".to_string(), pos: Position{line: 1, column: 1}},
|
||||||
|
Token{fragment:"bar".to_string(), pos: Position{line: 1, column: 5}}],
|
||||||
|
Position{line: 1, column: 0})))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_statement_parse() {
|
fn test_statement_parse() {
|
||||||
@ -744,19 +838,27 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_expression_parse() {
|
fn test_expression_parse() {
|
||||||
assert_eq!(expression(LocatedSpan::new("1")),
|
assert_eq!(expression(LocatedSpan::new("1")),
|
||||||
IResult::Done(LocatedSpan {
|
IResult::Done(LocatedSpan {
|
||||||
fragment: "",
|
fragment: "",
|
||||||
offset: 1,
|
offset: 1,
|
||||||
line: 1,
|
line: 1,
|
||||||
},
|
},
|
||||||
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 1})))));
|
Expression::Simple(Value::Int(value_node!(1, Position{line: 1, column: 1})))));
|
||||||
assert_eq!(expression(LocatedSpan::new("foo")),
|
assert_eq!(expression(LocatedSpan::new("foo")),
|
||||||
|
IResult::Done(LocatedSpan {
|
||||||
|
fragment: "",
|
||||||
|
offset: 3,
|
||||||
|
line: 1,
|
||||||
|
},
|
||||||
|
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 1})))));
|
||||||
|
assert_eq!(expression(LocatedSpan::new("foo.bar ")),
|
||||||
IResult::Done(LocatedSpan {
|
IResult::Done(LocatedSpan {
|
||||||
fragment: "",
|
fragment: "",
|
||||||
offset: 3,
|
offset: 8,
|
||||||
line: 1,
|
line: 1,
|
||||||
},
|
},
|
||||||
Expression::Simple(Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 1})))));
|
Expression::Simple(Value::Selector(make_value_node(vec![Token::new("foo", Position{line: 1, column: 1}),
|
||||||
|
Token::new("bar", Position{line: 1, column: 5})], 1, 0)))));
|
||||||
assert_eq!(expression(LocatedSpan::new("1 + 1")),
|
assert_eq!(expression(LocatedSpan::new("1 + 1")),
|
||||||
IResult::Done(LocatedSpan {
|
IResult::Done(LocatedSpan {
|
||||||
fragment: "",
|
fragment: "",
|
||||||
@ -1237,6 +1339,10 @@ mod test {
|
|||||||
IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" },
|
IResult::Done(LocatedSpan { offset: 10, line: 1, fragment: "" },
|
||||||
(Token::new("foo", Position{line: 1, column: 1}),
|
(Token::new("foo", Position{line: 1, column: 1}),
|
||||||
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), Position{line: 1, column: 7}))))) );
|
Expression::Simple(Value::Symbol(value_node!("bar".to_string(), Position{line: 1, column: 7}))))) );
|
||||||
|
assert_eq!(field_value(LocatedSpan::new("foo = bar.baz ")),
|
||||||
|
IResult::Done(LocatedSpan { offset: 14, line: 1, fragment: "" },
|
||||||
|
(Token::new("foo", Position{line: 1, column: 1}),
|
||||||
|
Expression::Simple(Value::Selector(make_value_node(vec![Token::new("bar", Position{line: 1, column: 7}), Token::new("baz", Position{line: 1, column: 11})], 1, 6))))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1257,19 +1363,6 @@ mod test {
|
|||||||
Value::Float(value_node!(0.1, Position{line: 1, column: 1}))) );
|
Value::Float(value_node!(0.1, Position{line: 1, column: 1}))) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_symbol_parsing() {
|
|
||||||
assert_eq!(symbol(LocatedSpan::new("foo")),
|
|
||||||
IResult::Done(LocatedSpan{fragment: "", offset: 3, line: 1},
|
|
||||||
Value::Symbol(value_node!("foo".to_string(), Position{line: 1, column: 1}))) );
|
|
||||||
assert_eq!(symbol(LocatedSpan::new("foo-bar")),
|
|
||||||
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
|
|
||||||
Value::Symbol(value_node!("foo-bar".to_string(), Position{line: 1, column: 1}))) );
|
|
||||||
assert_eq!(symbol(LocatedSpan::new("foo_bar")),
|
|
||||||
IResult::Done(LocatedSpan{fragment: "", offset: 7, line: 1},
|
|
||||||
Value::Symbol(value_node!("foo_bar".to_string(), Position{line: 1, column: 1}))) );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse() {
|
fn test_parse() {
|
||||||
let bad_input = LocatedSpan::new("import mylib as lib;");
|
let bad_input = LocatedSpan::new("import mylib as lib;");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user