Compare commits

...

5 Commits

11 changed files with 295 additions and 343 deletions

327
Cargo.lock generated
View File

@ -2,18 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@ -23,12 +11,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "anstream"
version = "0.6.13"
@ -64,7 +46,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
@ -74,100 +56,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
name = "ariadne"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd002a6223f12c7a95cdd4b1cb3a0149d22d37f7a9ecdb2cb691a071fe236c29"
dependencies = [
"unicode-width",
"yansi",
]
[[package]]
name = "cc"
version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chumsky"
version = "1.0.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9c28d4e5dd9a9262a38b231153591da6ce1471b818233f4727985d3dd0ed93c"
dependencies = [
"hashbrown",
"regex-automata 0.3.9",
"serde",
"stacker",
"unicode-ident",
]
[[package]]
name = "clap"
version = "4.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
@ -197,12 +100,7 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
name = "dust-lang"
version = "0.5.0"
dependencies = [
"ariadne",
"chumsky",
"clap",
"colored",
"env_logger",
"log",
"rand",
"rayon",
"serde",
@ -253,22 +151,6 @@ dependencies = [
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "humantime"
version = "2.1.0"
@ -281,12 +163,6 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.153"
@ -305,12 +181,6 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@ -326,15 +196,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "psm"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
dependencies = [
"cc",
]
[[package]]
name = "quote"
version = "1.0.35"
@ -402,19 +263,8 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.6",
"regex-syntax 0.8.2",
]
[[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",
"regex-automata",
"regex-syntax",
]
[[package]]
@ -425,15 +275,9 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.2",
"regex-syntax",
]
[[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.2"
@ -477,25 +321,6 @@ dependencies = [
"serde",
]
[[package]]
name = "stacker"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
dependencies = [
"cc",
"cfg-if",
"libc",
"psm",
"winapi",
]
[[package]]
name = "strsim"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "syn"
version = "2.0.53"
@ -513,83 +338,25 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[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 0.52.4",
]
[[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",
"windows-targets",
]
[[package]]
@ -598,121 +365,53 @@ version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[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.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@ -9,12 +9,7 @@ readme.workspace = true
repository.workspace = true
[dependencies]
ariadne = "0.4.0"
chumsky = { version = "1.0.0-alpha.6", features = ["pratt", "label"] }
clap = { version = "4.5.2", features = ["derive"] }
colored = "2.1.0"
env_logger = "0.11.3"
log = "0.4.21"
rand = "0.8.5"
rayon = "1.9.0"
serde = { version = "1.0.203", features = ["derive"] }

View File

@ -1,4 +1,4 @@
use crate::{Identifier, Span, Value};
use crate::{Identifier, ReservedIdentifier, Span, Value};
#[derive(Debug, PartialEq, Clone)]
pub struct Node {
@ -22,10 +22,12 @@ pub enum Statement {
// Expressions
Add(Box<Node>, Box<Node>),
PropertyAccess(Box<Node>, Box<Node>),
List(Vec<Node>),
Multiply(Box<Node>, Box<Node>),
// Hard-coded values
Constant(Value),
Identifier(Identifier),
ReservedIdentifier(ReservedIdentifier),
}

View File

@ -1,4 +1,4 @@
use crate::{Node, Span, Statement};
use crate::{Node, Statement};
pub fn analyze(abstract_tree: Vec<Node>) -> Result<(), AnalyzerError> {
let analyzer = Analyzer::new(abstract_tree);
@ -55,6 +55,18 @@ impl Analyzer {
self.analyze_node(&left)?;
self.analyze_node(&right)?;
}
Statement::PropertyAccess(left, right) => {
if let Statement::Identifier(_) = &left.statement {
// Identifier is in the correct position
} else {
return Err(AnalyzerError::ExpectedIdentifier {
actual: left.as_ref().clone(),
});
}
self.analyze_node(&right)?;
}
Statement::ReservedIdentifier(_) => {}
}
Ok(())

View File

@ -5,7 +5,7 @@
//! - [`Lexer`], which lexes the input a token at a time
use std::num::{ParseFloatError, ParseIntError};
use crate::{Identifier, Span, Token};
use crate::{Identifier, ReservedIdentifier, Span, Token};
/// Lex the input and return a vector of tokens and their positions.
pub fn lex(input: &str) -> Result<Vec<(Token, Span)>, LexError> {
@ -90,6 +90,10 @@ impl<'a> Lexer<'a> {
self.position += 1;
(Token::Comma, (self.position - 1, self.position))
}
'.' => {
self.position += 1;
(Token::Dot, (self.position - 1, self.position))
}
_ => (Token::Eof, (self.position, self.position)),
}
} else {
@ -115,6 +119,11 @@ impl<'a> Lexer<'a> {
self.source[self.position..].chars().next()
}
/// Peek at the second-to-next character without consuming it.
fn peek_second_char(&self) -> Option<char> {
self.source[self.position..].chars().nth(1)
}
/// Lex an integer or float token.
fn lex_number(&mut self) -> Result<(Token, Span), LexError> {
let start_pos = self.position;
@ -122,16 +131,20 @@ impl<'a> Lexer<'a> {
while let Some(c) = self.peek_char() {
if c == '.' {
is_float = true;
self.next_char();
while let Some(c) = self.peek_char() {
if c.is_ascii_digit() {
if let Some('0'..='9') = self.peek_second_char() {
if !is_float {
self.next_char();
} else {
break;
}
self.next_char();
while let Some('0'..='9') = self.peek_char() {
self.next_char();
}
is_float = true;
} else {
break;
}
}
@ -158,15 +171,20 @@ impl<'a> Lexer<'a> {
let start_pos = self.position;
while let Some(c) = self.peek_char() {
if c.is_ascii_alphanumeric() {
if c.is_ascii_alphanumeric() || c == '_' {
self.next_char();
} else {
break;
}
}
let identifier = &self.source[start_pos..self.position];
let token = Token::Identifier(Identifier::new(identifier));
let string = &self.source[start_pos..self.position];
let token = match string {
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven),
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd),
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length),
_ => Token::Identifier(Identifier::new(string)),
};
Ok((token, (start_pos, self.position)))
}
@ -194,6 +212,47 @@ impl From<ParseIntError> for LexError {
mod tests {
use super::*;
#[test]
fn integer_property_access() {
let input = "42.is_even";
assert_eq!(
lex(input),
Ok(vec![
(Token::Integer(42), (0, 2)),
(Token::Dot, (2, 3)),
(
Token::ReservedIdentifier(ReservedIdentifier::IsEven),
(3, 10)
),
(Token::Eof, (10, 10)),
])
)
}
#[test]
fn empty() {
let input = "";
assert_eq!(lex(input), Ok(vec![(Token::Eof, (0, 0))]))
}
#[test]
fn reserved_identifier() {
let input = "length";
assert_eq!(
lex(input),
Ok(vec![
(
Token::ReservedIdentifier(ReservedIdentifier::Length),
(0, 6)
),
(Token::Eof, (6, 6)),
])
)
}
#[test]
fn square_braces() {
let input = "[]";

View File

@ -21,7 +21,7 @@ pub use identifier::Identifier;
pub use lex::{lex, LexError, Lexer};
pub use parse::{parse, ParseError, Parser};
pub use r#type::Type;
pub use token::Token;
pub use token::{ReservedIdentifier, Token};
pub use value::{Value, ValueError};
pub use vm::{run, Vm, VmError};

View File

@ -85,6 +85,17 @@ impl<'src> Parser<'src> {
(left_start, right_end),
));
}
(Token::Dot, _) => {
self.next_token()?;
let right_node = self.parse_node(self.current_precedence())?;
let right_end = right_node.span.1;
return Ok(Node::new(
Statement::PropertyAccess(Box::new(left_node), Box::new(right_node)),
(left_start, right_end),
));
}
_ => {}
}
}
@ -159,12 +170,21 @@ impl<'src> Parser<'src> {
}
}
}
(Token::ReservedIdentifier(reserved), _) => {
self.next_token()?;
Ok(Node::new(
Statement::ReservedIdentifier(reserved),
self.current.1,
))
}
_ => Err(ParseError::UnexpectedToken(self.current.0.clone())),
}
}
fn current_precedence(&self) -> u8 {
match self.current.0 {
Token::Dot => 4,
Token::Equal => 3,
Token::Plus => 1,
Token::Star => 2,
@ -193,6 +213,53 @@ mod tests {
use super::*;
#[test]
fn list_access() {
let input = "[1, 2, 3].0";
assert_eq!(
parse(input),
Ok([Node::new(
Statement::PropertyAccess(
Box::new(Node::new(
Statement::List(vec![
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
Node::new(Statement::Constant(Value::integer(3)), (7, 8)),
]),
(0, 9)
)),
Box::new(Node::new(Statement::Constant(Value::integer(0)), (10, 11))),
),
(0, 11),
)]
.into())
);
}
#[test]
fn property_access() {
let input = "a.b";
assert_eq!(
parse(input),
Ok([Node::new(
Statement::PropertyAccess(
Box::new(Node::new(
Statement::Identifier(Identifier::new("a")),
(0, 1)
)),
Box::new(Node::new(
Statement::Identifier(Identifier::new("b")),
(2, 3)
)),
),
(0, 3),
)]
.into())
);
}
#[test]
fn complex_list() {
let input = "[1, 1 + 1, 2 + (4 * 10)]";

View File

@ -3,9 +3,11 @@ use crate::Identifier;
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
Comma,
Dot,
Eof,
Equal,
Identifier(Identifier),
ReservedIdentifier(ReservedIdentifier),
Integer(i64),
Plus,
Star,
@ -15,3 +17,10 @@ pub enum Token {
RightSquareBrace,
Float(f64),
}
#[derive(Debug, PartialEq, Clone)]
pub enum ReservedIdentifier {
IsEven,
IsOdd,
Length,
}

View File

@ -16,7 +16,6 @@ use std::{
fmt::{self, Display, Formatter},
};
use clap::error::Result;
use serde::{Deserialize, Serialize};
use crate::identifier::Identifier;

View File

@ -6,7 +6,6 @@ use std::{
sync::Arc,
};
use chumsky::container::Container;
use serde::{
de::Visitor,
ser::{SerializeMap, SerializeSeq, SerializeTuple},
@ -402,7 +401,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
where
A: serde::de::MapAccess<'de>,
{
let mut btree = BTreeMap::with_capacity(map.size_hint().unwrap_or(10));
let mut btree = BTreeMap::new();
while let Some((key, value)) = map.next_entry()? {
btree.insert(key, value);
@ -458,7 +457,7 @@ impl ValueInner {
}
}
ValueInner::Map(value_map) => {
let mut type_map = BTreeMap::with_capacity(value_map.len());
let mut type_map = BTreeMap::new();
for (identifier, value) in value_map {
let r#type = value.r#type();
@ -474,6 +473,18 @@ impl ValueInner {
}
}
pub trait ValueProperties<'a> {}
pub struct IntegerProperties<'a>(&'a Value);
impl<'a> IntegerProperties<'a> {
pub fn is_even(&self) -> bool {
self.0.as_integer().unwrap() % 2 == 0
}
}
impl<'a> ValueProperties<'a> for IntegerProperties<'a> {}
impl Eq for ValueInner {}
impl PartialOrd for ValueInner {
@ -516,4 +527,7 @@ impl Ord for ValueInner {
#[derive(Clone, Debug, PartialEq)]
pub enum ValueError {
CannotAdd(Value, Value),
PropertyNotFound { value: Value, property: Identifier },
IndexOutOfBounds { value: Value, index: i64 },
ExpectedList(Value),
}

View File

@ -1,13 +1,15 @@
use std::collections::{HashMap, VecDeque};
use crate::{parse, Identifier, Node, ParseError, Span, Statement, Value, ValueError};
use crate::{
parse, Identifier, Node, ParseError, ReservedIdentifier, Span, Statement, Value, ValueError,
};
pub fn run(
input: &str,
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
let instructions = parse(input)?;
let mut vm = Vm::new(instructions);
let abstract_syntax_tree = parse(input)?;
let mut vm = Vm::new(abstract_syntax_tree);
vm.run(variables)
}
@ -40,6 +42,9 @@ impl Vm {
variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError> {
match node.statement {
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => Ok(None),
Statement::ReservedIdentifier(_) => Ok(None),
Statement::Add(left, right) => {
let left_span = left.span;
let left = if let Some(value) = self.run_node(*left, variables)? {
@ -82,8 +87,6 @@ impl Vm {
Ok(None)
}
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => Ok(None),
Statement::List(nodes) => {
let values = nodes
.into_iter()
@ -100,6 +103,62 @@ impl Vm {
Ok(Some(Value::list(values)))
}
Statement::Multiply(_, _) => todo!(),
Statement::PropertyAccess(left, right) => {
let left_span = left.span;
let left = if let Some(value) = self.run_node(*left, variables)? {
value
} else {
return Err(VmError::ExpectedValue {
position: left_span,
});
};
let right_span = right.span;
if let Statement::ReservedIdentifier(reserved) = &right.statement {
match reserved {
ReservedIdentifier::IsEven => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 == 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::IsOdd => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 != 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::Length => {
if let Some(list) = left.as_list() {
return Ok(Some(Value::integer(list.len() as i64)));
} else {
return Err(VmError::ExpectedList {
position: right_span,
});
}
}
}
}
if let (Some(list), Statement::Constant(value)) = (left.as_list(), &right.statement)
{
if let Some(index) = value.as_integer() {
let value = list.get(index as usize).cloned();
return Ok(value);
}
}
Err(VmError::ExpectedIdentifierOrInteger {
position: right_span,
})
}
}
}
}
@ -112,6 +171,9 @@ pub enum VmError {
// Anaylsis Failures
// These should be prevented by running the analyzer before the VM
ExpectedValue { position: Span },
ExpectedIdentifierOrInteger { position: Span },
ExpectedList { position: Span },
ExpectedInteger { position: Span },
}
impl From<ParseError> for VmError {
@ -130,6 +192,40 @@ impl From<ValueError> for VmError {
mod tests {
use super::*;
#[test]
fn is_even() {
let input = "42.is_even";
assert_eq!(
run(input, &mut HashMap::new()),
Ok(Some(Value::boolean(true)))
);
}
#[test]
fn is_odd() {
let input = "42.is_odd";
assert_eq!(
run(input, &mut HashMap::new()),
Ok(Some(Value::boolean(false)))
);
}
#[test]
fn list_access() {
let input = "[1, 2, 3].1";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2))));
}
#[test]
fn property_access() {
let input = "[1, 2, 3].length";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
}
#[test]
fn add() {
let input = "1 + 2";