Skip to main content

pegtastic_runtime/
str.rs

1//! Utilities for `str` input
2
3use std::fmt::Display;
4use super::{RuleResult, Parse, ParseElem, ParseLiteral, ParseSlice};
5
6/// Line and column within a string
7#[derive(PartialEq, Eq, Debug, Clone)]
8pub struct LineCol {
9    /// Line (1-indexed)
10    pub line: usize,
11
12    /// Column (1-indexed)
13    pub column: usize,
14
15    /// Byte offset from start of string (0-indexed)
16    pub offset: usize,
17}
18
19impl Display for LineCol {
20    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
21        write!(fmt, "{}:{}", self.line, self.column)
22    }
23}
24
25impl Parse for str {
26    type PositionRepr = LineCol;
27    fn start(&self) -> usize { 0 }
28
29    fn position_repr(&self, pos: usize) -> LineCol {
30        let before = &self[..pos];
31		let line = before.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1;
32		let column = before.chars().rev().take_while(|&c| c != '\n').count() + 1;
33		LineCol { line, column, offset: pos}
34    }
35}
36
37impl ParseElem for str {
38    type Element = char;
39
40    fn parse_elem(&self, pos: usize) -> RuleResult<char> {
41        match self[pos..].chars().next() {
42            Some(c) => RuleResult::Matched(pos + c.len_utf8(), c),
43            None => RuleResult::Failed
44        }
45    }
46}
47
48impl ParseLiteral for str {
49    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> {
50        let l = literal.len();
51        if self.len() >= pos + l && &self.as_bytes()[pos..pos+l] == literal.as_bytes() {
52            RuleResult::Matched(pos+l, ())
53        } else {
54            RuleResult::Failed
55        }
56    }
57}
58
59impl<'input> ParseSlice<'input> for str {
60    type Slice = &'input str;
61    fn parse_slice(&'input self, p1: usize, p2: usize) -> &'input str {
62        &self[p1..p2]
63    }
64}