11use crate :: tokenizer:: * ;
2+ use core:: str:: FromStr ;
23
34type Integer = isize ;
45type Real = f64 ;
@@ -32,6 +33,11 @@ pub(crate) enum Statement<'src> {
3233 func : & ' src str ,
3334 args : Vec < Expression < ' src > > ,
3435 } ,
36+ For {
37+ var : & ' src str ,
38+ expr : Expression < ' src > ,
39+ lines : Lines < ' src > ,
40+ } ,
3541}
3642
3743#[ derive( Debug ) ]
@@ -71,6 +77,7 @@ pub enum ErrorType {
7177 UnexpectedEOL ,
7278 UnexpectedSpace ,
7379 Noop ,
80+ NotANumber ,
7481}
7582
7683macro_rules! err {
@@ -134,10 +141,10 @@ impl<'src> Script<'src> {
134141 }
135142}
136143
144+ type TokenGroup < ' src > = ( Token < ' src > , usize , usize ) ;
145+
137146impl < ' src > Function < ' src > {
138- fn parse (
139- tokens : & mut impl Iterator < Item = ( Token < ' src > , usize , usize ) > ,
140- ) -> Result < Self , Error > {
147+ fn parse ( tokens : & mut impl Iterator < Item = TokenGroup < ' src > > ) -> Result < Self , Error > {
141148 let name = match skip_whitespace ( tokens) {
142149 Some ( ( Token :: Name ( name) , _, _) ) => name,
143150 Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
@@ -162,27 +169,46 @@ impl<'src> Function<'src> {
162169 Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
163170 None => err ! ( UnexpectedEOL , 0 , 0 ) ,
164171 }
165- let mut tab_count = 0 ;
166- let ( mut tk, mut line, mut column) = loop {
167- match tokens. next ( ) {
168- Some ( ( Token :: Tab , _, _) ) => tab_count += 1 ,
169- Some ( e) => break e,
170- None => err ! ( UnexpectedEOL , 0 , 0 ) ,
171- }
172+
173+ // Ensure there is one and only one tab
174+ let ( l, c) = match tokens. next ( ) {
175+ Some ( ( Token :: Tab , l, c) ) => ( l, c) ,
176+ Some ( ( e, l, c) ) => err ! ( UnexpectedToken , l, c) ,
177+ None => err ! ( UnexpectedEOL , 0 , 0 ) ,
172178 } ;
173- let tab_count = tab_count;
174179
180+ Ok ( Self {
181+ name,
182+ parameters,
183+ lines : Self :: parse_block ( tokens, 1 , l, c) ?. 0 ,
184+ } )
185+ }
186+
187+ fn parse_block (
188+ tokens : & mut impl Iterator < Item = TokenGroup < ' src > > ,
189+ expected_indent : u8 ,
190+ mut line : usize ,
191+ mut column : usize ,
192+ ) -> Result < ( Lines < ' src > , u8 ) , Error > {
175193 let mut lines = Lines :: new ( ) ;
176- let mut curr_tabs = 0 ;
177194 loop {
178- match tk {
179- Token :: Space => err ! ( UnexpectedSpace , line, column) ,
180- Token :: Tab => curr_tabs += 1 ,
181- Token :: EOL => curr_tabs = 0 ,
182- Token :: Name ( name) => {
195+ match tokens. next ( ) {
196+ Some ( ( Token :: EOL , ..) ) => {
197+ for i in 0 ..expected_indent {
198+ if let Some ( ( tk, l, c) ) = tokens. next ( ) {
199+ if tk == Token :: Space {
200+ err ! ( UnexpectedToken , l, c) ;
201+ } else if tk != Token :: Tab {
202+ return Ok ( ( lines, i) ) ;
203+ }
204+ }
205+ }
206+ }
207+ Some ( ( Token :: Tab , l, c) ) => err ! ( UnexpectedToken , l, c) ,
208+ Some ( ( Token :: Name ( name) , ll, lc) ) => {
183209 let mut args = Vec :: new ( ) ;
184210 match skip_whitespace ( tokens) {
185- Some ( ( Token :: EOL , ..) ) => break ,
211+ Some ( ( Token :: EOL , ..) ) => continue ,
186212 Some ( ( Token :: BracketRoundOpen , l, c) ) => match skip_whitespace ( tokens) {
187213 Some ( ( Token :: BracketRoundClose , ..) ) => ( ) ,
188214 Some ( ( pre, ..) ) => {
@@ -205,18 +231,61 @@ impl<'src> Function<'src> {
205231 dbg ! ( e) ;
206232 todo ! ( )
207233 }
208- None => err ! ( UnexpectedEOL , 0 , 0 ) ,
234+ None => err ! ( UnexpectedEOL , ll , lc ) ,
209235 }
210236 }
211- _ => todo ! ( ) ,
212- }
237+ Some ( ( Token :: For , mut ll, mut lc) ) => {
238+ let var = match skip_whitespace ( tokens) {
239+ Some ( ( Token :: Name ( n) , ..) ) => n,
240+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
241+ None => err ! ( UnexpectedEOL , line, column) ,
242+ } ;
243+ match skip_whitespace ( tokens) {
244+ Some ( ( Token :: In , ..) ) => ( ) ,
245+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
246+ None => err ! ( UnexpectedEOL , line, column) ,
247+ }
248+ let ( expr, tk) = match skip_whitespace ( tokens) {
249+ Some ( ( tk, ..) ) => Expression :: parse ( tk, tokens) ?,
250+ None => err ! ( UnexpectedEOL , line, column) ,
251+ } ;
252+ if tk == Token :: EOL {
253+ let expected_indent = expected_indent + 1 ;
254+ ' eol: loop {
255+ for i in 0 ..expected_indent {
256+ match tokens. next ( ) {
257+ Some ( ( Token :: Tab , l, c) ) => {
258+ ll = l;
259+ lc = c;
260+ }
261+ Some ( ( Token :: EOL , l, c) ) => {
262+ ll = l;
263+ lc = c;
264+ continue ' eol;
265+ }
266+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
267+ None => err ! ( UnexpectedEOL , ll, lc) ,
268+ }
269+ }
270+ break ;
271+ }
272+ lines. push ( Statement :: For {
273+ var,
274+ expr,
275+ lines : Self :: parse_block ( tokens, expected_indent, ll, lc) ?. 0 ,
276+ } ) ;
277+ } else {
278+ err ! ( UnexpectedToken , 0 , 0 ) ;
279+ }
280+ }
281+ Some ( ( Token :: Pass , ..) ) => ( ) ,
282+ Some ( ( tk, ..) ) => {
283+ dbg ! ( tk) ;
284+ todo ! ( )
285+ }
286+ None => return Ok ( ( lines, 0 ) ) ,
287+ } ;
213288 }
214-
215- Ok ( Self {
216- name,
217- parameters,
218- lines,
219- } )
220289 }
221290}
222291
@@ -231,6 +300,17 @@ impl<'src> Expression<'src> {
231300 None => err ! ( UnexpectedEOL , 0 , 0 ) ,
232301 } ,
233302 Token :: String ( s) => ( Expression :: Atom ( Atom :: String ( s) ) , None ) ,
303+ Token :: Number ( n) => (
304+ Expression :: Atom ( if let Ok ( n) = parse_integer ( n) {
305+ Atom :: Integer ( n)
306+ } else if let Ok ( n) = Real :: from_str ( n) {
307+ Atom :: Real ( n)
308+ } else {
309+ dbg ! ( n) ;
310+ err ! ( NotANumber , 0 , 0 ) ;
311+ } ) ,
312+ None ,
313+ ) ,
234314 e => {
235315 dbg ! ( e) ;
236316 todo ! ( )
@@ -239,7 +319,9 @@ impl<'src> Expression<'src> {
239319 match skip_whitespace ( tokens) {
240320 Some ( ( Token :: BracketRoundClose , ..) ) => return Ok ( ( lhs, Token :: BracketRoundClose ) ) ,
241321 Some ( ( Token :: Comma , ..) ) => return Ok ( ( lhs, Token :: Comma ) ) ,
242- _ => todo ! ( ) ,
322+ Some ( ( Token :: EOL , ..) ) => return Ok ( ( lhs, Token :: EOL ) ) ,
323+ Some ( ( tk, ..) ) => todo ! ( "{:?}" , tk) ,
324+ None => todo ! ( "none" ) ,
243325 }
244326 /*
245327 let lhs = match skip_whitespace(tokens) {
@@ -261,3 +343,46 @@ impl Error {
261343 } )
262344 }
263345}
346+
347+ enum NumberParseError {
348+ InvalidBase ,
349+ InvalidDigit ,
350+ Empty ,
351+ }
352+
353+ /// Custom integer parsing function that allows underscores
354+ fn parse_integer ( s : & str ) -> Result < Integer , NumberParseError > {
355+ let mut chars = s. chars ( ) ;
356+ let ( mut chars, base) = if chars. next ( ) == Some ( '0' ) {
357+ if let Some ( c) = chars. next ( ) {
358+ let b = match c {
359+ 'x' => 16 ,
360+ 'b' => 2 ,
361+ 'o' => 8 ,
362+ _ => return Err ( NumberParseError :: InvalidBase ) ,
363+ } ;
364+ ( chars, b)
365+ } else {
366+ return Ok ( 0 ) ;
367+ }
368+ } else {
369+ ( s. chars ( ) , 10 )
370+ } ;
371+ if s == "" {
372+ Err ( NumberParseError :: Empty )
373+ } else {
374+ let mut chars = chars. peekable ( ) ;
375+ let neg = if chars. peek ( ) == Some ( & '-' ) {
376+ chars. next ( ) ;
377+ true
378+ } else {
379+ false
380+ } ;
381+ let mut n = 0 ;
382+ for c in chars. filter ( |& c| c != '_' ) {
383+ n *= base as Integer ;
384+ n += c. to_digit ( base) . ok_or ( NumberParseError :: InvalidDigit ) ? as isize ;
385+ }
386+ Ok ( if neg { -n } else { n } )
387+ }
388+ }
0 commit comments