@@ -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
2539fn 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
3655fn 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
165176fn 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