add label behaviour; update main.rs for improved output formatting
This commit is contained in:
parent
84cb7e52da
commit
8687b21821
|
@ -7,6 +7,7 @@ fn main() {
|
|||
let mut input = String::new();
|
||||
io::stdin().read_to_string(&mut input).expect("Failed to read from stdin");
|
||||
om::tokenizer::Tokenizer::new(input).for_each(|token| {
|
||||
println!("{:?}", token);
|
||||
println!("\n{:?}", token);
|
||||
});
|
||||
println!();
|
||||
}
|
||||
|
|
|
@ -1,36 +1,56 @@
|
|||
use std::str;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BehaviorItem {
|
||||
pub prefix: Option<String>,
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
pub enum BehaviorItem {
|
||||
KeyValue {
|
||||
prefix: Option<String>,
|
||||
key: String,
|
||||
value: String,
|
||||
},
|
||||
Label {
|
||||
prefix: Option<String>,
|
||||
label: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl BehaviorItem {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
prefix: Option::None,
|
||||
key: String::new(),
|
||||
value: String::new(),
|
||||
pub fn from(input: &str) -> Self {
|
||||
let (prefix, part) = input.split_once(':').unwrap_or(("", input));
|
||||
let (key, value) = part.split_once('=').unwrap_or((part, ""));
|
||||
if value.is_empty() {
|
||||
Self::Label {
|
||||
prefix: if prefix.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(prefix.to_string())
|
||||
},
|
||||
label: key.to_string(),
|
||||
}
|
||||
} else {
|
||||
Self::KeyValue {
|
||||
prefix: if prefix.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(prefix.to_string())
|
||||
},
|
||||
key: key.to_string(),
|
||||
value: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_prefix(&mut self, prefix: String) {
|
||||
self.prefix = Some(prefix);
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Behavior {
|
||||
pub items: Vec<BehaviorItem>,
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, value: String) {
|
||||
self.value = value;
|
||||
}
|
||||
|
||||
pub fn set_key(&mut self, key: String) {
|
||||
self.key = key;
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
match &self.prefix {
|
||||
Some(prefix) => format!("{}:{}", prefix, self.key),
|
||||
None => self.key.clone(),
|
||||
impl Behavior {
|
||||
pub fn new() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_item(&mut self, item: BehaviorItem) {
|
||||
self.items.push(item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::om::behavior::*;
|
||||
|
||||
pub struct Tokenizer {
|
||||
state: State,
|
||||
pos: usize,
|
||||
|
@ -34,15 +36,20 @@ impl Iterator for Tokenizer {
|
|||
type Item = Token;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.is_eof() {
|
||||
return None;
|
||||
}
|
||||
loop {
|
||||
if self.reconsume {
|
||||
self.pos -= 1;
|
||||
self.reconsume = false;
|
||||
}
|
||||
if self.pos >= self.input.len() {
|
||||
if self.pos > self.input.len() {
|
||||
return None;
|
||||
}
|
||||
self.pos += 1;
|
||||
return Some(Token::EOF);
|
||||
}
|
||||
let c = self.consume_input();
|
||||
print!("{}", c);
|
||||
match self.state {
|
||||
State::Data => match c {
|
||||
'(' => {
|
||||
|
@ -53,15 +60,12 @@ impl Iterator for Tokenizer {
|
|||
self.state = State::Data;
|
||||
return Some(Token::NodeEnd);
|
||||
}
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
}
|
||||
_ => {
|
||||
return Some(Token::Character(c));
|
||||
}
|
||||
},
|
||||
State::NodeOpen => match c {
|
||||
' ' | '\n' => {}
|
||||
' ' | '\n' | '\t' => {}
|
||||
x if x.is_ascii_alphanumeric() => {
|
||||
self.state = State::Define;
|
||||
self.reconsume = true;
|
||||
|
@ -73,126 +77,104 @@ impl Iterator for Tokenizer {
|
|||
_ => panic!("Unexpected character: {}", c),
|
||||
},
|
||||
State::Define => match c {
|
||||
x if x.is_ascii_alphanumeric() => {
|
||||
self.buffer.push(c);
|
||||
}
|
||||
' ' | '\n' => {
|
||||
' ' | '\n' | '\t' => {
|
||||
self.state = State::AfterDefine;
|
||||
self.latest = Some(Token::Define {
|
||||
name: self.buffer.clone(),
|
||||
behavior: Vec::new(),
|
||||
behavior: Behavior::new(),
|
||||
});
|
||||
self.buffer.clear();
|
||||
}
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
x => {
|
||||
if !x.is_ascii_alphanumeric() {
|
||||
panic!("Unexpected character: {}", c);
|
||||
}
|
||||
self.buffer.push(c);
|
||||
if self.is_eof() {
|
||||
return Some(Token::Define {
|
||||
name: self.buffer.clone(),
|
||||
behavior: Behavior::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => panic!("Unexpected character: {}", c),
|
||||
},
|
||||
State::AfterDefine => match c {
|
||||
' ' | '\n' => {}
|
||||
'[' => {
|
||||
State::AfterDefine => {
|
||||
if self.is_eof() {
|
||||
return self.latest.take();
|
||||
}
|
||||
match c {
|
||||
' ' | '\n' | '\t' => {}
|
||||
'[' => {
|
||||
self.state = State::Behavior;
|
||||
}
|
||||
_ => {
|
||||
self.state = State::Data;
|
||||
self.reconsume = true;
|
||||
return self.latest.take();
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Behavior => match c {
|
||||
' ' | '\n' | '\t' => {
|
||||
self.state = State::BehaviorSeparator;
|
||||
}
|
||||
']' => {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
if let Token::Define { behavior, .. } = t {
|
||||
behavior.add_item(BehaviorItem::from(&self.buffer));
|
||||
}
|
||||
}
|
||||
self.buffer.clear();
|
||||
self.state = State::Data;
|
||||
return self.latest.take();
|
||||
}
|
||||
x => {
|
||||
if !x.is_ascii_alphanumeric() && x != '=' && x != ':' {
|
||||
panic!("Unexpected character: {}", x);
|
||||
}
|
||||
self.buffer.push(x);
|
||||
if self.is_eof() {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
if let Token::Define { behavior, .. } = t {
|
||||
behavior.add_item(BehaviorItem::from(&self.buffer));
|
||||
}
|
||||
}
|
||||
self.buffer.clear();
|
||||
self.state = State::Data;
|
||||
return self.latest.take();
|
||||
}
|
||||
}
|
||||
},
|
||||
State::BehaviorSeparator => match c {
|
||||
' ' | '\n' | '\t' => {}
|
||||
'=' => {
|
||||
self.state = State::Behavior;
|
||||
self.buffer.push('=');
|
||||
}
|
||||
']' => {
|
||||
self.reconsume = true;
|
||||
self.state = State::Behavior;
|
||||
}
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
}
|
||||
_ => {
|
||||
self.state = State::Data;
|
||||
self.reconsume = true;
|
||||
return self.latest.take();
|
||||
}
|
||||
},
|
||||
State::Behavior => match c {
|
||||
x if x.is_ascii_alphanumeric() => {
|
||||
self.reconsume = true;
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
match t {
|
||||
Token::Define {
|
||||
name: _,
|
||||
ref mut behavior,
|
||||
} => {
|
||||
behavior.push(BehaviorItem::new());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
x => {
|
||||
if !x.is_ascii_alphanumeric() {
|
||||
panic!("Unexpected character: {}", x);
|
||||
}
|
||||
self.state = State::BehaviorKey;
|
||||
}
|
||||
' ' | '\n' => {}
|
||||
']' => {
|
||||
self.state = State::Data;
|
||||
return self.latest.take();
|
||||
}
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
}
|
||||
_ => panic!("Unexpected character: {}", c),
|
||||
},
|
||||
State::BehaviorKey => match c {
|
||||
x if x.is_ascii_alphanumeric() => {
|
||||
self.buffer.push(c);
|
||||
}
|
||||
':' => {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
match t {
|
||||
Token::Define {
|
||||
name: _,
|
||||
ref mut behavior,
|
||||
} => {
|
||||
behavior.last_mut().unwrap().set_prefix(self.buffer.clone());
|
||||
self.buffer.clear();
|
||||
self.state = State::BehaviorKey;
|
||||
if self.buffer.ends_with('=') {
|
||||
self.reconsume = true;
|
||||
self.state = State::Behavior;
|
||||
} else {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
if let Token::Define { behavior, .. } = t {
|
||||
behavior.add_item(BehaviorItem::from(&self.buffer));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
'=' => {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
match t {
|
||||
Token::Define {
|
||||
name: _,
|
||||
ref mut behavior,
|
||||
} => {
|
||||
behavior.last_mut().unwrap().set_key(self.buffer.clone());
|
||||
self.buffer.clear();
|
||||
self.state = State::BehaviorValue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
}
|
||||
_ => panic!("Unexpected character: {}", c),
|
||||
},
|
||||
State::BehaviorValue => match c {
|
||||
x if x.is_ascii_alphanumeric() => {
|
||||
self.buffer.push(c);
|
||||
}
|
||||
' ' | '\n' | '\t' | ']' => {
|
||||
if let Some(t) = self.latest.as_mut() {
|
||||
match t {
|
||||
Token::Define {
|
||||
name: _,
|
||||
ref mut behavior,
|
||||
} => {
|
||||
behavior.last_mut().unwrap().set_value(self.buffer.clone());
|
||||
self.buffer.clear();
|
||||
self.state = State::Behavior;
|
||||
self.reconsume = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.buffer.clear();
|
||||
|
||||
_ if self.is_eof() => {
|
||||
return Some(Token::EOF);
|
||||
self.reconsume = true;
|
||||
self.state = State::Behavior;
|
||||
println!("BehaviorItem: {:?}", BehaviorItem::from(&self.buffer));
|
||||
}
|
||||
}
|
||||
_ => panic!("Unexpected character: {}", c),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -206,18 +188,12 @@ enum State {
|
|||
Define,
|
||||
AfterDefine,
|
||||
Behavior,
|
||||
BehaviorKey,
|
||||
BehaviorValue,
|
||||
BehaviorSeparator,
|
||||
}
|
||||
|
||||
use crate::om::behavior::BehaviorItem;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Token {
|
||||
Define {
|
||||
name: String,
|
||||
behavior: Vec<BehaviorItem>,
|
||||
},
|
||||
Define { name: String, behavior: Behavior },
|
||||
Character(char),
|
||||
NodeEnd,
|
||||
EOF,
|
||||
|
@ -241,11 +217,13 @@ mod tests {
|
|||
let expected = [
|
||||
Token::Define {
|
||||
name: "foo".to_string(),
|
||||
behavior: vec![BehaviorItem {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
behavior: Behavior {
|
||||
items: vec![BehaviorItem::KeyValue {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
},
|
||||
},
|
||||
Token::EOF,
|
||||
];
|
||||
|
@ -261,19 +239,23 @@ mod tests {
|
|||
let expected = [
|
||||
Token::Define {
|
||||
name: "foo".to_string(),
|
||||
behavior: vec![BehaviorItem {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
behavior: Behavior {
|
||||
items: vec![BehaviorItem::KeyValue {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
},
|
||||
},
|
||||
Token::Define {
|
||||
name: "bar".to_string(),
|
||||
behavior: vec![BehaviorItem {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
behavior: Behavior {
|
||||
items: vec![BehaviorItem::KeyValue {
|
||||
prefix: Some("prefix".to_string()),
|
||||
key: "key".to_string(),
|
||||
value: "value".to_string(),
|
||||
}],
|
||||
},
|
||||
},
|
||||
Token::EOF,
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue
Block a user