summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2016-09-02 21:04:48 +0200
committerYorhel <git@yorhel.nl>2016-09-02 21:36:02 +0200
commit8578695be143045453cad83436f395cd09873435 (patch)
treea3b7c1530ca2869615c481fb4034d17cac0fd3c8 /src
parent39eb2ac55f5b8f4192064f1c05e6c77b8ca11eaa (diff)
Config parsing progress
Diffstat (limited to 'src')
-rw-r--r--src/config.rs163
-rw-r--r--src/main.rs3
2 files changed, 108 insertions, 58 deletions
diff --git a/src/config.rs b/src/config.rs
index 7d01c77..ea3a14a 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,16 +1,51 @@
use std;
+use std::str::FromStr;
use nom;
-use std::str;
use std::net::SocketAddr;
use nom::{IResult,Input,Consumer,ConsumerState,Move,Producer,HexDisplay};
-use nom::{alphanumeric,space,multispace,line_ending,not_line_ending};
+use nom::{alpha,alphanumeric,space,multispace,line_ending,not_line_ending};
-#[derive(Debug,Clone)]
+
+#[derive(Debug,PartialEq,Eq)]
+enum Expr<'a> {
+ Keyval(&'a str,&'a str),
+ Interface(&'a str),
+ Close,
+ Comment
+}
+
+named!(parse_itf<&[u8],Expr>, chain!(
+ tag!("interface") ~
+ space ~
+ val: map_res!(alpha, std::str::from_utf8) ~
+ opt!(space) ~
+ tag!("{"),
+ ||{ Expr::Interface(val) }
+));
+
+named!(parse_keyval<&[u8],Expr>, chain!(
+ key: map_res!(alphanumeric, std::str::from_utf8) ~
+ space ~
+ val: map_res!(not_line_ending, std::str::from_utf8) ~
+ line_ending,
+ ||{ Expr::Keyval(key, val.trim()) }
+));
+
+named!(parse_expr<&[u8],Expr>, alt!(
+ value!(Expr::Comment, multispace)
+ | value!(Expr::Comment, delimited!(tag!("#"), not_line_ending, line_ending))
+ | value!(Expr::Close, delimited!(tag!("}"), opt!(space), line_ending))
+ | parse_itf
+ | parse_keyval // Must be last, matches a lot
+));
+
+
+#[derive(Debug,Clone,Default)]
pub struct Interface {
addr: Vec<SocketAddr>
}
-#[derive(Debug,Clone)]
+#[derive(Debug,Clone,Default)]
pub struct Config {
itf: Vec<Interface>
}
@@ -22,42 +57,11 @@ pub enum Err {
Parse(()) // TODO: error info
}
-
-#[derive(Debug,PartialEq,Eq)]
-enum Expr<'a> {
- Keyval(&'a str,&'a str),
- Interface(&'a str),
- Close,
- Comment
-}
-
enum ParseState {
Root,
Interface
}
-named!(one_multispace, value!(b" ", one_of!(" \t\r\n")));
-
-named!(keyval<&[u8],Expr>, chain!(
- key: map_res!(alphanumeric, std::str::from_utf8) ~
- space ~
- val: map_res!(not_line_ending, std::str::from_utf8) ~
- line_ending,
- ||{ Expr::Keyval(key, val.trim()) }
-));
-
-named!(expr<&[u8],Expr>,
- // The switch!() macro doesn't support wildcard, so put keyval in an alt!()
- alt!(
- switch!(peek!(alt!(tag!("#") | tag!("}") | one_multispace)),
- b" " => value!(Expr::Comment, multispace) |
- b"#" => value!(Expr::Comment, delimited!(tag!("#"), not_line_ending, line_ending)) |
- b"}" => value!(Expr::Close, take!(1))
- ) | keyval
- )
-);
-
-
struct ConfigConsumer {
c_state: ConsumerState<(), (), nom::Move>,
state: ParseState,
@@ -65,16 +69,55 @@ struct ConfigConsumer {
}
+impl ConfigConsumer {
+ fn handle_root(&mut self, e: Expr) {
+ match e {
+ Expr::Interface(_) => {
+ self.cfg.itf.push(Default::default());
+ self.state = ParseState::Interface
+ },
+ _ => { panic!("Not implemented yet.") }
+ }
+ }
+
+ fn handle_itf(&mut self, e: Expr) {
+ let ref mut itf = self.cfg.itf.last_mut().unwrap();
+ match e {
+ Expr::Keyval("listen", a) => {
+ // TODO: More flexible input format (e.g. ":80" or dns "localhost:8080")
+ itf.addr.push(SocketAddr::from_str(a).expect("I crash on invalid strings"));
+ },
+ Expr::Close => {
+ if itf.addr.len() < 1 {
+ panic!("No interface address configured");
+ }
+ self.state = ParseState::Root
+ },
+ _ => { panic!("Not implemented yet in interface: {:?}.", e) }
+ }
+ }
+
+ fn token(&mut self, e: Expr) {
+ if e == Expr::Comment {
+ return;
+ }
+ match self.state {
+ ParseState::Root => self.handle_root(e),
+ ParseState::Interface => self.handle_itf(e)
+ }
+ }
+}
+
+
impl<'a> Consumer<&'a[u8], (), (), nom::Move> for ConfigConsumer {
fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<(), (), nom::Move> {
match input {
Input::Eof(None) => { self.c_state = ConsumerState::Done(Move::Consume(0), ()); },
Input::Empty => { self.c_state = ConsumerState::Continue(Move::Consume(0)); },
Input::Element(x) | Input::Eof(Some(x)) => {
- match expr(x) {
+ match parse_expr(x) {
IResult::Done(i, e) => {
- println!("{:?}", e);
- // TODO: Pass to state handler (if not comment)
+ self.token(e);
self.c_state = ConsumerState::Continue(Move::Consume(x.offset(i)));
},
IResult::Error(_) => { self.c_state = ConsumerState::Error(()); },
@@ -92,22 +135,16 @@ impl<'a> Consumer<&'a[u8], (), (), nom::Move> for ConfigConsumer {
impl Config {
- fn new() -> Config {
- Config {
- itf: Vec::new()
- }
- }
-
pub fn parse(file: &str) -> Result<Config, Err> {
- let mut p = try!(nom::FileProducer::new(file, 4096).map_err(Err::Io));
+ let mut p = try!(nom::FileProducer::new(file, 1024).map_err(Err::Io));
let mut c = ConfigConsumer{
state: ParseState::Root,
c_state: ConsumerState::Continue(Move::Consume(0)),
- cfg: Config::new()
+ cfg: Default::default()
};
loop {
match *p.apply(&mut c) {
- ConsumerState::Done(_, x) => { return Ok(c.cfg) }
+ ConsumerState::Done(_, _) => { return Ok(c.cfg) }
ConsumerState::Error(e) => { return Result::Err(Err::Parse(e)) }
ConsumerState::Continue(_) => {}
}
@@ -117,15 +154,27 @@ impl Config {
#[test]
-fn parse_expr() {
+fn test_parse_expr() {
let x = |e| { IResult::Done(&b"x"[..], e) };
- assert_eq!(expr(b" \r\n\tx"), x(Expr::Comment));
- assert_eq!(expr(b"\nx"), x(Expr::Comment));
- assert_eq!(expr(b"#\nx"), x(Expr::Comment));
- assert_eq!(expr(b"##/!@$% \nx"), x(Expr::Comment));
- assert_eq!(expr(b"}x"), x(Expr::Close));
- assert_eq!(expr(b"key val\nx"), x(Expr::Keyval("key", "val")));
- assert_eq!(expr(b"ke\t v a \nx"), x(Expr::Keyval("ke", "v a")));
- assert_eq!(expr(b""), IResult::Incomplete(nom::Needed::Size(1)));
- assert_eq!(expr(b"something"), IResult::Error(nom::Err::Position(nom::ErrorKind::Alt, &b"something"[..])));
+ let e = parse_expr;
+ assert_eq!(e(b" \r\n\tx"), x(Expr::Comment));
+ assert_eq!(e(b"\nx"), x(Expr::Comment));
+ assert_eq!(e(b"#\nx"), x(Expr::Comment));
+ assert_eq!(e(b"##/!@$% \nx"), x(Expr::Comment));
+ assert_eq!(e(b"}\nx"), x(Expr::Close));
+ assert_eq!(e(b"key val\nx"), x(Expr::Keyval("key", "val")));
+ assert_eq!(e(b"ke\t v a \nx"), x(Expr::Keyval("ke", "v a")));
+ assert_eq!(e(b"interface http {x"), x(Expr::Interface("http")));
+ assert_eq!(e(b"interface \thttp{x"), x(Expr::Interface("http")));
+
+ let l: &[&'static str] = &[
+ "",
+ "something",
+ "#something",
+ ][..];
+ for s in l {
+ if let IResult::Done(_,_) = e(s.as_bytes()) {
+ panic!("'{}' did not error", s);
+ }
+ }
}
diff --git a/src/main.rs b/src/main.rs
index 215670d..504b7f7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,9 @@
-// I'm playing around. Let me.
+/* I'm playing around. Let me.
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_mut)]
#![allow(unused_imports)]
+// */
#[macro_use] extern crate nom;
#[macro_use] extern crate log;