diff --git a/.gitignore b/.gitignore index 738f786..2359dec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,5 @@ -_build - - - -# Added by cargo - +result* /target - -# Added by cargo -# -# already existing elements were commented out - -#/target +*.bc +*.ll diff --git a/Cargo.lock b/Cargo.lock index 233f2ff..1b9201b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" @@ -139,6 +145,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "inkwell", "lalrpop", "lalrpop-util", ] @@ -206,6 +213,29 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inkwell" +version = "0.1.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#36c3b106e61b1b45295a35f94023d93d9328c76f" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot", +] + +[[package]] +name = "inkwell_internals" +version = "0.5.0" +source = "git+https://github.com/TheDan64/inkwell?branch=master#36c3b106e61b1b45295a35f94023d93d9328c76f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "itertools" version = "0.10.3" @@ -259,6 +289,19 @@ version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +[[package]] +name = "llvm-sys" +version = "120.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce76f8393b7a607a906087666db398d872db739622e644e58552c198ccdfdf45" +dependencies = [ + "cc", + "lazy_static", + "libc", + "regex", + "semver", +] + [[package]] name = "lock_api" version = "0.4.7" @@ -328,6 +371,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "petgraph" version = "0.5.1" @@ -450,6 +502,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -547,6 +617,12 @@ dependencies = [ "crunchy", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 8bc4c25..a5fc013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,10 @@ anyhow = "1.0.56" clap = { version = "3.1.8", features = ["derive"] } lalrpop-util = { version = "0.19.7", features = ["lexer"] } +[dependencies.inkwell] +git = "https://github.com/TheDan64/inkwell" +branch = "master" +features = ["llvm12-0"] + [build-dependencies] lalrpop = "0.19.7" diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..0921fee --- /dev/null +++ b/default.nix @@ -0,0 +1,15 @@ +{ rustPlatform, lib, nix-gitignore, llvmPackages_12 }: + +let llvmPkgs = llvmPackages_12; + +in with llvmPkgs; + +rustPlatform.buildRustPackage { + name = "e0"; + src = nix-gitignore.gitignoreSource [ ./.gitignore ] ./.; + + buildInputs = [ llvmPkgs.llvm.dev ]; + + cargoSha256 = lib.fakeSha256; + # cargoSha256 = "sha256-rWMnlkb/XoycP69NOOmg7Wd4qPgliuvOKGWaEth/8tg="; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..9c7371a --- /dev/null +++ b/flake.lock @@ -0,0 +1,41 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1648219316, + "narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1648297722, + "narHash": "sha256-W+qlPsiZd8F3XkzXOzAoR+mpFqzm3ekQkJNa+PIh1BQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..52686ce --- /dev/null +++ b/flake.nix @@ -0,0 +1,16 @@ +{ + description = "A very basic flake"; + + inputs = { utils.url = "github:numtide/flake-utils"; }; + + outputs = { self, nixpkgs, utils }: + utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + myPkgs = rec { e0 = pkgs.callPackage ./. { }; }; + + in rec { + packages = utils.lib.flattenTree myPkgs; + defaultPackage = packages.e0; + }); +} diff --git a/src/ast.rs b/src/ast.rs index 98da2cd..f6b3f38 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,10 +1,20 @@ use anyhow::Result; +use inkwell::{context::Context, module::Module}; #[derive(Debug)] pub enum Decl { Func(Func), } +impl Decl { + pub fn unwrap_func(&self) -> Option<&Func> { + match self { + Decl::Func(func) => Some(func), + _ => None, + } + } +} + #[derive(Debug)] pub struct Func { pub name: String, @@ -27,6 +37,22 @@ pub enum Type { Int, } -pub fn convert(program: Vec) -> Result { - Ok(String::new()) +pub fn convert(context: &mut Context, program: Vec) -> Result { + let module = context.create_module("program"); + let builder = context.create_builder(); + + for func in program.iter().filter_map(Decl::unwrap_func) { + // TODO: hardcoded void -> int function + let i64_ty = context.i64_type(); + let llvm_func_ty = i64_ty.fn_type(&[], false); + + let llvm_func = module.add_function(&func.name, llvm_func_ty, None); + let entry_block = context.append_basic_block(llvm_func, "entry"); + + builder.position_at_end(entry_block); + + builder.build_return(None); + } + + Ok(module) } diff --git a/src/main.rs b/src/main.rs index 7482e02..d991574 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,17 +7,21 @@ lalrpop_mod!(parser); mod ast; -use std::fs; +use std::fs::{self, File}; use std::path::PathBuf; use anyhow::Result; use clap::Parser; +use inkwell::context::Context; use crate::parser::ProgramParser; #[derive(Debug, Parser)] struct Opt { path: PathBuf, + + #[clap(short = 'o', long = "out")] + out_path: PathBuf, } fn main() -> Result<()> { @@ -29,5 +33,14 @@ fn main() -> Result<()> { let ast = parser.parse(&contents).unwrap(); println!("AST: {ast:?}"); + let mut context = Context::create(); + let module = ast::convert(&mut context, ast)?; + + { + let file = File::create(&opts.out_path)?; + module.write_bitcode_to_file(&file, true, true); + println!("Emitted."); + } + Ok(()) } diff --git a/src/parser.lalrpop b/src/parser.lalrpop index c4fddd0..cd7cdd2 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -9,7 +9,8 @@ Decl: Decl = { }; Func: Func = { - "fn" "(" ")" "->" "{" "}" => Func { name, return_ty, stmts }, + "fn" "(" ")" "->" "{" "}" => + Func { name, return_ty, stmts }, }; Stmt: Stmt = {