Skip to content

Commit 75781bb

Browse files
committed
Fix some parser issues
1 parent 15a8fbe commit 75781bb

File tree

1 file changed

+93
-11
lines changed

1 file changed

+93
-11
lines changed

cobalt-parser/src/lib.rs

Lines changed: 93 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,22 @@ fn got(src: &str) -> (ParserFound, usize) {
2020
}
2121
else {(ParserFound::Eof, 0)}
2222
}
23+
/// Take a parser function and update `src`, `start`, and `errs`
24+
fn process<'a, T>(parser: impl FnOnce(&'a str, usize) -> ParserReturn<'a, T>, src: &mut &'a str, start: &mut usize, errs: &mut Vec<CobaltError>) -> Option<(T, SourceSpan)> {
25+
let (found, span, rem, mut es) = parser(*src, *start)?;
26+
*start += span.len();
27+
*src = rem;
28+
errs.append(&mut es);
29+
Some((found, span))
30+
}
31+
32+
/// Things an identifier cannot be
33+
const KEYWORDS: &'static [&'static str] = &[
34+
"let", "mut", "const", "type", "fn", "module", "import", "if", "else", "while", // currently in use
35+
"trait", "spec", "break", "continue" // future-proofing
36+
];
2337

24-
/// Parse an identifier.
38+
/// Parse an identifier
2539
fn ident<'a>(allow_empty: bool, src: &'a str, start: usize) -> ParserReturn<'a, &'a str> {
2640
let mut it = src.char_indices();
2741
let first = it.next();
@@ -30,7 +44,12 @@ fn ident<'a>(allow_empty: bool, src: &'a str, start: usize) -> ParserReturn<'a,
3044
if !(is_xid_start(first) || first == '$' || first == '_') {return allow_empty.then_some(("", start.into(), src, vec![]))}
3145
let idx = it.skip_while(|x| is_xid_continue(x.1)).next().map_or(src.len(), |x| x.0);
3246
let (id, rem) = src.split_at(idx);
33-
Some((id, (start, idx).into(), rem, vec![]))
47+
let (id, errs) = if KEYWORDS.contains(&id) {("<error>", vec![CobaltError::ExpectedFound {
48+
ex: "identifier",
49+
found: ParserFound::Str(id.into()),
50+
loc: (start, idx).into()
51+
}])} else {(id, vec![])};
52+
Some((id, (start, idx).into(), rem, errs))
3453
}
3554
/// Parse any kind of whitepace
3655
fn whitespace<'a>(src: &'a str, start: usize) -> ParserReturn<'a, ()> {
@@ -153,14 +172,6 @@ fn global_id<'a>(mut src: &'a str, mut start: usize) -> ParserReturn<'a, DottedN
153172
}
154173
Some((DottedName::new(name, global), (old..start).into(), src, errs))
155174
}
156-
/// Take a parser function and update `src`, `start`, and `errs`
157-
fn process<'a, T>(parser: impl FnOnce(&'a str, usize) -> ParserReturn<'a, T>, src: &mut &'a str, start: &mut usize, errs: &mut Vec<CobaltError>) -> Option<(T, SourceSpan)> {
158-
let (found, span, rem, mut es) = parser(*src, *start)?;
159-
*start += span.len();
160-
*src = rem;
161-
errs.append(&mut es);
162-
Some((found, span))
163-
}
164175
/// Parse an annotation
165176
fn annotation<'a>(mut src: &'a str, mut start: usize) -> ParserReturn<'a, (&'a str, Option<&'a str>, SourceSpan)> {
166177
let begin = start;
@@ -1723,7 +1734,78 @@ fn expr<'a>(mode: u8, src: &'a str, start: usize) -> ParserReturn<'a, Box<dyn AS
17231734
}
17241735
Some((ast, (begin..start).into(), src, errs))
17251736
}
1726-
[log_or, assigns, compound][std::cmp::min(mode, 2) as usize](src, start)
1737+
fn cflow<'a>(mut next: impl for<'b> FnMut(&'b str, usize) -> ParserReturn<'b, Box<dyn AST>> + Copy, mut src: &'a str, mut start: usize) -> ParserReturn<'a, Box<dyn AST>> {
1738+
let begin = start;
1739+
let mut errs = vec![];
1740+
if process(|src, start| start_match("if", src, start), &mut src, &mut start, &mut errs).is_some() {
1741+
process(ignored, &mut src, &mut start, &mut errs);
1742+
let cond = match src.as_bytes().get(0) {
1743+
Some(b'(') | Some(b'{') => process(atom, &mut src, &mut start, &mut errs).unwrap().0,
1744+
_ => {
1745+
let got = got(src);
1746+
errs.push(CobaltError::ExpectedFound {
1747+
ex: r#""(" or "{" for `if` condition"#,
1748+
found: got.0,
1749+
loc: (start, got.1).into()
1750+
});
1751+
Box::new(NullAST::new(start.into())) as _
1752+
}
1753+
};
1754+
process(ignored, &mut src, &mut start, &mut errs);
1755+
let if_true = process(next, &mut src, &mut start, &mut errs).map_or_else(|| {
1756+
let got = got(src);
1757+
errs.push(CobaltError::ExpectedFound {
1758+
ex: r#"`if` body"#,
1759+
found: got.0,
1760+
loc: (start, got.1).into()
1761+
});
1762+
Box::new(NullAST::new(start.into())) as _
1763+
}, |x| x.0);
1764+
process(ignored, &mut src, &mut start, &mut errs);
1765+
let if_false = process(|src, start| start_match("else", src, start), &mut src, &mut start, &mut errs).map(|_| {
1766+
process(next, &mut src, &mut start, &mut errs).map_or_else(|| {
1767+
let got = got(src);
1768+
errs.push(CobaltError::ExpectedFound {
1769+
ex: r#"`else` body"#,
1770+
found: got.0,
1771+
loc: (start, got.1).into()
1772+
});
1773+
Box::new(NullAST::new(start.into())) as _
1774+
}, |x| x.0)
1775+
});
1776+
let ast = Box::new(IfAST::new((begin..start).into(), cond, if_true, if_false));
1777+
Some((ast, (begin..start).into(), src, errs))
1778+
}
1779+
else if process(|src, start| start_match("while", src, start), &mut src, &mut start, &mut errs).is_some() {
1780+
process(ignored, &mut src, &mut start, &mut errs);
1781+
let cond = match src.as_bytes().get(0) {
1782+
Some(b'(') | Some(b'{') => process(atom, &mut src, &mut start, &mut errs).unwrap().0,
1783+
_ => {
1784+
let got = got(src);
1785+
errs.push(CobaltError::ExpectedFound {
1786+
ex: r#""(" or "{" for `while` condition"#,
1787+
found: got.0,
1788+
loc: (start, got.1).into()
1789+
});
1790+
Box::new(NullAST::new(start.into())) as _
1791+
}
1792+
};
1793+
process(ignored, &mut src, &mut start, &mut errs);
1794+
let body = process(next, &mut src, &mut start, &mut errs).map_or_else(|| {
1795+
let got = got(src);
1796+
errs.push(CobaltError::ExpectedFound {
1797+
ex: r#"`while` body"#,
1798+
found: got.0,
1799+
loc: (start, got.1).into()
1800+
});
1801+
Box::new(NullAST::new(start.into())) as _
1802+
}, |x| x.0);
1803+
let ast = Box::new(WhileAST::new((begin..start).into(), cond, body));
1804+
Some((ast, (begin..start).into(), src, errs))
1805+
}
1806+
else {next(src, start)}
1807+
}
1808+
cflow([log_or, assigns, compound][std::cmp::min(mode, 2) as usize], src, start)
17271809
}
17281810
/// Parse a CompoundDottedNameSegment (CDNS)
17291811
/// A CDNS can be:

0 commit comments

Comments
 (0)