1
0
This commit is contained in:
2024-11-11 05:24:56 +03:00
parent 322a8faec7
commit 0f31e7a52e
18 changed files with 1202 additions and 379 deletions

369
Cargo.lock generated
View File

@@ -38,7 +38,7 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@@ -57,6 +57,36 @@ version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.19"
@@ -103,28 +133,96 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "crossterm"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags 1.3.2",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "developing-compilers"
version = "0.1.0"
dependencies = [
"anyhow",
"byteorder",
"clap",
"inquire",
"itertools",
"thiserror",
]
[[package]]
name = "dyn-clone"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "inquire"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a"
dependencies = [
"bitflags 2.6.0",
"crossterm",
"dyn-clone",
"fuzzy-matcher",
"fxhash",
"newline-converter",
"once_cell",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
@@ -140,6 +238,78 @@ dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "newline-converter"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.6",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
@@ -158,6 +328,57 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [
"bitflags 2.6.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "strsim"
version = "0.11.1"
@@ -166,9 +387,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.86"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
@@ -177,43 +398,117 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.66"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede"
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.66"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5"
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
@@ -222,28 +517,46 @@ 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_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[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.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[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.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -256,24 +569,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[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.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[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.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[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.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"

View File

@@ -5,6 +5,8 @@
[dependencies]
anyhow = "1.0.89"
byteorder = "1.5.0"
clap = { version = "4.5.19", features = ["derive"] }
inquire = "0.7.5"
itertools = "0.13.0"
thiserror = "1.0.66"
thiserror = "2.0.3"

7
rustfmt.toml Normal file
View File

@@ -0,0 +1,7 @@
match_block_trailing_comma = true
newline_style = "Unix"
style_edition = "2024"
group_imports = "StdExternalCrate"
imports_granularity = "Module"
unstable_features = true

View File

@@ -7,10 +7,8 @@ use std::str::FromStr;
use typed::{Type, TypedExpr};
pub use untyped::UntypedExpr;
use crate::{
error::{self, SemanticError, SemanticErrorKind},
symbols::SymbolsTable,
};
use crate::error::{self, SemanticError, SemanticErrorKind};
use crate::symbols::SymbolsTable;
#[derive(Debug, Copy, Clone)]
pub struct Span {
@@ -43,6 +41,31 @@ impl BinOp {
}
}
impl From<&BinOp> for u8 {
fn from(value: &BinOp) -> Self {
match value {
BinOp::Add => 1,
BinOp::Sub => 2,
BinOp::Mul => 3,
BinOp::Div => 4,
}
}
}
impl TryFrom<u8> for BinOp {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(BinOp::Add),
2 => Ok(BinOp::Sub),
3 => Ok(BinOp::Mul),
4 => Ok(BinOp::Div),
b => Err(b),
}
}
}
impl fmt::Display for BinOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
@@ -92,7 +115,7 @@ fn optimize_expr(expr: TypedExpr) -> TypedExpr {
BinOp::Div => lhs / rhs,
},
}
}
},
(TypedExpr::Float { value: lhs, .. }, TypedExpr::Float { value: rhs, .. }) => {
TypedExpr::Float {
span,
@@ -103,42 +126,42 @@ fn optimize_expr(expr: TypedExpr) -> TypedExpr {
BinOp::Div => lhs / rhs,
},
}
}
},
(lhs, TypedExpr::Int { value: 0, .. })
| (TypedExpr::Float { value: 0.0, .. }, lhs)
if matches!(op, BinOp::Add | BinOp::Sub) =>
{
lhs
}
},
(lhs, TypedExpr::Int { value: 1, .. })
| (lhs, TypedExpr::Float { value: 1.0, .. })
if matches!(op, BinOp::Mul | BinOp::Div) =>
{
lhs
}
},
(TypedExpr::Int { value: 0, .. }, rhs)
| (TypedExpr::Float { value: 0.0, .. }, rhs)
if matches!(op, BinOp::Add) =>
{
rhs
}
},
(TypedExpr::Int { value: 1, .. }, rhs)
| (TypedExpr::Float { value: 1.0, .. }, rhs)
if matches!(op, BinOp::Mul) =>
{
rhs
}
},
(TypedExpr::Int { value: 0, .. }, _) | (_, TypedExpr::Int { value: 0, .. })
if matches!(op, BinOp::Mul) =>
{
TypedExpr::Int { span, value: 0 }
}
},
(TypedExpr::Float { value: 0.0, .. }, _)
| (_, TypedExpr::Float { value: 0.0, .. })
if matches!(op, BinOp::Mul) =>
{
TypedExpr::Float { span, value: 0.0 }
}
},
(lhs, rhs) => TypedExpr::BinOp {
span,
lhs: Box::new(lhs),
@@ -146,7 +169,7 @@ fn optimize_expr(expr: TypedExpr) -> TypedExpr {
rhs: Box::new(rhs),
},
}
}
},
TypedExpr::IntToFloat { value } => {
let value = optimize_expr(*value);
if let TypedExpr::Int { value, span } = value {
@@ -159,7 +182,7 @@ fn optimize_expr(expr: TypedExpr) -> TypedExpr {
value: Box::new(value),
}
}
}
},
expr => expr,
};
@@ -192,17 +215,17 @@ fn convert_to_typed_expr(
span,
SemanticErrorKind::DuplicateSymbol(symbol.name.clone()),
)
.into())
}
.into());
},
(None, Some(ty)) => {
symbol.ty = Some(ty);
}
_ => {}
},
_ => {},
}
}
TypedExpr::Var { span, name }
}
},
UntypedExpr::BinOp { span, lhs, op, rhs } => {
let rhs = *rhs;
let lhs = *lhs;
@@ -217,19 +240,19 @@ fn convert_to_typed_expr(
*span,
SemanticErrorKind::DivisionByZero,
)
.into())
}
.into());
},
UntypedExpr::Float { span, value } if *value == 0.0 => {
return Err(SemanticError::new(
*span,
SemanticErrorKind::DivisionByZero,
)
.into())
.into());
},
_ => {},
}
_ => {}
}
}
_ => {}
},
_ => {},
}
let lhs = convert_to_typed_expr(lhs, symbols)?;
@@ -241,7 +264,7 @@ fn convert_to_typed_expr(
op,
rhs: Box::new(rhs),
}
}
},
};
Ok(expr)
@@ -259,7 +282,7 @@ fn coerce_types(expr: TypedExpr, symbols: &mut SymbolsTable) -> error::Result<Ty
}
expr
}
},
TypedExpr::BinOp { lhs, rhs, op, span } => {
let lhs = coerce_types(*lhs, symbols)?;
let rhs = coerce_types(*rhs, symbols)?;
@@ -270,11 +293,11 @@ fn coerce_types(expr: TypedExpr, symbols: &mut SymbolsTable) -> error::Result<Ty
(Type::Int, Type::Float) => {
let lhs = TypedExpr::cast_to_float(lhs);
(lhs, rhs)
}
},
(Type::Float, Type::Int) => {
let rhs = TypedExpr::cast_to_float(rhs);
(lhs, rhs)
}
},
};
TypedExpr::BinOp {
@@ -283,7 +306,7 @@ fn coerce_types(expr: TypedExpr, symbols: &mut SymbolsTable) -> error::Result<Ty
op,
rhs: Box::new(rhs),
}
}
},
TypedExpr::IntToFloat { .. } => expr,
};

View File

@@ -1,11 +1,9 @@
use std::{fmt, str::FromStr};
use crate::{
error::SemanticErrorKind,
symbols::{Symbol, SymbolsTable},
};
use std::fmt;
use std::str::FromStr;
use super::{BinOp, Span};
use crate::error::SemanticErrorKind;
use crate::symbols::{Symbol, SymbolsTable};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Type {
@@ -13,6 +11,27 @@ pub enum Type {
Float,
}
impl From<Type> for u8 {
fn from(value: Type) -> Self {
match value {
Type::Int => 1,
Type::Float => 2,
}
}
}
impl TryFrom<u8> for Type {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Type::Int),
2 => Ok(Type::Float),
b => Err(b),
}
}
}
impl FromStr for Type {
type Err = SemanticErrorKind;

View File

@@ -1,6 +1,5 @@
use crate::symbols::Symbol;
use super::{BinOp, Span};
use crate::symbols::Symbol;
#[derive(Debug)]
pub enum UntypedExpr {

View File

@@ -1,4 +1,5 @@
use std::{ops::Deref, path::PathBuf};
use std::ops::Deref;
use std::path::PathBuf;
use clap::{CommandFactory, Parser, Subcommand};
@@ -35,6 +36,15 @@ pub enum Command {
output: PathBuf,
output_symbols: PathBuf,
},
Com {
#[clap(short, long, default_value_t = false)]
optimize: bool,
input: PathBuf,
output: PathBuf,
},
Int {
input: PathBuf,
},
}
#[derive(Copy, Clone, PartialEq, Eq, clap::ValueEnum)]
@@ -52,7 +62,7 @@ impl Args {
Err(err) => {
let mut command = ArgsInner::command();
err.format(&mut command).exit();
}
},
};
Self { inner }
@@ -82,6 +92,8 @@ fn validate_inner(args: ArgsInner) -> Result<ArgsInner, clap::Error> {
output_symbols,
..
} => validate_gen(input, output, output_symbols)?,
Command::Com { input, output, .. } => validate_com(input, output)?,
Command::Int { input } => validate_int(input)?,
};
Ok(args)
@@ -180,3 +192,32 @@ fn validate_gen(
Ok(())
}
fn validate_com(input: &PathBuf, output: &PathBuf) -> Result<(), clap::Error> {
if !input.is_file() {
return Err(clap::Error::raw(
clap::error::ErrorKind::InvalidValue,
format!("Input file '{}' does not exist", input.display()),
));
}
if input == output {
return Err(clap::Error::raw(
clap::error::ErrorKind::InvalidValue,
"Input and output files cannot be the same",
));
};
Ok(())
}
fn validate_int(input: &PathBuf) -> Result<(), clap::Error> {
if !input.is_file() {
return Err(clap::Error::raw(
clap::error::ErrorKind::InvalidValue,
format!("Input file '{}' does not exist", input.display()),
));
}
Ok(())
}

6
src/lib.rs Normal file
View File

@@ -0,0 +1,6 @@
pub mod ast;
pub mod error;
pub mod parse;
pub mod representation;
pub mod symbols;
pub mod util;

View File

@@ -1,45 +1,252 @@
mod ast;
mod cli;
mod error;
mod parse;
mod representation;
mod symbols;
mod util;
use std::collections::HashMap;
use std::io::{self, Write};
use std::path::Path;
use std::{fmt, fs};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use cli::GenMode;
use developing_compilers::ast::BinOp;
use developing_compilers::ast::typed::Type;
use developing_compilers::representation::intermediate::{IntermediateExpr, IntermediateValue};
use developing_compilers::symbols::Symbol;
use developing_compilers::*;
use inquire::CustomType;
use parse::parser::Parser;
use std::{
io::{self, Write},
path::Path,
};
use symbols::SymbolsTable;
fn main() -> anyhow::Result<()> {
let args = cli::Args::parse();
match &args.command {
let result = match &args.command {
cli::Command::Lex {
input,
output_tokens,
output_symbols,
} => {
lex_command(input, output_tokens, output_symbols)?;
}
cli::Command::Syn { input, output_tree } => {
syn_command(input, output_tree)?;
}
cli::Command::Sem { input, output_tree } => {
sem_command(input, output_tree)?;
}
} => lex_command(input, output_tokens, output_symbols),
cli::Command::Syn { input, output_tree } => syn_command(input, output_tree),
cli::Command::Sem { input, output_tree } => sem_command(input, output_tree),
cli::Command::Gen {
mode,
optimize,
input,
output,
output_symbols,
} => {
gen_command(mode, *optimize, input, output, output_symbols)?;
} => gen_command(mode, *optimize, input, output, output_symbols),
cli::Command::Com {
optimize,
input,
output,
} => com_command(*optimize, input, output),
cli::Command::Int { input } => int_command(input),
};
if let Err(e) = result {
eprintln!("error: {}", e);
return Ok(());
}
Ok(())
}
fn int_command(input: &Path) -> Result<(), anyhow::Error> {
enum VarValue {
Int(i64),
Float(f64),
}
impl fmt::Display for VarValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VarValue::Int(v) => write!(f, "{}", v),
VarValue::Float(v) => {
if v == &v.trunc() {
write!(f, "{}.0", v)
} else {
write!(f, "{}", v)
}
},
}
}
}
fn value_as_i64(value: &IntermediateValue, vars: &HashMap<Symbol, VarValue>) -> i64 {
match value {
IntermediateValue::Int { value } => *value,
IntermediateValue::Var { name } => match vars.get(name) {
Some(VarValue::Int(v)) => *v,
_ => unreachable!(),
},
_ => unreachable!(),
}
}
fn value_as_f64(value: &IntermediateValue, vars: &HashMap<Symbol, VarValue>) -> f64 {
match value {
IntermediateValue::Float { value } => *value,
IntermediateValue::Var { name } => match vars.get(name) {
Some(VarValue::Float(v)) => *v,
_ => unreachable!(),
},
_ => unreachable!(),
}
}
let (symbols, ir) = {
let mut reader = io::BufReader::new(fs::File::open(input)?);
let symbols = SymbolsTable::from_reader(&mut reader)?;
let n = reader.read_u64::<BigEndian>()?;
let mut ir = Vec::with_capacity(n as usize);
for _ in 0..n {
ir.push(IntermediateExpr::from_reader(&mut reader)?);
}
(symbols, ir)
};
let mut vars = HashMap::new();
for (_, data) in &symbols {
let value = match data.ty {
Some(Type::Int) if !data.temporary => VarValue::Int(
CustomType::new(&format!("Input int {}", data.name))
.with_default(0)
.prompt()?,
),
Some(Type::Float) if !data.temporary => VarValue::Float(
CustomType::new(&format!("Input float {}", data.name))
.with_default(0.0)
.prompt()?,
),
Some(Type::Int) => VarValue::Int(0),
Some(Type::Float) => VarValue::Float(0.0),
None => continue,
};
vars.insert(data.id, value);
}
let mut last_result = None;
for expr in ir {
match expr {
IntermediateExpr::IntToFloat { result, value } => {
let value = value_as_i64(&value, &vars) as f64;
match vars.get_mut(&result) {
Some(VarValue::Float(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} if symbols.type_of(&result) == Some(Type::Int) => {
let lhs = value_as_i64(&lhs, &vars);
let rhs = value_as_i64(&rhs, &vars);
let value = match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
};
match vars.get_mut(&result) {
Some(VarValue::Int(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} if symbols.type_of(&result) == Some(Type::Float) => {
let lhs = value_as_f64(&lhs, &vars);
let rhs = value_as_f64(&rhs, &vars);
let value = match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
};
match vars.get_mut(&result) {
Some(VarValue::Float(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::Identity { result, value }
if symbols.type_of(&result) == Some(Type::Float) =>
{
let value = value_as_f64(&value, &vars);
match vars.get_mut(&result) {
Some(VarValue::Float(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
IntermediateExpr::Identity { result, value }
if symbols.type_of(&result) == Some(Type::Int) =>
{
let value = value_as_i64(&value, &vars);
match vars.get_mut(&result) {
Some(VarValue::Int(v)) => *v = value,
_ => unreachable!(),
};
last_result = Some(result);
},
_ => unreachable!(),
}
}
if let Some(result) = last_result {
println!("Result: {}", vars.get(&result).unwrap());
} else {
println!("No result");
}
Ok(())
}
fn com_command(optimize: bool, input: &Path, output: &Path) -> Result<(), anyhow::Error> {
let input = fs::read_to_string(input)?;
let mut symbols = SymbolsTable::default();
let typed_expr = match {
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
let mut parser = Parser::new(tokens);
parser.parse()
}
.and_then(|expr| ast::to_typed_expr(expr, optimize, &mut symbols))
{
Ok(expr) => expr,
Err(e) => {
return Err(e.into());
},
};
let ir = IntermediateExpr::from_typed_expr(typed_expr, optimize, &mut symbols);
{
let used_symbols = util::collect_used_symbols(&ir);
symbols.retain(&used_symbols);
}
let mut writer = io::BufWriter::new(fs::File::create(output)?);
symbols.to_writer(&mut writer)?;
writer.write_u64::<BigEndian>(ir.len() as u64)?;
for expr in ir {
expr.to_writer(&mut writer)?;
}
Ok(())
@@ -52,7 +259,7 @@ fn gen_command(
output: &Path,
output_symbols: &Path,
) -> Result<(), anyhow::Error> {
let input = std::fs::read_to_string(input)?;
let input = fs::read_to_string(input)?;
let mut symbols = SymbolsTable::default();
let typed_expr = match {
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
@@ -63,32 +270,28 @@ fn gen_command(
{
Ok(expr) => expr,
Err(e) => {
eprintln!("error: {}", e);
return Ok(());
}
return Err(e.into());
},
};
let mut writer = io::BufWriter::new(std::fs::File::create(output)?);
let mut writer = io::BufWriter::new(fs::File::create(output)?);
match mode {
GenMode::Intermediate => {
let intermediate_exprs = representation::intermediate::to_intermediate_expr(
typed_expr,
optimize,
&mut symbols,
);
let intermediate_exprs =
IntermediateExpr::from_typed_expr(typed_expr, optimize, &mut symbols);
let used_symbols = util::collect_used_symbols(&intermediate_exprs);
symbols.retain(&used_symbols);
util::print_intermediate_exprs(&intermediate_exprs, &mut writer)?;
}
},
GenMode::Postfix => {
util::print_postfix_expr(&typed_expr, &mut writer)?;
}
},
}
let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?);
let mut writer_symbols = io::BufWriter::new(fs::File::create(output_symbols)?);
for (name, data) in &symbols {
writeln!(writer_symbols, "{name} -> {}", data)?;
}
@@ -97,7 +300,7 @@ fn gen_command(
}
fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
let input = std::fs::read_to_string(input)?;
let input = fs::read_to_string(input)?;
let mut symbols = SymbolsTable::default();
let res = {
@@ -109,17 +312,17 @@ fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
match res {
Ok(expr) => {
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
let mut writer_tree = io::BufWriter::new(fs::File::create(output_tree)?);
util::print_typed_expr(&expr, &symbols, &mut writer_tree)?;
}
Err(e) => eprintln!("error: {}", e),
},
Err(e) => return Err(e.into()),
};
Ok(())
}
fn syn_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
let input = std::fs::read_to_string(input)?;
let input = fs::read_to_string(input)?;
let mut symbols = SymbolsTable::default();
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols);
@@ -128,10 +331,10 @@ fn syn_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
match res {
Ok(expr) => {
let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?);
let mut writer_tree = io::BufWriter::new(fs::File::create(output_tree)?);
util::print_untyped_expr(&expr, &mut writer_tree)?;
}
Err(e) => eprintln!("error: {}", e),
},
Err(e) => return Err(e.into()),
};
Ok(())
@@ -142,26 +345,26 @@ fn lex_command(
output_tokens: &Path,
output_symbols: &Path,
) -> Result<(), anyhow::Error> {
let input = std::fs::read_to_string(input)?;
let input = fs::read_to_string(input)?;
let mut symbols = SymbolsTable::default();
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols).collect::<Result<Vec<_>, _>>();
match tokens {
Ok(tokens) => {
let mut writer_tokens = io::BufWriter::new(std::fs::File::create(output_tokens)?);
let mut writer_tokens = io::BufWriter::new(fs::File::create(output_tokens)?);
for (_, token, _) in tokens {
writeln!(writer_tokens, "{token:>6} - {}", token.as_str())?;
}
let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?);
let mut writer_symbols = io::BufWriter::new(fs::File::create(output_symbols)?);
for (name, data) in &symbols {
writeln!(writer_symbols, "{name} -> {}", data)?;
}
}
},
Err(e) => {
eprintln!("error: {}", e);
}
return Err(e.into());
},
};
Ok(())

View File

@@ -1,21 +1,20 @@
use std::collections::VecDeque;
use itertools::PeekNth;
use crate::{
ast::Span,
error::{LexicalError, LexicalErrorKind},
symbols::SymbolsTable,
};
use super::token::Token;
use crate::ast::Span;
use crate::error::{LexicalError, LexicalErrorKind};
use crate::symbols::SymbolsTable;
pub type SpannedToken = (usize, Token, usize);
pub type LexerResult = Result<SpannedToken, LexicalError>;
#[derive(Debug)]
pub struct Lexer<'s, T: Iterator<Item = (usize, char)>> {
pub struct Lexer<'s, T: Iterator<Item = char>> {
chars: PeekNth<T>,
pos: usize,
pending: Vec<SpannedToken>,
pending: VecDeque<SpannedToken>,
symbols: &'s mut SymbolsTable,
}
@@ -23,16 +22,16 @@ pub fn make_tokenizer<'s>(
input: &'s str,
symbols: &'s mut SymbolsTable,
) -> impl Iterator<Item = LexerResult> + 's {
let chars = input.char_indices();
let chars = input.chars();
Lexer::new(chars, symbols)
}
impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
impl<'s, T: Iterator<Item = char>> Lexer<'s, T> {
pub fn new(chars: T, symbols: &'s mut SymbolsTable) -> Self {
Self {
chars: itertools::peek_nth(chars),
pos: 0,
pending: vec![],
pending: VecDeque::new(),
symbols,
}
}
@@ -42,16 +41,15 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
self.consume_token()?;
}
Ok(self.pending.remove(0))
Ok(self.pending.pop_front().unwrap())
}
fn consume_token(&mut self) -> Result<(), LexicalError> {
if let Some(c) = self.peek_char_nth(0) {
let c1 = self.peek_char_nth(1);
if self.is_name_start(c) {
let name = self.lex_name()?;
self.emit(name);
} else if self.is_number_start(c, c1) {
} else if self.is_number_start(c) {
let number = self.lex_number()?;
self.emit(number);
} else {
@@ -98,7 +96,10 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
while let Some(c) = self.peek_char_nth(0) {
if self.is_digit(c) {
number.push(self.next_char().expect("lex_number: no more characters"));
} else if !passed_dot && c == '.' {
} else if !passed_dot
&& c == '.'
&& self.peek_char_nth(1).map_or(false, |c| self.is_digit(c))
{
passed_dot = true;
number.push(self.next_char().expect("lex_number: no more characters"));
} else {
@@ -118,8 +119,8 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
return Err(LexicalError::new(
Span::new(start, end),
LexicalErrorKind::BadNumber(number),
))
}
));
},
},
},
end,
@@ -144,7 +145,7 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
// if c == '\n' {
// self.emit((start, Token::NewLine, end));
// }
}
},
_ => {
let pos = self.get_pos();
let _ = self.next_char();
@@ -152,7 +153,7 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
Span::new(pos, self.get_pos()),
LexicalErrorKind::UnrecognizedToken,
));
}
},
}
Ok(())
@@ -166,9 +167,8 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
self.emit((start, token, end));
}
fn is_number_start(&self, c: char, c1: Option<char>) -> bool {
fn is_number_start(&self, c: char) -> bool {
c.is_ascii_digit()
// || (c == '-' && c1.map_or(false, |c| c.is_ascii_digit()))
}
fn is_digit(&self, c: char) -> bool {
@@ -184,14 +184,14 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
}
fn next_char(&mut self) -> Option<char> {
let (pos, char) = self.chars.next()?;
self.pos = pos + 1;
let char = self.chars.next()?;
self.pos += char.len_utf8();
Some(char)
}
fn emit(&mut self, token: SpannedToken) {
self.pending.push(token);
self.pending.push_back(token);
}
fn get_pos(&self) -> usize {
@@ -199,11 +199,11 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
}
fn peek_char_nth(&mut self, n: usize) -> Option<char> {
self.chars.peek_nth(n).map(|(_, c)| *c)
self.chars.peek_nth(n).cloned()
}
}
impl<'s, T: Iterator<Item = (usize, char)>> Iterator for Lexer<'s, T> {
impl<'s, T: Iterator<Item = char>> Iterator for Lexer<'s, T> {
type Item = LexerResult;
fn next(&mut self) -> Option<Self::Item> {

View File

@@ -1,14 +1,9 @@
use itertools::PeekNth;
use crate::{
ast::{Span, UntypedExpr},
error::{self, ParseError, ParseErrorKind},
};
use super::{
lexer::{LexerResult, SpannedToken},
token::Token,
};
use super::lexer::{LexerResult, SpannedToken};
use super::token::Token;
use crate::ast::{Span, UntypedExpr};
use crate::error::{self, ParseError, ParseErrorKind};
#[derive(Debug)]
pub struct Parser<T: Iterator<Item = LexerResult>> {
@@ -68,7 +63,7 @@ where
break;
}
rhs = self.parse_expr_inner(rhs, op1.precedence() + 1)?;
rhs = self.parse_expr_inner(rhs, op2.precedence())?;
op = self.peek_token_nth(0).and_then(|token| token.as_bin_op());
}
@@ -97,21 +92,21 @@ where
value,
}),
(start, Token::Name(name), end) => {
let typename = match self.peek_token_nth(0) {
let (typename, end) = match self.peek_token_nth(0) {
Some(Token::LBracket) => {
let _ = self.next_token()?;
let typename =
let (_, typename, _) =
self.expect_token_predicate(|t| matches!(t, Token::Name(_)))?;
let _ = self.expect_token(Token::RBracket)?;
let (_, end) = self.expect_token(Token::RBracket)?;
let typename = match typename.1 {
let typename = match typename {
Token::Name(id) => id,
_ => unreachable!(),
};
Some(typename)
}
_ => None,
(Some(typename), end)
},
_ => (None, end),
};
Ok(UntypedExpr::Var {
@@ -119,13 +114,13 @@ where
name,
typename,
})
}
},
(_, Token::LParen, _) => {
let expr = self.parse_expr()?;
let _ = self.expect_token(Token::RParen)?;
Ok(expr)
}
},
(start, _, end) => Err(ParseError::new(
Span::new(start, end),
ParseErrorKind::ExpectedExpr,
@@ -139,7 +134,7 @@ where
Some(Ok((start, token, end))) => {
self.last_span = Span::new(start, end);
Ok((start, token, end))
}
},
Some(Err(e)) => Err(e.into()),
None => Err(ParseError::new(self.last_span, ParseErrorKind::UnexpectedEOF).into()),
}
@@ -162,7 +157,7 @@ where
(start, t, end) if t == token => Ok((start, end)),
(start, _, end) => {
Err(ParseError::new(Span::new(start, end), ParseErrorKind::UnexpectedToken).into())
}
},
}
}
@@ -175,7 +170,7 @@ where
(start, t, end) if pred(&t) => Ok((start, t, end)),
(start, _, end) => {
Err(ParseError::new(Span::new(start, end), ParseErrorKind::UnexpectedToken).into())
}
},
}
}
}

View File

@@ -1,6 +1,7 @@
use std::fmt;
use crate::{ast::BinOp, symbols::Symbol};
use crate::ast::BinOp;
use crate::symbols::Symbol;
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
@@ -56,7 +57,13 @@ impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Name(id) => write!(f, "<id,{id}>"),
Token::Float(number) => write!(f, "<{number}>"),
Token::Float(number) => {
if number == &number.trunc() {
write!(f, "<{number}.0>")
} else {
write!(f, "<{number}>")
}
},
Token::Int(number) => write!(f, "<{number}>"),
Token::Plus => write!(f, "<+>"),
Token::Minus => write!(f, "<->"),

View File

@@ -1,10 +1,11 @@
use std::fmt;
use std::{fmt, io};
use crate::ast::typed::Type;
use crate::{
ast::{typed::TypedExpr, BinOp},
symbols::{Symbol, SymbolsTable},
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::ast::BinOp;
use crate::ast::typed::TypedExpr;
use crate::representation::util::TempVarContext;
use crate::symbols::{Symbol, SymbolsTable};
#[derive(Debug)]
pub enum IntermediateValue {
@@ -13,11 +14,58 @@ pub enum IntermediateValue {
Var { name: Symbol },
}
impl IntermediateValue {
pub fn as_u8(&self) -> u8 {
match self {
IntermediateValue::Int { .. } => b'i',
IntermediateValue::Float { .. } => b'f',
IntermediateValue::Var { .. } => b'v',
}
}
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u8(self.as_u8())?;
match self {
IntermediateValue::Int { value } => writer.write_i64::<BigEndian>(*value)?,
IntermediateValue::Float { value } => writer.write_f64::<BigEndian>(*value)?,
IntermediateValue::Var { name } => writer.write_u64::<BigEndian>(name.into())?,
}
Ok(())
}
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> {
let b = reader.read_u8()?;
match b {
b'i' => Ok(IntermediateValue::Int {
value: reader.read_i64::<BigEndian>()?,
}),
b'f' => Ok(IntermediateValue::Float {
value: reader.read_f64::<BigEndian>()?,
}),
b'v' => Ok(IntermediateValue::Var {
name: reader.read_u64::<BigEndian>()?.into(),
}),
b => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid byte: {b}"),
)),
}
}
}
impl fmt::Display for IntermediateValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IntermediateValue::Int { value } => write!(f, "{}", value),
IntermediateValue::Float { value } => write!(f, "{:.2}", value),
IntermediateValue::Float { value } => {
if *value == value.trunc() {
write!(f, "{value}.0")
} else {
write!(f, "{value}")
}
},
IntermediateValue::Var { name } => write!(f, "<id,{}>", name),
}
}
@@ -35,71 +83,141 @@ pub enum IntermediateExpr {
op: BinOp,
rhs: IntermediateValue,
},
Identity {
result: Symbol,
value: IntermediateValue,
},
}
fn add_temp_var(temp_var_counter: &mut usize, ty: Type, symbols: &mut SymbolsTable) -> Symbol {
let result = symbols.add(format!("#T{}", temp_var_counter));
{
let data = symbols.resolve_mut(&result).unwrap();
data.ty = Some(ty);
data.temporary = true;
impl fmt::Display for IntermediateExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IntermediateExpr::IntToFloat { result, value } => {
write!(f, "i2f <id,{}>, {}", result, value)
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
write!(f, "{:#} <id,{}>, {}, {}", op, result, lhs, rhs)
},
IntermediateExpr::Identity { result, value } => {
write!(f, "idt <id,{}>, {}", result, value)
},
}
}
*temp_var_counter += 1;
result
}
fn to_intermediate_expr_inner(
impl IntermediateExpr {
pub fn as_u8(&self) -> u8 {
match self {
IntermediateExpr::IntToFloat { .. } => 0x01,
IntermediateExpr::BinOp { .. } => 0x02,
IntermediateExpr::Identity { .. } => 0x03,
}
}
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u8(self.as_u8())?;
match self {
IntermediateExpr::IntToFloat { result, value } => {
writer.write_u64::<BigEndian>(result.into())?;
value.to_writer(writer)?;
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
writer.write_u64::<BigEndian>(result.into())?;
lhs.to_writer(writer)?;
writer.write_u8(op.into())?;
rhs.to_writer(writer)?;
},
IntermediateExpr::Identity { result, value } => {
writer.write_u64::<BigEndian>(result.into())?;
value.to_writer(writer)?;
},
}
Ok(())
}
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> {
let b = reader.read_u8()?;
match b {
0x01 => Ok(IntermediateExpr::IntToFloat {
result: reader.read_u64::<BigEndian>()?.into(),
value: IntermediateValue::from_reader(reader)?,
}),
0x02 => Ok(IntermediateExpr::BinOp {
result: reader.read_u64::<BigEndian>()?.into(),
lhs: IntermediateValue::from_reader(reader)?,
op: BinOp::try_from(reader.read_u8()?)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid bin op"))?,
rhs: IntermediateValue::from_reader(reader)?,
}),
0x03 => Ok(IntermediateExpr::Identity {
result: reader.read_u64::<BigEndian>()?.into(),
value: IntermediateValue::from_reader(reader)?,
}),
b => Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("invalid byte: {b}"),
)),
}
}
pub fn from_typed_expr(
expr: TypedExpr,
reuse_symbols: bool,
symbols: &mut SymbolsTable,
temp_var_counter: &mut usize,
exprs: &mut Vec<IntermediateExpr>,
temp_float_vars: &mut Vec<Symbol>,
temp_int_vars: &mut Vec<Symbol>,
) -> IntermediateValue {
) -> Vec<IntermediateExpr> {
let ty = expr.ty(symbols);
let mut exprs = Vec::new();
let mut temp_var_context = TempVarContext::new(reuse_symbols, symbols);
let value = Self::from_typed_expr_inner(expr, &mut exprs, &mut temp_var_context);
if exprs.is_empty() {
return vec![IntermediateExpr::Identity {
result: temp_var_context.get_temp_var(ty),
value,
}];
}
exprs
}
fn from_typed_expr_inner(
expr: TypedExpr,
exprs: &mut Vec<IntermediateExpr>,
temp_var_context: &mut TempVarContext,
) -> IntermediateValue {
let ty = expr.ty(temp_var_context.symbols());
match expr {
TypedExpr::Int { value, .. } => IntermediateValue::Int { value },
TypedExpr::Float { value, .. } => IntermediateValue::Float { value },
TypedExpr::Var { name, .. } => IntermediateValue::Var { name },
TypedExpr::BinOp { lhs, op, rhs, .. } => {
let lhs = to_intermediate_expr_inner(
*lhs,
reuse_symbols,
symbols,
temp_var_counter,
exprs,
temp_float_vars,
temp_int_vars,
);
let rhs = to_intermediate_expr_inner(
*rhs,
reuse_symbols,
symbols,
temp_var_counter,
exprs,
temp_float_vars,
temp_int_vars,
);
let lhs = Self::from_typed_expr_inner(*lhs, exprs, temp_var_context);
let rhs = Self::from_typed_expr_inner(*rhs, exprs, temp_var_context);
if let IntermediateValue::Var { name } = lhs {
free_temp_var(name, ty, temp_int_vars, temp_float_vars, symbols)
temp_var_context.free_temp_var(name)
}
if let IntermediateValue::Var { name } = rhs {
free_temp_var(name, ty, temp_int_vars, temp_float_vars, symbols)
temp_var_context.free_temp_var(name)
}
let result = allocate_temp_var(
ty,
reuse_symbols,
temp_var_counter,
temp_float_vars,
temp_int_vars,
symbols,
);
let result = temp_var_context.get_temp_var(ty);
exprs.push(IntermediateExpr::BinOp {
result,
@@ -109,95 +227,20 @@ fn to_intermediate_expr_inner(
});
IntermediateValue::Var { name: result }
}
},
TypedExpr::IntToFloat { value, .. } => {
let value = to_intermediate_expr_inner(
*value,
reuse_symbols,
symbols,
temp_var_counter,
exprs,
temp_float_vars,
temp_int_vars,
);
let value = Self::from_typed_expr_inner(*value, exprs, temp_var_context);
if let IntermediateValue::Var { name: value } = value {
free_temp_var(value, Type::Int, temp_int_vars, temp_float_vars, symbols)
temp_var_context.free_temp_var(value)
}
let result = allocate_temp_var(
ty,
reuse_symbols,
temp_var_counter,
temp_float_vars,
temp_int_vars,
symbols,
);
let result = temp_var_context.get_temp_var(ty);
exprs.push(IntermediateExpr::IntToFloat { result, value });
IntermediateValue::Var { name: result }
},
}
}
}
fn allocate_temp_var(
ty: Type,
reuse_symbols: bool,
temp_var_counter: &mut usize,
temp_float_vars: &mut Vec<Symbol>,
temp_int_vars: &mut Vec<Symbol>,
symbols: &mut SymbolsTable,
) -> Symbol {
if reuse_symbols {
match ty {
Type::Int if !temp_int_vars.is_empty() => temp_int_vars.pop().unwrap(),
Type::Float if !temp_float_vars.is_empty() => temp_float_vars.pop().unwrap(),
_ => add_temp_var(temp_var_counter, ty, symbols),
}
} else {
add_temp_var(temp_var_counter, ty, symbols)
}
}
fn free_temp_var(
name: Symbol,
ty: Type,
temp_int_vars: &mut Vec<Symbol>,
temp_float_vars: &mut Vec<Symbol>,
symbols: &mut SymbolsTable,
) {
let temporary = symbols.temporary(&name).unwrap();
if !temporary {
return;
}
if ty == Type::Int {
temp_int_vars.push(name);
} else {
temp_float_vars.push(name);
}
}
pub fn to_intermediate_expr(
expr: TypedExpr,
reuse_symbols: bool,
symbols: &mut SymbolsTable,
) -> Vec<IntermediateExpr> {
let mut exprs = Vec::new();
let mut intermediate_var_counter = 0;
let mut temp_float_vars = Vec::new();
let mut temp_int_vars = Vec::new();
to_intermediate_expr_inner(
expr,
reuse_symbols,
symbols,
&mut intermediate_var_counter,
&mut exprs,
&mut temp_float_vars,
&mut temp_int_vars,
);
exprs
}

View File

@@ -1 +1,2 @@
pub mod intermediate;
mod util;

View File

@@ -0,0 +1,71 @@
use crate::ast::typed::Type;
use crate::symbols::{Symbol, SymbolsTable};
#[derive(Debug)]
pub struct TempVarContext<'t> {
counter: usize,
floats: Vec<Symbol>,
ints: Vec<Symbol>,
reuse_symbols: bool,
symbols: &'t mut SymbolsTable,
}
impl<'t> TempVarContext<'t> {
pub fn new(reuse_symbols: bool, symbols: &'t mut SymbolsTable) -> Self {
Self {
counter: 0,
floats: Vec::new(),
ints: Vec::new(),
reuse_symbols,
symbols,
}
}
pub fn get_temp_var(&mut self, ty: Type) -> Symbol {
if self.reuse_symbols {
match ty {
Type::Int if !self.ints.is_empty() => self.ints.pop().unwrap(),
Type::Float if !self.floats.is_empty() => self.floats.pop().unwrap(),
_ => self.allocate_temp_var(ty),
}
} else {
self.allocate_temp_var(ty)
}
}
pub fn symbols(&self) -> &SymbolsTable {
self.symbols
}
fn allocate_temp_var(&mut self, ty: Type) -> Symbol {
let result = self.symbols.add(format!("#T{}", self.counter));
{
let data = self.symbols.resolve_mut(&result).unwrap();
data.ty = Some(ty);
data.temporary = true;
}
self.counter += 1;
result
}
pub fn free_temp_var(&mut self, name: Symbol) {
let Some(data) = self.symbols.resolve(&name) else {
return;
};
if !data.temporary {
return;
}
let Some(ty) = data.ty else {
return;
};
if ty == Type::Int {
self.ints.push(name);
} else {
self.floats.push(name);
}
}
}

View File

View File

@@ -1,14 +1,25 @@
pub mod builtin;
use std::collections::{HashMap, hash_map};
use std::fmt::Display;
use std::io;
use std::{
collections::{hash_map, HashMap},
fmt::Display,
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::ast::typed::Type;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Symbol(usize);
pub struct Symbol(u64);
impl From<&Symbol> for u64 {
fn from(value: &Symbol) -> Self {
value.0
}
}
impl From<u64> for Symbol {
fn from(value: u64) -> Self {
Self(value)
}
}
#[derive(Debug)]
pub struct SymbolData {
@@ -18,6 +29,43 @@ pub struct SymbolData {
pub temporary: bool,
}
impl SymbolData {
fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> {
let id = reader.read_u64::<BigEndian>()?;
let name = {
let n = reader.read_u64::<BigEndian>()?;
let mut buf = vec![0; n as usize];
reader.read_exact(&mut buf)?;
String::from_utf8(buf)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid utf-8"))?
};
let ty = {
let b = reader.read_u8()?;
Type::try_from(b).ok()
};
let temporary = reader.read_u8()? != 0;
Ok(Self {
id: Symbol(id),
name,
ty,
temporary,
})
}
fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u64::<BigEndian>(self.id.0)?;
writer.write_u64::<BigEndian>(self.name.len() as u64)?;
writer.write_all(self.name.as_bytes())?;
writer.write_u8(self.ty.map_or(0, |ty| ty.into()))?;
writer.write_u8(self.temporary as u8)?;
Ok(())
}
}
impl Display for SymbolData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut builder = f.debug_struct("symbol");
@@ -44,7 +92,7 @@ impl Display for Symbol {
#[derive(Debug)]
pub struct SymbolsTable {
symbols: HashMap<String, SymbolData>,
next_id: usize,
next_id: u64,
}
impl SymbolsTable {
@@ -55,6 +103,36 @@ impl SymbolsTable {
}
}
pub fn from_reader(reader: &mut impl io::Read) -> io::Result<Self> {
let n = reader.read_u64::<BigEndian>()?;
let mut max_id = 0;
let mut symbols = Vec::with_capacity(n as usize);
for _ in 0..n {
let data = SymbolData::from_reader(reader)?;
max_id = max_id.max(data.id.0);
symbols.push(data);
}
Ok(Self {
symbols: symbols
.into_iter()
.map(|data| (data.name.clone(), data))
.collect(),
next_id: max_id + 1,
})
}
pub fn to_writer(&self, writer: &mut impl io::Write) -> io::Result<()> {
writer.write_u64::<BigEndian>(self.symbols.len() as u64)?;
for data in self.symbols.values() {
data.to_writer(writer)?;
}
Ok(())
}
pub fn retain(&mut self, symbols: &[Symbol]) {
self.symbols.retain(|_, data| symbols.contains(&data.id));
}
@@ -81,34 +159,18 @@ impl SymbolsTable {
}
pub fn resolve(&self, symbol: &Symbol) -> Option<&SymbolData> {
self.symbols.iter().find_map(
|(_name, data)| {
if &data.id == symbol {
Some(data)
} else {
None
}
},
)
self.symbols.values().find(|data| &data.id == symbol)
}
pub fn resolve_mut(&mut self, symbol: &Symbol) -> Option<&mut SymbolData> {
self.symbols.iter_mut().find_map(
|(_name, data)| {
if &data.id == symbol {
Some(data)
} else {
None
}
},
)
self.symbols.values_mut().find(|data| &data.id == symbol)
}
pub fn type_of(&self, symbol: &Symbol) -> Option<Type> {
self.resolve(symbol).and_then(|data| data.ty)
}
pub fn temporary(&self, symbol: &Symbol) -> Option<bool> {
pub fn is_temporary(&self, symbol: &Symbol) -> Option<bool> {
self.resolve(symbol).map(|data| data.temporary)
}
}

View File

@@ -1,13 +1,10 @@
use std::collections::HashSet;
use std::io;
use crate::representation::intermediate::IntermediateValue;
use crate::symbols::Symbol;
use crate::{
ast::{typed::TypedExpr, UntypedExpr},
representation::intermediate::IntermediateExpr,
symbols::SymbolsTable,
};
use crate::ast::UntypedExpr;
use crate::ast::typed::TypedExpr;
use crate::representation::intermediate::{IntermediateExpr, IntermediateValue};
use crate::symbols::{Symbol, SymbolsTable};
pub fn collect_used_symbols(expr: &[IntermediateExpr]) -> Vec<Symbol> {
let mut used_symbols = HashSet::new();
@@ -16,21 +13,31 @@ pub fn collect_used_symbols(expr: &[IntermediateExpr]) -> Vec<Symbol> {
match expr {
IntermediateExpr::IntToFloat { result, value } => {
used_symbols.insert(*result);
if let IntermediateValue::Var { name } = value {
used_symbols.insert(*name);
}
}
},
IntermediateExpr::BinOp {
result, lhs, rhs, ..
} => {
used_symbols.insert(*result);
if let IntermediateValue::Var { name } = lhs {
used_symbols.insert(*name);
}
if let IntermediateValue::Var { name } = rhs {
used_symbols.insert(*name);
}
},
IntermediateExpr::Identity { result, value } => {
used_symbols.insert(*result);
if let IntermediateValue::Var { name } = value {
used_symbols.insert(*name);
}
},
}
}
@@ -42,19 +49,7 @@ pub fn print_intermediate_exprs(
writer: &mut impl io::Write,
) -> io::Result<()> {
for expr in exprs {
match expr {
IntermediateExpr::IntToFloat { result, value } => {
writeln!(writer, "i2f <id,{}>, {}", result, value)?;
}
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
writeln!(writer, "{:#} <id,{}>, {}, {}", op, result, lhs, rhs)?;
}
}
writeln!(writer, "{}", expr)?;
}
Ok(())
@@ -69,11 +64,11 @@ pub fn print_postfix_expr(expr: &TypedExpr, writer: &mut impl io::Write) -> io::
print_postfix_expr(lhs, writer)?;
print_postfix_expr(rhs, writer)?;
write!(writer, "{} ", op)?;
}
},
TypedExpr::IntToFloat { value, .. } => {
print_postfix_expr(value, writer)?;
write!(writer, "i2f ")?;
}
},
}
Ok(())
@@ -92,11 +87,17 @@ fn write_typed_expr(
match expr {
TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
TypedExpr::Float { value, .. } => {
if value == &value.trunc() {
writeln!(writer, "<{}.0>", value)
} else {
writeln!(writer, "<{}>", value)
}
},
TypedExpr::Var { name, .. } => {
let ty = symbols.resolve(name).unwrap().ty.unwrap();
writeln!(writer, "<id,{},{}>", name, ty)
}
},
TypedExpr::BinOp { lhs, op, rhs, .. } => {
writeln!(writer, "<{}>", op)?;
@@ -108,7 +109,7 @@ fn write_typed_expr(
write_typed_expr(lhs, symbols, writer, &new_prefix, false)?;
write_typed_expr(rhs, symbols, writer, &new_prefix, true)
}
},
TypedExpr::IntToFloat { value, .. } => {
writeln!(writer, "i2f")?;
@@ -119,7 +120,7 @@ fn write_typed_expr(
};
write_typed_expr(value, symbols, writer, &new_prefix, true)
}
},
}
}
@@ -143,7 +144,13 @@ fn write_untyped_expr(
match expr {
UntypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value),
UntypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value),
UntypedExpr::Float { value, .. } => {
if value == &value.trunc() {
writeln!(writer, "<{}.0>", value)
} else {
writeln!(writer, "<{}>", value)
}
},
UntypedExpr::Var {
name: id, typename, ..
} => {
@@ -152,7 +159,7 @@ fn write_untyped_expr(
write!(writer, ",{}", typename)?;
}
writeln!(writer, ">")
}
},
UntypedExpr::BinOp { lhs, op, rhs, .. } => {
writeln!(writer, "<{}>", op)?;
@@ -164,7 +171,7 @@ fn write_untyped_expr(
write_untyped_expr(lhs, writer, &new_prefix, false)?;
write_untyped_expr(rhs, writer, &new_prefix, true)
}
},
}
}