use std::{fmt, io};
use std::net::AddrParseError;
use bytes::{BufMut, Bytes, BytesMut};
use failure::Fail;
use ::bits::name;
use ::bits::name::Dname;
use ::utils::{base32, base64};
pub trait CharSource {
fn next(&mut self) -> Result<Option<char>, io::Error>;
}
#[derive(Clone, Debug)]
pub struct Scanner<C: CharSource> {
chars: C,
buf: Vec<Token>,
start: usize,
cur: usize,
start_pos: Pos,
cur_pos: Pos,
paren: bool,
newline: NewlineMode,
origin: Option<Dname>,
}
impl<C: CharSource> Scanner<C> {
pub fn new(chars: C) -> Self {
Scanner::with_pos(chars, Pos::new())
}
pub fn with_pos(chars: C, pos: Pos) -> Self {
Scanner {
chars,
buf: Vec::new(),
start: 0,
cur: 0,
start_pos: pos,
cur_pos: pos,
paren: false,
newline: NewlineMode::Unknown,
origin: None,
}
}
}
impl<C: CharSource> Scanner<C> {
pub fn origin(&self) -> &Option<Dname> {
&self.origin
}
pub fn set_origin(&mut self, origin: Option<Dname>) {
self.origin = origin
}
}
impl<C: CharSource> Scanner<C> {
#[allow(wrong_self_convention)] pub fn is_eof(&mut self) -> bool {
match self.peek() {
Ok(Some(_)) => false,
_ => true
}
}
pub fn pos(&self) -> Pos {
self.cur_pos
}
pub fn scan_word<T, U, F, G>(&mut self, mut target: T, mut symbolop: F,
finalop: G) -> Result<U, ScanError>
where F: FnMut(&mut T, Symbol)
-> Result<(), SyntaxError>,
G: FnOnce(T) -> Result<U, SyntaxError> {
match self.peek()? {
Some(Token::Symbol(ch)) => {
if !ch.is_word_char() {
return self.err(SyntaxError::Unexpected(ch))
}
}
Some(Token::Newline) => {
return self.err(SyntaxError::UnexpectedNewline)
}
None => return self.err(SyntaxError::UnexpectedEof)
};
while let Some(ch) = self.cond_read_symbol(Symbol::is_word_char)? {
if let Err(err) = symbolop(&mut target, ch) {
return self.err_cur(err)
}
}
let res = match finalop(target) {
Ok(res) => res,
Err(err) => return self.err(err)
};
self.skip_delimiter()?;
Ok(res)
}
pub fn scan_string_word<U, G>(&mut self, finalop: G)
-> Result<U, ScanError>
where G: FnOnce(String) -> Result<U, SyntaxError> {
self.scan_word(
String::new(),
|res, ch| {
let ch = match ch {
Symbol::Char(ch) | Symbol::SimpleEscape(ch) => ch,
Symbol::DecimalEscape(ch) => ch as char,
};
res.push(ch);
Ok(())
},
finalop
)
}
pub fn scan_quoted<T, U, F, G>(&mut self, mut target: T, mut symbolop: F,
finalop: G) -> Result<U, ScanError>
where F: FnMut(&mut T, Symbol)
-> Result<(), SyntaxError>,
G: FnOnce(T) -> Result<U, SyntaxError> {
match self.read()? {
Some(Token::Symbol(Symbol::Char('"'))) => { }
Some(Token::Symbol(ch)) => {
return self.err(SyntaxError::Unexpected(ch))
}
Some(Token::Newline) => {
return self.err(SyntaxError::UnexpectedNewline)
}
None => return self.err(SyntaxError::UnexpectedEof)
}
loop {
match self.read()? {
Some(Token::Symbol(Symbol::Char('"'))) => break,
Some(Token::Symbol(ch)) => {
if let Err(err) = symbolop(&mut target, ch) {
return self.err(err)
}
}
Some(Token::Newline) => {
return self.err(SyntaxError::UnexpectedNewline)
}
None => return self.err(SyntaxError::UnexpectedEof),
}
}
let res = match finalop(target) {
Ok(res) => res,
Err(err) => return self.err(err)
};
self.skip_delimiter()?;
Ok(res)
}
pub fn scan_phrase<T, U, F, G>(&mut self, target: T, symbolop: F,
finalop: G) -> Result<U, ScanError>
where F: FnMut(&mut T, Symbol)
-> Result<(), SyntaxError>,
G: FnOnce(T) -> Result<U, SyntaxError> {
if let Some(Token::Symbol(Symbol::Char('"'))) = self.peek()? {
self.scan_quoted(target, symbolop, finalop)
}
else {
self.scan_word(target, symbolop, finalop)
}
}
pub fn scan_byte_phrase<U, G>(&mut self, finalop: G)
-> Result<U, ScanError>
where G: FnOnce(Bytes) -> Result<U, SyntaxError> {
self.scan_phrase(
BytesMut::new(),
|buf, symbol| symbol.push_to_buf(buf).map_err(Into::into),
|buf| finalop(buf.freeze())
)
}
pub fn scan_string_phrase<U, G>(&mut self, finalop: G)
-> Result<U, ScanError>
where G: FnOnce(String)
-> Result<U, SyntaxError> {
self.scan_phrase(
String::new(),
|res, ch| {
let ch = match ch {
Symbol::Char(ch) | Symbol::SimpleEscape(ch) => ch,
Symbol::DecimalEscape(ch) => ch as char,
};
res.push(ch);
Ok(())
},
finalop
)
}
pub fn scan_newline(&mut self) -> Result<(), ScanError> {
match self.read()? {
Some(Token::Symbol(Symbol::Char(';'))) => {
while let Some(ch) = self.read()? {
if ch.is_newline() {
break
}
}
self.ok(())
}
Some(Token::Newline) => self.ok(()),
None => self.ok(()),
_ => self.err(SyntaxError::ExpectedNewline)
}
}
pub fn scan_space(&mut self) -> Result<(), ScanError> {
if self.skip_space()? {
self.ok(())
}
else {
self.err(SyntaxError::ExpectedSpace)
}
}
pub fn scan_opt_space(&mut self) -> Result<(), ScanError> {
self.skip_space()?;
Ok(())
}
pub fn skip_entry(&mut self) -> Result<(), ScanError> {
let mut quote = false;
loop {
match self.read()? {
None => break,
Some(Token::Newline) => {
if !quote && !self.paren {
break
}
}
Some(Token::Symbol(Symbol::Char('"'))) => quote = !quote,
Some(Token::Symbol(Symbol::Char('('))) => {
if !quote {
if self.paren {
return self.err(SyntaxError::NestedParentheses)
}
self.paren = true
}
}
Some(Token::Symbol(Symbol::Char(')'))) => {
if !quote {
if !self.paren {
return self.err(SyntaxError::Unexpected(')'.into()))
}
self.paren = false
}
}
_ => { }
}
}
self.ok(())
}
pub fn skip_literal(&mut self, literal: &str) -> Result<(), ScanError> {
self.scan_word(
literal,
|left, symbol| {
let first = match left.chars().next() {
Some(ch) => ch,
None => return Err(SyntaxError::Expected(literal.into()))
};
match symbol {
Symbol::Char(ch) if ch == first => {
*left = &left[ch.len_utf8()..];
Ok(())
}
_ => Err(SyntaxError::Expected(literal.into()))
}
},
|left| {
if left.is_empty() {
Ok(())
}
else {
Err(SyntaxError::Expected(literal.into()))
}
}
)
}
}
impl<C: CharSource> Scanner<C> {
pub fn scan_hex_word<U, G>(&mut self, finalop: G) -> Result<U, ScanError>
where G: FnOnce(Bytes) -> Result<U, SyntaxError> {
self.scan_word(
(BytesMut::new(), None), |&mut (ref mut res, ref mut first), symbol | {
hex_symbolop(res, first, symbol)
},
|(res, first)| {
if let Some(ch) = first {
Err(SyntaxError::Unexpected(
Symbol::Char(::std::char::from_digit(ch, 16)
.unwrap())))
}
else {
finalop(res.freeze())
}
}
)
}
pub fn scan_hex_words<U, G>(&mut self, finalop: G) -> Result<U, ScanError>
where G: FnOnce(Bytes) -> Result<U, SyntaxError> {
let start_pos = self.pos();
let mut buf = BytesMut::new();
let mut first = true;
loop {
let res = self.scan_word(
(&mut buf, None),
|&mut (ref mut buf, ref mut first), symbol| {
hex_symbolop(buf, first, symbol)
},
|(_, first)| {
if let Some(ch) = first {
Err(SyntaxError::Unexpected(
Symbol::Char(
::std::char::from_digit(ch, 16).unwrap()
)
))
}
else {
Ok(())
}
}
);
if first {
if let Err(err) = res {
return Err(err)
}
first = false;
}
else if res.is_err() {
break
}
}
finalop(buf.freeze()).map_err(|err| (err, start_pos).into())
}
pub fn scan_base32hex_phrase<U, G>(
&mut self,
finalop: G
) -> Result<U, ScanError>
where G: FnOnce(Bytes) -> Result<U, SyntaxError> {
self.scan_phrase(
base32::Decoder::new_hex(),
|decoder, symbol| {
decoder.push(symbol.into_char()?)
.map_err(SyntaxError::content)
},
|decoder| {
finalop(decoder.finalize().map_err(SyntaxError::content)?)
}
)
}
pub fn scan_base64_phrases<U, G>(
&mut self,
finalop: G
) -> Result<U, ScanError>
where G: FnOnce(Bytes) -> Result<U, SyntaxError> {
let start_pos = self.pos();
let mut decoder = base64::Decoder::new();
let mut first = true;
loop {
let res = self.scan_phrase(
&mut decoder,
|decoder, symbol| {
decoder.push(symbol.into_char()?)
.map_err(SyntaxError::content)
},
Ok
);
if first {
if let Err(err) = res {
return Err(err)
}
first = false;
}
else if res.is_err() {
break
}
}
let bytes = decoder.finalize().map_err(|err| {
(SyntaxError::content(err), self.pos())
})?;
finalop(bytes).map_err(|err| (err, start_pos).into())
}
}
fn hex_symbolop(
buf: &mut BytesMut,
first: &mut Option<u32>,
symbol: Symbol
) -> Result<(), SyntaxError> {
let ch = match symbol {
Symbol::Char(ch) => {
match ch.to_digit(16) {
Some(ch) => ch,
_ => return Err(SyntaxError::Unexpected(symbol))
}
}
_ => return Err(SyntaxError::Unexpected(symbol))
};
if let Some(ch1) = first.take() {
if buf.remaining_mut() == 0 {
buf.reserve(1)
}
buf.put_u8((ch1 as u8) << 4 | (ch as u8));
}
else {
*first = Some(ch)
}
Ok(())
}
impl<C: CharSource> Scanner<C> {
fn chars_next(&mut self) -> Result<Option<char>, ScanError> {
self.chars.next().map_err(|err| {
let mut pos = self.cur_pos;
for ch in &self.buf {
pos.update(*ch)
}
ScanError::Source(err, pos)
})
}
fn source_token(&mut self) -> Result<bool, ScanError> {
let ch = match self.chars_next()? {
Some(ch) => ch,
None => return Ok(false),
};
if ch == '\\' {
self.source_escape()
}
else {
self.source_normal(ch)
}
}
fn source_escape(&mut self) -> Result<bool, ScanError> {
let ch = match self.chars_next()? {
Some(ch) if ch.is_digit(10) => {
let ch = ch.to_digit(10).unwrap() * 100;
let ch2 = match self.chars_next()? {
Some(ch) => match ch.to_digit(10) {
Some(ch) => ch * 10,
None => {
return self.err_cur(SyntaxError::IllegalEscape)
}
}
None => {
return self.err_cur(SyntaxError::UnexpectedEof)
}
};
let ch3 = match self.chars_next()? {
Some(ch) => match ch.to_digit(10) {
Some(ch) => ch,
None => {
return self.err_cur(SyntaxError::IllegalEscape)
}
}
None => {
return self.err_cur(SyntaxError::UnexpectedEof)
}
};
let res = ch + ch2 + ch3;
if res > 255 {
return self.err_cur(SyntaxError::IllegalEscape)
}
else {
Symbol::DecimalEscape(res as u8)
}
}
Some(ch) => Symbol::SimpleEscape(ch),
None => {
return self.err_cur(SyntaxError::UnexpectedEof)
}
};
self.buf.push(Token::Symbol(ch));
Ok(true)
}
fn source_normal(&mut self, ch: char) -> Result<bool, ScanError> {
match self.newline {
NewlineMode::Single(sep) => {
if ch == sep {
self.buf.push(Token::Newline)
}
else {
self.buf.push(Token::Symbol(Symbol::Char(ch)))
}
Ok(true)
}
NewlineMode::Double(first, second) => {
if ch != first {
self.buf.push(Token::Symbol(Symbol::Char(ch)));
Ok(true)
}
else {
match self.chars_next()? {
Some(ch) if ch == second => {
self.buf.push(Token::Newline);
Ok(true)
}
Some(ch) => {
self.buf.push(Token::Symbol(Symbol::Char(first)));
self.buf.push(Token::Symbol(Symbol::Char(ch)));
Ok(true)
}
None => {
Ok(false)
}
}
}
}
NewlineMode::Unknown => {
if ch != '\r' && ch != '\n' {
self.buf.push(Token::Symbol(Symbol::Char(ch)));
Ok(true)
}
else if let Some(second) = self.chars_next()? {
match (ch, second) {
('\r', '\n') | ('\n', '\r') => {
self.newline = NewlineMode::Double(ch, second);
self.buf.push(Token::Newline);
}
('\r', '\r') | ('\n', '\n') => {
self.newline = NewlineMode::Single(ch);
self.buf.push(Token::Newline);
self.buf.push(Token::Newline);
}
('\r', _) | ('\n', _) => {
self.newline = NewlineMode::Single(ch);
self.buf.push(Token::Newline);
self.buf.push(Token::Symbol(Symbol::Char(second)));
}
_ => {
self.buf.push(Token::Symbol(Symbol::Char(ch)));
self.buf.push(Token::Symbol(Symbol::Char(second)));
}
}
Ok(true)
}
else {
if ch == '\r' || ch == '\n' {
self.buf.push(Token::Newline);
}
else {
self.buf.push(Token::Symbol(Symbol::Char(ch)))
}
Ok(true)
}
}
}
}
fn peek(&mut self) -> Result<Option<Token>, ScanError> {
if self.buf.len() == self.cur && !self.source_token()? {
return Ok(None)
}
Ok(Some(self.buf[self.cur]))
}
fn read(&mut self) -> Result<Option<Token>, ScanError> {
self.peek().map(|res| match res {
Some(ch) => {
self.cur += 1;
self.cur_pos.update(ch);
Some(ch)
}
None => None
})
}
fn skip(&mut self, ch: Token) {
self.cur += 1;
self.cur_pos.update(ch)
}
fn ok<T>(&mut self, t: T) -> Result<T, ScanError> {
if self.buf.len() == self.cur {
self.buf.clear();
self.start = 0;
self.cur = 0;
} else {
self.start = self.cur;
}
self.start_pos = self.cur_pos;
Ok(t)
}
fn err<T>(&mut self, err: SyntaxError) -> Result<T, ScanError> {
let pos = self.start_pos;
self.err_at(err, pos)
}
fn err_cur<T>(&mut self, err: SyntaxError) -> Result<T, ScanError> {
let pos = self.cur_pos;
self.err_at(err, pos)
}
fn err_at<T>(&mut self, err: SyntaxError, pos: Pos)
-> Result<T, ScanError> {
self.cur = self.start;
self.cur_pos = self.start_pos;
Err(ScanError::Syntax(err, pos))
}
}
impl<C: CharSource> Scanner<C> {
fn cond_read<F>(&mut self, f: F)
-> Result<Option<Token>, ScanError>
where F: FnOnce(Token) -> bool {
match self.peek()? {
Some(ch) if f(ch) => self.read(),
_ => Ok(None)
}
}
fn cond_read_symbol<F>(&mut self, f: F)
-> Result<Option<Symbol>, ScanError>
where F: FnOnce(Symbol) -> bool {
match self.peek()? {
Some(Token::Symbol(ch)) if f(ch) => {
self.skip(Token::Symbol(ch));
Ok(Some(ch))
}
_ => Ok(None)
}
}
fn skip_delimiter(&mut self) -> Result<(), ScanError> {
if self.skip_space()? {
self.ok(())
}
else {
match self.peek()? {
Some(ch) if ch.is_newline_ahead() => self.ok(()),
None => self.ok(()),
_ => self.err(SyntaxError::ExpectedSpace)
}
}
}
fn skip_space(&mut self) -> Result<bool, ScanError> {
let mut res = false;
loop {
if self.paren {
match self.cond_read(Token::is_paren_space)? {
None => break,
Some(Token::Symbol(Symbol::Char('('))) => {
let pos = self.cur_pos.prev();
return self.err_at(SyntaxError::NestedParentheses,
pos)
}
Some(Token::Symbol(Symbol::Char(')'))) => {
self.paren = false;
}
Some(Token::Symbol(Symbol::Char(';'))) => {
while let Some(ch) = self.read()? {
if ch.is_newline() {
break
}
}
}
_ => { }
}
}
else {
match self.cond_read(Token::is_non_paren_space)? {
None => break,
Some(Token::Symbol(Symbol::Char('('))) => {
self.paren = true;
}
Some(Token::Symbol(Symbol::Char(')'))) => {
let pos = self.cur_pos.prev();
return self.err_at(SyntaxError::Unexpected(
')'.into()), pos)
}
_ => { }
}
}
res = true;
}
Ok(res)
}
}
pub trait Scan: Sized {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError>;
}
impl Scan for u32 {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
scanner.scan_phrase(
0u32,
|res, symbol| {
let ch = match symbol {
Symbol::Char(ch) => {
if let Some(value) = ch.to_digit(10) {
value
}
else {
return Err(SyntaxError::Unexpected(symbol))
}
}
_ => return Err(SyntaxError::Unexpected(symbol))
};
*res = match res.checked_mul(10) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
*res = match res.checked_add(ch) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
Ok(())
},
Ok
)
}
}
impl Scan for u16 {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
scanner.scan_phrase(
0u16,
|res, symbol| {
let ch = match symbol {
Symbol::Char(ch) => {
if let Some(value) = ch.to_digit(10) {
value as u16
}
else {
return Err(SyntaxError::Unexpected(symbol))
}
}
_ => return Err(SyntaxError::Unexpected(symbol))
};
*res = match res.checked_mul(10) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
*res = match res.checked_add(ch) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
Ok(())
},
Ok
)
}
}
impl Scan for u8 {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
scanner.scan_phrase(
0u8,
|res, symbol| {
let ch = match symbol {
Symbol::Char(ch) => {
if let Some(value) = ch.to_digit(10) {
value as u8
}
else {
return Err(SyntaxError::Unexpected(symbol))
}
}
_ => return Err(SyntaxError::Unexpected(symbol))
};
*res = match res.checked_mul(10) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
*res = match res.checked_add(ch) {
Some(res) => res,
None => return Err(SyntaxError::IllegalInteger)
};
Ok(())
},
Ok
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Symbol {
Char(char),
SimpleEscape(char),
DecimalEscape(u8),
}
impl Symbol {
pub fn from_chars<C>(chars: C) -> Result<Option<Self>, SymbolError>
where C: IntoIterator<Item=char> {
let mut chars = chars.into_iter();
let ch = match chars.next() {
Some(ch) => ch,
None => return Ok(None),
};
if ch != '\\' {
return Ok(Some(Symbol::Char(ch)))
}
match chars.next() {
Some(ch) if ch.is_digit(10) => {
let ch = ch.to_digit(10).unwrap() * 100;
let ch2 = match chars.next() {
Some(ch) => match ch.to_digit(10) {
Some(ch) => ch * 10,
None => return Err(SymbolError::BadEscape)
}
None => return Err(SymbolError::ShortInput)
};
let ch3 = match chars.next() {
Some(ch) => match ch.to_digit(10) {
Some(ch) => ch,
None => return Err(SymbolError::BadEscape)
}
None => return Err(SymbolError::ShortInput)
};
let res = ch + ch2 + ch3;
if res > 255 {
return Err(SymbolError::BadEscape)
}
Ok(Some(Symbol::DecimalEscape(res as u8)))
}
Some(ch) => Ok(Some(Symbol::SimpleEscape(ch))),
None => Err(SymbolError::ShortInput)
}
}
pub fn from_byte(ch: u8) -> Self {
if ch == b' ' || ch == b'"' || ch == b'\\' || ch == b';' {
Symbol::SimpleEscape(ch as char)
}
else if ch < 0x20 || ch > 0x7E {
Symbol::DecimalEscape(ch)
}
else {
Symbol::Char(ch as char)
}
}
pub fn into_byte(self) -> Result<u8, BadSymbol> {
match self {
Symbol::Char(ch) | Symbol::SimpleEscape(ch) => {
if ch.is_ascii() && ch >= '\u{20}' && ch <= '\u{7E}' {
Ok(ch as u8)
}
else {
Err(BadSymbol(self))
}
}
Symbol::DecimalEscape(ch) => Ok(ch),
}
}
pub fn into_char(self) -> Result<char, BadSymbol> {
match self {
Symbol::Char(ch) | Symbol::SimpleEscape(ch) => Ok(ch),
Symbol::DecimalEscape(_) => Err(BadSymbol(self))
}
}
pub fn into_digit(self, base: u32) -> Result<u32, SyntaxError> {
if let Symbol::Char(ch) = self {
match ch.to_digit(base) {
Some(ch) => Ok(ch),
None => Err(SyntaxError::Unexpected(self))
}
}
else {
Err(SyntaxError::Unexpected(self))
}
}
pub fn push_to_buf(self, buf: &mut BytesMut) -> Result<(), BadSymbol> {
self.into_byte().map(|ch| {
if buf.remaining_mut() == 0 {
buf.reserve(1);
}
buf.put_u8(ch)
})
}
pub fn is_word_char(self) -> bool {
match self {
Symbol::Char(ch) => {
ch != ' ' && ch != '\t' && ch != '(' && ch != ')' &&
ch != ';' && ch != '"'
}
_ => true
}
}
}
impl From<char> for Symbol {
fn from(ch: char) -> Symbol {
Symbol::Char(ch)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Symbol::Char(ch) => write!(f, "{}", ch),
Symbol::SimpleEscape(ch) => write!(f, "\\{}", ch),
Symbol::DecimalEscape(ch) => write!(f, "\\{:03}", ch),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Token {
Symbol(Symbol),
Newline,
}
impl Token {
fn is_non_paren_space(self) -> bool {
match self {
Token::Symbol(Symbol::Char(ch)) => {
ch == ' ' || ch == '\t' || ch == '(' || ch == ')'
}
_ => false
}
}
fn is_paren_space(self) -> bool {
match self {
Token::Symbol(Symbol::Char(ch)) => {
ch == ' ' || ch == '\t' || ch == '(' || ch == ')' ||
ch == ';'
}
Token::Newline => true,
_ => false
}
}
fn is_newline(self) -> bool {
match self {
Token::Newline => true,
_ => false,
}
}
fn is_newline_ahead(self) -> bool {
match self {
Token::Symbol(Symbol::Char(';')) => true,
Token::Newline => true,
_ => false,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum NewlineMode {
Single(char),
Double(char, char),
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum SymbolError {
#[fail(display="illegal escape sequence")]
BadEscape,
#[fail(display="unexpected end of input")]
ShortInput
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
#[fail(display="bad symbol '{}'", _0)]
pub struct BadSymbol(pub Symbol);
#[derive(Debug, Fail)]
pub enum SyntaxError {
#[fail(display="expected '{}'", _0)]
Expected(String),
#[fail(display="expected a new line")]
ExpectedNewline,
#[fail(display="expected white space")]
ExpectedSpace,
#[fail(display="invalid escape sequence")]
IllegalEscape,
#[fail(display="invalid integer value")]
IllegalInteger,
#[fail(display="invalid address: {}", _0)]
IllegalAddr(AddrParseError),
#[fail(display="illegal domain name: {}", _0)]
IllegalName(name::FromStrError),
#[fail(display="character string too long")]
LongCharStr,
#[fail(display="hex string with an odd number of characters")]
UnevenHexString,
#[fail(display="more data given than in the length byte")]
LongGenericData,
#[fail(display="nested parentheses")]
NestedParentheses,
#[fail(display="omitted TTL but no default TTL given")]
NoDefaultTtl,
#[fail(display="omitted class but no previous class given")]
NoLastClass,
#[fail(display="omitted owner but no previous owner given")]
NoLastOwner,
#[fail(display="owner @ without preceding $ORIGIN")]
NoOrigin,
#[fail(display="relative domain name")]
RelativeName,
#[fail(display="unexpected '{}'", _0)]
Unexpected(Symbol),
#[fail(display="unexpected newline")]
UnexpectedNewline,
#[fail(display="unexpected end of file")]
UnexpectedEof,
#[fail(display="unknown mnemonic")]
UnknownMnemonic,
#[fail(display="{}", _0)]
Content(Box<Fail>),
}
impl SyntaxError {
pub fn content<E: Fail>(err: E) -> Self {
SyntaxError::Content(Box::new(err))
}
}
impl From<BadSymbol> for SyntaxError {
fn from(err: BadSymbol) -> SyntaxError {
SyntaxError::Unexpected(err.0)
}
}
impl From<AddrParseError> for SyntaxError {
fn from(err: AddrParseError) -> SyntaxError {
SyntaxError::IllegalAddr(err)
}
}
impl From<name::FromStrError> for SyntaxError {
fn from(err: name::FromStrError) -> SyntaxError {
SyntaxError::IllegalName(err)
}
}
impl From<name::PushNameError> for SyntaxError {
fn from(err: name::PushNameError) -> SyntaxError {
SyntaxError::from(name::FromStrError::from(err))
}
}
#[derive(Debug)]
pub enum ScanError {
Source(io::Error, Pos),
Syntax(SyntaxError, Pos),
}
impl From<(io::Error, Pos)> for ScanError {
fn from(err: (io::Error, Pos)) -> ScanError {
ScanError::Source(err.0, err.1)
}
}
impl From<(SyntaxError, Pos)> for ScanError {
fn from(err: (SyntaxError, Pos)) -> ScanError {
ScanError::Syntax(err.0, err.1)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Pos {
line: usize,
col: usize
}
impl Pos {
pub fn new() -> Pos {
Pos { line: 1, col: 1 }
}
pub fn line(&self) -> usize { self.line }
pub fn col(&self) -> usize { self.col }
pub fn update(&mut self, ch: Token) {
match ch {
Token::Symbol(Symbol::Char(_)) => self.col += 1,
Token::Symbol(Symbol::SimpleEscape(_)) => self.col += 2,
Token::Symbol(Symbol::DecimalEscape(_)) => self.col += 4,
Token::Newline => { self.line += 1; self.col = 1 }
}
}
pub fn prev(&self) -> Pos {
Pos { line: self.line,
col: if self.col <= 1 { 1 } else { self.col - 1 }
}
}
}
impl From<(usize, usize)> for Pos {
fn from(src: (usize, usize)) -> Pos {
Pos { line: src.0, col: src.1 }
}
}
impl PartialEq<(usize, usize)> for Pos {
fn eq(&self, other: &(usize, usize)) -> bool {
self.line == other.0 && self.col == other.1
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn scan_word() {
let mut scanner = Scanner::new("one two three\nfour");
assert_eq!(scanner.scan_string_word(Ok).unwrap(), "one");
}
}