Skip to content

Commit defcf2e

Browse files
committed
runtime: split out Parser into a parser module.
1 parent 75e50d5 commit defcf2e

File tree

7 files changed

+197
-167
lines changed

7 files changed

+197
-167
lines changed

macros/tests/basic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ macro_rules! testcases {
3737

3838
let result = match &result {
3939
Ok(result) => format!("{:#?}", result),
40-
Err(gll::runtime::ParseError {
40+
Err(gll::parser::ParseError {
4141
at,
4242
expected,
4343
}) => {

src/forest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::str;
1010

1111
/// A parse forest, in SPPF (Shared Packed Parse Forest) representation.
1212
pub struct ParseForest<'i, P: ParseNodeKind, I: Input> {
13-
// HACK(eddyb) `pub(crate)` only for `runtime`.
13+
// HACK(eddyb) `pub(crate)` only for `parser`.
1414
pub(crate) input: Container<'i, I::Container>,
1515
pub(crate) possible_choices: HashMap<ParseNode<'i, P>, BTreeSet<P>>,
1616
pub(crate) possible_splits: HashMap<ParseNode<'i, P>, BTreeSet<usize>>,

src/generate/rust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ where
939939
pub fn parse(input: I)
940940
-> Result<
941941
OwnedHandle<I, Self>,
942-
gll::runtime::ParseError<I::SourceInfoPoint>,
942+
gll::parser::ParseError<I::SourceInfoPoint>,
943943
>
944944
{
945945
gll::runtime::Runtime::parse(

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub mod input;
1616
#[forbid(unsafe_code)]
1717
pub mod parse_node;
1818
#[forbid(unsafe_code)]
19+
pub mod parser;
20+
#[forbid(unsafe_code)]
1921
pub mod proc_macro;
2022
#[forbid(unsafe_code)]
2123
pub mod runtime;

src/parse_grammar.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use crate as gll;
77

88
include!(concat!(env!("OUT_DIR"), "/parse_grammar.rs"));
99

10+
use crate::parser::ParseError;
1011
use crate::proc_macro::{FlatToken, Span, TokenStream};
11-
use crate::runtime;
1212
use crate::scannerless::Pat as SPat;
1313
use std::ops::Bound;
1414
use std::str::FromStr;
1515

1616
pub fn parse_grammar<Pat: From<SPat>>(
1717
stream: TokenStream,
18-
) -> Result<grammer::Grammar<Pat>, runtime::ParseError<Span>> {
18+
) -> Result<grammer::Grammar<Pat>, ParseError<Span>> {
1919
let mut grammar = grammer::Grammar::new();
2020
Grammar::parse(stream)?.with(|g| {
2121
for rule_def in g.one().unwrap().rules {

src/parser.rs

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
use crate::forest::{OwnedParseForestAndNode, ParseForest, ParseNode, ParseNodeKind};
2+
use crate::high::ErasableL;
3+
use crate::input::{Input, InputMatch, Range};
4+
use indexing::{self, Index, Unknown};
5+
use std::collections::HashMap;
6+
use std::fmt;
7+
8+
pub struct Parser<'a, 'i, P: ParseNodeKind, I: Input> {
9+
state: &'a mut ParserState<'i, P, I>,
10+
result: Range<'i>,
11+
remaining: Range<'i>,
12+
}
13+
14+
struct ParserState<'i, P: ParseNodeKind, I: Input> {
15+
forest: ParseForest<'i, P, I>,
16+
last_input_pos: Index<'i, Unknown>,
17+
expected_pats: Vec<&'static dyn fmt::Debug>,
18+
}
19+
20+
#[derive(Debug)]
21+
pub struct ParseError<A> {
22+
pub at: A,
23+
pub expected: Vec<&'static dyn fmt::Debug>,
24+
}
25+
26+
pub type ParseResult<A, T> = Result<T, ParseError<A>>;
27+
28+
impl<'i, P: ParseNodeKind, I: Input> Parser<'_, 'i, P, I> {
29+
pub fn parse_with(
30+
input: I,
31+
f: impl for<'i2> FnOnce(Parser<'_, 'i2, P, I>) -> Option<ParseNode<'i2, P>>,
32+
) -> ParseResult<I::SourceInfoPoint, OwnedParseForestAndNode<P, I>> {
33+
ErasableL::indexing_scope(input.to_container(), |lifetime, input| {
34+
let range = Range(input.range());
35+
let mut state = ParserState {
36+
forest: ParseForest {
37+
input,
38+
possible_choices: HashMap::new(),
39+
possible_splits: HashMap::new(),
40+
},
41+
last_input_pos: range.first(),
42+
expected_pats: vec![],
43+
};
44+
45+
let result = f(Parser {
46+
state: &mut state,
47+
result: Range(range.frontiers().0),
48+
remaining: range,
49+
});
50+
51+
let error = ParseError {
52+
at: I::source_info_point(&state.forest.input, state.last_input_pos),
53+
expected: state.expected_pats,
54+
};
55+
match result {
56+
None => Err(error),
57+
Some(node) => {
58+
// The result is only a successful parse if it's as long as the input.
59+
if node.range == range {
60+
Ok(OwnedParseForestAndNode::pack(
61+
lifetime,
62+
(state.forest, node),
63+
))
64+
} else {
65+
Err(error)
66+
}
67+
}
68+
}
69+
})
70+
}
71+
72+
// FIXME(eddyb) find an nicer way for algorithms to manipulate these ranges.
73+
pub fn result(&self) -> Range<'i> {
74+
self.result
75+
}
76+
77+
pub fn remaining(&self) -> Range<'i> {
78+
self.remaining
79+
}
80+
81+
pub fn with_result_and_remaining<'a>(
82+
&'a mut self,
83+
result: Range<'i>,
84+
remaining: Range<'i>,
85+
) -> Parser<'a, 'i, P, I> {
86+
// HACK(eddyb) enforce that `result` and `remaining` are inside `self`.
87+
assert_eq!(self.result, Range(self.remaining.frontiers().0));
88+
let full_new_range = result.join(remaining.0).unwrap();
89+
assert!(self.remaining.start() <= full_new_range.start());
90+
assert_eq!(self.remaining.end(), full_new_range.end());
91+
92+
Parser {
93+
state: self.state,
94+
result,
95+
remaining,
96+
}
97+
}
98+
99+
pub fn input_consume_left<'a, Pat: fmt::Debug>(
100+
&'a mut self,
101+
pat: &'static Pat,
102+
) -> Option<Parser<'a, 'i, P, I>>
103+
where
104+
I::Slice: InputMatch<Pat>,
105+
{
106+
let start = self.remaining.first();
107+
if start > self.state.last_input_pos {
108+
self.state.last_input_pos = start;
109+
self.state.expected_pats.clear();
110+
}
111+
match self.state.forest.input(self.remaining).match_left(pat) {
112+
Some(n) => {
113+
let (matching, after, _) = self.remaining.split_at(n);
114+
if n > 0 {
115+
self.state.last_input_pos = after.first();
116+
self.state.expected_pats.clear();
117+
}
118+
Some(Parser {
119+
state: self.state,
120+
result: Range(self.result.join(matching).unwrap()),
121+
remaining: Range(after),
122+
})
123+
}
124+
None => {
125+
if start == self.state.last_input_pos {
126+
self.state.expected_pats.push(pat);
127+
}
128+
None
129+
}
130+
}
131+
}
132+
133+
pub fn input_consume_right<'a, Pat>(
134+
&'a mut self,
135+
pat: &'static Pat,
136+
) -> Option<Parser<'a, 'i, P, I>>
137+
where
138+
I::Slice: InputMatch<Pat>,
139+
{
140+
// FIXME(eddyb) implement error reporting support like in `input_consume_left`
141+
match self.state.forest.input(self.remaining).match_right(pat) {
142+
Some(n) => {
143+
let (before, matching, _) = self.remaining.split_at(self.remaining.len() - n);
144+
Some(Parser {
145+
state: self.state,
146+
result: Range(matching.join(self.result.0).unwrap()),
147+
remaining: Range(before),
148+
})
149+
}
150+
None => None,
151+
}
152+
}
153+
154+
pub fn forest_add_choice(&mut self, kind: P, choice: P) {
155+
self.state
156+
.forest
157+
.possible_choices
158+
.entry(ParseNode {
159+
kind,
160+
range: self.result,
161+
})
162+
.or_default()
163+
.insert(choice);
164+
}
165+
166+
// FIXME(eddyb) safeguard this against misuse.
167+
pub fn forest_add_split(&mut self, kind: P, left: ParseNode<'i, P>) {
168+
self.state
169+
.forest
170+
.possible_splits
171+
.entry(ParseNode {
172+
kind,
173+
range: self.result,
174+
})
175+
.or_default()
176+
.insert(left.range.len());
177+
}
178+
}

0 commit comments

Comments
 (0)