Prior to the start

By putting together the basic structure of a project before writing the compiler, Rust is really friendly to create projects as long as

$ cargo new lox-rs --bin
Copy the code

I can create a bin project, and THEN I use the Rust compiler with the latest nightly edition. Since there are few compiler bugs to write this application, I can use the nightly edition with confidence. In order to keep the code style consistent, create rustfmt. Toml first, not much content, other default, these should be specified.

max_width = 120
fn_call_width = 100
tab_spaces = 2
Copy the code

When it’s time to commit, format the code with Rustfmt. Cargo. Toml comes with a couple of third-party dependencies, as well as the current native Core package, which contains the source code for the compiler we need to implement.

[package]
name = "lox-rs"
version = "0.1.0 from"
edition = "2018"
authors = ["Limit Liu <[email protected]>"]

[workspace]

[dependencies]
core = { path = "core" }
ansi_term = "0.12"
rustyline = "9.0.0"
getopts = "0.2"
Copy the code

Our final project structure looks like this

$tree. / ├ ─ ─ Cargo. Lock ├ ─ ─ Cargo. Toml ├ ─ ─ the README. Md ├ ─ ─ the core │ ├ ─ ─ Cargo. Toml │ └ ─ ─ the SRC │ ├ ─ ─ common │ │ └ ─ ─ mod. Rs │ ├ ─ ─ the lexer │ │ └ ─ ─ mod. Rs │ ├ ─ ─ lib. Rs │ └ ─ ─ parser │ └ ─ ─ mod. Rs ├ ─ ─ pbcopy ├ ─ ─ rustfmt. Toml └ ─ ─ the SRC ├ ─ ─ lib. Rs ├ ─ ─ ├── ├─ 6.Exdirectories, 14 filesCopy the code

The ansi_term package is used to display colors on the terminal, and the REPL is used to implement the language. Rustyline is easier to use, otherwise you need to manually implement things like arrow keys, which is very troublesome. Getopts is the terminal command program and parameter package. In fact, the Rust edition 2021 is coming soon, and you can change 2018 to 2021 at a later date. I personally try not to use the third-party library to achieve some functions, but some terminal related, too many details, affecting the study of the project theme. For GC, there are already packages available, so it’s really easy to use them, but you can’t learn how to implement them that way, so it’s more fun to do it yourself. Then fill the contents in main.rs. Now the main implementation is simple interaction with the terminal

use getopts::Options;
use std::env;

use lox_rs::repl;
use lox_rs::run;

fn print_usage(program: &str, opts: Options) {
  let brief = format!(
    "Usage: {} [OPTIONS] COMMAND [PARAMS] Commands: repl\t\tlaunch repl run INPUT\t\tlaunch a script file",
    program
  );
  print!("{}", opts.usage(&brief));
}

fn main() {
  let args: Vec<String> = env::args().collect();
  let program = args.first().unwrap();
  let mut opts = Options::new();

  opts.optflag("h"."help"."print this help menu");
  let matches = opts.parse(&args[1. ] ).unwrap();if matches.opt_present("h") || matches.free.is_empty() {
    print_usage(program, opts);
    return;
  }

  let command = matches.free[0].as_str();
  match command {
    "repl" => repl::main(),
    "run"= >match matches.free.get(1) {
      Some(p) => run::main(p),
      _ => print_usage(program, opts),
    },
    _ => print_usage(program, opts),
  }
}
Copy the code

For now, between repl. Rs and Run. rs

// repl
pub fn main() {
  println!("The Lox programming language REPL");
}

// run
pub fn main(p: &str) {}
Copy the code

Now use cargo Run to run the project. After the build passes, ignore the warning and commit and push to git hosting platform. After filling in the core content, we need to improve some cli operations.