diff --git a/Cargo.lock b/Cargo.lock index 47b7240..8c66a3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,7 @@ dependencies = [ name = "boring-lang" version = "0.1.0" dependencies = [ + "inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)", "lalrpop 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -117,6 +118,11 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.10" @@ -233,6 +239,30 @@ dependencies = [ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "inkwell" +version = "0.1.0" +source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#6929dadf09adb4b0458285999e33b0f6b173ce8e" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "inkwell_internals 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-sys 70.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inkwell_internals" +version = "0.1.0" +source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#6929dadf09adb4b0458285999e33b0f6b173ce8e" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.8.2" @@ -283,6 +313,26 @@ name = "libc" version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "llvm-sys" +version = "70.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -301,6 +351,11 @@ name = "new_debug_unreachable" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -311,6 +366,28 @@ name = "ordermap" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "petgraph" version = "0.4.13" @@ -342,6 +419,14 @@ name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "1.0.10" @@ -350,6 +435,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.3" @@ -504,6 +597,24 @@ dependencies = [ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.106" @@ -538,6 +649,11 @@ name = "siphasher" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "string_cache" version = "0.7.5" @@ -574,6 +690,16 @@ name = "strsim" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "1.0.17" @@ -607,6 +733,11 @@ name = "typenum" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -653,6 +784,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" @@ -669,21 +801,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +"checksum inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)" = "" +"checksum inkwell_internals 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)" = "" "checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" "checksum lalrpop 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "de5e019883a6e9734d093f34216a3857160c6bc2a9a1ec196a177aaa737c74af" "checksum lalrpop-util 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d6e9bc1801eb54529fd6a020aaf9514e8193bb6b42d96d0fe7da99187efa93d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +"checksum llvm-sys 70.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e8e9fc46a848cf4170694144102ec07f6eada790d8b3d7e92ffa9cc7416fc869" +"checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" +"checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +"checksum parking_lot_core 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e136c1904604defe99ce5fd71a28d473fa60a12255d511aa78a9ddf11237aeb" "checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" "checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" "checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -701,18 +842,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" "checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" "checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" "checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +"checksum smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a" "checksum string_cache 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67" "checksum string_cache_codegen 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/Cargo.toml b/Cargo.toml index a640066..4cbe6af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ features = ["lexer"] [dependencies] lalrpop-util = "0.18.1" regex = "1" +inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" } diff --git a/Dockerfile b/Dockerfile index 18a9be9..ff8c9ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ FROM rust:1.39 +RUN apt update && apt-get install -y llvm clang WORKDIR /code diff --git a/src/ast.rs b/src/ast.rs index 1516434..c27409d 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -5,19 +5,19 @@ pub enum Operator { Div, Plus, Minus, - Gt, - Gte, - Lt, - Lte, - Eq, - Mod, - Exp, - FloorDiv, + // Gt, + // Gte, + // Lt, + // Lte, + // Eq, + // Mod, + // Exp, + // FloorDiv, } pub struct LiteralInt { - pub value: i32 + pub value: i64 } // pub struct LiteralString { @@ -28,9 +28,15 @@ pub struct Identifier { pub name: String } +pub struct FunctionCall { + pub name: Identifier, + pub arguments: Vec>, +} + pub enum Expression { LiteralInt(LiteralInt), // LiteralString(LiteralString), + FunctionCall(FunctionCall), Identifier(Identifier), Op(Box, Operator, Box), } @@ -58,6 +64,6 @@ pub struct Function { // } -pub struct Program { +pub struct Module { pub functions: Vec, } diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..31d3c97 --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,125 @@ +use std::collections::HashMap; +use std::mem; +use std::convert::TryInto; +use inkwell::builder::Builder; +use inkwell::context::Context; +use inkwell::module::Module; +use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; + +use crate::ast; + +type Scope<'ctx> = HashMap>; + +pub struct ModuleCodeGen<'ctx> { + context: &'ctx Context, + module: Module<'ctx>, + builder: Builder<'ctx>, + scope: Scope<'ctx>, +} + + +impl<'ctx> ModuleCodeGen<'ctx> { + pub fn new(context: &'ctx Context, name: String) -> Self { + return ModuleCodeGen{ + context: context, + module: context.create_module(&name), + builder: context.create_builder(), + scope: Scope::new(), + } + } + + pub fn gen_literal_int(&mut self, literal_int: ast::LiteralInt) -> IntValue<'ctx> { + self.context.i64_type().const_int(unsafe { mem::transmute::(literal_int.value) }, true) + } + + pub fn gen_op_expression(&mut self, scope: &Scope<'ctx>, lhs: Box, op: ast::Operator, rhs: Box) -> IntValue<'ctx> { + let lhs_result = self.gen_expression(scope, lhs); + let rhs_result = self.gen_expression(scope, rhs); + self.gen_op_int(lhs_result, rhs_result, op) + } + + pub fn gen_op_int(&mut self, lhs: IntValue<'ctx>, rhs: IntValue<'ctx>, op: ast::Operator) -> IntValue<'ctx> { + match op { + ast::Operator::Plus => self.builder.build_int_add(lhs, rhs, "add"), + ast::Operator::Minus => self.builder.build_int_sub(lhs, rhs, "sub"), + ast::Operator::Mul => self.builder.build_int_mul(lhs, rhs, "mul"), + ast::Operator::Div => self.builder.build_int_signed_div(lhs, rhs, "div"), + } + } + + pub fn gen_expression(&mut self, scope: &Scope<'ctx>, expression: Box) -> IntValue<'ctx> { + match *expression { + ast::Expression::LiteralInt(literal_int) => self.gen_literal_int(literal_int), + ast::Expression::Identifier(identifier) => { + match scope[&identifier.name] { + BasicValueEnum::IntValue(value) => value, + _ => panic!("function returned type other than int, no types yet"), + } + }, + ast::Expression::FunctionCall(function_call) => self.gen_function_call(scope, function_call), + ast::Expression::Op(lhs, op, rhs) => self.gen_op_expression(scope, lhs, op, rhs), + } + } + + pub fn gen_function_call(&mut self, scope: &Scope<'ctx>, function_call: ast::FunctionCall) -> IntValue<'ctx> { + println!("Calling function: {}", &function_call.name.name); + let fn_value = self.module.get_function(&function_call.name.name).unwrap(); + let mut arguments = Vec::new(); + for expression in function_call.arguments.into_iter() { + arguments.push(BasicValueEnum::IntValue(self.gen_expression(scope, expression))); + } + + let result = self.builder.build_call(fn_value, &arguments, &function_call.name.name) + .try_as_basic_value() + .left() + .unwrap(); + match result { + BasicValueEnum::IntValue(value) => value, + _ => panic!("function returned type other than int, no types yet"), + } + } + + // Generates a FunctionValue for an `ast::Function`. This does not genereate a body, + // that task is left to the `gen_function` function. The reason this is split + // between two functions is that first all signatures are generated and then all bodies. This + // allows bodies to reference `FunctionValue` wherever they are declared in the file. + pub fn gen_signature(&mut self, function: &ast::Function) -> FunctionValue { + let mut args = Vec::new(); + for _ in &function.arguments { + args.push(self.context.i64_type().into()); + } + let fn_type = self.context.i64_type().fn_type(&args, false); + println!("Adding function: {}", &function.name.name); + let fn_value = self.module.add_function(&function.name.name, fn_type, None); + fn_value + } + + pub fn gen_function(&mut self, function: ast::Function) { + let fn_value = self.module.get_function(&function.name.name).unwrap(); + let basic_block = self.context.append_basic_block(fn_value, "entry"); + + self.builder.position_at_end(basic_block); + + let mut scope = self.scope.clone(); + for (i, param) in function.arguments.into_iter().enumerate() { + scope.insert(param.name.name, fn_value.get_nth_param(i.try_into().unwrap()).unwrap()); + } + let body = function.block; + let return_value = self.gen_expression(&scope, body.expression); + self.builder.build_return(Some(&return_value)); + } + + pub fn gen_module(&mut self, module: ast::Module) { + // generate all signatures before the fuction bodies + for function in &module.functions { + self.gen_signature(&function); + } + for function in module.functions { + self.gen_function(function); + } + } + + pub fn dump(&self) -> String { + self.module.print_to_string().to_string() + } +} diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index c7fcc87..df3102a 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -6,13 +6,17 @@ grammar; pub LiteralInt: ast::LiteralInt = { - r"[0-9]+" => ast::LiteralInt{value: i32::from_str(<>).unwrap()} + r"[0-9]+" => ast::LiteralInt{value: i64::from_str(<>).unwrap()} }; pub Identifier: ast::Identifier = { r"[A-Za-z][A-Za-z0-9_]*" => ast::Identifier{name: <>.to_string()} }; +pub FunctionCall: ast::FunctionCall = { + "(" > ")" => ast::FunctionCall{name:i, arguments: args} +} + pub Expression: Box = { "+" => Box::new(ast::Expression::Op(l, ast::Operator::Plus, r)), "-" => Box::new(ast::Expression::Op(l, ast::Operator::Minus, r)), @@ -28,6 +32,7 @@ pub Factor: Box = { pub Term: Box = { LiteralInt => Box::new(ast::Expression::LiteralInt(<>)), Identifier => Box::new(ast::Expression::Identifier(<>)), + => Box::new(ast::Expression::FunctionCall(<>)), "(" ")", } @@ -44,8 +49,8 @@ pub Function: ast::Function = { } -pub Program: ast::Program = { - => ast::Program{functions: fs} +pub Module: ast::Module = { + => ast::Module{functions: fs} } diff --git a/src/main.rs b/src/main.rs index c6da792..a97ab6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,26 @@ mod ast; lalrpop_mod!(pub grammar); // synthesized by LALRPOP +mod compiler; +use inkwell::context::Context; + fn main() { - println!("Hello, world!"); + let module_ast = grammar::ModuleParser::new().parse(" + fn add(a, b) { + a + b + } + fn subtract(a, b) { + a - b + } + fn main() { + add(4, subtract(5, 2)) + } + ").unwrap(); + + let context = Context::create(); + let mut code_gen = compiler::ModuleCodeGen::new(&context, "main".to_string()); + code_gen.gen_module(module_ast); + println!("{}", code_gen.dump()); } @@ -32,6 +50,8 @@ fn grammar() { assert!(grammar::FunctionParser::new().parse("fn add(a, b) { a + }").is_err()); assert!(grammar::FunctionParser::new().parse("fn add(a, b)").is_err()); - assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b }").is_ok()); - assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b } fn subtract(a, b) { a - b }").is_ok()); + assert!(grammar::FunctionCallParser::new().parse("foo(1, 2)").is_ok()); + + assert!(grammar::ModuleParser::new().parse("fn add(a, b) { a + b }").is_ok()); + assert!(grammar::ModuleParser::new().parse("fn add(a, b) { a + b } fn subtract(a, b) { a - b }").is_ok()); }