fomoscript/
lib.rs

1#![no_std]
2use log::info;
3extern crate alloc;
4use alloc::{boxed::Box, format, string::String, vec::Vec};
5use core::{ops::Rem, result::Result};
6
7pub type ID = String;
8pub type BN = Box<N>;
9pub type VN = Vec<N>;
10
11macro_rules! bx {
12    ($e:expr) => {
13        Box::new($e)
14    };
15}
16
17/// fomoscript AST node
18#[derive(Debug, Clone)]
19pub enum N {
20    FuncCall {
21        func: BN,
22        args: VN,
23    },
24    Block(VN),
25    If {
26        condition: BN,
27        path_true: BN,
28        path_false: BN,
29    },
30    While {
31        condition: BN,
32        body: BN,
33    },
34    Set(ID, BN),
35    Get(ID),
36    Unary(Op, BN),
37    Binary(Op, BN, BN),
38    //Terminal nodes, the following nodes can be output by eval
39    FuncDef {
40        args_name: Vec<ID>,
41        scope: BN,
42    },
43    FuncNativeDef(Native),
44    Array(VN),
45    Num(f64),
46    Str(String),
47    Unit,
48}
49
50///Native rust closure wrapper, to be inserted in the script
51#[derive(Clone)]
52pub struct Native(pub alloc::rc::Rc<dyn Fn(N, N, N, N) -> N>);
53
54impl core::fmt::Debug for Native {
55    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
56        write!(f, "Native")
57    }
58}
59
60#[repr(u8)]
61#[derive(Debug, Clone, PartialEq, Eq, Copy)]
62pub enum Op {
63    Mul = 0,
64    Div = 1,
65    Equals,
66    NotEquals,
67    Lesser,
68    Greater,
69    Modulus,
70    And,
71    Or,
72    Plus,
73    Plus2,
74    Shift,
75    Minus,
76    Assign,
77}
78impl Op {
79    fn term_separate(self) -> bool {
80        self as u8 > 1
81    }
82}
83
84impl N {
85    pub fn as_f64(&self) -> f64 {
86        match self {
87            N::Num(x) => *x,
88            _ => 0.0,
89        }
90    }
91    ///Cast to to boolean. The equivalent of js: self == true
92    pub fn to_bool(&self) -> bool {
93        match self {
94            N::Num(x) if *x != 0.0 => true,
95            N::Str(s) => !s.is_empty(),
96            N::Array(vec) => !vec.is_empty(),
97            _ => false,
98        }
99    }
100    pub fn to_str(&self) -> String {
101        match self {
102            N::Num(x) => format!("{}", x),
103            N::Str(s) => s.clone(),
104            e => format!("{:?}", e),
105        }
106    }
107}
108
109/// Token generated while lexing the code.
110///
111/// Consumed to produce the AST.
112#[derive(Debug, Clone)]
113enum Token {
114    BlockStart,
115    BlockEnd,
116    If,
117    Else,
118    Comma,
119    ParStart,
120    ParEnd,
121    While,
122    Quoted(String),
123    Bin(Op),
124    N(N),
125    Let(ID),
126    Err(String),
127    Assoc,
128    ArrayStart,
129    ArrayEnd,
130}
131
132/// Interpreter context, holds all state during execution.
133pub struct Ctx {
134    pub values: Vec<N>,
135    pub idents: Vec<String>,
136    pub code: Vec<char>,
137    pub deep: usize,
138}
139
140impl Ctx {
141    pub fn new() -> Ctx {
142        Ctx {
143            values: Vec::new(),
144            idents: Vec::new(),
145            code: Vec::new(),
146            deep: 0,
147        }
148    }
149
150    #[inline(always)]
151    pub fn drain(&mut self, from: usize) {
152        self.values.drain(from..);
153        self.idents.drain(from..);
154    }
155
156    #[inline(always)]
157    pub fn set_val(&mut self, name: &str, n: N) {
158        self.idents.push(String::from(name));
159        self.values.push(n);
160    }
161
162    #[inline(always)]
163    pub fn set_val_absolute(&mut self, i: usize, name: &str, n: N) {
164        self.idents[i] = String::from(name);
165        self.values[i] = n;
166    }
167    /// Find a variable declared in the scope, or any parent scope
168    ///
169    /// returns the path and the variable value
170    pub fn find_var(&mut self, name: &str) -> Option<(usize, &mut N)> {
171        for (i, id) in self.idents.iter().enumerate().rev() {
172            if id == name {
173                return Some((i, &mut self.values[i]));
174            }
175        }
176        info!("Unknown variable {}", name);
177        None
178    }
179
180    pub fn insert_code(&mut self, code: &str) {
181        self.code.extend(code.chars());
182    }
183
184    pub fn parse_next_expr(&mut self) -> Result<N, Error> {
185        let mut i = 0;
186        let res = parse_expr(&mut i, &self.code, 0)?;
187        self.code.drain(0..i);
188        Ok(res)
189    }
190}
191
192impl Default for Ctx {
193    fn default() -> Self {
194        Ctx::new()
195    }
196}
197
198pub fn parse_eval(code: &str) -> N {
199    let mut ctx = Ctx::new();
200    ctx.insert_code(code);
201    let mut res = N::Unit;
202    while let Ok(mut parent) = ctx.parse_next_expr() {
203        res = eval(&mut parent, &mut ctx);
204    }
205    res
206}
207
208fn bool_n(b: bool) -> N {
209    N::Num(if b { 1.0 } else { 0.0 })
210}
211
212///Interprets the node using the ctx/interpreter provided
213pub fn eval(n: &N, ctx: &mut Ctx) -> N {
214    ctx.deep += 1;
215    if log::log_enabled!(log::Level::Info) {
216        info!("\n{}eval {:?}", pa(ctx.deep), n);
217        for i in 0..ctx.idents.len() {
218            info!(
219                "{}{} {:?}:{:?}",
220                pa(ctx.deep),
221                i,
222                ctx.idents[i],
223                ctx.values[i]
224            );
225        }
226    }
227    let res = match n {
228        N::If {
229            condition,
230            path_true,
231            path_false,
232        } => match eval(condition, ctx).to_bool() {
233            true => eval(path_true, ctx),
234            false => eval(path_false, ctx),
235        },
236        N::While { condition, body } => {
237            let mut res = N::Unit;
238            while eval(condition, ctx).to_bool() {
239                res = eval(body, ctx)
240            }
241            res
242        }
243        N::Block(arr) => {
244            let variable_skip_begin = ctx.values.len();
245            let mut res = N::Unit;
246            for a in arr.iter() {
247                res = eval(a, ctx);
248            }
249            if log::log_enabled!(log::Level::Info) {
250                for i in variable_skip_begin..ctx.values.len() {
251                    info!(
252                        "block forget {} {:?}:  {:?}",
253                        i, ctx.idents[i], ctx.values[i]
254                    );
255                }
256            }
257            ctx.drain(variable_skip_begin);
258            res
259        }
260        N::Set(name, val) => {
261            let val = eval(val, ctx);
262            ctx.set_val(name, val);
263            N::Unit
264        }
265        N::Get(name) => ctx.find_var(name).map(|e| e.1.clone()).unwrap_or(N::Unit),
266        N::FuncCall { func, args } => match eval(func, ctx) {
267            N::FuncNativeDef(native) => native.0(
268                args.first().map(|e| eval(e, ctx)).unwrap_or(N::Unit),
269                args.get(1).map(|e| eval(e, ctx)).unwrap_or(N::Unit),
270                args.get(2).map(|e| eval(e, ctx)).unwrap_or(N::Unit),
271                args.get(3).map(|e| eval(e, ctx)).unwrap_or(N::Unit),
272            ),
273            N::FuncDef {
274                args_name,
275                mut scope,
276            } => {
277                let variable_scope_index = ctx.values.len();
278                for (i, arg_name) in args_name.iter().enumerate() {
279                    let val = args.get(i).map(|e| eval(e, ctx)).unwrap_or(N::Unit);
280                    ctx.set_val(arg_name, val);
281                }
282                let res = eval(&mut scope, ctx);
283                if log::log_enabled!(log::Level::Info) {
284                    for i in variable_scope_index..ctx.values.len() {
285                        info!("forget {} {:?}:  {:?}", i, ctx.idents[i], ctx.values[i]);
286                    }
287                }
288                ctx.drain(variable_scope_index);
289                res
290            }
291            N::Array(mut v) => {
292                if let Some(index) = args.first().map(|e| eval(e, ctx)) {
293                    match index {
294                        N::Num(i) => {
295                            let mut i = i as isize;
296                            if i < 0 {
297                                i = v.len() as isize + (i as isize);
298                            }
299                            v.get(i as usize).cloned().unwrap_or(N::Unit)
300                        }
301                        N::FuncDef { args_name, scope } => {
302                            for (index, e) in v.iter_mut().enumerate() {
303                                let variable_scope_index = ctx.values.len();
304                                if let Some(s) = args_name.first() {
305                                    ctx.set_val(s, e.clone());
306                                }
307                                if let Some(s) = args_name.get(1) {
308                                    ctx.set_val(s, N::Num(index as f64));
309                                }
310                                *e = eval(&scope, ctx);
311                                ctx.drain(variable_scope_index);
312                            }
313                            N::Array(v)
314                        }
315                        _ => N::Unit,
316                    }
317                } else {
318                    N::Num(v.len() as f64)
319                }
320            }
321            _ => N::Unit,
322        },
323        N::Binary(op, l, r) => {
324            if let Op::Assign = op {
325                if let N::Get(name) = l.as_ref() {
326                    if let Some((key, _)) = ctx.find_var(name) {
327                        let v = eval(r, ctx);
328                        ctx.set_val_absolute(key, name, v);
329                    }
330                }
331                return N::Unit;
332            }
333            let lt = eval(l, ctx);
334            let rt = eval(r, ctx);
335            match (op.clone(), &lt, &rt) {
336                (Op::Plus, N::Num(li), N::Num(ri)) => N::Num(li + ri),
337                (Op::Plus, N::Num(li), N::Unit) => N::Num(*li),
338                (Op::Plus, N::Unit, N::Num(ri)) => N::Num(*ri),
339                (Op::Greater, N::Num(li), N::Num(ri)) => bool_n(li > ri),
340                (Op::Lesser, N::Num(li), N::Num(ri)) => bool_n(li < ri),
341                (Op::Equals, N::Num(li), N::Num(ri)) => bool_n(li == ri),
342                (Op::Equals, N::Str(li), N::Str(ri)) => bool_n(li == ri),
343                (Op::NotEquals, N::Num(li), N::Num(ri)) => bool_n(li != ri),
344                (Op::NotEquals, N::Str(li), N::Str(ri)) => bool_n(li != ri),
345                (Op::Minus, N::Num(li), N::Num(ri)) => N::Num(li - ri),
346                (Op::Mul, N::Num(li), N::Num(ri)) => N::Num(li * ri),
347                (Op::Div, N::Num(li), N::Num(ri)) => N::Num(li / ri),
348                (Op::Modulus, N::Num(li), N::Num(ri)) => N::Num(li.rem(ri)),
349                (Op::Plus, N::Str(li), ri) => N::Str(format!("{}{}", li, ri.to_str())),
350                (Op::Plus, li, N::Str(ri)) => N::Str(format!("{}{}", li.to_str(), ri)),
351                (Op::Plus2, N::Array(li), N::Array(ri)) => {
352                    N::Array(li.iter().chain(ri).cloned().collect())
353                }
354                (Op::Plus, N::Array(li), ri) => {
355                    N::Array(li.iter().chain(core::iter::once(ri)).cloned().collect())
356                }
357                (Op::Plus, li, N::Array(ri)) => {
358                    N::Array(core::iter::once(li).chain(ri.iter()).cloned().collect())
359                }
360                (Op::And, N::Array(li), N::FuncDef { args_name, scope }) => {
361                    let mut new_arr = Vec::new();
362                    for (index, e) in li.iter().enumerate() {
363                        let variable_scope_index = ctx.values.len();
364                        if let Some(s) = args_name.first() {
365                            ctx.set_val(s, e.clone());
366                        }
367                        if let Some(s) = args_name.get(1) {
368                            ctx.set_val(s, N::Num(index as f64));
369                        }
370                        if eval(&scope, ctx).to_bool() {
371                            new_arr.push(e.clone());
372                        }
373                        ctx.drain(variable_scope_index);
374                    }
375                    N::Array(new_arr)
376                }
377                (Op::Or, N::Array(li), N::FuncDef { args_name, scope }) => {
378                    let mut acc = li.first().cloned().unwrap_or(N::Unit);
379
380                    for e in li.iter().skip(1) {
381                        let variable_scope_index = ctx.values.len();
382                        if let Some(s) = args_name.first() {
383                            ctx.set_val(s, acc);
384                        }
385                        if let Some(s) = args_name.get(1) {
386                            ctx.set_val(s, e.clone());
387                        }
388                        acc = eval(&scope, ctx);
389                        ctx.drain(variable_scope_index);
390                    }
391                    acc
392                }
393                (Op::And, li, ri) => bool_n(li.to_bool() && ri.to_bool()),
394                (Op::Or, li, ri) => bool_n(li.to_bool() || ri.to_bool()),
395                _ => {
396                    info!("unknown bin  {:?} {:?} {:?}", lt, op, rt);
397                    N::Unit
398                }
399            }
400        }
401        N::FuncDef { args_name, scope } => N::FuncDef {
402            args_name: args_name.clone(),
403            scope: bx!(dup(&mut args_name.clone(), &mut scope.clone(), ctx)),
404        },
405        e => {
406            info!("noop");
407            e.clone()
408        }
409    };
410
411    ctx.deep -= 1;
412    res
413}
414
415/// Create a new FuncDef by replacing known variables (excluding shadowed)
416pub fn dup(excl: &mut Vec<ID>, n: &mut N, ctx: &mut Ctx) -> N {
417    info!("instanciate {:?}", n);
418    match n {
419        N::Block(scope) => N::Block(scope.iter_mut().map(|e| dup(excl, e, ctx)).collect()),
420        N::While { condition, body } => N::While {
421            condition: bx!(dup(excl, condition, ctx)),
422            body: bx!(dup(excl, body, ctx)),
423        },
424        N::FuncCall { func, args } => N::FuncCall {
425            func: bx!(dup(excl, func, ctx)),
426            args: args.iter_mut().map(|e| dup(excl, e, ctx)).collect(),
427        },
428        N::FuncDef { args_name, scope } => N::FuncDef {
429            args_name: args_name.clone(),
430            scope: bx!(dup(excl, scope, ctx)),
431        },
432        N::If {
433            condition,
434            path_true,
435            path_false,
436        } => N::If {
437            condition: bx!(dup(excl, condition, ctx)),
438            path_true: bx!(dup(excl, path_true, ctx)),
439            path_false: bx!(dup(excl, path_false, ctx)),
440        },
441        N::Get(name) => {
442            if excl.contains(name) {
443                return N::Get(name.clone());
444            }
445            match ctx.find_var(name) {
446                Some((_, n)) => n.clone(),
447                _ => N::Get(name.clone()),
448            }
449        }
450        N::Set(name, val) => {
451            if let Some(index) = excl.iter().position(|x| x == name) {
452                excl.remove(index);
453            }
454            N::Set(name.clone(), val.clone())
455        }
456        N::Binary(op, l, r) => N::Binary(*op, bx!(dup(excl, l, ctx)), bx!(dup(excl, r, ctx))),
457        N::Array(v) => N::Array(v.iter_mut().map(|e| dup(excl, e, ctx)).collect()),
458        e => e.clone(),
459    }
460}
461
462fn next_token(i: &mut usize, code: &[char]) -> Token {
463    let skip_whitespaces = |i: &mut usize| {
464        while *i < code.len() && (code[*i] == ' ' || code[*i] == '\n') {
465            *i += 1;
466        }
467    };
468
469    let parse_number = |i: &mut usize| {
470        let backup_i = *i;
471        let mut id = String::from("");
472        while code.len() > *i && (code[*i].is_ascii_digit() || code[*i] == '.') {
473            id = format!("{}{}", id, code[*i]);
474            *i += 1;
475        }
476        if !id.is_empty() {
477            if let Ok(j) = id.parse::<f64>() {
478                Some(j)
479            } else {
480                *i = backup_i;
481                None
482            }
483        } else {
484            *i = backup_i;
485            None
486        }
487    };
488
489    let parse_ident = |i: &mut usize| {
490        let mut id = String::from("");
491        while code.len() > *i && (code[*i].is_alphanumeric() || code[*i] == '_') {
492            id = format!("{}{}", id, code[*i]);
493            *i += 1;
494        }
495        if !id.is_empty() {
496            Some(id)
497        } else {
498            None
499        }
500    };
501
502    let starts_with = |mut i: usize, e: &str| {
503        if i + e.len() > code.len() {
504            return false;
505        }
506        for c in e.chars() {
507            if code[i] != c {
508                return false;
509            }
510            i += 1;
511        }
512        true
513    };
514    loop {
515        skip_whitespaces(i);
516
517        if *i >= code.len() {
518            break Token::Err(String::from("i>code"));
519        }
520
521        if code[*i] == '"' {
522            let mut builder = String::from("");
523            while *i + 1 < code.len() {
524                *i += 1;
525                match code[*i] {
526                    '"' => {
527                        *i += 1;
528                        return Token::Quoted(builder);
529                    }
530                    c => builder.push(c),
531                }
532            }
533            return Token::Err(String::from("i>code"));
534        }
535
536        for (s, tok) in [
537            ("if", Token::If),
538            ("else", Token::Else),
539            ("while", Token::While),
540        ] {
541            if starts_with(*i, s)
542                && *i + s.len() < code.len()
543                && [' ', '{'].contains(&code[*i + s.len()])
544            {
545                *i += s.len();
546                return tok;
547            }
548        }
549
550        if starts_with(*i, "let ") && *i + 4 < code.len() {
551            *i += 4;
552            skip_whitespaces(i);
553            let id = match parse_ident(i) {
554                Some(id) => id,
555                None => break Token::Err(String::from("no id after let # ")),
556            };
557            skip_whitespaces(i);
558            if *i >= code.len() || code[*i] != '=' {
559                break Token::Err(String::from("no equal after let 'id' # "));
560            }
561            *i += 1;
562            break Token::Let(id);
563        }
564
565        if let Some(num) = parse_number(i) {
566            break Token::N(N::Num(num));
567        }
568
569        if let Some(id) = parse_ident(i) {
570            break Token::N(N::Get(id));
571        }
572
573        for (st, tok) in [
574            ("==", Token::Bin(Op::Equals)),
575            ("!=", Token::Bin(Op::NotEquals)),
576            ("++", Token::Bin(Op::Plus2)),
577            ("<<", Token::Bin(Op::Shift)),
578            ("=>", Token::Assoc),
579        ] {
580            if starts_with(*i, st) {
581                *i += 2;
582                return tok;
583            }
584        }
585
586        for (key, val) in [
587            ('{', Token::BlockStart),
588            ('}', Token::BlockEnd),
589            (',', Token::Comma),
590            ('(', Token::ParStart),
591            (')', Token::ParEnd),
592            ('=', Token::Bin(Op::Assign)),
593            ('+', Token::Bin(Op::Plus)),
594            ('-', Token::Bin(Op::Minus)),
595            ('*', Token::Bin(Op::Mul)),
596            ('/', Token::Bin(Op::Div)),
597            ('>', Token::Bin(Op::Greater)),
598            ('<', Token::Bin(Op::Lesser)),
599            ('%', Token::Bin(Op::Modulus)),
600            ('&', Token::Bin(Op::And)),
601            ('|', Token::Bin(Op::Or)),
602            ('[', Token::ArrayStart),
603            (']', Token::ArrayEnd),
604        ] {
605            if code[*i] == key {
606                *i += 1;
607                return val;
608            }
609        }
610
611        *i += 1;
612    }
613}
614
615fn pa(i: usize) -> String {
616    format!("{:width$}", "", width = i * 5)
617}
618type Error = &'static str;
619
620fn parse_expr(i: &mut usize, code: &[char], pad: usize) -> Result<N, Error> {
621    info!(
622        "{}parse expr {:?}",
623        pa(pad),
624        &code[*i..(*i + 5).min(if code.is_empty() { *i } else { code.len() - 1 })]
625    );
626    let term = parse_term(i, code, pad + 1)?;
627
628    let mut j = *i;
629    let token = next_token(&mut j, code);
630
631    if let Token::Bin(op) = token {
632        // if op.term_separate()
633        {
634            *i = j;
635            let term_right = parse_expr(i, code, pad + 1)?;
636            let n = N::Binary(op, bx!(term), bx!(term_right));
637            return Ok(n);
638        }
639    }
640
641    Ok(term)
642}
643
644fn parse_term(i: &mut usize, code: &[char], pad: usize) -> Result<N, Error> {
645    info!(
646        "{}parse_term {:?}",
647        pa(pad),
648        &code[*i..(*i + 5).min(if code.is_empty() { *i } else { code.len() - 1 })]
649    );
650
651    let factor = parse_factor(i, code, pad + 1)?;
652    let mut j = *i;
653    let token = next_token(&mut j, code);
654    info!("{:?}", token);
655    match token {
656        Token::Bin(Op::Mul) | Token::Bin(Op::Div) | Token::ParStart => {
657            *i = j;
658            match token {
659                Token::Bin(op) if !op.term_separate() => {
660                    let factor_right = parse_term(i, code, pad + 1)?;
661                    let n = N::Binary(op, bx!(factor), bx!(factor_right));
662                    return Ok(n);
663                }
664
665                Token::ParStart => {
666                    info!("Function call start");
667                    let mut args = Vec::new();
668                    loop {
669                        info!("args enum");
670                        let mut j = *i;
671                        let e = parse_expr(&mut j, code, pad + 1);
672                        match e {
673                            Ok(expr) => {
674                                info!("args enum got");
675                                *i = j;
676                                args.push(expr);
677
678                                let mut k = *i;
679                                let token = next_token(&mut k, code);
680                                if let Token::Comma = token {
681                                    *i = k
682                                }
683                            }
684                            Err(_) => {
685                                info!("args enum end");
686                                break;
687                            }
688                        }
689                    }
690                    let token = next_token(i, code);
691                    if let Token::ParEnd = token {
692                        return Ok(N::FuncCall {
693                            func: bx!(factor),
694                            args,
695                        });
696                    } else {
697                        return Err("No parenthesis close");
698                    }
699                }
700                _ => {}
701            }
702        }
703        _ => {}
704    }
705
706    Ok(factor)
707}
708
709fn parse_factor(i: &mut usize, code: &[char], pad: usize) -> Result<N, Error> {
710    if *i >= code.len() {
711        return Err("EOF");
712    }
713
714    info!(
715        "{}parse_factor {:?}",
716        pa(pad),
717        &code[*i..(*i + 5).min(if code.is_empty() { *i } else { code.len() - 1 })]
718    );
719
720    let token = next_token(i, code);
721    info!("{}{:?}", pa(pad), token);
722    if let Token::BlockStart = token {
723        let mut scope = Vec::new();
724
725        loop {
726            let mut j = *i;
727            let e = parse_expr(&mut j, code, pad + 1);
728            match e {
729                Ok(expr) => {
730                    *i = j;
731                    scope.push(expr);
732                }
733                Err(_) => {
734                    break;
735                }
736            }
737        }
738        let token = next_token(i, code);
739        if let Token::BlockEnd = token {
740            return Ok(N::Block(scope));
741        } else {
742            return Err("No block end");
743        }
744    }
745
746    if let Token::ArrayStart = token {
747        let mut es = Vec::new();
748
749        loop {
750            let mut j = *i;
751            let next = parse_expr(&mut j, code, pad);
752            match next {
753                Ok(expr) => {
754                    *i = j;
755                    es.push(expr)
756                }
757                Err(_) => {
758                    let next = next_token(i, code);
759                    match next {
760                        Token::Comma => continue,
761                        Token::ArrayEnd => break,
762                        _ => break,
763                    }
764                }
765            }
766        }
767
768        return Ok(N::Array(es));
769    }
770
771    if let Token::ParStart = token {
772        info!("Function definition start");
773        let mut args_name = Vec::new();
774
775        loop {
776            let token = next_token(i, code);
777            match token {
778                Token::N(N::Get(name)) => {
779                    info!("name {}", name);
780                    args_name.push(name);
781                }
782                Token::Comma => {}
783                Token::ParEnd => {
784                    break;
785                }
786                _ => {}
787            }
788        }
789
790        let token = next_token(i, code);
791        if let Token::Assoc = token {
792            let scope = parse_expr(i, code, pad + 1)?;
793            let n = N::FuncDef {
794                args_name,
795                scope: bx!(scope),
796            };
797
798            return Ok(n);
799        } else {
800            return Err("No => after func def");
801        }
802    }
803
804    if let Token::Quoted(s) = token {
805        let n = N::Str(s);
806        return Ok(n);
807    }
808
809    if let Token::While = token {
810        let condition = parse_expr(i, code, pad + 1)?;
811        let body = parse_expr(i, code, pad + 1)?;
812        let n = N::While {
813            condition: bx!(condition),
814            body: bx!(body),
815        };
816
817        return Ok(n);
818    }
819
820    if let Token::If = token {
821        let cond_expr = parse_expr(i, code, pad + 1)?;
822        let true_expr = parse_expr(i, code, pad + 1)?;
823        let mut j = *i;
824        let token = next_token(&mut j, code);
825        let else_expr;
826        if let Token::Else = token {
827            *i = j;
828            else_expr = parse_expr(i, code, pad + 1)?;
829        } else {
830            else_expr = N::Unit;
831        }
832        let n = N::If {
833            condition: bx!(cond_expr),
834            path_true: bx!(true_expr),
835            path_false: bx!(else_expr),
836        };
837        return Ok(n);
838    }
839
840    if let Token::Let(name) = token {
841        let val = parse_expr(i, code, pad + 1)?;
842        let n = N::Set(name, bx!(val));
843        return Ok(n);
844    }
845
846    if let Token::N(N::Num(num)) = token {
847        return Ok(N::Num(num));
848    }
849
850    if let Token::N(N::Get(name)) = token {
851        return Ok(N::Get(name));
852    }
853
854    Err("No term found")
855}
856
857#[cfg(test)]
858mod test;