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