some random changes

This commit is contained in:
tezlm 2023-05-09 06:48:20 -07:00
parent 27587a5e3f
commit 4108cb9d21
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
5 changed files with 133 additions and 24 deletions

6
src/compiler.rs Normal file
View file

@ -0,0 +1,6 @@
use crate::parser;
use crate::lexer;
pub fn compile(tree: &parser::Tree) {
}

View file

@ -1,26 +1,32 @@
use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder};
#[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum TokenType {
Space, Int, Float, String, Ident, Paran, Symb
Space, Int, Float, String, Ident, Paran, Symbol, Keyword,
}
macro_rules! regex {
($regex:expr) => {
RegexBuilder::new($regex).case_insensitive(true).build().unwrap()
}
}
static TOKEN_MATCHERS: Lazy<[(TokenType, Regex); 9]> = once_cell::sync::Lazy::new(|| [
(TokenType::Space, regex!(r"^[ \n\t]+")),
(TokenType::Int, regex!(r"^0(x[0-9a-f]+|b[01]+|o[0-7]+)")),
(TokenType::Float, regex!(r"^[0-9]+(\.[0-9]+)?")),
(TokenType::String, regex!(r#"^"(.*?[^\\])?""#)),
(TokenType::String, regex!(r"^'(.*?[^\\])?'")),
(TokenType::Ident, regex!(r"^[a-z_][a-z0-9_]*")),
(TokenType::Paran, regex!(r"^[\[\]\(\)\{\}\<\>]")),
(TokenType::Symbol, regex!(r"^[^ \n\ta-z0-9_\[\]\(\)]{1,2}")),
(TokenType::Keyword, regex!(r"^(let|mut|const|type|fn|if|else|match|for|in|while|loop|export|import|struct|enum|async)")),
]);
pub fn lex(input: &str) -> Vec<(TokenType, &str)> {
let mut code = input.to_owned();
let mut tokens = Vec::new();
static TOKEN_MATCHERS: Lazy<[(TokenType, Regex); 8]> = once_cell::sync::Lazy::new(|| {
[
(TokenType::Space, RegexBuilder::new(r"^[ \n\t]+").case_insensitive(true).build().unwrap()),
(TokenType::Int, RegexBuilder::new(r"^0(x[0-9a-f]+|b[01]+|o[0-7]+)").case_insensitive(true).build().unwrap()),
(TokenType::Float, RegexBuilder::new(r"^[0-9]+(\.[0-9]+)?").case_insensitive(true).build().unwrap()),
(TokenType::String, RegexBuilder::new(r#"^"(.*?[^\\])?""#).case_insensitive(true).build().unwrap()),
(TokenType::String, RegexBuilder::new(r"^'(.*?[^\\])?'").case_insensitive(true).build().unwrap()),
(TokenType::Ident, RegexBuilder::new(r"^[a-z_][a-z0-9_]*").case_insensitive(true).build().unwrap()),
(TokenType::Paran, RegexBuilder::new(r"^[\[\]\(\)]").case_insensitive(true).build().unwrap()),
(TokenType::Symb, RegexBuilder::new(r"^[^ \n\ta-z0-9_\[\]\(\)]{1,2}").case_insensitive(true).build().unwrap()),
]
});
let mut i = 0;
while !code.is_empty() {
for (token_type, regex) in TOKEN_MATCHERS.iter() {

View file

@ -6,9 +6,12 @@
mod lexer;
mod parser;
mod compiler;
mod runner;
fn test(code: &str) {
use runner::Value;
fn test(code: &str) -> Value {
let tokens = lexer::lex(code);
let tokens: Vec<_> = tokens
.iter()
@ -16,14 +19,11 @@ fn test(code: &str) {
.collect();
let tree = parser::parse(&mut tokens.iter().peekable(), 0);
let result = runner::expr(&tree);
dbg!(result);
dbg!(&result);
result
}
fn main() {
test("123");
test("-123");
test("2 + 3 * 4");
test("(2 + 3) * 4");
// test("math.sin");
// test("math.sin(10 * math.pi)");
test("\"foo\" in [\"fooo\", \"bar\", \"baz\"]");
@ -35,3 +35,28 @@ fn main() {
// test("str.capitalize(\"hello world\")");
// test("\"apple\" in str.split(\"apple banana orange\") ? \"apple exists\" : \"apple doesn\'t exist\"");
}
#[cfg(test)]
mod tests {
use super::{Value, test};
#[test]
fn test_number() {
assert_eq!(test("123"), Value::Number(123.0));
}
#[test]
fn test_negate() {
assert_eq!(test("-123"), Value::Number(-123.0));
}
#[test]
fn test_expr() {
assert_eq!(test("2 + 3 * 4"), Value::Number(14.0));
}
#[test]
fn test_paran() {
assert_eq!(test("(2 + 3) * 4"), Value::Number(20.0));
}
}

View file

@ -1,5 +1,10 @@
use crate::lexer;
#[derive(Debug)]
pub enum ParserError {
InvalidOperator(String),
}
#[derive(Debug)]
pub enum Tree {
Unary { op: String, term: Box<Tree> },
@ -11,6 +16,73 @@ pub enum Tree {
Value { term: String, kind: lexer::TokenType },
}
#[derive(Debug)]
pub enum UnaryOpType {
Negative, Not,
}
#[derive(Debug)]
pub enum BinaryOpType {
Dot, Subtract, Multiply, Power, Divide, Percent, Add,
Equal, NotEqual, GreaterOrEqual, Greater, LessOrEqual, Less,
In, And, Or, Comma,
}
#[derive(Debug)]
pub enum TernaryOpType {
Switch
}
impl TryFrom<&str> for UnaryOpType {
type Error = ParserError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"-" => Ok(UnaryOpType::Negative),
"!" => Ok(UnaryOpType::Not),
_ => Err(ParserError::InvalidOperator(value.to_string())),
}
}
}
impl TryFrom<&str> for BinaryOpType {
type Error = ParserError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"." => Ok(BinaryOpType::Dot),
"-" => Ok(BinaryOpType::Subtract),
"*" => Ok(BinaryOpType::Multiply),
"**" => Ok(BinaryOpType::Power),
"/" => Ok(BinaryOpType::Divide),
"%" => Ok(BinaryOpType::Percent),
"+" => Ok(BinaryOpType::Add),
"==" => Ok(BinaryOpType::Equal),
"!=" => Ok(BinaryOpType::NotEqual),
">=" => Ok(BinaryOpType::GreaterOrEqual),
">" => Ok(BinaryOpType::Greater),
"<=" => Ok(BinaryOpType::LessOrEqual),
"<" => Ok(BinaryOpType::Less),
"in" => Ok(BinaryOpType::In),
"&&" => Ok(BinaryOpType::And),
"||" => Ok(BinaryOpType::Or),
"," => Ok(BinaryOpType::Comma),
_ => Err(ParserError::InvalidOperator(value.to_string())),
}
}
}
impl TryFrom<&str> for TernaryOpType {
type Error = ParserError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"?" => Ok(TernaryOpType::Switch),
_ => Err(ParserError::InvalidOperator(value.to_string())),
}
}
}
pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenType, &str)>>, min_bp: usize) -> Tree {
let mut lhs = match tokens.next().expect("missing token") {
token @ (_, "-") | token @ (_, "!") => Tree::Unary { op: token.1.to_owned(), term: Box::new(parse(tokens, 19)) },
@ -44,7 +116,7 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
tokens.next();
Tree::Array { terms: cons }
},
token @ (lexer::TokenType::Symb, _) => panic!("unexpected token {}", token.1),
token @ (lexer::TokenType::Symbol, _) => panic!("unexpected token {}", token.1),
token @ (_, "in") => panic!("unexpected token {}", token.1),
token @ (kind, _) => Tree::Value { term: token.1.to_owned(), kind: *kind },
};
@ -53,7 +125,7 @@ pub fn parse(tokens: &mut std::iter::Peekable<std::slice::Iter<&(lexer::TokenTyp
let Some(next) = tokens.peek() else { break };
match next {
(_, ")") | (_, "]") | (_, ",") | (_, ":") => break,
(lexer::TokenType::Symb, _) | (lexer::TokenType::Paran, _) | (_, "in") => {},
(lexer::TokenType::Symbol, _) | (lexer::TokenType::Paran, _) | (_, "in") => {},
(_, s) => panic!("unexpected token {}", s),
};
let Some((left_bp, right_bp)) = get_bp(next.1) else { panic!("invalid symbol") };

View file

@ -153,10 +153,10 @@ pub fn expr(tree: &parser::Tree) -> Value {
}
},
Tree::Array { terms } => {
if terms.len() == 0 {
if terms.is_empty() {
Value::Array { kind: ValueType::Number, values: vec![] }
} else {
let values: Vec<_> = terms.iter().map(|t| expr(t)).collect();
let values: Vec<_> = terms.iter().map(expr).collect();
let kind = values[0].get_type();
Value::Array { kind, values }
}