diff --git a/Cargo.lock b/Cargo.lock index ad20d91..5256ce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "Yard" version = "0.1.0" dependencies = [ "lazy_static", + "rand", "regex", ] @@ -19,18 +20,77 @@ dependencies = [ "memchr", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[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.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "regex" version = "1.6.0" @@ -47,3 +107,9 @@ name = "regex-syntax" version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/Cargo.toml b/Cargo.toml index e989419..9401403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] regex = "*" -lazy_static = "1.4.0" \ No newline at end of file +lazy_static = "1.4.0" +rand = "0.8.5" \ No newline at end of file diff --git a/README.md b/README.md index c7a49a0..3f76447 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,4 @@ Yard is an funny programming language compiler and interpreter written in pure R It *will* contain features such as: 1. a COMEFROM keyword (inverse goto) 2. a ```don't``` code block which never executes +3. swapped meaning of "" (for single characters) and '' (now for string literal) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b679e21..aba5822 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,12 +9,10 @@ fn main() { let source = r" -foo(c) = 3 * c +pi = 3.1415926 main() { - x = foo(5 * 6) - - 4 * 3 + } "; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index bdc938f..54e1598 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -220,7 +220,7 @@ fn discover_exprs<'a>(functions: &mut Vec>) { /// parse a single term using a modified shunting yard fn parse_term<'a>(term: &mut VecDeque>, scope: &mut Scope) { let mut op_stack = vec![]; - let mut output = VecDeque::new(); + let mut output = VecDeque::with_capacity(term.len()); 'outer: while let Some(token) = term.pop_front() { @@ -273,8 +273,10 @@ fn parse_term<'a>(term: &mut VecDeque>, scope: &mut Scope) { let prec1 = op1.prec(); if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { - output.push_back(op_stack.pop().unwrap()) + output.push_back(op_stack.pop().unwrap()); + continue } + break }, _ => break } diff --git a/src/token/mod.rs b/src/token/mod.rs index 1ddb627..4937078 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -2,6 +2,17 @@ use std::collections::{VecDeque}; #[derive(Debug, Hash, PartialEq, Eq)] pub enum Operator { + Or, + And, + Xor, + + Eq, + Lt, + Gt, + GtEq, + LtEq, + NotEq, + Add, Sub, Mul, @@ -19,6 +30,17 @@ pub enum Assoc { impl Operator { pub fn parse<'a>(str: &'a str) -> Self { return match str { + "|" => Operator::Or, + "&" => Operator::And, + "^" => Operator::Xor, + + "==" => Operator::Eq, + "<" => Operator::Lt, + ">" => Operator::Gt, + "<=" => Operator::LtEq, + ">=" => Operator::GtEq, + "!=" => Operator::NotEq, + "+" => Operator::Add, "-" => Operator::Sub, "*" => Operator::Mul, @@ -31,6 +53,17 @@ impl Operator { pub fn prec(&self) -> usize { return match self { + Operator::Eq => 2, + Operator::Lt => 2, + Operator::Gt => 2, + Operator::LtEq => 2, + Operator::GtEq => 2, + Operator::NotEq => 2, + + Operator::Or => 0, + Operator::Xor => 0, + Operator::And => 1, + Operator::Add => 3, Operator::Sub => 3, @@ -62,9 +95,10 @@ pub enum Token<'a> { Var(&'a str), Arg(&'a str), Assign(&'a str), + Bool(bool), } -const TOKEN_REGEX_SRC: &'static str = r"(#.*)|([A-Za-z_]+)\s*=|([A-Za-z_]+)|(\d*\.?\d+)|([+\-*/=])|([(){}])|(\n)"; +const TOKEN_REGEX_SRC: &'static str = r"(#.*)|(true|false|yes|no|maybe)|([A-Za-z_]+)\s*=|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>])|([(){}])|(\n)"; lazy_static::lazy_static! { static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap(); @@ -86,12 +120,13 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque> { // if we have a match, save it as token if let Some(mat) = group { tokens.push_back(match i { - 2 => Token::Assign(mat.as_str()), - 3 => Token::Word(mat.as_str()), - 4 => Token::Number(mat.as_str()), - 5 => Token::Operator(Operator::parse(mat.as_str())), - 6 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap()), - 7 => Token::LineBreak, + 2 => Token::Bool(parse_bool(mat.as_str())), + 3 => Token::Assign(mat.as_str()), + 4 => Token::Word(mat.as_str()), + 5 => Token::Number(mat.as_str()), + 6 => Token::Operator(Operator::parse(mat.as_str())), + 7 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap()), + 8 => Token::LineBreak, _ => panic!("Unknown match to tokenize: {}", mat.as_str()) }); @@ -100,4 +135,13 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque> { } return tokens; +} + +fn parse_bool(text: &str) -> bool { + return match text.to_ascii_lowercase().as_str() { + "true" | "ye" => true, + "false" |"no" => false, + "maybe" => rand::random(), + _ => panic!("Not a recognized boolean {text}") + } } \ No newline at end of file