Add block_scalar
This commit is contained in:
parent
1894d11a26
commit
89b9c6b1db
3 changed files with 201 additions and 2 deletions
|
@ -59,6 +59,10 @@ pub struct Parser<T> {
|
||||||
token: Option<Token>,
|
token: Option<Token>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait EventReceiver {
|
||||||
|
fn on_event(&mut self, ev: &Event);
|
||||||
|
}
|
||||||
|
|
||||||
pub type ParseResult = Result<Event, ScanError>;
|
pub type ParseResult = Result<Event, ScanError>;
|
||||||
|
|
||||||
impl<T: Iterator<Item=char>> Parser<T> {
|
impl<T: Iterator<Item=char>> Parser<T> {
|
||||||
|
|
|
@ -147,6 +147,10 @@ fn is_blank(c: char) -> bool {
|
||||||
fn is_blankz(c: char) -> bool {
|
fn is_blankz(c: char) -> bool {
|
||||||
is_blank(c) || is_breakz(c)
|
is_blank(c) || is_breakz(c)
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_digit(c: char) -> bool {
|
||||||
|
c >= '0' && c <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
pub type ScanResult = Result<(), ScanError>;
|
pub type ScanResult = Result<(), ScanError>;
|
||||||
|
|
||||||
|
@ -312,8 +316,10 @@ impl<T: Iterator<Item=char>> Scanner<T> {
|
||||||
'*' => unimplemented!(),
|
'*' => unimplemented!(),
|
||||||
'&' => unimplemented!(),
|
'&' => unimplemented!(),
|
||||||
'!' => unimplemented!(),
|
'!' => unimplemented!(),
|
||||||
'|' if self.flow_level == 0 => unimplemented!(),
|
// Is it a literal scalar?
|
||||||
'>' if self.flow_level == 0 => unimplemented!(),
|
'|' if self.flow_level == 0 => try!(self.fetch_block_scalar(true)),
|
||||||
|
// Is it a folded scalar?
|
||||||
|
'>' if self.flow_level == 0 => try!(self.fetch_block_scalar(false)),
|
||||||
'\'' => try!(self.fetch_flow_scalar(true)),
|
'\'' => try!(self.fetch_flow_scalar(true)),
|
||||||
'"' => try!(self.fetch_flow_scalar(false)),
|
'"' => try!(self.fetch_flow_scalar(false)),
|
||||||
// plain scalar
|
// plain scalar
|
||||||
|
@ -517,6 +523,194 @@ impl<T: Iterator<Item=char>> Scanner<T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult {
|
||||||
|
try!(self.save_simple_key());
|
||||||
|
self.allow_simple_key();
|
||||||
|
let tok = try!(self.scan_block_scalar(literal));
|
||||||
|
|
||||||
|
self.tokens.push_back(tok);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_block_scalar(&mut self, literal: bool) -> Result<Token, ScanError> {
|
||||||
|
let start_mark = self.mark;
|
||||||
|
let mut chomping: i32 = 0;
|
||||||
|
let mut increment: usize = 0;
|
||||||
|
let mut indent: usize = 0;
|
||||||
|
let mut trailing_blank: bool = false;
|
||||||
|
let mut leading_blank: bool = false;
|
||||||
|
|
||||||
|
let mut string = String::new();
|
||||||
|
let mut leading_break = String::new();
|
||||||
|
let mut trailing_breaks = String::new();
|
||||||
|
|
||||||
|
// skip '|' or '>'
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
|
||||||
|
if self.ch() == '+' || self.ch() == '-' {
|
||||||
|
if self.ch() == '+' {
|
||||||
|
chomping = 1;
|
||||||
|
} else {
|
||||||
|
chomping = -1;
|
||||||
|
}
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
if is_digit(self.ch()) {
|
||||||
|
if self.ch() == '0' {
|
||||||
|
return Err(ScanError::new(start_mark,
|
||||||
|
"while scanning a block scalar, found an intendation indicator equal to 0"));
|
||||||
|
}
|
||||||
|
increment = (self.ch() as usize) - ('0' as usize);
|
||||||
|
self.skip();
|
||||||
|
}
|
||||||
|
} else if is_digit(self.ch()) {
|
||||||
|
if self.ch() == '0' {
|
||||||
|
return Err(ScanError::new(start_mark,
|
||||||
|
"while scanning a block scalar, found an intendation indicator equal to 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
increment = (self.ch() as usize) - ('0' as usize);
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
if self.ch() == '+' || self.ch() == '-' {
|
||||||
|
if self.ch() == '+' {
|
||||||
|
chomping = 1;
|
||||||
|
} else {
|
||||||
|
chomping = -1;
|
||||||
|
}
|
||||||
|
self.skip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat whitespaces and comments to the end of the line.
|
||||||
|
self.lookahead(1);
|
||||||
|
|
||||||
|
while is_blank(self.ch()) {
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ch() == '#' {
|
||||||
|
while !is_breakz(self.ch()) {
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we are at the end of the line.
|
||||||
|
if !is_breakz(self.ch()) {
|
||||||
|
return Err(ScanError::new(start_mark,
|
||||||
|
"while scanning a block scalar, did not find expected comment or line break"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_break(self.ch()) {
|
||||||
|
self.lookahead(2);
|
||||||
|
self.skip_line();
|
||||||
|
}
|
||||||
|
|
||||||
|
if increment > 0 {
|
||||||
|
indent = if self.indent >= 0 { (self.indent + increment as isize) as usize } else { increment }
|
||||||
|
}
|
||||||
|
// Scan the leading line breaks and determine the indentation level if needed.
|
||||||
|
try!(self.block_scalar_breaks(&mut indent, &mut trailing_breaks));
|
||||||
|
|
||||||
|
self.lookahead(1);
|
||||||
|
|
||||||
|
let start_mark = self.mark;
|
||||||
|
|
||||||
|
while self.mark.col == indent && !is_z(self.ch()) {
|
||||||
|
println!("--> {:?}", self.ch());
|
||||||
|
// We are at the beginning of a non-empty line.
|
||||||
|
trailing_blank = is_blank(self.ch());
|
||||||
|
if !literal && !leading_break.is_empty()
|
||||||
|
&& !leading_blank && !trailing_blank {
|
||||||
|
if trailing_breaks.is_empty() {
|
||||||
|
string.push(' ');
|
||||||
|
}
|
||||||
|
leading_break.clear();
|
||||||
|
} else {
|
||||||
|
string.extend(leading_break.chars());
|
||||||
|
leading_break.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
string.extend(trailing_breaks.chars());
|
||||||
|
trailing_breaks.clear();
|
||||||
|
|
||||||
|
leading_blank = is_blank(self.ch());
|
||||||
|
|
||||||
|
while !is_breakz(self.ch()) {
|
||||||
|
println!("----> {:?}", self.ch());
|
||||||
|
string.push(self.ch());
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.lookahead(2);
|
||||||
|
self.skip_line();
|
||||||
|
|
||||||
|
// Eat the following intendation spaces and line breaks.
|
||||||
|
try!(self.block_scalar_breaks(&mut indent, &mut trailing_breaks));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chomp the tail.
|
||||||
|
if chomping != -1 {
|
||||||
|
string.extend(leading_break.chars());
|
||||||
|
}
|
||||||
|
|
||||||
|
if chomping == 1 {
|
||||||
|
string.extend(trailing_breaks.chars());
|
||||||
|
}
|
||||||
|
|
||||||
|
if literal {
|
||||||
|
Ok(Token(start_mark, TokenType::ScalarToken(TScalarStyle::Literal, string)))
|
||||||
|
} else {
|
||||||
|
Ok(Token(start_mark, TokenType::ScalarToken(TScalarStyle::Foled, string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_scalar_breaks(&mut self, indent: &mut usize, breaks: &mut String) -> ScanResult {
|
||||||
|
let mut max_indent = 0;
|
||||||
|
loop {
|
||||||
|
self.lookahead(1);
|
||||||
|
while (*indent == 0 || self.mark.col < *indent)
|
||||||
|
&& self.buffer[0] == ' ' {
|
||||||
|
self.skip();
|
||||||
|
self.lookahead(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.mark.col > max_indent {
|
||||||
|
max_indent = self.mark.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a tab character messing the intendation.
|
||||||
|
if (*indent == 0 || self.mark.col < *indent)
|
||||||
|
&& self.buffer[0] == '\t' {
|
||||||
|
return Err(ScanError::new(self.mark,
|
||||||
|
"while scanning a block scalar, found a tab character where an intendation space is expected"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_break(self.ch()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.lookahead(2);
|
||||||
|
// Consume the line break.
|
||||||
|
self.read_break(breaks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if *indent == 0 {
|
||||||
|
*indent = max_indent;
|
||||||
|
if *indent < (self.indent + 1) as usize {
|
||||||
|
*indent = (self.indent + 1) as usize;
|
||||||
|
}
|
||||||
|
if *indent < 1 {
|
||||||
|
*indent = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
|
fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult {
|
||||||
try!(self.save_simple_key());
|
try!(self.save_simple_key());
|
||||||
self.disallow_simple_key();
|
self.disallow_simple_key();
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum TestEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yaml_to_test_events(docs: &Vec<Yaml>) -> Vec<TestEvent> {
|
fn yaml_to_test_events(docs: &Vec<Yaml>) -> Vec<TestEvent> {
|
||||||
|
println!("DOCS {:?}", docs);
|
||||||
fn next(root: &Yaml, evs: &mut Vec<TestEvent>) {
|
fn next(root: &Yaml, evs: &mut Vec<TestEvent>) {
|
||||||
match *root {
|
match *root {
|
||||||
Yaml::BadValue => { panic!("unexpected BadValue"); },
|
Yaml::BadValue => { panic!("unexpected BadValue"); },
|
||||||
|
|
Loading…
Reference in a new issue