@@ -20,8 +20,22 @@ fn got(src: &str) -> (ParserFound, usize) {
20
20
}
21
21
else { ( ParserFound :: Eof , 0 ) }
22
22
}
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
+ ] ;
23
37
24
- /// Parse an identifier.
38
+ /// Parse an identifier
25
39
fn ident < ' a > ( allow_empty : bool , src : & ' a str , start : usize ) -> ParserReturn < ' a , & ' a str > {
26
40
let mut it = src. char_indices ( ) ;
27
41
let first = it. next ( ) ;
@@ -30,7 +44,12 @@ fn ident<'a>(allow_empty: bool, src: &'a str, start: usize) -> ParserReturn<'a,
30
44
if !( is_xid_start ( first) || first == '$' || first == '_' ) { return allow_empty. then_some ( ( "" , start. into ( ) , src, vec ! [ ] ) ) }
31
45
let idx = it. skip_while ( |x| is_xid_continue ( x. 1 ) ) . next ( ) . map_or ( src. len ( ) , |x| x. 0 ) ;
32
46
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) )
34
53
}
35
54
/// Parse any kind of whitepace
36
55
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
153
172
}
154
173
Some ( ( DottedName :: new ( name, global) , ( old..start) . into ( ) , src, errs) )
155
174
}
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
- }
164
175
/// Parse an annotation
165
176
fn annotation < ' a > ( mut src : & ' a str , mut start : usize ) -> ParserReturn < ' a , ( & ' a str , Option < & ' a str > , SourceSpan ) > {
166
177
let begin = start;
@@ -1723,7 +1734,78 @@ fn expr<'a>(mode: u8, src: &'a str, start: usize) -> ParserReturn<'a, Box<dyn AS
1723
1734
}
1724
1735
Some ( ( ast, ( begin..start) . into ( ) , src, errs) )
1725
1736
}
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)
1727
1809
}
1728
1810
/// Parse a CompoundDottedNameSegment (CDNS)
1729
1811
/// A CDNS can be:
0 commit comments