add label behaviour; update main.rs for improved output formatting

This commit is contained in:
Keisuke Hirata 2024-12-09 04:22:02 +09:00
parent 84cb7e52da
commit 8687b21821
3 changed files with 166 additions and 163 deletions

View File

@ -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!();
} }

View File

@ -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(),
}
} }
} }

View File

@ -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 {