]> Witch of Git - ivy/blob - src/main.rs
Add a compiler CLI
[ivy] / src / main.rs
1 use ivy::{
2 ast::Ast,
3 parse,
4 trans::{self, translate},
5 BUILTINS,
6 };
7 use std::{
8 ffi::OsStr,
9 fs,
10 io::{self, Read, Write},
11 path::{Path, PathBuf},
12 process::Command,
13 };
14 use structopt::{clap, StructOpt};
15 use tempfile;
16
17 /// The Ivy compiler.
18 ///
19 /// If no mode is specified, this will fully compile the program.
20 #[derive(Debug, StructOpt)]
21 #[structopt(setting = clap::AppSettings::ArgRequiredElseHelp)]
22 struct Opt {
23 /// Output assembly.
24 #[structopt(short = "S", long = "assembly", conflicts_with = "pretty")]
25 assembly: bool,
26
27 /// Pretty-print the source code.
28 #[structopt(short = "p", long = "pretty")]
29 pretty: bool,
30
31 /// Input path. Use "-" for stdin.
32 input: PathBuf,
33
34 /// Output path. Defaults to stdout or a.out, depending on the mode.
35 #[structopt(short = "o", long = "output")]
36 output: Option<PathBuf>,
37 }
38
39 fn main() -> io::Result<()> {
40 let opt = Opt::from_args();
41 let text = match &opt.input {
42 path if path == Path::new("-") => {
43 let mut text = String::new();
44 std::io::stdin().read_to_string(&mut text)?;
45 text
46 }
47 path => fs::read_to_string(path)?,
48 };
49 let sexp = match parse(&text) {
50 Ok(item) => item,
51 Err(err) => {
52 println!("{:?}", err);
53 std::process::exit(1);
54 }
55 };
56 let (ast, mut builtins) = match Ast::parse(BUILTINS, &sexp) {
57 Ok(ast) => ast,
58 Err(err) => {
59 println!("{}", err);
60 std::process::exit(1);
61 }
62 };
63 if opt.pretty {
64 match opt.output {
65 Some(path) => {
66 let mut file = fs::File::create(path)?;
67 writeln!(file, "{}", ast.to_doc().pretty(80))?;
68 }
69 None => println!("{}", ast.to_doc().pretty(80)),
70 }
71 return Ok(());
72 }
73 let code = match translate(&ast) {
74 Ok(code) => code,
75 Err(err) => {
76 println!("{}", err);
77 std::process::exit(1);
78 }
79 };
80 builtins.retain(|_, v| code.globals.contains(&v.global_number().unwrap()));
81 if opt.assembly {
82 match opt.output {
83 Some(path) => {
84 let mut file = fs::File::create(path)?;
85 trans::x64::write_compile(&builtins, &mut file, &code)?;
86 }
87 None => {
88 let stdout = std::io::stdout();
89 trans::x64::write_compile(&builtins, &mut stdout.lock(), &code)?;
90 }
91 }
92 return Ok(());
93 }
94 let mut file = tempfile::Builder::new().suffix(".s").tempfile()?;
95 trans::x64::write_compile(&builtins, &mut file, &code)?;
96 Command::new("clang")
97 .args(&[
98 "-masm=intel",
99 "-nostartfiles",
100 "-Lrt/target/release",
101 "-lrt",
102 "-Wl,-e,_start",
103 ])
104 .arg(file.path())
105 .arg("-o")
106 .arg(opt.output.unwrap_or_else(|| "a.out".into()))
107 .spawn()?
108 .wait()?;
109 Ok(())
110 }