Теперь, когда у нас есть синтаксический анализатор и вычислитель, мы можем объединить их, чтобы создать цикл чтения-оценки-печати. Основная идея REPL состоит в том, чтобы прочитать строку из ввода, проанализировать ее, оценить и распечатать результат. Без какой-либо причудливой логики мы можем просто использовать то, что мы уже построили, чтобы создать что-то вроде этого:

pub fn repl(context: &mut Context) {
   loop {
      print!("> ");
      let _ = io::stdout().flush();
      let mut input = String::new();
      io::stdin().read_line(&mut input).expect("Error reading from stdin");

      if input.contains(":=") {
         match parse_binding(input) { Result::Err(e) => {
            println!("{}", e);
         }, Result::Ok((k,v)) => {
            context.bind_global(&k,v);
         }}
      } else {
         match parse_rhs(input) { Result::Err(e) => {
            println!("{}", e);
         }, Result::Ok(program) => {
            match eval_rhs(context.clone(), &program) { Result::Err(e) => {
               println!("{}", e);
            }, Result::Ok(r) => {
               println!("{}", r.to_string());
            }}
         }}
      }
   }
}

Затем, предоставляя эту функцию CLI, мы получаем работающий цикл чтения-оценки-печати.

lambda_calculus repl
> f := λx. x x
> f := λx x. x
> f a
(a a)
> f a a
a
>

Полный пример рабочего кода доступен на GitHub. Далее мы реализуем простую систему типов и вывод типов.

Если вам нравится эта серия, рассмотрите возможность подписаться на Medium, это очень помогает поддерживать больше подобных работ.

Предыдущие статьи

Создание компилятора для современного функционального языка с нуля на Rust (Часть 1: Парсинг)

Создание компилятора для современного функционального языка с нуля в Rust (Часть 2: Оценка)