diff --git a/.gitignore b/.gitignore
index 088ba6b..b73286e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,6 @@ Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
+
+# vscode
+/.vscode/
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..d085ce7
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "uwucode"
+version = "0.1.0"
+authors = ["Sai kumar Murali krishnan
+
+
+ A language based around egirl slang...
+
+
+
+
+
uwucode
+
+
+ Explore the docs »
+
+
+ Report Bug / Request Feature
+
This is the documentation for uwucode
.
+owo var_name = value;
"+""+(item.is_alias===true?(""+item.alias+" - see "):"")+item.displayPath+""+name+" | "+""+""+escape(item.desc)+" |
"+code.outerHTML+" |
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ * -> vec
)","Search multiple things at once by splitting your query with comma (e.g., \
+ str,u8
or String,struct:Vec,test
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");var div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +
+use super::eval::Object; +use std::collections::HashMap; + +pub struct Env { + pub env: HashMap<String, Object>, +} + +impl Env { + pub fn new() -> Self { + Env { + env: HashMap::new(), + } + } + + pub fn set(&mut self, key: String, value: Object) { + self.env.insert(key, value); + } + + pub fn get(&self, key: &str) -> Option<Object> { + self.env.get(key).map(|val| val.clone()) + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +
+use crate::parser::ast::Statement; +use crate::parser::ast::Expr; +use crate::parser::ast::Operator; +use crate::parser::ast::Prefix; + +pub use super::env::Env; + +#[derive(Debug, PartialEq, Clone)] +pub enum Object { + Null, + Integer(i64), + String(String), + Boolean(bool), + Return(Box<Object>), + Function { + parameters: Vec<String>, + body: Vec<Statement>, + }, +} + +fn eval_expr(expression: Expr, env: &mut Env) -> Object { + match expression { + Expr::String(string) => Object::String(string), + Expr::Integer(num) => Object::Integer(num), + Expr::Boolean(val) => Object::Boolean(val), + Expr::Prefix { + prefix: Prefix::Bang, + value: expr, + } => match eval_expr(*expr, env) { + Object::Boolean(val) => Object::Boolean(!val), + _ => panic!("! operator only valid for boolean type"), + }, + Expr::Prefix { + prefix: Prefix::Minus, + value: expr, + } => match eval_expr(*expr, env) { + Object::Integer(val) => Object::Integer(-val), + _ => panic!("minus operator only valid for integer type"), + }, + Expr::Infix { + left, + operator: Operator::Plus, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Integer(left + right), + (Object::String(left), Object::String(right)) => Object::String(left + &right), + _ => panic!("plus operator used on invalid types"), + }, + Expr::Infix { + left, + operator: Operator::Minus, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Integer(left - right), + _ => panic!("minus operator only valid on integer types"), + }, + Expr::Infix { + left, + operator: Operator::Multiply, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Integer(left * right), + _ => panic!("multiply operator only valid on integer types"), + }, + Expr::Infix { + left, + operator: Operator::Divide, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Integer(left / right), + _ => panic!("divide operator only valid on integer types"), + }, + Expr::Infix { + left, + operator: Operator::LessThan, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Boolean(left < right), + _ => panic!("less than operator only valid on integer types"), + }, + Expr::Infix { + left, + operator: Operator::GreaterThan, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Boolean(left > right), + _ => panic!("greater than operator only valid on integer types"), + }, + Expr::Infix { + left, + operator: Operator::Equals, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Boolean(left == right), + (Object::Boolean(left), Object::Boolean(right)) => Object::Boolean(left == right), + _ => panic!("equals operator used on invalid types"), + }, + Expr::Infix { + left, + operator: Operator::NotEquals, + right, + } => match (eval_expr(*left, env), eval_expr(*right, env)) { + (Object::Integer(left), Object::Integer(right)) => Object::Boolean(left != right), + (Object::Boolean(left), Object::Boolean(right)) => Object::Boolean(left != right), + _ => panic!("not equals operator used on invalid types"), + }, + Expr::If { + condition, + consequence, + alternative, + } => { + if eval_expr(*condition, env) == Object::Boolean(true) { + eval_statements(consequence, env) + } else { + eval_statements(alternative, env) + } + } + Expr::Variable(name) => env.get(&name).expect("attempted access to invalid binding"), + Expr::Function { parameters, body } => Object::Function { parameters, body }, + Expr::Call { + function, + arguments, + } => { + let (parameters, body) = match *function { + Expr::Variable(func_name) => match env.get(&func_name) { + Some(Object::Function { parameters, body }) => (parameters, body), + None => { + let arguments = arguments + .into_iter() + .map(|expr| eval_expr(expr, env)) + .collect(); + println!("{:?}", arguments); + println!("{:?}", env.get(&"fn")); + return eval_builtin(&func_name, arguments) + .expect("error calling function"); + } + _ => panic!("attempted to call non-function"), + }, + Expr::Function { parameters, body } => (parameters, body), + _ => panic!("attempted to call non-function"), + }; + + // run user defined function + assert_eq!( + parameters.len(), + arguments.len(), + "called function with wrong number of parameters" + ); + + let mut env_func = Env::new(); + for (parameter, arg_value) in parameters.into_iter().zip(arguments.into_iter()) { + env_func.set(parameter, eval_expr(arg_value, env)); + } + + eval_return_scope(body, &mut env_func) + } + } +} + +fn eval_builtin(func_name: &str, arguments: Vec<Object>) -> Option<Object> { + println!("{:?}", arguments.as_slice()); + println!("AS"); + match (func_name, arguments.as_slice()) { + ("len", [Object::String(string)]) => Some(Object::Integer(string.len() as i64)), + _ => None, + } +} + +fn eval_statement(statement: Statement, env: &mut Env) -> Object { + match statement { + Statement::Expression(expr) => eval_expr(expr, env), + Statement::Let { name, value } => { + let value = eval_expr(value, env); + + env.set(name, value.clone()); + value + }, + Statement::Define {func_name, func} => { + let value = eval_expr(func,env); + + env.set(func_name, value.clone()); + value + + } + Statement::Return { value: expr } => Object::Return(Box::new(eval_expr(expr, env))), + } +} + +/// similar to eval_return_scope but doesn't unwrap Return types +/// useful for if-else blocks where the return should return from the parent scope as well +fn eval_statements(statements: Vec<Statement>, env: &mut Env) -> Object { + let mut result = Object::Null; + + for statement in statements { + result = eval_statement(statement, env); + + if let &Object::Return(_) = &result { + return result; + } + } + + result +} + +pub fn eval_return_scope(statements: Vec<Statement>, env: &mut Env) -> Object { + let result = eval_statements(statements, env); + + match result { + // unwrap Return type + Object::Return(res) => *res, + _ => result, + } +} +
1 +2 +
+pub mod env; +pub mod eval; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +
+use crate::token::token::{Token,lookup_ident}; +use ::std::iter::Peekable; +use std::str; +use std::str::Chars; + +pub struct Lexer<'a> { + /* + Takes in a string then stores its iterator. + Info: <'a> indicates a speciifed lifetime. + */ + pub chr_iter: Peekable<Chars<'a>>, +} + +impl<'a> Lexer<'a> { + pub fn read_char(&mut self) -> Option<char> { + // Returns the next item in the iterator. + return self.chr_iter.next(); + } + + pub fn new(file_string: &'a str) -> Lexer<'a> { + return Lexer { + chr_iter: file_string.chars().peekable(), + }; + } + + pub fn skip_whitespace(&mut self) { + while let Some(&chr) = self.chr_iter.peek() { + if chr.is_whitespace() { + self.chr_iter.next(); + } else { + break; + } + } + } + + pub fn read_identifier(&mut self, first_letter: char) -> String { + let mut expression: String = String::from(first_letter); + + // Peek at top element, determine if alphabetic then add. + while let Some(&chr) = self.chr_iter.peek() { + if chr.is_alphabetic() || chr == '=' { + expression.push(self.read_char().unwrap()); + } else { + break; + } + } + return expression; + } + + pub fn read_string(&mut self) -> String { + let mut expression: String = String::new(); + + // Peek at top element, determine if alphabetic then add. + while let Some(&chr) = self.chr_iter.peek() { + if chr == '"' { + break; + } else { + expression.push(self.read_char().unwrap()); + } + } + return expression; + } + + pub fn read_number(&mut self, first_chr: char) -> i64 { + let mut expression: String = String::from(first_chr); + + while let Some(&chr) = self.chr_iter.peek() { + if char::is_digit(chr, 10) { + expression.push(self.read_char().unwrap()); + } else { + break; + } + } + + return expression.parse().unwrap(); + } + + pub fn next_token(&mut self) -> Token { + self.skip_whitespace(); + + match self.read_char() { + // = first, into ASSIGN and EQUAL + Some('=') => { + // Comparison operator + if self.chr_iter.peek().unwrap() == &'=' { + self.read_char(); + return Token::EQ; + } else { + return Token::ASSIGN; + } + } + Some(',') => Token::COMMA, + Some(';') => Token::SEMICOLON, + Some('+') => Token::PLUS, + Some('-') => Token::MINUS, + Some('*') => Token::ASTERISK, + Some('/') => Token::SLASH, + + Some('(') => Token::LPAR, + Some(')') => Token::RPAR, + Some('{') => Token::LBRA, + Some('}') => Token::RBRA, + + Some('>') => { + if self.chr_iter.peek().unwrap() == &'=' { + self.read_char(); + return Token::GEQ; + } else { + return Token::GE; + } + } + + Some('<') => { + if self.chr_iter.peek().unwrap() == &'=' { + self.read_char(); + return Token::LEQ; + } else { + return Token::LE; + } + } + + Some('!') => { + if self.chr_iter.peek().unwrap() == &'=' { + self.read_char(); + return Token::NEQ; + } else { + return Token::BANG; + } + } + + None => Token::EOF, + + Some('"') => { + self.read_char(); + Token::STRING(self.read_string()) + } + + // Deal with expressions and primitives + Some(chr) => { + if chr.is_alphabetic() { + // Converts to either keyword or identifier + let token = self.read_identifier(chr); + return lookup_ident(&token as &str); + } + // Could be an integer + else if char::is_digit(chr, 10) { + return Token::INT(self.read_number(chr)); + } + // Nope, just ignore it + else { + return Token::ILLEGAL(String::from(chr)); + } + } + } + } + + pub fn lex(&mut self) -> Vec<Token> { + let mut token_vec: Vec<Token> = Vec::new(); + + loop { + match self.chr_iter.peek() { + None => break, + _ => token_vec.push(self.next_token()), + } + } + // Important, I'm reversing the list because implementation from the back is much better in terms of time complexity. Pop better than remove. + token_vec.reverse(); + return token_vec; + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +
+/*
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+ #[test]
+ fn test_tokens()
+ {
+ let input:&str = "=+(){},;";
+ struct testing_struct {
+ token_vec: Vec<(token::token_type,&'static str)>
+ }
+
+ let tests:testing_struct = testing_struct{
+ token_vec: vec![
+ (token.ASSIGN,"=")]
+ };
+ assert!(token_vec[0][1]=="=");
+ }
+}*/
+
1 +2 +
+pub mod lexer; +pub mod lexer_test; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +
+mod eval; +mod lexer; +mod parser; +mod repl; +mod tests; +mod token; + +fn main() { + println!("uwu *nuzzles* wewcome to uwucode! Is for me..? 🥺👉👈"); + repl::repl::start(); +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +
+use crate::token::token:: {Token}; + +#[derive(Debug, Clone, PartialEq)] +pub enum Statement { + Let { name: String, value: Expr }, + Define { func_name: String, func: Expr }, + Return { value: Expr }, + Expression(Expr), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Expr { + String(String), + Variable(String), + Boolean(bool), + Integer(i64), + Prefix { + prefix: Prefix, + value: Box<Expr>, + }, + Infix { + left: Box<Expr>, + operator: Operator, + right: Box<Expr>, + }, + If { + condition: Box<Expr>, + consequence: Vec<Statement>, + alternative: Vec<Statement>, + }, + Function { + parameters: Vec<String>, + body: Vec<Statement>, + }, + Call { + function: Box<Expr>, + arguments: Vec<Expr>, + }, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum Prefix { + Bang, + Minus, +} + +#[derive(PartialOrd, PartialEq,Debug)] +pub enum Precedence { + Lowest, + Equals, + LessGreater, + Sum, + Product, + Prefix, +} +#[derive(Debug, Clone, PartialEq)] +pub enum Operator { + Plus, + Minus, + Multiply, + Divide, + GreaterThan, + LessThan, + Equals, + NotEquals, +} + +impl Token { + pub fn priority(&self) -> Precedence { + match self { + Token::PLUS => Precedence::Sum, + Token::MINUS => Precedence::Sum, + Token::SLASH => Precedence::Product, + Token::ASTERISK => Precedence::Product, + Token::LEQ => Precedence::LessGreater, + Token::LE => Precedence::LessGreater, + Token::GEQ => Precedence::LessGreater, + Token::GE => Precedence::LessGreater, + Token::EQ => Precedence::Equals, + Token::NEQ => Precedence::Equals, + _ => Precedence::Lowest, + } + } +} +
1 +2 +
+pub mod ast; +pub mod parser; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +
+use crate::parser::ast::{Expr, Operator, Precedence, Prefix, Statement}; +use crate::token::token::Token; + +pub fn parse(input: &mut Vec<Token>) -> Vec<Statement> { + /* + This function should be able to parse the following: + + Primitives into primitives (duh) + variables + + */ + let mut statements = vec![]; + + // Process each statement here + loop { + let top_token = match input.last() { + Some(token) => token, + None => panic!("fuck, the token vec is empty"), + }; + + + // We need to check against six possible cases: + /* + - Let statements + - Function defining + - EOF token + - Expression + - Right braces + - Returns + */ + match top_token { + Token::EOF => break, // We've reached the end of line or file + Token::LET => parse_let(input, &mut statements), // Define a variable + Token::FUNCTION => parse_function(input, &mut statements), // Define a function + Token::RBRA => break, // We've reached the end of an enclosing + Token::RETURN => parse_return(input, &mut statements), + _ => statements.push(Statement::Expression(parse_expression( + input, + Precedence::Lowest, + ))), // Deal with an expression + } + + + // Since the subcalls modify the vector of tokens, we should reach a semicolon at the end. + // THE BACK OF THE VECTOR IS THE TOP LIKE A STACK LOL + + + assert_eq!(input.pop(), Some(Token::SEMICOLON)); + } + + return statements; +} + +fn parse_let(input: &mut Vec<Token>, statements: &mut Vec<Statement>) { + /* + We need to look at our enum here. Let {name:String, value: Expr}. When we encounter a let, we need to pop it off the grill. + LET STRING = THING (in uwu speak, its owo STRING = THING) + */ + assert_eq!(input.pop(), Some(Token::LET)); // Sanity Check duhs + + // wtfs going on here lol, double enum extraction + let var_name: String = match input.pop() { + Some(Token::IDENT(var)) => var, + _ => panic!("Uh we don't have a string strangely"), + }; + + // We're at = stage + assert_eq!(input.pop(), Some(Token::ASSIGN)); + // Now we're at the expression eval stage, leave it to parse expr + let value = parse_expression(input, Precedence::Lowest); + statements.push(Statement::Let { + name: var_name, + value, + }); +} + +fn parse_return(input: &mut Vec<Token>, statements: &mut Vec<Statement>) { + /* + Let's have a look at our Return enum now. Return {value:Expr} which means + we need to just parse the expression. + */ + assert_eq!(input.pop(), Some(Token::RETURN)); + // Now evaluate the expression + let value = parse_expression(input, Precedence::Lowest); + statements.push(Statement::Return { value }); +} + +fn parse_function(input: &mut Vec<Token>, statements: &mut Vec<Statement>) { + /* + Lets have a look at the Define enum, iu + + Ideal structure looks like this: + + DEFINE FUNCTIONNAME(args..) { + body + } + in uwu code: + uwu funcName(args) { + body + } + */ + assert_eq!(input.pop(), Some(Token::FUNCTION)); + + // Next thing is the function name, add it in + let func_name: String = match input.pop() { + Some(Token::IDENT(name)) => name, + a => panic!("Huh, we didnt get a string, instead I got {:?}", a), + }; + + // Now we're at args, first thing is the LPAR + assert_eq!(input.pop(), Some(Token::LPAR)); + + // Arguments here + let mut parameters = vec![]; + + loop { + match input.pop() { + Some(Token::RPAR) => break, + Some(Token::IDENT(var)) => { + // Find an arg, add then proceed + parameters.push(var); // push to vec list + match input.pop() { + Some(Token::RPAR) => break, + Some(Token::COMMA) => continue, + _ => panic!("Object after param was not comma or bracket"), + }; + } + _ => panic!("Object after param was not comma or bracket"), + } + } + + // We've reached the end of args, now parse body + assert_eq!(input.pop(), Some(Token::LBRA)); // { + let body = parse(input); // will return code of inside + assert_eq!(input.pop(), Some(Token::RBRA)); // } + + statements.push(Statement::Define { + func_name, + func: Expr::Function { parameters, body }, + }); +} + +fn parse_expression(input: &mut Vec<Token>, precedence: Precedence) -> Expr { + let mut left_expr = match input.pop() { + Some(val) => { + + match val { + + // This is a Token type + // Primitives + Token::INT(value) => Expr::Integer(value), + Token::TRUE => Expr::Boolean(true), + Token::FALSE => Expr::Boolean(false), + Token::IDENT(value) => { + if input.last() == Some(&Token::LPAR) + { + input.pop(); + let mut args = vec![]; + + loop { + match input.last() { + Some(Token::RPAR) => { + input.pop(); + break; + }, + None => panic!("weird stuff happened"), + _ => args.push(parse_expression(input, Precedence::Lowest)), + } + + match input.pop() { + Some(Token::RPAR) => break, + Some(Token::COMMA) => continue, + _ => panic!("Unexpected parameter"), + } + } + Expr::Call { + function: Box::new(Expr::Variable(value)), + arguments:args + } + } + else { + Expr::Variable(value) + } + + } + Token::STRING(value) => Expr::String(value), + + // Prefix types [A B] + Token::BANG => Expr::Prefix { + prefix: Prefix::Bang, + value: Box::new(parse_expression(input, Precedence::Prefix)), + }, + + Token::MINUS => Expr::Prefix { + prefix: Prefix::Minus, + value: Box::new(parse_expression(input, Precedence::Prefix)), + }, + + // conditional + Token::IF => { + assert_eq!(Some(Token::LPAR), input.pop()); + let condition = parse_expression(input, Precedence::Lowest); + assert_eq!(Some(Token::RPAR), input.pop()); + + // Parse body + assert_eq!(Some(Token::LBRA), input.pop()); + let consequence = parse(input); + assert_eq!(Some(Token::RBRA), input.pop()); + + let alternative = if input.last() == Some(&Token::ELSE) { + // ELSE CONDITION + input.pop(); + assert_eq!(Some(Token::LBRA), input.pop()); + let alternative = parse(input); + assert_eq!(Some(Token::RBRA), input.pop()); + alternative + } else { + Vec::new() + }; + + Expr::If { + condition: Box::new(condition), + consequence, + alternative, + } + } + + // Error + _ => panic!("Parser error: Not recognized!"), + } + } + _ => panic!("The vector is empty"), + }; + + while precedence < input.last().unwrap().priority() { + + left_expr = parse_infix(left_expr, input); + } + + left_expr +} + +fn parse_infix(left: Expr, input: &mut Vec<Token>) -> Expr { + let next_token = match input.pop() { + Some(value) => value, + None => panic!("Empty list..."), + }; + + let operator = match next_token { + Token::PLUS => Operator::Plus, + Token::MINUS => Operator::Minus, + Token::SLASH => Operator::Divide, + Token::ASTERISK => Operator::Multiply, + Token::LEQ => Operator::LessThan, + Token::LE => Operator::LessThan, + Token::GEQ => Operator::GreaterThan, + Token::GE => Operator::GreaterThan, + Token::EQ => Operator::Equals, + Token::NEQ => Operator::NotEquals, + _ => panic!("parse infix called on invalid operator"), + }; + + Expr::Infix { + left: Box::new(left), + operator, + right: Box::new(parse_expression(input, next_token.priority())), + } +} +
1
+
+pub mod repl; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +
+use crate::eval::eval::{eval_return_scope, Env, Object}; +use crate::lexer::lexer::Lexer; +use crate::parser::parser::{parse}; +use ::std::io::Write; +use std::io; + +//use colored::*; + +const PROMPT: &str = "( ᴜ ω ᴜ )⭜"; + +pub fn start() { + let mut env = Env::new(); + loop { + print!("{} ", PROMPT);//.truecolor(255, 69, 0)); + std::io::stdout().flush().expect("Flushing failed"); + let mut user_in: String = String::new(); + io::stdin().read_line(&mut user_in).expect("Could not read"); + let mut lexer = Lexer::new(&user_in as &str); + let mut token_vec = lexer.lex(); + + let parsed = parse(&mut token_vec); + //println!("{:?}",parsed); + display_object(eval_return_scope(parsed, &mut env)); + } +} + +fn display_object(obj: Object) { + match obj { + Object::Integer(num) => println!("{}", num), + Object::String(string) => println!("{}", string), + Object::Boolean(val) => match val { + true=> println!("truwu"), + false=> println!("fowose"), + }, + Object::Function { + parameters: _, + body: _, + } => println!("function"), + Object::Null => println!("null"), + Object::Return(obj) => display_object(*obj), + } +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +
+ + + +#[cfg(test)] +mod tests { + use crate::lexer; + use crate::token::token:: {Token}; + #[test] + fn test_token_basic() { + let input: &str = "=+(){},;"; + struct TestingStruct { + token_vec: Vec<Token>, + } + let mut test_lexer = lexer::lexer::Lexer::new(input); + + let tests: TestingStruct = TestingStruct { + token_vec: vec![ + Token::ASSIGN, + Token::PLUS, + Token::LPAR, + Token::RPAR, + Token::LBRA, + Token::RBRA, + Token::COMMA, + Token::SEMICOLON, + ], + }; + for test in tests.token_vec.iter() { + let current_token = test_lexer.next_token(); + assert_eq!(test, ¤t_token); + } + } + + #[test] + fn test_token_strings() { + let input: &str = "owo five = 5; + owo ten = 10; + owo add = uwu(x,y) { + x+y; + }; + "; + struct TestingStruct { + token_vec: Vec<Token>, + } + let mut test_lexer = lexer::lexer::Lexer::new(input); + + let tests: TestingStruct = TestingStruct { + token_vec: vec![ + Token::LET, + Token::IDENT(String::from("five")), + Token::ASSIGN, + Token::INT(5), + Token::SEMICOLON, + Token::LET, + Token::IDENT(String::from("ten")), + Token::ASSIGN, + Token::INT(10), + Token::SEMICOLON, + Token::LET, + Token::IDENT(String::from("add")), + Token::ASSIGN, + Token::FUNCTION, + Token::LPAR, + Token::IDENT(String::from("x")), + Token::COMMA, + Token::IDENT(String::from("y")), + Token::RPAR, + Token::LBRA, + Token::IDENT(String::from("x")), + Token::PLUS, + Token::IDENT(String::from("y")), + Token::SEMICOLON, + Token::RBRA, + Token::SEMICOLON, + ], + }; + for test in tests.token_vec.iter() { + let current_token = test_lexer.next_token(); + assert_eq!(test, ¤t_token); + } + } +} +
1
+
+pub mod token; +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +
+pub fn lookup_ident(ident: &str) -> Token { + match ident { + "uwu" => Token::FUNCTION, + "owo" => Token::LET, + "nuzzles" => Token::IF, + "dab" => Token::ELIF, + "rawr" => Token::ELSE, + "sugoi" => Token::RETURN, + "truwu" => Token::TRUE, + "fowose" => Token::FALSE, + _ => Token::IDENT(String::from(ident)), + } +} + +#[derive(PartialEq, Clone, Debug)] +pub enum Token { + ILLEGAL(String), + EOF, + IDENT(String), + + ASSIGN, + PLUS, + MINUS, + ASTERISK, + SLASH, + + EQ, + LEQ, + LE, + GEQ, + GE, + NEQ, + + COMMA, + SEMICOLON, + + LPAR, + RPAR, + LBRA, + RBRA, + + BANG, + + FUNCTION, + LET, + RETURN, + + IF, + ELIF, + ELSE, + + INT(i64), + STRING(String), + TRUE, + FALSE, +} +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +
+/// token docs + +pub mod token { + +pub fn lookup_ident(ident: &str) -> Token { + + match ident { + "uwu" => Token::FUNCTION, + "owo" => Token::LET, + "nuzzles" => Token::IF, + "dab" => Token::ELIF, + "rawr" => Token::ELSE, + "sugoi" => Token::RETURN, + "truwu" => Token::TRUE, + "fowose" => Token::FALSE, + _ => Token::IDENT(String::from(ident)), + } +} + +#[derive(PartialEq, Clone, Debug)] +pub enum Token { + ILLEGAL(String), + EOF, + IDENT(String), + + ASSIGN, + PLUS, + MINUS, + ASTERISK, + SLASH, + + EQ, + LEQ, + LE, + GEQ, + GE, + NEQ, + + COMMA, + SEMICOLON, + + LPAR, + RPAR, + LBRA, + RBRA, + + BANG, + + FUNCTION, + LET, + RETURN, + + IF, + ELIF, + ELSE, + + INT(i64), + STRING(String), + TRUE, + FALSE, +} +}
token | token docs + |
ILLEGAL(String)
IDENT(String)
INT(i64)
STRING(String)
impl Clone for Token
[src]impl Debug for Token
[src]impl PartialEq<Token> for Token
[src]impl StructuralPartialEq for Token
[src]impl RefUnwindSafe for Token
impl Send for Token
impl Sync for Token
impl Unpin for Token
impl UnwindSafe for Token
impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+fn to_owned(&self) -> T
[src]fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]pub fn lookup_ident(ident: &str) -> Token
token docs
+Token |
lookup_ident |