Big restructure pt.1
This commit is contained in:
Generated
+34
-291
@@ -2,42 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a"
|
||||
dependencies = [
|
||||
"object",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arcstr"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d"
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
@@ -62,16 +32,6 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
@@ -79,16 +39,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "chumsky"
|
||||
version = "0.11.2"
|
||||
name = "convert_case"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acc17a6284abccac6e50db35c1cee87f605474a72939b959a3a67d9371800efd"
|
||||
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
"stacker",
|
||||
"unicode-ident",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
@@ -100,49 +55,27 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||
checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
@@ -163,23 +96,6 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "leaf_allocators"
|
||||
version = "0.1.0"
|
||||
@@ -200,6 +116,16 @@ dependencies = [
|
||||
"scc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leaf_compiler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arcstr",
|
||||
"leaf_allocators",
|
||||
"leaf_assembly",
|
||||
"leaf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leaf_interpreter"
|
||||
version = "0.1.0"
|
||||
@@ -212,68 +138,40 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leaf_parsing"
|
||||
name = "leaf_parser"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arcstr",
|
||||
"chumsky",
|
||||
"logos",
|
||||
"derive_more",
|
||||
"peg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
name = "peg"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[package]]
|
||||
name = "logos"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff472f899b4ec2d99161c51f60ff7075eeb3097069a36050d8037a6325eb8154"
|
||||
checksum = "9928cfca101b36ec5163e70049ee5368a8a1c3c6efc9ca9c5f9cc2f816152477"
|
||||
dependencies = [
|
||||
"logos-derive",
|
||||
"peg-macros",
|
||||
"peg-runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-codegen"
|
||||
version = "0.15.1"
|
||||
name = "peg-macros"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "192a3a2b90b0c05b27a0b2c43eecdb7c415e29243acc3f89cc8247a5b693045c"
|
||||
checksum = "6298ab04c202fa5b5d52ba03269fb7b74550b150323038878fe6c372d8280f71"
|
||||
dependencies = [
|
||||
"beef",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"peg-runtime",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex-syntax 0.8.8",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-derive"
|
||||
version = "0.15.1"
|
||||
name = "peg-runtime"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "605d9697bcd5ef3a42d38efc51541aa3d6a4a25f7ab6d1ed0da5ac632a26b470"
|
||||
dependencies = [
|
||||
"logos-codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
checksum = "132dca9b868d927b35b5dd728167b2dee150eb1ad686008fc71ccb298b776fca"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
@@ -284,16 +182,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01"
|
||||
dependencies = [
|
||||
"ar_archive_writer",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
@@ -303,29 +191,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.7.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -363,61 +228,12 @@ version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.110"
|
||||
@@ -447,79 +263,6 @@ version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.27"
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["allocators","assembly", "interpreter", "parsing"]
|
||||
members = ["allocators","assembly", "compiler", "interpreter", "parser"]
|
||||
|
||||
@@ -1,24 +1,41 @@
|
||||
use crate::{
|
||||
assembly::intrinsic_types::make_intrinsic_types,
|
||||
functions::Function,
|
||||
types::{
|
||||
Type,
|
||||
derivations::{FuncT, TypeDerivations},
|
||||
intrinsics::*,
|
||||
},
|
||||
values::{Const, Int},
|
||||
values::{Const, ConstData, Int},
|
||||
};
|
||||
use derive_more::Debug;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use scc::HashMap;
|
||||
use std::{hash::Hash, sync::OnceLock};
|
||||
use std::{borrow::Cow, hash::Hash, sync::OnceLock};
|
||||
|
||||
#[derive(derive_more::Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[debug("{major}.{minor}.{patch}.{build}")]
|
||||
pub struct Version {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
pub patch: u16,
|
||||
pub build: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AssemblyIdentifier {
|
||||
pub version: Version,
|
||||
pub name: Cow<'static, str>,
|
||||
}
|
||||
|
||||
pub type Ctx<'l> = &'l Context<'l>;
|
||||
|
||||
pub struct Context<'l> {
|
||||
pub(crate) alloc: &'l dyn SyncAllocator,
|
||||
pub(crate) derivations: TypeDerivations<'l>,
|
||||
|
||||
constants: HashMap<&'l Const<'l>, &'l Const<'l>>,
|
||||
constants: HashMap<&'l ConstData<'l>, &'l Const<'l>>,
|
||||
intrinsics: OnceLock<Box<intrinsic_types::IntrinsicTypesArray<'l>>>,
|
||||
assemblies: HashMap<AssemblyIdentifier, &'l Assembly<'l>>,
|
||||
}
|
||||
|
||||
impl Eq for Context<'_> {}
|
||||
@@ -31,30 +48,91 @@ impl PartialEq for Context<'_> {
|
||||
|
||||
impl Hash for Context<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
(self as *const Self).hash(state);
|
||||
std::ptr::hash(self, state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> Context<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> &'l Context<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> &'l Self {
|
||||
let ctx = alloc.alloc(Self {
|
||||
alloc,
|
||||
constants: HashMap::new(),
|
||||
derivations: TypeDerivations::new(alloc),
|
||||
intrinsics: OnceLock::new(),
|
||||
assemblies: Default::default(),
|
||||
});
|
||||
ctx.intrinsics
|
||||
.set(Box::new(intrinsic_types::make_intrinsic_types(ctx)))
|
||||
.set(Box::new(make_intrinsic_types(ctx)))
|
||||
.unwrap();
|
||||
ctx
|
||||
}
|
||||
|
||||
pub fn get_assembly(&'l self, ident: &AssemblyIdentifier) -> Option<&'l Assembly<'l>> {
|
||||
self.assemblies.get_sync(ident).map(|v| *v)
|
||||
}
|
||||
|
||||
pub fn get_or_create_assembly(&'l self, ident: AssemblyIdentifier) -> &'l Assembly<'l> {
|
||||
&*self
|
||||
.assemblies
|
||||
.entry_sync(ident.clone())
|
||||
.or_insert_with(|| Assembly::new(self, ident))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Assembly<'l> {
|
||||
#[debug(skip)]
|
||||
ctx: &'l Context<'l>,
|
||||
ident: AssemblyIdentifier,
|
||||
#[debug("{:#?}", {
|
||||
let mut c = vec![];
|
||||
constants.iter_sync(|k, _| {c.push(*k); true});
|
||||
c
|
||||
})]
|
||||
constants: HashMap<&'l Const<'l>, &'l Const<'l>>,
|
||||
}
|
||||
|
||||
impl Eq for Assembly<'_> {}
|
||||
|
||||
impl PartialEq for Assembly<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::ptr::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Assembly<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
(self as *const Self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> Assembly<'l> {
|
||||
pub fn new(ctx: &'l Context<'l>, ident: AssemblyIdentifier) -> &'l Self {
|
||||
let assembly = ctx.alloc.alloc(Self {
|
||||
ctx,
|
||||
ident,
|
||||
constants: HashMap::new(),
|
||||
});
|
||||
assembly
|
||||
}
|
||||
|
||||
pub fn ctx(&self) -> Ctx<'l> {
|
||||
self.ctx
|
||||
}
|
||||
|
||||
pub fn create_function(&'l self, ty: &'l FuncT<'l>) -> &'l Function<'l> {
|
||||
self.alloc.alloc(Function {
|
||||
let func = self.ctx.alloc.alloc(Function {
|
||||
ty,
|
||||
name: OnceLock::new(),
|
||||
body: OnceLock::new(),
|
||||
ctx: self,
|
||||
})
|
||||
declaring_assembly: self,
|
||||
});
|
||||
let constant = self.ctx.alloc.alloc(Const {
|
||||
ctx: self.ctx,
|
||||
data: ConstData::Function(func),
|
||||
});
|
||||
self.constants.insert_sync(constant, constant).unwrap();
|
||||
func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +146,11 @@ macro_rules! create_const {
|
||||
impl<'l> CreateConst<'l, $ty> for Context<'l> {
|
||||
fn create_const(&'l self, value: $ty) -> &'l Const<'l> {
|
||||
let constant = ($expr)(self, value);
|
||||
if let Some(existing) = self.constants.get_sync(&constant) {
|
||||
if let Some(existing) = self.constants.get_sync(&constant.data) {
|
||||
return *existing;
|
||||
}
|
||||
let constant = self.alloc.alloc(constant);
|
||||
*self.constants.entry_sync(constant).or_insert(constant)
|
||||
*self.constants.entry_sync(&constant.data).or_insert(constant)
|
||||
}
|
||||
}
|
||||
)*
|
||||
@@ -80,22 +158,22 @@ macro_rules! create_const {
|
||||
}
|
||||
|
||||
create_const! {
|
||||
impl i8: |ctx, val| Const::Int(Int::I8(val), ctx),
|
||||
impl i16: |ctx, val| Const::Int(Int::I16(val), ctx),
|
||||
impl i32: |ctx, val| Const::Int(Int::I32(val), ctx),
|
||||
impl i64: |ctx, val| Const::Int(Int::I64(val), ctx),
|
||||
impl i128: |ctx, val| Const::Int(Int::I128(val), ctx),
|
||||
impl i8: |ctx, val| Const { ctx, data: ConstData::Int(Int::I8(val)) },
|
||||
impl i16: |ctx, val| Const { ctx, data: ConstData::Int(Int::I16(val)) },
|
||||
impl i32: |ctx, val| Const { ctx, data: ConstData::Int(Int::I32(val)) },
|
||||
impl i64: |ctx, val| Const { ctx, data: ConstData::Int(Int::I64(val)) },
|
||||
impl i128: |ctx, val| Const { ctx, data: ConstData::Int(Int::I128(val)) },
|
||||
|
||||
impl u8: |ctx, val| Const::Int(Int::U8(val), ctx),
|
||||
impl u16: |ctx, val| Const::Int(Int::U16(val), ctx),
|
||||
impl u32: |ctx, val| Const::Int(Int::U32(val), ctx),
|
||||
impl u64: |ctx, val| Const::Int(Int::U64(val), ctx),
|
||||
impl u128: |ctx, val| Const::Int(Int::U128(val), ctx),
|
||||
impl u8: |ctx, val| Const { ctx, data: ConstData::Int(Int::U8(val)) },
|
||||
impl u16: |ctx, val| Const { ctx, data: ConstData::Int(Int::U16(val)) },
|
||||
impl u32: |ctx, val| Const { ctx, data: ConstData::Int(Int::U32(val)) },
|
||||
impl u64: |ctx, val| Const { ctx, data: ConstData::Int(Int::U64(val)) },
|
||||
impl u128: |ctx, val| Const { ctx, data: ConstData::Int(Int::U128(val)) },
|
||||
|
||||
impl (): |ctx, _| Const::Void(ctx),
|
||||
impl char: |ctx, val| Const::Char(val, ctx),
|
||||
impl bool: |ctx, val| Const::Bool(val, ctx),
|
||||
impl &'l str: |ctx, val| Const::Str(val, ctx),
|
||||
impl (): |ctx, _| Const { ctx, data: ConstData::Void },
|
||||
impl char: |ctx, val| Const { ctx, data: ConstData::Char(val) },
|
||||
impl bool: |ctx, val| Const { ctx, data: ConstData::Bool(val) },
|
||||
impl &'l str: |ctx, val| Const { ctx, data: ConstData::Str(val) },
|
||||
}
|
||||
|
||||
mod intrinsic_types {
|
||||
@@ -111,7 +189,7 @@ mod intrinsic_types {
|
||||
|
||||
pub type IntrinsicTypesArray<'l> = [Type<'l>; IntrinsicTypeKind::COUNT as usize];
|
||||
|
||||
pub fn make_intrinsic_types<'l>(ctx: Ctx<'l>) -> IntrinsicTypesArray<'l> {
|
||||
pub fn make_intrinsic_types<'l>(ctx: &'l Context<'l>) -> IntrinsicTypesArray<'l> {
|
||||
unsafe {
|
||||
const C: usize = IntrinsicTypeKind::COUNT as usize;
|
||||
let mut intrinsics = [MaybeUninit::<Type>::uninit(); C];
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
context::Ctx,
|
||||
assembly::Ctx,
|
||||
functions::{Function, FunctionBody},
|
||||
types::{Type, derivations::*},
|
||||
values::{Value, ValueFlags},
|
||||
@@ -55,7 +55,7 @@ impl<'l> Into<Value<'l>> for &'l Instruction<'l> {
|
||||
impl<'l> Instruction<'l> {
|
||||
#[inline]
|
||||
pub fn ctx(&self) -> Ctx<'l> {
|
||||
self.parent_block.func.ctx
|
||||
self.parent_block.func.declaring_assembly.ctx()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -342,7 +342,7 @@ impl<'l> BlockBuilder<'l> {
|
||||
let ret_t = self.block.func.ty.ret_t;
|
||||
let value_ty = match value {
|
||||
Some(v) => v.ty(),
|
||||
None => self.block.func.ctx.void_t(),
|
||||
None => self.block.func.ctx().void_t(),
|
||||
};
|
||||
if value_ty != ret_t {
|
||||
return Err(format!(
|
||||
@@ -377,7 +377,7 @@ impl<'l> BlockBuilder<'l> {
|
||||
if self.has_termination() {
|
||||
return Err(format!("Block #{} has already terminated", self.block.id).into());
|
||||
}
|
||||
let instruction = &*self.block.func.ctx.alloc.alloc(Instruction {
|
||||
let instruction = &*self.block.func.ctx().alloc.alloc(Instruction {
|
||||
id: Id(UnsafeCell::new(u32::MAX)),
|
||||
parent_block: self.block,
|
||||
variant,
|
||||
@@ -420,7 +420,7 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
}
|
||||
|
||||
pub fn create_block(&mut self) -> &'l Block<'l> {
|
||||
let block = &*self.func.ctx.alloc.alloc(Block {
|
||||
let block = &*self.func.ctx().alloc.alloc(Block {
|
||||
id: self.blocks.len() as u32,
|
||||
func: self.func,
|
||||
instructions: OnceLock::new(),
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
use crate::{
|
||||
context::Ctx,
|
||||
assembly::{Assembly, Ctx},
|
||||
functions::ir::{Block, FunctionBodyBuilder},
|
||||
types::derivations::FuncT,
|
||||
};
|
||||
use std::{fmt::Debug as FmtDebug, sync::OnceLock};
|
||||
use std::{
|
||||
fmt::{Debug as FmtDebug, Display},
|
||||
hash::Hash,
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
pub mod ir;
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct Function<'l> {
|
||||
pub ty: &'l FuncT<'l>,
|
||||
pub name: OnceLock<&'l str>,
|
||||
pub(crate) body: OnceLock<FunctionBody<'l>>,
|
||||
|
||||
pub(crate) ctx: Ctx<'l>,
|
||||
pub(crate) declaring_assembly: &'l Assembly<'l>,
|
||||
}
|
||||
|
||||
impl<'l> Function<'l> {
|
||||
pub fn ctx(&self) -> Ctx<'l> {
|
||||
self.ctx
|
||||
self.declaring_assembly.ctx()
|
||||
}
|
||||
|
||||
pub fn body(&self) -> Option<&FunctionBody<'l>> {
|
||||
@@ -40,6 +44,15 @@ impl PartialEq for Function<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Function<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.name.get() {
|
||||
Some(n) => write!(f, "{} @ {}", self.ty, n),
|
||||
None => Display::fmt(&self.ty, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtDebug for Function<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let body: &dyn FmtDebug = match self.body() {
|
||||
@@ -54,6 +67,12 @@ impl FmtDebug for Function<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Function<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::ptr::hash(self, state);
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct FunctionBody<'l> {
|
||||
pub blocks: Vec<&'l Block<'l>>,
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
pub mod context;
|
||||
pub mod assembly;
|
||||
pub mod functions;
|
||||
pub mod types;
|
||||
pub mod values;
|
||||
|
||||
@@ -122,7 +122,7 @@ impl Display for FuncT<'_> {
|
||||
write!(f, "{separator}{ty}")?;
|
||||
separator = ", ";
|
||||
}
|
||||
write!(f, ") -> {}", self.ret_t)?;
|
||||
write!(f, ") {}", self.ret_t)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{context::Ctx, types::Type};
|
||||
use crate::{assembly::Ctx, types::Type};
|
||||
use derive_more::{Debug, Display};
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, Display, PartialEq, Eq, Hash)]
|
||||
#[display("type")]
|
||||
@@ -68,7 +69,11 @@ impl<'l> Into<Type<'l>> for &'l ConstStrT<'l> {
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Display, PartialEq, Eq, Hash)]
|
||||
#[display("{}{}", if *signed { "i" } else { "u" }, precision)]
|
||||
#[display(
|
||||
"{}{}",
|
||||
if *signed { "i" } else { "u" },
|
||||
if *precision == u32::MAX { &"size" as &dyn Display } else { precision })
|
||||
]
|
||||
#[debug("{self}")]
|
||||
pub struct IntT<'l> {
|
||||
pub signed: bool,
|
||||
|
||||
@@ -2,7 +2,7 @@ pub mod derivations;
|
||||
pub mod intrinsics;
|
||||
|
||||
use crate::{
|
||||
context::Ctx,
|
||||
assembly::Ctx,
|
||||
types::{derivations::*, intrinsics::*},
|
||||
};
|
||||
use derive_more::{Debug, Display};
|
||||
|
||||
+39
-29
@@ -1,4 +1,8 @@
|
||||
use crate::{context::Ctx, functions::ir::Instruction, types::Type};
|
||||
use crate::{
|
||||
assembly::Context,
|
||||
functions::{Function, ir::Instruction},
|
||||
types::Type,
|
||||
};
|
||||
use bitflags::bitflags;
|
||||
use derive_more::{Debug, Display};
|
||||
use half::f16;
|
||||
@@ -12,6 +16,7 @@ bitflags! {
|
||||
const Const = 0b00000001_00000000;
|
||||
const ConstOnly = 0b00000011_00000000;
|
||||
const Type = 0b00000111_00000000;
|
||||
const Function = 0b00001011_00000000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,51 +55,51 @@ impl Hash for Float {
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Const<'l> {
|
||||
pub enum ConstData<'l> {
|
||||
#[display("()")]
|
||||
#[debug("()")]
|
||||
Void(Ctx<'l>),
|
||||
|
||||
Void,
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Bool(bool, Ctx<'l>),
|
||||
|
||||
Bool(bool),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Char(char, Ctx<'l>),
|
||||
|
||||
Char(char),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("\"{}\"", _0)]
|
||||
Str(&'l str, Ctx<'l>),
|
||||
|
||||
Str(&'l str),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Int(Int, Ctx<'l>),
|
||||
|
||||
Int(Int),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Float(Float, Ctx<'l>),
|
||||
Float(Float),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Function(&'l Function<'l>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[debug("{:?}", data)]
|
||||
#[display("{}", data)]
|
||||
pub struct Const<'l> {
|
||||
pub ctx: &'l Context<'l>,
|
||||
pub data: ConstData<'l>,
|
||||
}
|
||||
|
||||
impl<'l> Const<'l> {
|
||||
pub fn flags(&self) -> ValueFlags {
|
||||
match self {
|
||||
Const::Void(_) => ValueFlags::Const,
|
||||
Const::Char(_, _) => ValueFlags::Const,
|
||||
Const::Bool(_, _) => ValueFlags::Const,
|
||||
Const::Str(_, _) => ValueFlags::Const,
|
||||
Const::Int(_, _) => ValueFlags::Const,
|
||||
Const::Float(_, _) => ValueFlags::Const,
|
||||
}
|
||||
ValueFlags::Const
|
||||
}
|
||||
|
||||
pub fn ty(&self) -> Type<'l> {
|
||||
match self {
|
||||
Const::Void(ctx) => ctx.void_t(),
|
||||
Const::Char(_, ctx) => ctx.char_t(),
|
||||
Const::Bool(_, ctx) => ctx.bool_t(),
|
||||
Const::Str(_, ctx) => ctx.const_str_t(),
|
||||
Const::Int(v, ctx) => match v {
|
||||
let ctx = self.ctx;
|
||||
match self.data {
|
||||
ConstData::Void => ctx.void_t(),
|
||||
ConstData::Char(_) => ctx.char_t(),
|
||||
ConstData::Bool(_) => ctx.bool_t(),
|
||||
ConstData::Str(_) => ctx.const_str_t(),
|
||||
ConstData::Int(v) => match v {
|
||||
Int::I8(_) => ctx.i8_t(),
|
||||
Int::I16(_) => ctx.i16_t(),
|
||||
Int::I32(_) => ctx.i32_t(),
|
||||
@@ -106,11 +111,12 @@ impl<'l> Const<'l> {
|
||||
Int::U64(_) => ctx.u64_t(),
|
||||
Int::U128(_) => ctx.u128_t(),
|
||||
},
|
||||
Const::Float(v, ctx) => match v {
|
||||
ConstData::Float(v) => match v {
|
||||
Float::F16(_) => ctx.f16_t(),
|
||||
Float::F32(_) => ctx.f32_t(),
|
||||
Float::F64(_) => ctx.f64_t(),
|
||||
},
|
||||
ConstData::Function(v) => Type::Func(v.ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,12 +127,14 @@ impl<'l> Into<Value<'l>> for &'l Const<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Value<'l> {
|
||||
#[display("{}", _0)]
|
||||
Const(&'l Const<'l>),
|
||||
#[display("{}", _0)]
|
||||
Type(Type<'l>),
|
||||
#[display("<function>")]
|
||||
Func(&'l Function<'l>),
|
||||
#[display("%{}", _0.id())]
|
||||
Instruction(&'l Instruction<'l>),
|
||||
}
|
||||
@@ -136,6 +144,7 @@ impl<'l> Value<'l> {
|
||||
match self {
|
||||
Value::Const(c) => c.flags(),
|
||||
Value::Type(_) => ValueFlags::Type,
|
||||
Value::Func(_) => ValueFlags::Function,
|
||||
Value::Instruction(i) => i.value_flags(),
|
||||
}
|
||||
}
|
||||
@@ -144,6 +153,7 @@ impl<'l> Value<'l> {
|
||||
match self {
|
||||
Value::Const(v) => v.ty(),
|
||||
Value::Type(v) => v.ctx().type_t(),
|
||||
Value::Func(v) => Type::Func(v.ty),
|
||||
Value::Instruction(v) => v.value_ty(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "leaf_compiler"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
leaf_parser = { path = "../parser" }
|
||||
leaf_assembly = { path = "../assembly" }
|
||||
leaf_allocators = { path = "../allocators" }
|
||||
arcstr = "1.2.0"
|
||||
@@ -0,0 +1,52 @@
|
||||
use leaf_parser::{LineCol, ParseError};
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::SourceFile;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Kind {
|
||||
Unknown = 0x0000,
|
||||
|
||||
Parsing = 0x0100,
|
||||
|
||||
SymbolNotFound = 0x0200,
|
||||
UninitializedSymbol = 0x0201,
|
||||
NotAType = 0x0202,
|
||||
|
||||
FunctionCompilationFailed = 0x0301,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Location {
|
||||
None,
|
||||
Range {
|
||||
file: SourceFile,
|
||||
range: Range<usize>,
|
||||
},
|
||||
Position {
|
||||
file: SourceFile,
|
||||
position: LineCol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationError {
|
||||
pub kind: Kind,
|
||||
pub message: String,
|
||||
pub location: Location,
|
||||
pub cause: Option<Box<CompilationError>>,
|
||||
}
|
||||
|
||||
impl CompilationError {
|
||||
pub fn parsing(file: SourceFile, err: ParseError<LineCol>) -> Self {
|
||||
Self {
|
||||
kind: Kind::Parsing,
|
||||
message: err.to_string(),
|
||||
location: Location::Position {
|
||||
file,
|
||||
position: err.location,
|
||||
},
|
||||
cause: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
use crate::{error::CompilationError, scope::Scope};
|
||||
use arcstr::literal_substr;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use leaf_assembly::{
|
||||
assembly::{Assembly, AssemblyIdentifier, Context},
|
||||
values::Value,
|
||||
};
|
||||
use leaf_parser::SourceCode;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
mod error;
|
||||
mod scope;
|
||||
|
||||
pub type SourceFile = Arc<SourceCode>;
|
||||
|
||||
pub struct CompilationContext<'l> {
|
||||
ctx: &'l Context<'l>,
|
||||
alloc: &'l dyn SyncAllocator,
|
||||
}
|
||||
|
||||
impl<'l> CompilationContext<'l> {
|
||||
pub fn new(alloc: &'l dyn SyncAllocator) -> Self {
|
||||
Self {
|
||||
alloc,
|
||||
ctx: Context::new(alloc),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_assembly(&self, ident: &AssemblyIdentifier) -> Option<&'l Assembly<'l>> {
|
||||
self.ctx.get_assembly(ident)
|
||||
}
|
||||
|
||||
pub fn extend(
|
||||
&'l self,
|
||||
ident: AssemblyIdentifier,
|
||||
sources: &[Arc<SourceCode>],
|
||||
) -> Result<(), CompilationError> {
|
||||
let assembly = self.ctx.get_or_create_assembly(ident.clone());
|
||||
|
||||
let mut units = Vec::with_capacity(sources.len());
|
||||
for src in sources {
|
||||
match leaf_parser::parse(src) {
|
||||
Ok(unit) => units.push(unit),
|
||||
Err(err) => return Err(CompilationError::parsing(src.clone(), err)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut scopes: Vec<_> = sources
|
||||
.iter()
|
||||
.map(|src| {
|
||||
let mut scope = Scope::new(assembly, src.clone());
|
||||
scope.insert(literal_substr!("void"), Value::Type(self.ctx.void_t()));
|
||||
scope.insert(literal_substr!("i8"), Value::Type(self.ctx.i8_t()));
|
||||
scope.insert(literal_substr!("i16"), Value::Type(self.ctx.i16_t()));
|
||||
scope.insert(literal_substr!("i32"), Value::Type(self.ctx.i32_t()));
|
||||
scope.insert(literal_substr!("i64"), Value::Type(self.ctx.i64_t()));
|
||||
scope.insert(literal_substr!("i128"), Value::Type(self.ctx.i128_t()));
|
||||
scope.insert(literal_substr!("isize"), Value::Type(self.ctx.isize_t()));
|
||||
scope.insert(literal_substr!("u8"), Value::Type(self.ctx.u8_t()));
|
||||
scope.insert(literal_substr!("u16"), Value::Type(self.ctx.u16_t()));
|
||||
scope.insert(literal_substr!("u32"), Value::Type(self.ctx.u32_t()));
|
||||
scope.insert(literal_substr!("u64"), Value::Type(self.ctx.u64_t()));
|
||||
scope.insert(literal_substr!("u128"), Value::Type(self.ctx.u128_t()));
|
||||
scope.insert(literal_substr!("usize"), Value::Type(self.ctx.usize_t()));
|
||||
scope.insert(literal_substr!("f16"), Value::Type(self.ctx.f16_t()));
|
||||
scope.insert(literal_substr!("f32"), Value::Type(self.ctx.f32_t()));
|
||||
scope.insert(literal_substr!("f64"), Value::Type(self.ctx.f64_t()));
|
||||
scope.insert(literal_substr!("type"), Value::Type(self.ctx.type_t()));
|
||||
scope
|
||||
})
|
||||
.collect();
|
||||
|
||||
for i in 0..sources.len() {
|
||||
let unit = &units[i];
|
||||
let scope = &mut scopes[i];
|
||||
scope.declare_constants(&unit.decls);
|
||||
}
|
||||
|
||||
for i in 0..sources.len() {
|
||||
let unit = &units[i];
|
||||
let scope = &mut scopes[i];
|
||||
scope.define_constants(&unit.decls)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use arcstr::ArcStr;
|
||||
use leaf_allocators::SyncArenaAllocator;
|
||||
use leaf_assembly::assembly::{AssemblyIdentifier, Version};
|
||||
use leaf_compiler::CompilationContext;
|
||||
use leaf_parser::SourceCode;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
fn main() {
|
||||
let alloc = SyncArenaAllocator::default();
|
||||
let context = CompilationContext::new(&alloc);
|
||||
let ident = AssemblyIdentifier {
|
||||
version: Version::default(),
|
||||
name: std::borrow::Cow::Borrowed("leaf_test"),
|
||||
};
|
||||
if let Err(err) = context.extend(
|
||||
ident.clone(),
|
||||
&[Arc::new(SourceCode {
|
||||
text: ArcStr::from(std::fs::read_to_string("../test.leaf").unwrap()),
|
||||
file: PathBuf::from("../test.leaf"),
|
||||
})],
|
||||
) {
|
||||
println!("{}", err.message);
|
||||
} else {
|
||||
println!("{:#?}", context.get_assembly(&ident));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
use arcstr::Substr;
|
||||
use leaf_assembly::{
|
||||
assembly::Assembly,
|
||||
types::{Type, derivations::MakeTypeDerivations},
|
||||
values::Value,
|
||||
};
|
||||
use leaf_parser::{
|
||||
SourceCode,
|
||||
ast::{self, ConstDecl, Expr, Ident},
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scope<'l> {
|
||||
assembly: &'l Assembly<'l>,
|
||||
source: Arc<SourceCode>,
|
||||
values: HashMap<Substr, Option<Value<'l>>>,
|
||||
}
|
||||
|
||||
impl<'l> Scope<'l> {
|
||||
pub fn new(assembly: &'l Assembly<'l>, source: Arc<SourceCode>) -> Self {
|
||||
Self {
|
||||
assembly,
|
||||
source,
|
||||
values: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: Substr, value: Value<'l>) {
|
||||
self.values.insert(name, Some(value));
|
||||
}
|
||||
|
||||
pub fn declare_constants(&mut self, decl: &[ConstDecl]) {
|
||||
for val in decl {
|
||||
for Ident(name) in val.names.as_slice() {
|
||||
self.values.insert(name.clone(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_constants(&mut self, decl: &[ConstDecl]) -> Result<(), CompilationError> {
|
||||
for val in decl {
|
||||
let expr = self.compile_expression(&val.value)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile_expression(&self, expr: &Expr) -> Result<Value<'l>, CompilationError> {
|
||||
match expr {
|
||||
Expr::Ident(Ident(name)) => match self.values.get(name) {
|
||||
None => Err(CompilationError {
|
||||
kind: Kind::SymbolNotFound,
|
||||
message: format!("Symbol `{name}` does not exist in the current scope."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: name.range(),
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(None) => Err(CompilationError {
|
||||
kind: Kind::UninitializedSymbol,
|
||||
message: format!("Symbol `{name}` is not initialized at this time."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: name.range(),
|
||||
},
|
||||
cause: None,
|
||||
}),
|
||||
Some(Some(value)) => Ok(*value),
|
||||
},
|
||||
Expr::Func(func) => self.compile_function(func).map_err(|err| CompilationError {
|
||||
kind: Kind::FunctionCompilationFailed,
|
||||
message: format!("Could not compile function."),
|
||||
location: Location::Range {
|
||||
file: self.source.clone(),
|
||||
range: func.text.range(),
|
||||
},
|
||||
cause: Some(Box::new(err)),
|
||||
}),
|
||||
_ => todo!("{expr:#?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_function(&self, func: &ast::Function) -> Result<Value<'l>, CompilationError> {
|
||||
let ret_ty = self.assert_type(self.compile_expression(&func.ret)?)?;
|
||||
let mut par_ty = Vec::with_capacity(func.args.len());
|
||||
for arg in &func.args {
|
||||
let ty = self.assert_type(self.compile_expression(&arg.r#type)?)?;
|
||||
par_ty.push(ty);
|
||||
}
|
||||
let fn_ty = ret_ty.make_fn(par_ty);
|
||||
Ok(Value::Func(self.assembly.create_function(fn_ty)))
|
||||
}
|
||||
|
||||
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> {
|
||||
match val {
|
||||
Value::Type(ty) => Ok(ty),
|
||||
_ => Err(CompilationError {
|
||||
kind: Kind::NotAType,
|
||||
message: format!("Value is not a type."),
|
||||
location: Location::None,
|
||||
cause: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use leaf_assembly::{
|
||||
ir::{Cmp, Instruction, InstructionVariant},
|
||||
},
|
||||
types::{Type, intrinsics::IntT},
|
||||
values::{Const, Int, Value},
|
||||
values::{Const, ConstData, Int, Value},
|
||||
};
|
||||
use scc::HashMap;
|
||||
use std::{alloc::Layout, fmt::Debug, ops::Range, sync::Arc};
|
||||
@@ -112,7 +112,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
..
|
||||
},
|
||||
),
|
||||
Value::Const(Const::Int(Int::U8(v), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U8(v)),
|
||||
ctx,
|
||||
}),
|
||||
) => {
|
||||
assert_eq!(ctx.u8_t(), *ty);
|
||||
opcodes.push(OpCode::Store_CL_U8(*v, memory_ranges[&t.id()].start));
|
||||
@@ -125,7 +128,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
..
|
||||
},
|
||||
),
|
||||
Value::Const(Const::Int(Int::U16(v), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U16(v)),
|
||||
ctx,
|
||||
}),
|
||||
) => {
|
||||
assert_eq!(ctx.u16_t(), *ty);
|
||||
opcodes.push(OpCode::Store_CL_U16(*v, memory_ranges[&t.id()].start));
|
||||
@@ -138,7 +144,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
..
|
||||
},
|
||||
),
|
||||
Value::Const(Const::Int(Int::U32(v), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U32(v)),
|
||||
ctx,
|
||||
}),
|
||||
) => {
|
||||
assert_eq!(ctx.u32_t(), *ty);
|
||||
opcodes.push(OpCode::Store_CL_U32(*v, memory_ranges[&t.id()].start));
|
||||
@@ -151,7 +160,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
..
|
||||
},
|
||||
),
|
||||
Value::Const(Const::Int(Int::U64(v), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U64(v)),
|
||||
ctx,
|
||||
}),
|
||||
) => {
|
||||
assert_eq!(ctx.u64_t(), *ty);
|
||||
opcodes.push(OpCode::Store_CL_U64(*v, memory_ranges[&t.id()].start));
|
||||
@@ -200,7 +212,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
|
||||
InstructionVariant::IAdd(
|
||||
Value::Instruction(a),
|
||||
Value::Const(Const::Int(Int::U32(b), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U32(b)),
|
||||
ctx,
|
||||
}),
|
||||
) => {
|
||||
assert!(matches!(
|
||||
a.value_ty(),
|
||||
@@ -217,7 +232,10 @@ impl<'l> InstructionCacheEntry<'l> {
|
||||
|
||||
InstructionVariant::ICmp(
|
||||
Value::Instruction(a),
|
||||
Value::Const(Const::Int(Int::U32(b), ctx)),
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U32(b)),
|
||||
ctx,
|
||||
}),
|
||||
cmp,
|
||||
) => {
|
||||
assert!(matches!(
|
||||
|
||||
@@ -4,10 +4,10 @@ use crate::{
|
||||
};
|
||||
use fxhash::FxHashMap;
|
||||
use leaf_assembly::{
|
||||
context::Ctx,
|
||||
assembly::Ctx,
|
||||
functions::Function,
|
||||
types::{Type, intrinsics::IntT},
|
||||
values::{Const, Int, Value},
|
||||
values::{Const, ConstData, Int, Value},
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
@@ -211,7 +211,10 @@ impl<'l> Interpreter<'l> {
|
||||
fn push_ctx_val(&mut self, sp: &mut usize, value: &Value) -> Range<usize> {
|
||||
let ptr = &self.stack[*sp] as *const u8;
|
||||
match value {
|
||||
Value::Const(Const::Int(Int::U32(v), _)) => {
|
||||
Value::Const(Const {
|
||||
data: ConstData::Int(Int::U32(v)),
|
||||
..
|
||||
}) => {
|
||||
*sp += ptr.align_offset(align_of::<u32>());
|
||||
let range = *sp..*sp + size_of::<u32>();
|
||||
self.stack[range.clone()].copy_from_slice(&v.to_ne_bytes());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use leaf_allocators::SyncArenaAllocator;
|
||||
use leaf_assembly::context::{Context, CreateConst};
|
||||
use leaf_assembly::assembly::{Assembly, AssemblyIdentifier, Context, CreateConst, Version};
|
||||
use leaf_assembly::functions::ir::Cmp;
|
||||
use leaf_assembly::types::derivations::MakeTypeDerivations;
|
||||
use leaf_interpreter::interpreter::{AnyValue, Error, Interpreter, NativeFunction};
|
||||
@@ -9,17 +9,21 @@ use std::time::{Duration, Instant};
|
||||
fn main() {
|
||||
let allocator = SyncArenaAllocator::default();
|
||||
let context = Context::new(&allocator);
|
||||
let assembly = context.get_or_create_assembly(AssemblyIdentifier {
|
||||
version: Version::default(),
|
||||
name: "test".into(),
|
||||
});
|
||||
|
||||
let puts = context.create_function(
|
||||
let puts = assembly.create_function(
|
||||
context
|
||||
.void_t()
|
||||
.make_fn([context.u8_t().make_ptr(false).into()]),
|
||||
);
|
||||
|
||||
let print_u32 = context.create_function(context.void_t().make_fn([context.u32_t().into()]));
|
||||
let print_u32 = assembly.create_function(context.void_t().make_fn([context.u32_t().into()]));
|
||||
|
||||
let random_func = {
|
||||
let func = context.create_function(context.u32_t().make_fn([]));
|
||||
let func = assembly.create_function(context.u32_t().make_fn([]));
|
||||
let mut builder = func.create_body().unwrap();
|
||||
|
||||
let loop_check = builder.create_block();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "leaf_parser"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
arcstr = "1.2.0"
|
||||
derive_more = { version = "2.1.0", features = ["deref", "debug", "display"] }
|
||||
peg = "0.8.5"
|
||||
@@ -0,0 +1,140 @@
|
||||
use arcstr::Substr;
|
||||
use derive_more::Deref;
|
||||
|
||||
#[derive(Debug, Deref)]
|
||||
pub struct Ident(pub Substr);
|
||||
|
||||
#[derive(Debug, Deref)]
|
||||
pub struct Import(pub Expr);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Number {
|
||||
pub text: Substr,
|
||||
pub r#type: Option<Ident>,
|
||||
}
|
||||
|
||||
#[derive(derive_more::Debug)]
|
||||
pub enum Expr {
|
||||
#[debug("uninit")]
|
||||
Uninit(Substr),
|
||||
#[debug("Ident({:?})", _0.0)]
|
||||
Ident(Ident),
|
||||
#[debug("{_0:?}")]
|
||||
Number(Number),
|
||||
String(Substr),
|
||||
#[debug("{_0:?}")]
|
||||
Binary(Box<BinaryExpr>),
|
||||
Index(Box<IndexingExpr>),
|
||||
Tuple(Vec<Expr>),
|
||||
List(Vec<Expr>),
|
||||
Struct(Box<StructCtor>),
|
||||
#[debug("{_0:?}")]
|
||||
Block(Block),
|
||||
#[debug("{_0:?}")]
|
||||
Func(Box<Function>),
|
||||
|
||||
#[debug("{_0:?}")]
|
||||
ConstDecl(Box<ConstDecl>),
|
||||
#[debug("{_0:?}")]
|
||||
VarDecl(Box<VarDecl>),
|
||||
#[debug("{_0:?}")]
|
||||
For(Box<For>),
|
||||
|
||||
Call {
|
||||
func: Box<Expr>,
|
||||
args: Vec<Expr>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryExpr {
|
||||
pub lhs: Expr,
|
||||
pub op: BinaryOp,
|
||||
pub rhs: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IndexingExpr {
|
||||
pub value: Expr,
|
||||
pub index: Expr,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(derive_more::Debug)]
|
||||
pub enum BinaryOp {
|
||||
#[debug("{_0:?}")] Add(Substr),
|
||||
#[debug("{_0:?}")] Sub(Substr),
|
||||
#[debug("{_0:?}")] Mul(Substr),
|
||||
#[debug("{_0:?}")] Div(Substr),
|
||||
#[debug("{_0:?}")] Mod(Substr),
|
||||
#[debug("{_0:?}")] Dot(Substr),
|
||||
#[debug("{_0:?}")] Range(Substr),
|
||||
#[debug("{_0:?}")] Assign(Substr),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConstDecl {
|
||||
pub names: NamePattern,
|
||||
pub r#type: Option<Expr>,
|
||||
pub value: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VarDecl {
|
||||
pub names: NamePattern,
|
||||
pub r#type: Option<Expr>,
|
||||
pub value: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NamePattern {
|
||||
Single(Ident),
|
||||
Tuple(Vec<Ident>),
|
||||
List(Vec<Ident>),
|
||||
}
|
||||
|
||||
impl NamePattern {
|
||||
pub fn as_slice(&self) -> &[Ident] {
|
||||
match self {
|
||||
NamePattern::Single(ident) => std::slice::from_ref(ident),
|
||||
NamePattern::Tuple(idents) => idents.as_slice(),
|
||||
NamePattern::List(idents) => idents.as_slice(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Function {
|
||||
pub text: Substr,
|
||||
pub args: Vec<NameValuePair>,
|
||||
pub ret: Expr,
|
||||
pub block: Option<Block>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NameValuePair {
|
||||
pub name: Ident,
|
||||
pub r#type: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StructCtor {
|
||||
pub r#type: Expr,
|
||||
pub r#values: Vec<NameValuePair>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Block(pub Vec<Expr>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct For {
|
||||
pub names: NamePattern,
|
||||
pub value: Expr,
|
||||
pub block: Block,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationUnit {
|
||||
pub imports: Vec<Import>,
|
||||
pub decls: Vec<ConstDecl>,
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use arcstr::ArcStr;
|
||||
pub use parser::{compilation_unit as parse, *};
|
||||
use std::{fmt::Debug, path::PathBuf};
|
||||
|
||||
pub mod ast;
|
||||
mod parser;
|
||||
|
||||
pub struct SourceCode {
|
||||
pub text: ArcStr,
|
||||
pub file: PathBuf,
|
||||
}
|
||||
|
||||
impl Debug for SourceCode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SourceCode")
|
||||
.field("text", &self.text)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
use arcstr::ArcStr;
|
||||
use leaf_parser::SourceCode;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let source = SourceCode {
|
||||
text: ArcStr::from(std::fs::read_to_string("../test.leaf").unwrap()),
|
||||
file: PathBuf::from("../test.leaf"),
|
||||
};
|
||||
let unit = leaf_parser::parse(&source);
|
||||
let _ = dbg!(unit);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
use crate::SourceCode;
|
||||
use crate::ast::*;
|
||||
use arcstr::Substr;
|
||||
use peg::{Parse, ParseElem, ParseLiteral, ParseSlice};
|
||||
pub use peg::{error::*, str::LineCol};
|
||||
|
||||
impl Parse for SourceCode {
|
||||
type PositionRepr = LineCol;
|
||||
|
||||
#[inline]
|
||||
fn start<'input>(&'input self) -> usize {
|
||||
self.text.as_str().start()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_eof<'input>(&'input self, p: usize) -> bool {
|
||||
self.text.as_str().is_eof(p)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn position_repr<'input>(&'input self, p: usize) -> Self::PositionRepr {
|
||||
self.text.as_str().position_repr(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input> ParseElem<'input> for SourceCode {
|
||||
type Element = char;
|
||||
|
||||
#[inline]
|
||||
fn parse_elem(&'input self, pos: usize) -> peg::RuleResult<Self::Element> {
|
||||
self.text.as_str().parse_elem(pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseLiteral for SourceCode {
|
||||
#[inline]
|
||||
fn parse_string_literal(&self, pos: usize, literal: &str) -> peg::RuleResult<()> {
|
||||
self.text.as_str().parse_string_literal(pos, literal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input> ParseSlice<'input> for SourceCode {
|
||||
type Slice = Substr;
|
||||
|
||||
#[inline]
|
||||
fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice {
|
||||
self.text.substr(p1..p2)
|
||||
}
|
||||
}
|
||||
|
||||
peg::parser! {
|
||||
grammar leaf_parser() for SourceCode {
|
||||
// #### ATOMS ####
|
||||
rule number() -> Number
|
||||
= text:$(['0'..='9']+) r#type:ident()? { Number { text, r#type } }
|
||||
/ "0x" text:$(['0'..='9'|'a'..='f'|'A'..'F']+) r#type:ident()? { Number { text, r#type } }
|
||||
/ "0b" text:$(['0'|'1']+) r#type:ident()? { Number { text, r#type } }
|
||||
|
||||
rule ident() -> Ident
|
||||
= text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) }
|
||||
|
||||
rule string() -> Substr
|
||||
= str:$("\"" char()* "\"") { str }
|
||||
|
||||
rule char() -> char = normal()
|
||||
|
||||
rule normal() -> char = [^'\\'|'"']
|
||||
|
||||
// ### EXPRESSIONS ####
|
||||
|
||||
rule expr() -> Expr = precedence! {
|
||||
lhs:(@) __ op:$("=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
|
||||
lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) }
|
||||
lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Box::new(lhs), args } }
|
||||
value:(@) "[" __ index:expr() __ "]" { Expr::Index(Box::new(IndexingExpr { value, index })) }
|
||||
r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Box::new(StructCtor { r#type, values })) }
|
||||
--
|
||||
lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) }
|
||||
lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) }
|
||||
--
|
||||
lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) }
|
||||
lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) }
|
||||
lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) }
|
||||
--
|
||||
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
|
||||
--
|
||||
block:block() { Expr::Block(block)}
|
||||
for_loop:for_loop() { Expr::For(Box::new(for_loop))}
|
||||
func:func() { Expr::Func(Box::new(func))}
|
||||
var_decl:var_decl() { Expr::VarDecl(Box::new(var_decl)) }
|
||||
const_decl:const_decl() { Expr::ConstDecl(Box::new(const_decl)) }
|
||||
"(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) }
|
||||
"[" __ list:(expr() **<0,> ("," __)) __ "]" { Expr::List(list) }
|
||||
"(" __ v:expr() __ ")" { v }
|
||||
v:string() { Expr::String(v) }
|
||||
v:number() { Expr::Number(v) }
|
||||
v:ident() { Expr::Ident(v) }
|
||||
}
|
||||
|
||||
rule block() -> Block
|
||||
= "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) }
|
||||
|
||||
rule func() -> Function
|
||||
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:expr() __ block:block()? e:position!()
|
||||
{ Function { args, ret, block, text: t.parent().substr(s..e), } }
|
||||
|
||||
rule name_value_pair() -> NameValuePair
|
||||
= name:ident() __ ":" __ r#type:expr() { NameValuePair { name, r#type } }
|
||||
|
||||
rule name_value_pairs() -> Vec<NameValuePair>
|
||||
= v:(name_value_pair() ** ("," __)) { v }
|
||||
|
||||
rule import() -> Import
|
||||
= "import" _ expr:expr() { Import(expr) }
|
||||
|
||||
rule name_pattern() -> NamePattern
|
||||
= "(" __ tuple:(ident() ** ("," __)) __ ")" { NamePattern::Tuple(tuple) }
|
||||
/ "[" __ slice:(ident() ** ("," __)) __ "]" { NamePattern::List(slice) }
|
||||
/ ident:ident() { NamePattern::Single(ident) }
|
||||
|
||||
rule const_decl() -> ConstDecl =
|
||||
names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? ":" _ value:expr()
|
||||
{ ConstDecl { names, r#type, value } }
|
||||
|
||||
rule var_decl() -> VarDecl =
|
||||
names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? "=" _ value:expr()
|
||||
{ VarDecl { names, r#type, value } }
|
||||
|
||||
rule for_loop() -> For =
|
||||
"for" _ names:name_pattern() _ "in" _ value:expr() _ block:block()
|
||||
{ For { names, value, block } }
|
||||
|
||||
pub rule compilation_unit() -> CompilationUnit =
|
||||
__ imports:(i:import() statement_separator() {i})*
|
||||
__ decls:(d:const_decl() statement_separator() {d})*
|
||||
__
|
||||
{ CompilationUnit { imports, decls } }
|
||||
|
||||
// #### MISC ####
|
||||
rule _ = quiet! { [' '|'\t']+ }
|
||||
rule __ = quiet! { [' '|'\t'|'\n']* }
|
||||
rule statement_separator() = quiet! { [';'|'\n'] __ }
|
||||
}
|
||||
}
|
||||
|
||||
pub use leaf_parser::compilation_unit;
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "leaf_parsing"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
arcstr = "1.2.0"
|
||||
chumsky = { version = "0.11.1", features = ["pratt"] }
|
||||
logos = "0.15.1"
|
||||
@@ -1,93 +0,0 @@
|
||||
use crate::tokenizer::Token;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct AstRoot {
|
||||
pub imports: Vec<Import>,
|
||||
pub decls: Vec<ConstDecl>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Ident {
|
||||
pub tok_ident: Token,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Import {
|
||||
pub tok_pub: Option<Token>,
|
||||
pub tok_import: Token,
|
||||
pub value: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Struct {
|
||||
pub tok_struct: Token,
|
||||
pub tok_open_curly: Token,
|
||||
pub fields: Vec<StructField>,
|
||||
pub tok_close_curly: Token,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct StructField {
|
||||
pub ident: Ident,
|
||||
pub tok_colon: Token,
|
||||
pub r#type: Value,
|
||||
}
|
||||
|
||||
pub enum Number {
|
||||
Integer { value: i128, token: Token },
|
||||
Decimal { value: f64, token: Token },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum Value {
|
||||
Ident(Ident),
|
||||
Struct(Struct),
|
||||
Statement(Statement),
|
||||
|
||||
BinaryOp {
|
||||
lhs: Box<Value>,
|
||||
tok_op: Token,
|
||||
rhs: Box<Value>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum Statement {
|
||||
While(While),
|
||||
Return(Return),
|
||||
ConstDecl(ConstDecl),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct ConstDecl {
|
||||
pub name: Ident,
|
||||
pub tok_colon_t: Token,
|
||||
pub r#type: Option<Box<Value>>,
|
||||
pub tok_colon_v: Token,
|
||||
pub value: Box<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct While {
|
||||
pub tok_while: Token,
|
||||
pub condition: Box<Value>,
|
||||
pub tok_open_curly: Token,
|
||||
pub statements: Vec<Statement>,
|
||||
pub tok_close_curly: Token,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub struct Return {
|
||||
pub tok_return: Token,
|
||||
pub value: Box<Value>,
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
use arcstr::Substr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub mod ast;
|
||||
pub mod parser;
|
||||
pub mod tokenizer;
|
||||
|
||||
pub struct SourceCode {
|
||||
pub text: Substr,
|
||||
pub file: PathBuf,
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use arcstr::literal_substr;
|
||||
use chumsky::{Parser, input::Stream};
|
||||
use leaf_parsing::{SourceCode, tokenizer::tokenize};
|
||||
|
||||
fn main() {
|
||||
let source = SourceCode {
|
||||
text: literal_substr!(
|
||||
"
|
||||
import leaf.intrinsics;
|
||||
import leaf.values;
|
||||
|
||||
Vector3 :: struct {
|
||||
x: 2,
|
||||
}
|
||||
"
|
||||
),
|
||||
file: PathBuf::from("test.leaf"),
|
||||
};
|
||||
let tokens = tokenize(&source).unwrap();
|
||||
let stream = Stream::from_iter(tokens.iter().cloned());
|
||||
let ast = leaf_parsing::parser::ast_root().parse(stream);
|
||||
println!("{ast:#?}")
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
use crate::{ast::*, tokenizer::*};
|
||||
use chumsky::{
|
||||
extra::Err,
|
||||
input::Stream,
|
||||
pratt::{infix, left},
|
||||
prelude::*,
|
||||
util::Maybe,
|
||||
};
|
||||
|
||||
pub type Tokens<T> = Stream<T>;
|
||||
|
||||
pub fn parse<'l>(tokens: Vec<Token>) -> ParseResult<AstRoot, Simple<'l, Token>> {
|
||||
let stream = Stream::from_iter(tokens);
|
||||
ast_root().parse(stream)
|
||||
}
|
||||
|
||||
macro_rules! make_parsers {
|
||||
(
|
||||
$(
|
||||
$vis:vis fn $name:ident() -> $type:ty {
|
||||
$($tt:tt)*
|
||||
}
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
$vis fn $name<'l, T: Iterator<Item = Token> + 'l>() -> impl Parser<'l, Tokens<T>, $type, Err<Simple<'l, Token>>> {
|
||||
$($tt)*
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
make_parsers! {
|
||||
pub fn ident() -> Ident {
|
||||
tok(TokenKind::Ident).map(|tok_ident| Ident { tok_ident })
|
||||
}
|
||||
|
||||
pub fn value() -> Value {
|
||||
let atom = choice((
|
||||
choice((
|
||||
ident().map(Value::Ident),
|
||||
type_struct().map(Value::Struct),
|
||||
)),
|
||||
statement_val(),
|
||||
));
|
||||
atom.pratt((
|
||||
infix(left(1), tok(TokenKind::Add), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
infix(left(1), tok(TokenKind::Sub), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
infix(left(2), tok(TokenKind::Mul), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
infix(left(2), tok(TokenKind::Div), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
infix(left(2), tok(TokenKind::Mod), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
infix(left(3), tok(TokenKind::Period), |lhs, tok_op, rhs, _| Value::BinaryOp { lhs: Box::new(lhs), tok_op, rhs: Box::new(rhs) }),
|
||||
)).boxed()
|
||||
}
|
||||
|
||||
pub fn type_struct() -> Struct {
|
||||
let struct_fld = ident()
|
||||
.then(tok(TokenKind::Colon))
|
||||
.then(value())
|
||||
.map(|((ident, tok_colon), r#type)| StructField { ident, tok_colon, r#type });
|
||||
|
||||
tok(TokenKind::Struct)
|
||||
.then(tok(TokenKind::OpenCurly))
|
||||
.then(struct_fld.separated_by(tok(TokenKind::Comma)).allow_trailing().collect())
|
||||
.then(tok(TokenKind::CloseCurly))
|
||||
.map(|(((tok_struct, tok_open_curly), fields), tok_close_curly)| {
|
||||
Struct { tok_struct, tok_open_curly, fields, tok_close_curly }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn statement() -> Statement {
|
||||
choice((
|
||||
const_decl().map(Statement::ConstDecl),
|
||||
statement_while().map(Statement::While),
|
||||
statement_return().map(Statement::Return),
|
||||
)).boxed()
|
||||
}
|
||||
|
||||
pub fn statement_val() -> Value {
|
||||
choice((
|
||||
statement_while().map(Statement::While),
|
||||
statement_return().map(Statement::Return),
|
||||
)).map(Value::Statement)
|
||||
}
|
||||
|
||||
pub fn statement_return() -> Return {
|
||||
tok(TokenKind::Return)
|
||||
.then(value())
|
||||
.map(|(tok_return, value)| Return { tok_return, value: Box::new(value) })
|
||||
}
|
||||
|
||||
pub fn statement_while() -> While {
|
||||
tok(TokenKind::While)
|
||||
.then(value())
|
||||
.then(tok(TokenKind::OpenCurly))
|
||||
.then(statement().repeated().collect())
|
||||
.then(tok(TokenKind::CloseCurly))
|
||||
.map(| ((((tok_while, condition), tok_open_curly), statements), tok_close_curly)| While {
|
||||
tok_while, condition: Box::new(condition), tok_open_curly, statements, tok_close_curly
|
||||
})
|
||||
}
|
||||
|
||||
pub fn const_decl() -> ConstDecl {
|
||||
ident()
|
||||
.then(tok(TokenKind::Colon))
|
||||
.then(value().or_not())
|
||||
.then(tok(TokenKind::Colon))
|
||||
.then(value())
|
||||
.map(|((((name, tok_colon_t), r#type), tok_colon_v), value)| ConstDecl {
|
||||
name,
|
||||
tok_colon_t,
|
||||
r#type: r#type.map(Box::new),
|
||||
tok_colon_v,
|
||||
value: Box::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn import() -> Import {
|
||||
tok(TokenKind::Pub).or_not()
|
||||
.then(tok(TokenKind::Import))
|
||||
.then(value())
|
||||
.map(|((tok_pub, tok_import), value)| Import { tok_pub, tok_import, value })
|
||||
}
|
||||
|
||||
pub fn ast_root() -> AstRoot {
|
||||
let imports = import().then_ignore(tok(TokenKind::Semicolon)).repeated().collect::<Vec<_>>();
|
||||
let decls = const_decl().repeated().collect::<Vec<_>>();
|
||||
imports.then(decls).map(|(imports, decls)| AstRoot { imports, decls })
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tok<'l, T: Iterator<Item = Token> + 'l>(
|
||||
k: TokenKind,
|
||||
) -> impl Parser<'l, Tokens<T>, Token, Err<Simple<'l, Token>>> {
|
||||
custom(move |inp| {
|
||||
let before = inp.cursor();
|
||||
match inp.next() {
|
||||
Some(token @ Token { kind, .. }) if kind == k => Ok(token),
|
||||
None => Err(Simple::new(None, inp.span_since(&before))),
|
||||
Some(token) => Err(Simple::new(
|
||||
Some(Maybe::Val(token)),
|
||||
inp.span_since(&before),
|
||||
)),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
use arcstr::Substr;
|
||||
use logos::{Logos, Source, source::Chunk};
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::SourceCode;
|
||||
|
||||
#[derive(Logos, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[logos(source = SourceCode)]
|
||||
pub enum TokenKind {
|
||||
#[regex(r"[ \t\n\f\r]+", logos::skip)]
|
||||
Whitespace,
|
||||
|
||||
#[token("fn")]
|
||||
Fn,
|
||||
#[token("enum")]
|
||||
Enum,
|
||||
#[token("union")]
|
||||
Union,
|
||||
#[token("struct")]
|
||||
Struct,
|
||||
#[token("interface")]
|
||||
Interface,
|
||||
|
||||
#[token("pub")]
|
||||
Pub,
|
||||
#[token("mut")]
|
||||
Mut,
|
||||
#[token("for")]
|
||||
For,
|
||||
#[token("while")]
|
||||
While,
|
||||
#[token("yield")]
|
||||
Yield,
|
||||
#[token("import")]
|
||||
Import,
|
||||
#[token("return")]
|
||||
Return,
|
||||
#[token("continue")]
|
||||
Continue,
|
||||
|
||||
#[token("+")]
|
||||
Add,
|
||||
#[token("-")]
|
||||
Sub,
|
||||
#[token("*")]
|
||||
Mul,
|
||||
#[token("/")]
|
||||
Div,
|
||||
#[token("%")]
|
||||
Mod,
|
||||
#[token(":")]
|
||||
Colon,
|
||||
#[token(",")]
|
||||
Comma,
|
||||
#[token(".")]
|
||||
Period,
|
||||
#[token(";")]
|
||||
Semicolon,
|
||||
|
||||
#[token("=")]
|
||||
Eq,
|
||||
#[token("==")]
|
||||
CmpEq,
|
||||
#[token("!=")]
|
||||
CmpNe,
|
||||
#[token("<")]
|
||||
CmpLt,
|
||||
#[token("<=")]
|
||||
CmpLe,
|
||||
#[token(">")]
|
||||
CmpGt,
|
||||
#[token(">=")]
|
||||
CmpGe,
|
||||
|
||||
#[token("(")]
|
||||
OpenRound,
|
||||
#[token("[")]
|
||||
OpenSquare,
|
||||
#[token("{")]
|
||||
OpenCurly,
|
||||
#[token(")")]
|
||||
CloseRound,
|
||||
#[token("]")]
|
||||
CloseSquare,
|
||||
#[token("}")]
|
||||
CloseCurly,
|
||||
|
||||
#[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
|
||||
Ident,
|
||||
#[regex(r"[0-9]+")]
|
||||
#[regex(r"[0-9]+\.[0-9]+")]
|
||||
Number,
|
||||
}
|
||||
|
||||
impl Source for SourceCode {
|
||||
type Slice<'a> = Substr;
|
||||
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
Source::len(self.text.as_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read<'a, Chunk>(&'a self, offset: usize) -> Option<Chunk>
|
||||
where
|
||||
Chunk: self::Chunk<'a>,
|
||||
{
|
||||
Source::read(self.text.as_str(), offset)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn read_byte_unchecked(&self, offset: usize) -> u8 {
|
||||
unsafe { Source::read_byte_unchecked(self.text.as_str(), offset) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice(&self, range: std::ops::Range<usize>) -> Option<Self::Slice<'_>> {
|
||||
_ = self.text.get(range.clone())?;
|
||||
Some(self.text.substr(range))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn slice_unchecked(&self, range: std::ops::Range<usize>) -> Self::Slice<'_> {
|
||||
self.text.substr(range)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_boundary(&self, index: usize) -> bool {
|
||||
Source::is_boundary(self.text.as_str(), index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Token {
|
||||
pub text: Substr,
|
||||
pub kind: TokenKind,
|
||||
}
|
||||
|
||||
impl PartialEq<TokenKind> for Token {
|
||||
#[inline]
|
||||
fn eq(&self, other: &TokenKind) -> bool {
|
||||
self.kind == *other
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokenize(source: &SourceCode) -> Result<Vec<Token>, Range<usize>> {
|
||||
let mut tokens = Vec::with_capacity(1024);
|
||||
let mut lexer = TokenKind::lexer(&source).spanned();
|
||||
while let Some((token, span)) = lexer.next() {
|
||||
match token {
|
||||
Ok(kind) => tokens.push(Token {
|
||||
kind,
|
||||
text: source.text.substr(span),
|
||||
}),
|
||||
Err(()) => {
|
||||
return Err(lexer.slice().range());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import leaf.reflection.comptime
|
||||
|
||||
add :: fn(a: u32, b: u32) u32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
Vector :: fn(T: type, count: usize) type {
|
||||
NAMES :: ["x", "y", "z", "w"]
|
||||
|
||||
ty := TypeBuilder.struct()
|
||||
for i in 0..count {
|
||||
ty.push(Field {
|
||||
name: NAMES[i],
|
||||
type: T,
|
||||
flags: FieldFlags.Public
|
||||
})
|
||||
}
|
||||
|
||||
ty.build()
|
||||
}
|
||||
Reference in New Issue
Block a user