mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
We are so back part 2
This commit is contained in:
parent
9eb4bf27fb
commit
019bc88186
299
Cargo.lock
generated
299
Cargo.lock
generated
|
@ -13,6 +13,55 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is-terminal",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ariadne"
|
name = "ariadne"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -29,10 +78,17 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ariadne",
|
"ariadne",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
|
"clap",
|
||||||
"syntax",
|
"syntax",
|
||||||
"typing",
|
"typing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.79"
|
version = "1.0.79"
|
||||||
|
@ -55,6 +111,75 @@ dependencies = [
|
||||||
"stacker",
|
"stacker",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
|
@ -65,10 +190,51 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "heck"
|
||||||
version = "0.2.140"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.142"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
|
@ -76,6 +242,15 @@ version = "1.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psm"
|
name = "psm"
|
||||||
version = "0.1.21"
|
version = "0.1.21"
|
||||||
|
@ -85,6 +260,29 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b864d3c18a5785a05953adeed93e2dca37ed30f18e69bba9f30079d51f363f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stacker"
|
name = "stacker"
|
||||||
version = "0.1.15"
|
version = "0.1.15"
|
||||||
|
@ -98,6 +296,23 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syntax"
|
name = "syntax"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -113,12 +328,24 @@ dependencies = [
|
||||||
"syntax",
|
"syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -147,6 +374,72 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yansi"
|
name = "yansi"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
|
@ -6,5 +6,6 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ariadne = "0.2.0"
|
ariadne = "0.2.0"
|
||||||
chumsky = "1.0.0-alpha.3"
|
chumsky = "1.0.0-alpha.3"
|
||||||
|
clap = { version = "4.2.4", features = ["derive"] }
|
||||||
syntax = { path = "../syntax" }
|
syntax = { path = "../syntax" }
|
||||||
typing = { path = "../typing" }
|
typing = { path = "../typing" }
|
||||||
|
|
12
bin/src/args.rs
Normal file
12
bin/src/args.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
pub struct Args {
|
||||||
|
/// The path to the file to be compiled.
|
||||||
|
#[arg(required = true)]
|
||||||
|
pub file: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_args() -> Args {
|
||||||
|
Args::parse()
|
||||||
|
}
|
|
@ -3,48 +3,37 @@ use chumsky::{Parser, prelude::Input};
|
||||||
use syntax::parser::{lexer, exprs_parser};
|
use syntax::parser::{lexer, exprs_parser};
|
||||||
use typing::infer::infer_exprs;
|
use typing::infer::infer_exprs;
|
||||||
|
|
||||||
|
pub mod args;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let src = "
|
let args = args::get_args();
|
||||||
let r = {
|
let filename = args.file.clone();
|
||||||
let x =
|
let src = std::fs::read_to_string(&args.file).expect("file not found");
|
||||||
if 0 == 1
|
|
||||||
then {
|
|
||||||
let x = true;
|
|
||||||
if x then 1 else 2
|
|
||||||
}
|
|
||||||
else 34 + {
|
|
||||||
let foo = 30 in
|
|
||||||
foo + 5
|
|
||||||
};
|
|
||||||
let y = { 1 } * 2;
|
|
||||||
if 1 + 1 == 2
|
|
||||||
then x
|
|
||||||
else y
|
|
||||||
};
|
|
||||||
".to_string();
|
|
||||||
let filename = "?".to_string();
|
|
||||||
|
|
||||||
let (ts, errs) = lexer().parse(&src).into_output_errors();
|
let (ts, errs) = lexer().parse(&src).into_output_errors();
|
||||||
|
|
||||||
let parse_errs = if let Some(tokens) = &ts {
|
let (ast, parse_errs) = if let Some(tokens) = &ts {
|
||||||
let (ast, parse_errs) = exprs_parser()
|
let (ast, parse_errs) = exprs_parser()
|
||||||
.map_with_span(|ast, span| (ast, span))
|
.map_with_span(|ast, span| (ast, span))
|
||||||
.parse(tokens.as_slice().spanned((src.len()..src.len()).into()))
|
.parse(tokens.as_slice().spanned((src.len()..src.len()).into()))
|
||||||
.into_output_errors();
|
.into_output_errors();
|
||||||
|
|
||||||
if let Some(ast) = ast.filter(|_| errs.len() + parse_errs.len() == 0) {
|
(ast, parse_errs)
|
||||||
let (ast, e) = infer_exprs(ast.0);
|
|
||||||
if !e.is_empty() {
|
|
||||||
println!("{:?}", e);
|
|
||||||
}
|
|
||||||
if !ast.is_empty() {
|
|
||||||
println!("{:?}", ast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_errs
|
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
(None, vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_typed_ast, _type_errs) = if let Some(ast) = ast.filter(|_| errs.len() + parse_errs.len() == 0) {
|
||||||
|
let (ast, e) = infer_exprs(ast.0);
|
||||||
|
if !e.is_empty() {
|
||||||
|
e.iter().for_each(|e| println!("{e:?}"));
|
||||||
|
}
|
||||||
|
if !ast.is_empty() {
|
||||||
|
ast.iter().for_each(|(e, _)| println!("{e:?}"));
|
||||||
|
}
|
||||||
|
(Some(ast), e)
|
||||||
|
} else {
|
||||||
|
(None, vec![])
|
||||||
};
|
};
|
||||||
|
|
||||||
errs.into_iter()
|
errs.into_iter()
|
||||||
|
|
|
@ -4,4 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chumsky = "1.0.0-alpha.3"
|
chumsky = { version = "1.0.0-alpha.3", features = ["label"] }
|
||||||
|
|
|
@ -15,10 +15,20 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, e
|
||||||
.then_ignore(just('"'))
|
.then_ignore(just('"'))
|
||||||
.map_slice(Token::Str);
|
.map_slice(Token::Str);
|
||||||
|
|
||||||
let word = text::ident().map(|s: &str| match s {
|
fn id_filter<C>(c: &C) -> bool where C: text::Char {
|
||||||
|
c.to_char().is_ascii_alphabetic()
|
||||||
|
|| "_'".contains(c.to_char())
|
||||||
|
}
|
||||||
|
let id = any()
|
||||||
|
.filter(id_filter)
|
||||||
|
.then(any()
|
||||||
|
.filter(id_filter)
|
||||||
|
.repeated())
|
||||||
|
.slice();
|
||||||
|
|
||||||
|
let word = id.map(|s: &str| match s {
|
||||||
"true" => Token::Bool(true),
|
"true" => Token::Bool(true),
|
||||||
"false" => Token::Bool(false),
|
"false" => Token::Bool(false),
|
||||||
"unit" => Token::Unit,
|
|
||||||
"let" => Token::Let,
|
"let" => Token::Let,
|
||||||
"in" => Token::In,
|
"in" => Token::In,
|
||||||
"func" => Token::Func,
|
"func" => Token::Func,
|
||||||
|
@ -30,6 +40,7 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, e
|
||||||
});
|
});
|
||||||
|
|
||||||
let sym = choice((
|
let sym = choice((
|
||||||
|
just("()").to(Token::Unit),
|
||||||
just("\\").to(Token::Lambda),
|
just("\\").to(Token::Lambda),
|
||||||
just("->").to(Token::Arrow),
|
just("->").to(Token::Arrow),
|
||||||
|
|
||||||
|
@ -72,7 +83,7 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, e
|
||||||
));
|
));
|
||||||
|
|
||||||
token
|
token
|
||||||
.map_with_span(|tok, span| (tok, span))
|
.map_with_span(move |tok, span| (tok, span))
|
||||||
.padded()
|
.padded()
|
||||||
// If we get an error, skip to the next character and try again.
|
// If we get an error, skip to the next character and try again.
|
||||||
.recover_with(skip_then_retry_until(any().ignored(), end()))
|
.recover_with(skip_then_retry_until(any().ignored(), end()))
|
||||||
|
@ -297,8 +308,8 @@ pub fn expr_parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(clippy::let_and_return)]
|
|
||||||
logical
|
logical
|
||||||
|
.labelled("expression")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,11 +321,20 @@ pub fn type_parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
||||||
> + Clone {
|
> + Clone {
|
||||||
recursive(|ty| {
|
recursive(|ty| {
|
||||||
let lit_ty = select! {
|
let lit_ty = select! {
|
||||||
Token::Ident("bool") => Type::Bool,
|
Token::Ident("Bool") => Type::Bool,
|
||||||
Token::Ident("num") => Type::Num,
|
Token::Ident("Num") => Type::Num,
|
||||||
Token::Ident("str") => Type::Str,
|
Token::Ident("Str") => Type::Str,
|
||||||
|
// TODO: Support type variables in both the parser and the type checker.
|
||||||
|
Token::Ident(_) => Type::Var(69),
|
||||||
Token::Unit => Type::Unit,
|
Token::Unit => Type::Unit,
|
||||||
};
|
}.validate(|tys, span, emitter| {
|
||||||
|
if let Type::Var(_) = tys {
|
||||||
|
emitter.emit(Rich::custom(span,
|
||||||
|
"Type variables are not yet supported.".to_string()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
tys
|
||||||
|
});
|
||||||
|
|
||||||
let tys_paren = ty.clone()
|
let tys_paren = ty.clone()
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
|
@ -351,6 +371,8 @@ pub fn type_parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
||||||
.or(array)
|
.or(array)
|
||||||
.or(func)
|
.or(func)
|
||||||
.or(tuple)
|
.or(tuple)
|
||||||
|
.boxed()
|
||||||
|
.labelled("type")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
test.hlm
47
test.hlm
|
@ -1,46 +1 @@
|
||||||
-- Source
|
let f = \f, g, h, a, b, c, d = ;
|
||||||
|
|
||||||
fun make_add() : (num, num) -> num =
|
|
||||||
\a, b -> num = {
|
|
||||||
println(a + b);
|
|
||||||
return a + b;
|
|
||||||
};
|
|
||||||
|
|
||||||
let add = make_add();
|
|
||||||
|
|
||||||
fun main() = {
|
|
||||||
let foo = 34;
|
|
||||||
|
|
||||||
let bar = 35 in {
|
|
||||||
let r = add(foo, bar);
|
|
||||||
|
|
||||||
match r
|
|
||||||
| 69 -> println(r);
|
|
||||||
| 42 -> println("What");
|
|
||||||
| _ -> println("Unreachable");
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
--- Alpha
|
|
||||||
Convert `match` to `if-else`
|
|
||||||
Convert `let` to `call`
|
|
||||||
---
|
|
||||||
|
|
||||||
(fun make_add []
|
|
||||||
(lambda [a b] (do
|
|
||||||
(println (+ a b))
|
|
||||||
(+ a b)
|
|
||||||
)))
|
|
||||||
|
|
||||||
(fun add [a b] (+ a b))
|
|
||||||
|
|
||||||
(fun main [] (do
|
|
||||||
(def foo 34)
|
|
||||||
|
|
||||||
((lambda [bar] (do
|
|
||||||
(def r (add foo bar))
|
|
||||||
(if (= r 69) (println r)
|
|
||||||
(= r 42) (println "What")
|
|
||||||
true (println "Unreachable"))
|
|
||||||
)) bar)
|
|
||||||
))
|
|
|
@ -10,12 +10,27 @@ use syntax::{
|
||||||
|
|
||||||
use super::typed::TExpr;
|
use super::typed::TExpr;
|
||||||
|
|
||||||
|
macro_rules! ok {
|
||||||
|
($e:expr) => {
|
||||||
|
($e, vec![])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! unbox {
|
macro_rules! unbox {
|
||||||
($e:expr) => {
|
($e:expr) => {
|
||||||
(*$e.0, $e.1)
|
(*$e.0, $e.1)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum InferError<'src> {
|
||||||
|
UnboundVariable(&'src str, SimpleSpan),
|
||||||
|
UnboundFunction(&'src str, SimpleSpan),
|
||||||
|
InfiniteType(Type, Type),
|
||||||
|
LengthMismatch(Type, Type),
|
||||||
|
TypeMismatch(Type, Type),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Infer<'src> {
|
struct Infer<'src> {
|
||||||
env: HashMap<&'src str, Type>,
|
env: HashMap<&'src str, Type>,
|
||||||
|
@ -71,7 +86,7 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unify two types
|
/// Unify two types
|
||||||
fn unify(&mut self, t1: Type, t2: Type) -> Result<(), String> {
|
fn unify(&mut self, t1: Type, t2: Type) -> Result<(), InferError<'src>> {
|
||||||
use Type::*;
|
use Type::*;
|
||||||
match (t1, t2) {
|
match (t1, t2) {
|
||||||
// Literal types
|
// Literal types
|
||||||
|
@ -92,7 +107,7 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
// If the variable occurs in t2
|
// If the variable occurs in t2
|
||||||
if self.occurs(i, t2.clone()) {
|
if self.occurs(i, t2.clone()) {
|
||||||
return Err(format!("Infinite type: '{} = {}", itoa(i), t2));
|
return Err(InferError::InfiniteType(Var(i), t2));
|
||||||
}
|
}
|
||||||
// Set the substitution
|
// Set the substitution
|
||||||
self.subst[i] = t2;
|
self.subst[i] = t2;
|
||||||
|
@ -105,7 +120,7 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.occurs(i, t1.clone()) {
|
if self.occurs(i, t1.clone()) {
|
||||||
return Err(format!("Infinite type: '{} = {}", itoa(i), t1));
|
return Err(InferError::InfiniteType(Var(i), t1));
|
||||||
}
|
}
|
||||||
self.subst[i] = t1;
|
self.subst[i] = t1;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -115,7 +130,7 @@ impl<'src> Infer<'src> {
|
||||||
(Func(a1, r1), Func(a2, r2)) => {
|
(Func(a1, r1), Func(a2, r2)) => {
|
||||||
// Check the number of arguments
|
// Check the number of arguments
|
||||||
if a1.len() != a2.len() {
|
if a1.len() != a2.len() {
|
||||||
return Err(format!("Function argument mismatch: {} != {}", a1.len(), a2.len()));
|
return Err(InferError::LengthMismatch(Func(a1, r1), Func(a2, r2)));
|
||||||
}
|
}
|
||||||
// Unify the arguments
|
// Unify the arguments
|
||||||
for (a1, a2) in a1.into_iter().zip(a2.into_iter()) {
|
for (a1, a2) in a1.into_iter().zip(a2.into_iter()) {
|
||||||
|
@ -129,7 +144,7 @@ impl<'src> Infer<'src> {
|
||||||
(Tuple(t1), Tuple(t2)) => {
|
(Tuple(t1), Tuple(t2)) => {
|
||||||
// Check the number of elements
|
// Check the number of elements
|
||||||
if t1.len() != t2.len() {
|
if t1.len() != t2.len() {
|
||||||
return Err(format!("Tuple element mismatch: {} != {}", t1.len(), t2.len()));
|
return Err(InferError::LengthMismatch(Tuple(t1), Tuple(t2)));
|
||||||
}
|
}
|
||||||
// Unify the elements
|
// Unify the elements
|
||||||
for (t1, t2) in t1.into_iter().zip(t2.into_iter()) {
|
for (t1, t2) in t1.into_iter().zip(t2.into_iter()) {
|
||||||
|
@ -142,12 +157,12 @@ impl<'src> Infer<'src> {
|
||||||
(Array(t1), Array(t2)) => self.unify(*t1, *t2),
|
(Array(t1), Array(t2)) => self.unify(*t1, *t2),
|
||||||
|
|
||||||
// The rest will be type mismatch
|
// The rest will be type mismatch
|
||||||
(t1, t2) => Err(format!("Type mismatch: {} != {}", t1, t2)),
|
(t1, t2) => Err(InferError::TypeMismatch(t1, t2)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Solve the constraints by unifying them
|
/// Solve the constraints by unifying them
|
||||||
fn solve(&mut self) -> Result<(), String> {
|
fn solve(&mut self) -> Result<(), InferError<'src>> {
|
||||||
for (t1, t2, _span) in self.constraints.clone().into_iter() {
|
for (t1, t2, _span) in self.constraints.clone().into_iter() {
|
||||||
self.unify(t1, t2)?;
|
self.unify(t1, t2)?;
|
||||||
}
|
}
|
||||||
|
@ -266,30 +281,45 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infer the type of an expression
|
/// Infer the type of an expression
|
||||||
fn infer(&mut self, e: (Expr<'src>, SimpleSpan), expected: Type) -> Result<TExpr<'src>, String> {
|
fn infer(
|
||||||
let (e, span) = e;
|
&mut self, e: (Expr<'src>, SimpleSpan), expected: Type
|
||||||
match e {
|
) -> (TExpr<'src>, Vec<InferError<'src>>) {
|
||||||
|
let span = e.1;
|
||||||
|
match e.0 {
|
||||||
// Literal values
|
// Literal values
|
||||||
// Push the constraint (expected type to be the literal type) and
|
// Push the constraint (expected type to be the literal type) and
|
||||||
// return the typed expression
|
// return the typed expression
|
||||||
Expr::Lit(l) => {
|
Expr::Lit(l) => match l {
|
||||||
let t = match l {
|
Lit::Unit => {
|
||||||
Lit::Unit => Type::Unit,
|
self.add_constraint(expected, Type::Unit, span);
|
||||||
Lit::Bool(_) => Type::Bool,
|
ok!(TExpr::Lit(Lit::Unit))
|
||||||
Lit::Num(_) => Type::Num,
|
}
|
||||||
Lit::Str(_) => Type::Str,
|
Lit::Bool(b) => {
|
||||||
};
|
self.add_constraint(expected, Type::Bool, span);
|
||||||
self.add_constraint(expected, t, span);
|
ok!(TExpr::Lit(Lit::Bool(b)))
|
||||||
Ok(TExpr::Lit(l))
|
}
|
||||||
},
|
Lit::Num(i) => {
|
||||||
|
self.add_constraint(expected, Type::Num, span);
|
||||||
|
ok!(TExpr::Lit(Lit::Num(i)))
|
||||||
|
}
|
||||||
|
Lit::Str(s) => {
|
||||||
|
self.add_constraint(expected, Type::Str, span);
|
||||||
|
ok!(TExpr::Lit(Lit::Str(s)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
// The same as literals but the type is looked up in the environment
|
// The same as literals but the type is looked up in the environment
|
||||||
Expr::Ident(ref x) => {
|
Expr::Ident(ref x) => {
|
||||||
let t = self.env.get(x)
|
if let Some(t) = self.env.get(x) {
|
||||||
.ok_or(format!("Unbound variable: {}", x))?;
|
self.add_constraint(expected, t.clone(), span);
|
||||||
self.add_constraint(expected, t.clone(), span);
|
ok!(TExpr::Ident(x))
|
||||||
Ok(TExpr::Ident(x.clone()))
|
} else {
|
||||||
|
(TExpr::Ident(x), vec![match expected {
|
||||||
|
Type::Func(_, _) => InferError::UnboundFunction(x, span),
|
||||||
|
_ => InferError::UnboundVariable(x, span),
|
||||||
|
}])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unary & binary operators
|
// Unary & binary operators
|
||||||
|
@ -298,23 +328,23 @@ impl<'src> Infer<'src> {
|
||||||
Expr::Unary(op, e) => match op {
|
Expr::Unary(op, e) => match op {
|
||||||
// Numeric operators (Num -> Num)
|
// Numeric operators (Num -> Num)
|
||||||
UnaryOp::Neg => {
|
UnaryOp::Neg => {
|
||||||
let et = self.infer(unbox!(e), Type::Num)?;
|
let (te, err) = self.infer(unbox!(e), Type::Num);
|
||||||
self.add_constraint(expected, Type::Num, span);
|
self.add_constraint(expected, Type::Num, span);
|
||||||
Ok(TExpr::Unary {
|
(TExpr::Unary {
|
||||||
op,
|
op,
|
||||||
expr: (Box::new(et), e.1),
|
expr: (Box::new(te), span),
|
||||||
ret_ty: Type::Num,
|
ret_ty: Type::Num,
|
||||||
})
|
}, err)
|
||||||
},
|
},
|
||||||
// Boolean operators (Bool -> Bool)
|
// Boolean operators (Bool -> Bool)
|
||||||
UnaryOp::Not => {
|
UnaryOp::Not => {
|
||||||
let et = self.infer(unbox!(e), Type::Bool)?;
|
let (te, err) = self.infer(unbox!(e), Type::Bool);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
self.add_constraint(expected, Type::Bool, span);
|
||||||
Ok(TExpr::Unary {
|
(TExpr::Unary {
|
||||||
op,
|
op,
|
||||||
expr: (Box::new(et), e.1),
|
expr: (Box::new(te), span),
|
||||||
ret_ty: Type::Bool,
|
ret_ty: Type::Bool,
|
||||||
})
|
}, err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Expr::Binary(op, lhs, rhs) => match op {
|
Expr::Binary(op, lhs, rhs) => match op {
|
||||||
|
@ -325,29 +355,31 @@ impl<'src> Infer<'src> {
|
||||||
| BinaryOp::Div
|
| BinaryOp::Div
|
||||||
| BinaryOp::Rem
|
| BinaryOp::Rem
|
||||||
=> {
|
=> {
|
||||||
let lt = self.infer(unbox!(lhs), Type::Num)?;
|
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Num);
|
||||||
let rt = self.infer(unbox!(rhs), Type::Num)?;
|
let (rt, errs1) = self.infer(unbox!(rhs), Type::Num);
|
||||||
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Num, span);
|
self.add_constraint(expected, Type::Num, span);
|
||||||
Ok(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
rhs: (Box::new(rt), rhs.1),
|
rhs: (Box::new(rt), rhs.1),
|
||||||
ret_ty: Type::Num,
|
ret_ty: Type::Num,
|
||||||
})
|
}, errs0)
|
||||||
},
|
},
|
||||||
// Boolean operators (Bool -> Bool -> Bool)
|
// Boolean operators (Bool -> Bool -> Bool)
|
||||||
BinaryOp::And
|
BinaryOp::And
|
||||||
| BinaryOp::Or
|
| BinaryOp::Or
|
||||||
=> {
|
=> {
|
||||||
let lt = self.infer(unbox!(lhs), Type::Bool)?;
|
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Bool);
|
||||||
let rt = self.infer(unbox!(rhs), Type::Bool)?;
|
let (rt, errs1) = self.infer(unbox!(rhs), Type::Bool);
|
||||||
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
self.add_constraint(expected, Type::Bool, span);
|
||||||
Ok(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
rhs: (Box::new(rt), rhs.1),
|
rhs: (Box::new(rt), rhs.1),
|
||||||
ret_ty: Type::Bool,
|
ret_ty: Type::Bool,
|
||||||
})
|
}, errs0)
|
||||||
},
|
},
|
||||||
// Comparison operators ('a -> 'a -> Bool)
|
// Comparison operators ('a -> 'a -> Bool)
|
||||||
BinaryOp::Eq
|
BinaryOp::Eq
|
||||||
|
@ -361,15 +393,16 @@ impl<'src> Infer<'src> {
|
||||||
// expected type for both the left and right hand side
|
// expected type for both the left and right hand side
|
||||||
// so the type on both side have to be the same
|
// so the type on both side have to be the same
|
||||||
let t = self.fresh();
|
let t = self.fresh();
|
||||||
let lt = self.infer(unbox!(lhs), t.clone())?;
|
let (lt, mut errs0) = self.infer(unbox!(lhs), t.clone());
|
||||||
let rt = self.infer(unbox!(rhs), t)?;
|
let (rt, errs1) = self.infer(unbox!(rhs), t);
|
||||||
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
self.add_constraint(expected, Type::Bool, span);
|
||||||
Ok(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
rhs: (Box::new(rt), rhs.1),
|
rhs: (Box::new(rt), rhs.1),
|
||||||
ret_ty: Type::Bool,
|
ret_ty: Type::Bool,
|
||||||
})
|
}, errs0)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +421,7 @@ impl<'src> Infer<'src> {
|
||||||
xs.clone().into_iter().for_each(|(x, t)| { env.insert(x, t); });
|
xs.clone().into_iter().for_each(|(x, t)| { env.insert(x, t); });
|
||||||
let mut inf = self.clone();
|
let mut inf = self.clone();
|
||||||
inf.env = env;
|
inf.env = env;
|
||||||
let bt = inf.infer(unbox!(b), rt.clone())?;
|
let (bt, errs) = inf.infer(unbox!(b), rt.clone());
|
||||||
|
|
||||||
// Add the substitutions & constraints from the body
|
// Add the substitutions & constraints from the body
|
||||||
// if it doesn't already exist
|
// if it doesn't already exist
|
||||||
|
@ -411,11 +444,11 @@ impl<'src> Infer<'src> {
|
||||||
Box::new(rt.clone()),
|
Box::new(rt.clone()),
|
||||||
), span);
|
), span);
|
||||||
|
|
||||||
Ok(TExpr::Lambda {
|
(TExpr::Lambda {
|
||||||
params: xs,
|
params: xs,
|
||||||
body: (Box::new(bt), b.1),
|
body: (Box::new(bt), b.1),
|
||||||
ret_ty: rt,
|
ret_ty: rt,
|
||||||
})
|
}, errs)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Call
|
// Call
|
||||||
|
@ -430,41 +463,53 @@ impl<'src> Infer<'src> {
|
||||||
Box::new(expected),
|
Box::new(expected),
|
||||||
);
|
);
|
||||||
// Expect the function to have the function type
|
// Expect the function to have the function type
|
||||||
let ft = self.infer(unbox!(f), fsig)?;
|
let (ft, mut errs) = self.infer(unbox!(f), fsig);
|
||||||
// Infer the arguments
|
// Infer the arguments
|
||||||
let xs = args.into_iter()
|
let (xs, xerrs) = args.into_iter()
|
||||||
.zip(freshes.into_iter())
|
.zip(freshes.into_iter())
|
||||||
.map(|(x, t)| Ok((self.infer(x, t)?, span)))
|
.map(|(x, t)| {
|
||||||
.collect::<Result<Vec<_>, String>>()?;
|
let span = x.1;
|
||||||
|
let (xt, err) = self.infer(x, t);
|
||||||
|
((xt, span), err)
|
||||||
|
})
|
||||||
|
// Flatten errors
|
||||||
|
.fold((vec![], vec![]), |(mut xs, mut errs), ((x, span), err)| {
|
||||||
|
xs.push((x, span));
|
||||||
|
errs.extend(err);
|
||||||
|
(xs, errs)
|
||||||
|
});
|
||||||
|
errs.extend(xerrs);
|
||||||
|
|
||||||
Ok(TExpr::Call {
|
(TExpr::Call {
|
||||||
func: (Box::new(ft), f.1),
|
func: (Box::new(ft), f.1),
|
||||||
args: xs,
|
args: xs,
|
||||||
})
|
}, errs)
|
||||||
},
|
},
|
||||||
|
|
||||||
// If
|
// If
|
||||||
Expr::If { cond, t, f } => {
|
Expr::If { cond, t, f } => {
|
||||||
// Condition has to be a boolean
|
// Condition has to be a boolean
|
||||||
let ct = self.infer(unbox!(cond), Type::Bool)?;
|
let (ct, mut errs) = self.infer(unbox!(cond), Type::Bool);
|
||||||
// The type of the if expression is the same as the
|
// The type of the if expression is the same as the
|
||||||
// expected type
|
// expected type
|
||||||
let tt = self.infer(unbox!(t), expected.clone())?;
|
let (tt, terrs) = self.infer(unbox!(t), expected.clone());
|
||||||
let et = self.infer(unbox!(f), expected.clone())?;
|
let (ft, ferrs) = self.infer(unbox!(f), expected.clone());
|
||||||
|
errs.extend(terrs);
|
||||||
|
errs.extend(ferrs);
|
||||||
|
|
||||||
Ok(TExpr::If {
|
(TExpr::If {
|
||||||
cond: (Box::new(ct), cond.1),
|
cond: (Box::new(ct), cond.1),
|
||||||
t: (Box::new(tt), t.1),
|
t: (Box::new(tt), t.1),
|
||||||
f: (Box::new(et), f.1),
|
f: (Box::new(ft), f.1),
|
||||||
br_ty: expected,
|
br_ty: expected,
|
||||||
})
|
}, errs)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Let & define
|
// Let & define
|
||||||
Expr::Let { name, ty, value, body } => {
|
Expr::Let { name, ty, value, body } => {
|
||||||
// Infer the type of the value
|
// Infer the type of the value
|
||||||
let ty = ty.unwrap_or(self.fresh());
|
let ty = ty.unwrap_or(self.fresh());
|
||||||
let vt = self.infer(unbox!(value), ty.clone())?;
|
let (vt, mut errs) = self.infer(unbox!(value), ty.clone());
|
||||||
|
|
||||||
// Create a new environment and add the binding to it
|
// Create a new environment and add the binding to it
|
||||||
// and then use the new environment to infer the body
|
// and then use the new environment to infer the body
|
||||||
|
@ -472,23 +517,27 @@ impl<'src> Infer<'src> {
|
||||||
env.insert(name.clone(), ty.clone());
|
env.insert(name.clone(), ty.clone());
|
||||||
let mut inf = Infer::new();
|
let mut inf = Infer::new();
|
||||||
inf.env = env;
|
inf.env = env;
|
||||||
let bt = inf.infer(unbox!(body), expected.clone())?;
|
let (bt, berrs) = inf.infer(unbox!(body), expected.clone());
|
||||||
|
errs.extend(berrs);
|
||||||
|
|
||||||
Ok(TExpr::Let {
|
(TExpr::Let {
|
||||||
name, ty,
|
name, ty,
|
||||||
value: (Box::new(vt), value.1),
|
value: (Box::new(vt), value.1),
|
||||||
body: (Box::new(bt), body.1),
|
body: (Box::new(bt), body.1),
|
||||||
})
|
}, errs)
|
||||||
},
|
},
|
||||||
Expr::Define { name, ty, value } => {
|
Expr::Define { name, ty, value } => {
|
||||||
let ty = ty.unwrap_or(self.fresh());
|
let ty = ty.unwrap_or(self.fresh());
|
||||||
let vt = self.infer(unbox!(value), ty.clone())?;
|
let (val_ty, errs) = self.infer(unbox!(value), ty.clone());
|
||||||
self.env.insert(name.clone(), ty.clone());
|
self.env.insert(name.clone(), ty.clone());
|
||||||
|
|
||||||
Ok(TExpr::Define {
|
self.constraints.push((expected, Type::Unit, e.1));
|
||||||
name, ty,
|
|
||||||
value: (Box::new(vt), value.1),
|
(TExpr::Define {
|
||||||
})
|
name,
|
||||||
|
ty,
|
||||||
|
value: (Box::new(val_ty), value.1),
|
||||||
|
}, errs)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Block
|
// Block
|
||||||
|
@ -496,18 +545,23 @@ impl<'src> Infer<'src> {
|
||||||
// Infer the type of each expression
|
// Infer the type of each expression
|
||||||
let mut last = None;
|
let mut last = None;
|
||||||
let len = exprs.len();
|
let len = exprs.len();
|
||||||
let xs = exprs.into_iter()
|
let (texprs, errs) = exprs.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, x)| {
|
.map(|(i, x)| {
|
||||||
|
let span = x.1;
|
||||||
let t = self.fresh();
|
let t = self.fresh();
|
||||||
let xt = self.infer(unbox!(x), t.clone())?;
|
let (xt, err) = self.infer(unbox!(x), t.clone());
|
||||||
// Save the type of the last expression
|
// Save the type of the last expression
|
||||||
if i == len - 1 {
|
if i == len - 1 {
|
||||||
last = Some(t);
|
last = Some(t);
|
||||||
}
|
}
|
||||||
Ok((xt, x.1))
|
((xt, span), err)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, String>>()?;
|
.fold((vec![], vec![]), |(mut xs, mut errs), ((x, span), err)| {
|
||||||
|
xs.push((x, span));
|
||||||
|
errs.extend(err);
|
||||||
|
(xs, errs)
|
||||||
|
});
|
||||||
|
|
||||||
let rt = if void || last.is_none() {
|
let rt = if void || last.is_none() {
|
||||||
// If the block is void or there is no expression,
|
// If the block is void or there is no expression,
|
||||||
|
@ -520,70 +574,42 @@ impl<'src> Infer<'src> {
|
||||||
expected
|
expected
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(TExpr::Block {
|
(TExpr::Block {
|
||||||
exprs: xs,
|
exprs: texprs,
|
||||||
void,
|
void,
|
||||||
ret_ty: rt,
|
ret_ty: rt,
|
||||||
})
|
}, errs)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infer a list of expressions
|
/// Infer a list of expressions
|
||||||
pub fn infer_exprs(es: Vec<(Expr, SimpleSpan)>) -> (Vec<(TExpr, SimpleSpan)>, String) {
|
pub fn infer_exprs(es: Vec<(Expr, SimpleSpan)>) -> (Vec<(TExpr, SimpleSpan)>, Vec<InferError>) {
|
||||||
let mut inf = Infer::new();
|
let mut inf = Infer::new();
|
||||||
// Typed expressions
|
let mut typed_exprs = vec![];
|
||||||
let mut tes = vec![];
|
let mut errors = vec![];
|
||||||
// Typed expressions without substitutions
|
|
||||||
let mut tes_nosub = vec![];
|
|
||||||
// Errors
|
|
||||||
let mut errs = vec![];
|
|
||||||
|
|
||||||
for (e, s) in es {
|
for e in es {
|
||||||
let f = inf.fresh();
|
let span = e.1;
|
||||||
let t = inf.infer((e, s), f).unwrap();
|
let fresh = inf.fresh();
|
||||||
tes.push(Some((t.clone(), s)));
|
let (te, err) = inf.infer(e, fresh);
|
||||||
tes_nosub.push((t, s));
|
typed_exprs.push((te, span));
|
||||||
|
if !err.is_empty() {
|
||||||
match inf.solve() {
|
errors.extend(err);
|
||||||
Ok(_) => {
|
|
||||||
// Substitute the type variables for the solved expressions
|
|
||||||
tes = tes.into_iter()
|
|
||||||
.map(|te| match te {
|
|
||||||
Some((t, s)) => {
|
|
||||||
Some((inf.substitute_texp(t), s))
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
errs.push(e);
|
|
||||||
// Replace the expression with None
|
|
||||||
tes.pop();
|
|
||||||
tes.push(None);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Union typed expressions, replacing None with the typed expression without substitutions
|
match inf.solve() {
|
||||||
// None means that the expression has an error
|
Ok(_) => {
|
||||||
let mut tes_union = vec![];
|
typed_exprs = typed_exprs.into_iter()
|
||||||
for (te, te_nosub) in tes.into_iter().zip(tes_nosub.into_iter()) {
|
.map(|(x, s)| (inf.substitute_texp(x), s))
|
||||||
match te {
|
.collect();
|
||||||
Some(t) => {
|
}
|
||||||
tes_union.push(t);
|
Err(e) => {
|
||||||
},
|
errors.push(e);
|
||||||
None => {
|
|
||||||
tes_union.push(te_nosub);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(typed_exprs, errors)
|
||||||
// Renamer::new().process(tes_union),
|
|
||||||
tes_union,
|
|
||||||
errs.join("\n")
|
|
||||||
)
|
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
use chumsky::span::SimpleSpan;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
expr::{
|
expr::{
|
||||||
BinaryOp,
|
BinaryOp,
|
||||||
|
|
Loading…
Reference in a new issue