use crate::ported::lint::markedjson::composer::{AnyEvent, EventKind};
use crate::ported::lint::markedjson::error::MarkedError;
use crate::ported::lint::markedjson::events::{MappingStartEvent, ScalarEvent, SequenceStartEvent};
use crate::ported::lint::markedjson::nodes::Mark;
#[derive(Debug, Clone)]
pub struct ParserError(pub MarkedError);
impl std::fmt::Display for ParserError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for ParserError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TokenKind {
StreamStart,
StreamEnd,
FlowSequenceStart,
FlowSequenceEnd,
FlowMappingStart,
FlowMappingEnd,
Key,
Value,
FlowEntry,
Scalar,
}
#[derive(Debug, Clone)]
pub enum AnyToken {
StreamStart {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
encoding: Option<String>,
},
StreamEnd {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
FlowSequenceStart {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
FlowSequenceEnd {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
FlowMappingStart {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
FlowMappingEnd {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
Key {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
Value {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
FlowEntry {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
},
Scalar {
start_mark: Option<Mark>,
end_mark: Option<Mark>,
value: serde_json::Value,
plain: bool,
style: Option<char>,
},
}
impl AnyToken {
pub fn token_kind(&self) -> TokenKind {
match self {
AnyToken::StreamStart { .. } => TokenKind::StreamStart,
AnyToken::StreamEnd { .. } => TokenKind::StreamEnd,
AnyToken::FlowSequenceStart { .. } => TokenKind::FlowSequenceStart,
AnyToken::FlowSequenceEnd { .. } => TokenKind::FlowSequenceEnd,
AnyToken::FlowMappingStart { .. } => TokenKind::FlowMappingStart,
AnyToken::FlowMappingEnd { .. } => TokenKind::FlowMappingEnd,
AnyToken::Key { .. } => TokenKind::Key,
AnyToken::Value { .. } => TokenKind::Value,
AnyToken::FlowEntry { .. } => TokenKind::FlowEntry,
AnyToken::Scalar { .. } => TokenKind::Scalar,
}
}
pub fn token_start_mark(&self) -> Option<Mark> {
match self {
AnyToken::StreamStart { start_mark, .. }
| AnyToken::StreamEnd { start_mark, .. }
| AnyToken::FlowSequenceStart { start_mark, .. }
| AnyToken::FlowSequenceEnd { start_mark, .. }
| AnyToken::FlowMappingStart { start_mark, .. }
| AnyToken::FlowMappingEnd { start_mark, .. }
| AnyToken::Key { start_mark, .. }
| AnyToken::Value { start_mark, .. }
| AnyToken::FlowEntry { start_mark, .. }
| AnyToken::Scalar { start_mark, .. } => start_mark.clone(),
}
}
pub fn token_end_mark(&self) -> Option<Mark> {
match self {
AnyToken::StreamStart { end_mark, .. }
| AnyToken::StreamEnd { end_mark, .. }
| AnyToken::FlowSequenceStart { end_mark, .. }
| AnyToken::FlowSequenceEnd { end_mark, .. }
| AnyToken::FlowMappingStart { end_mark, .. }
| AnyToken::FlowMappingEnd { end_mark, .. }
| AnyToken::Key { end_mark, .. }
| AnyToken::Value { end_mark, .. }
| AnyToken::FlowEntry { end_mark, .. }
| AnyToken::Scalar { end_mark, .. } => end_mark.clone(),
}
}
pub fn token_id(&self) -> &'static str {
match self {
AnyToken::StreamStart { .. } => "<stream start>",
AnyToken::StreamEnd { .. } => "<stream end>",
AnyToken::FlowSequenceStart { .. } => "[",
AnyToken::FlowSequenceEnd { .. } => "]",
AnyToken::FlowMappingStart { .. } => "{",
AnyToken::FlowMappingEnd { .. } => "}",
AnyToken::Key { .. } => "?",
AnyToken::Value { .. } => ":",
AnyToken::FlowEntry { .. } => ",",
AnyToken::Scalar { .. } => "<scalar>",
}
}
}
pub trait TokenStream {
fn check_token(&mut self, kinds: &[TokenKind]) -> bool;
fn peek_token(&mut self) -> Option<AnyToken>;
fn get_token(&mut self) -> AnyToken;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum State {
StreamStart,
ImplicitDocumentStart,
DocumentStart,
DocumentEnd,
DocumentContent,
Node,
FlowSequenceFirstEntry,
FlowSequenceEntry,
FlowSequenceEntryMappingEnd,
FlowMappingFirstKey,
FlowMappingKey,
FlowMappingValue,
Done,
}
pub struct Parser {
pub current_event: Option<AnyEvent>,
pub yaml_version: Option<String>,
pub states: Vec<State>,
pub marks: Vec<Option<Mark>>,
pub state: State,
}
impl Default for Parser {
fn default() -> Self {
Self::new()
}
}
impl Parser {
pub fn new() -> Self {
Self {
current_event: None,
yaml_version: None,
states: Vec::new(),
marks: Vec::new(),
state: State::StreamStart,
}
}
pub fn dispose(&mut self) {
self.states.clear();
self.state = State::Done;
}
pub fn check_event<S: TokenStream>(&mut self, scanner: &mut S, choices: &[EventKind]) -> bool {
if self.current_event.is_none() && self.state != State::Done {
self.current_event = Some(self.dispatch_state(scanner));
}
if let Some(ev) = &self.current_event {
if choices.is_empty() {
return true;
}
return choices.contains(&ev.kind());
}
false
}
pub fn peek_event<S: TokenStream>(&mut self, scanner: &mut S) -> Option<AnyEvent> {
if self.current_event.is_none() && self.state != State::Done {
self.current_event = Some(self.dispatch_state(scanner));
}
self.current_event.clone()
}
pub fn get_event<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
if self.current_event.is_none() && self.state != State::Done {
self.current_event = Some(self.dispatch_state(scanner));
}
self.current_event.take().unwrap_or(AnyEvent::StreamEnd)
}
fn dispatch_state<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
match self.state {
State::StreamStart => self.parse_stream_start(scanner),
State::ImplicitDocumentStart => self.parse_implicit_document_start(scanner),
State::DocumentStart => self.parse_document_start(scanner),
State::DocumentEnd => self.parse_document_end(scanner),
State::DocumentContent => self.parse_document_content(scanner),
State::Node => self.parse_node(scanner, false),
State::FlowSequenceFirstEntry => self.parse_flow_sequence_first_entry(scanner),
State::FlowSequenceEntry => self.parse_flow_sequence_entry(scanner, false),
State::FlowSequenceEntryMappingEnd => {
self.parse_flow_sequence_entry_mapping_end(scanner)
}
State::FlowMappingFirstKey => self.parse_flow_mapping_first_key(scanner),
State::FlowMappingKey => self.parse_flow_mapping_key(scanner, false),
State::FlowMappingValue => self.parse_flow_mapping_value(scanner),
State::Done => AnyEvent::StreamEnd,
}
}
fn parse_stream_start<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
let token = scanner.get_token();
let _ = token;
self.state = State::ImplicitDocumentStart;
AnyEvent::StreamStart
}
fn parse_implicit_document_start<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
if !scanner.check_token(&[TokenKind::StreamEnd]) {
let _ = scanner.peek_token();
self.states.push(State::DocumentEnd);
self.state = State::Node;
AnyEvent::DocumentStart
} else {
self.parse_document_start(scanner)
}
}
fn parse_document_start<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
if !scanner.check_token(&[TokenKind::StreamEnd]) {
let _ = scanner.peek_token();
return AnyEvent::StreamEnd;
}
let _ = scanner.get_token();
debug_assert!(self.states.is_empty());
debug_assert!(self.marks.is_empty());
self.state = State::Done;
AnyEvent::StreamEnd
}
fn parse_document_end<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
let _ = scanner.peek_token();
self.state = State::DocumentStart;
AnyEvent::DocumentEnd
}
fn parse_document_content<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
self.parse_node(scanner, false)
}
fn parse_node<S: TokenStream>(
&mut self,
scanner: &mut S,
_indentless_sequence: bool,
) -> AnyEvent {
let start_mark = scanner.peek_token().and_then(|t| t.token_start_mark());
if scanner.check_token(&[TokenKind::Scalar]) {
let token = scanner.get_token();
if let AnyToken::Scalar {
value,
plain,
style,
end_mark,
..
} = token
{
let implicit = plain;
self.state = self.states.pop().unwrap_or(State::Done);
return AnyEvent::Scalar(ScalarEvent::new(
implicit, value, start_mark, end_mark, style,
));
}
}
if scanner.check_token(&[TokenKind::FlowSequenceStart]) {
let end_mark = scanner.peek_token().and_then(|t| t.token_end_mark());
self.state = State::FlowSequenceFirstEntry;
return AnyEvent::SequenceStart(SequenceStartEvent::new(
true,
start_mark,
end_mark,
Some(true),
));
}
if scanner.check_token(&[TokenKind::FlowMappingStart]) {
let end_mark = scanner.peek_token().and_then(|t| t.token_end_mark());
self.state = State::FlowMappingFirstKey;
return AnyEvent::MappingStart(MappingStartEvent::new(
true,
start_mark,
end_mark,
Some(true),
));
}
AnyEvent::StreamEnd
}
fn parse_flow_sequence_first_entry<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
let token = scanner.get_token();
self.marks.push(token.token_start_mark());
self.parse_flow_sequence_entry(scanner, true)
}
fn parse_flow_sequence_entry<S: TokenStream>(
&mut self,
scanner: &mut S,
first: bool,
) -> AnyEvent {
if !scanner.check_token(&[TokenKind::FlowSequenceEnd]) {
if !first {
if scanner.check_token(&[TokenKind::FlowEntry]) {
let _ = scanner.get_token();
} else {
return AnyEvent::SequenceEnd;
}
}
if !scanner.check_token(&[TokenKind::FlowSequenceEnd]) {
self.states.push(State::FlowSequenceEntry);
return self.parse_node(scanner, false);
}
}
let _ = scanner.get_token();
let prev = self.states.pop().unwrap_or(State::Done);
self.state = prev;
self.marks.pop();
AnyEvent::SequenceEnd
}
fn parse_flow_sequence_entry_mapping_end<S: TokenStream>(
&mut self,
scanner: &mut S,
) -> AnyEvent {
self.state = State::FlowSequenceEntry;
let _ = scanner.peek_token();
AnyEvent::MappingEnd
}
fn parse_flow_mapping_first_key<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
let token = scanner.get_token();
self.marks.push(token.token_start_mark());
self.parse_flow_mapping_key(scanner, true)
}
fn parse_flow_mapping_key<S: TokenStream>(&mut self, scanner: &mut S, first: bool) -> AnyEvent {
if !scanner.check_token(&[TokenKind::FlowMappingEnd]) {
if !first {
if scanner.check_token(&[TokenKind::FlowEntry]) {
let _ = scanner.get_token();
} else {
return AnyEvent::MappingEnd;
}
}
if scanner.check_token(&[TokenKind::Key]) {
let _ = scanner.get_token();
if !scanner.check_token(&[
TokenKind::Value,
TokenKind::FlowEntry,
TokenKind::FlowMappingEnd,
]) {
self.states.push(State::FlowMappingValue);
return self.parse_node(scanner, false);
}
} else if !scanner.check_token(&[TokenKind::FlowMappingEnd]) {
return AnyEvent::MappingEnd;
}
}
let _ = scanner.get_token();
let prev = self.states.pop().unwrap_or(State::Done);
self.state = prev;
self.marks.pop();
AnyEvent::MappingEnd
}
fn parse_flow_mapping_value<S: TokenStream>(&mut self, scanner: &mut S) -> AnyEvent {
if scanner.check_token(&[TokenKind::Value]) {
let _ = scanner.get_token();
if !scanner.check_token(&[TokenKind::FlowEntry, TokenKind::FlowMappingEnd]) {
self.states.push(State::FlowMappingKey);
return self.parse_node(scanner, false);
}
}
AnyEvent::MappingEnd
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
struct FakeScanner {
tokens: std::collections::VecDeque<AnyToken>,
}
impl FakeScanner {
fn new(tokens: Vec<AnyToken>) -> Self {
Self {
tokens: tokens.into(),
}
}
}
impl TokenStream for FakeScanner {
fn check_token(&mut self, kinds: &[TokenKind]) -> bool {
self.tokens
.front()
.map(|t| kinds.contains(&t.token_kind()))
.unwrap_or(false)
}
fn peek_token(&mut self) -> Option<AnyToken> {
self.tokens.front().cloned()
}
fn get_token(&mut self) -> AnyToken {
self.tokens.pop_front().expect("token underflow")
}
}
fn ss() -> AnyToken {
AnyToken::StreamStart {
start_mark: None,
end_mark: None,
encoding: None,
}
}
fn se() -> AnyToken {
AnyToken::StreamEnd {
start_mark: None,
end_mark: None,
}
}
fn scalar(v: serde_json::Value) -> AnyToken {
AnyToken::Scalar {
start_mark: None,
end_mark: None,
value: v,
plain: true,
style: None,
}
}
#[test]
fn parser_error_implements_error_traits() {
let me = MarkedError::new(Some("ctx"), None, Some("prob"), None, None);
let e = ParserError(me);
let _: &dyn std::error::Error = &e;
}
#[test]
fn parser_starts_at_stream_start_state() {
let p = Parser::new();
assert_eq!(p.state, State::StreamStart);
assert!(p.current_event.is_none());
assert!(p.states.is_empty());
assert!(p.marks.is_empty());
}
#[test]
fn dispose_clears_state_machine() {
let mut p = Parser::new();
p.states.push(State::DocumentEnd);
p.dispose();
assert_eq!(p.state, State::Done);
assert!(p.states.is_empty());
}
#[test]
fn check_event_with_no_choices_returns_true() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![ss(), se()]);
assert!(p.check_event(&mut s, &[]));
}
#[test]
fn check_event_matches_stream_start() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![ss(), se()]);
assert!(p.check_event(&mut s, &[EventKind::StreamStart]));
}
#[test]
fn check_event_rejects_wrong_kind() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![ss(), se()]);
assert!(!p.check_event(&mut s, &[EventKind::Scalar]));
}
#[test]
fn get_event_drains_stream_start_then_stream_end() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![ss(), se()]);
assert_eq!(p.get_event(&mut s).kind(), EventKind::StreamStart);
let ev = p.get_event(&mut s);
assert_eq!(ev.kind(), EventKind::StreamEnd);
}
#[test]
fn parse_node_scalar_emits_scalar_event() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![scalar(json!("hello"))]);
let ev = p.parse_node(&mut s, false);
match ev {
AnyEvent::Scalar(se) => {
assert_eq!(se.value, json!("hello"));
}
_ => panic!("expected ScalarEvent"),
}
}
#[test]
fn parse_node_flow_seq_emits_sequence_start() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![AnyToken::FlowSequenceStart {
start_mark: None,
end_mark: None,
}]);
let ev = p.parse_node(&mut s, false);
assert_eq!(ev.kind(), EventKind::SequenceStart);
assert_eq!(p.state, State::FlowSequenceFirstEntry);
}
#[test]
fn parse_node_flow_map_emits_mapping_start() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![AnyToken::FlowMappingStart {
start_mark: None,
end_mark: None,
}]);
let ev = p.parse_node(&mut s, false);
assert_eq!(ev.kind(), EventKind::MappingStart);
assert_eq!(p.state, State::FlowMappingFirstKey);
}
#[test]
fn any_token_kind_dispatches_correctly() {
assert_eq!(ss().token_kind(), TokenKind::StreamStart);
assert_eq!(se().token_kind(), TokenKind::StreamEnd);
assert_eq!(scalar(json!(0)).token_kind(), TokenKind::Scalar);
}
#[test]
fn any_token_id_strings_match_upstream() {
assert_eq!(ss().token_id(), "<stream start>");
assert_eq!(se().token_id(), "<stream end>");
assert_eq!(scalar(json!(0)).token_id(), "<scalar>");
assert_eq!(
AnyToken::FlowSequenceStart {
start_mark: None,
end_mark: None
}
.token_id(),
"["
);
assert_eq!(
AnyToken::FlowMappingEnd {
start_mark: None,
end_mark: None
}
.token_id(),
"}"
);
}
#[test]
fn parse_simple_scalar_stream_end_to_end() {
let mut p = Parser::new();
let mut s = FakeScanner::new(vec![ss(), scalar(json!("v")), se()]);
assert_eq!(p.get_event(&mut s).kind(), EventKind::StreamStart);
assert_eq!(p.get_event(&mut s).kind(), EventKind::DocumentStart);
assert_eq!(p.get_event(&mut s).kind(), EventKind::Scalar);
assert_eq!(p.get_event(&mut s).kind(), EventKind::DocumentEnd);
assert_eq!(p.get_event(&mut s).kind(), EventKind::StreamEnd);
}
#[test]
fn token_marks_round_trip() {
let t = AnyToken::Key {
start_mark: Some(Mark { line: 1, column: 2 }),
end_mark: Some(Mark { line: 1, column: 3 }),
};
assert_eq!(t.token_start_mark().unwrap().line, 1);
assert_eq!(t.token_end_mark().unwrap().column, 3);
}
#[test]
fn typed_events_constructable_from_events_module() {
use crate::ported::lint::markedjson::events::{
DocumentEndEvent, DocumentStartEvent, MappingEndEvent, SequenceEndEvent,
StreamEndEvent, StreamStartEvent,
};
let _ = StreamStartEvent::new(None, None, None);
let _ = StreamEndEvent::new(None, None);
let _ = DocumentStartEvent::new(None, None, Some(false), None, None);
let _ = DocumentEndEvent::new(None, None, Some(false));
let _ = SequenceEndEvent::new(None, None);
let _ = MappingEndEvent::new(None, None);
}
}