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