├── Cargo.toml ├── src ├── test │ ├── test_parser.pst │ └── test_eval.pst ├── ast.rs ├── main.rs ├── pistolet.pest ├── parser.rs └── interpreter.rs ├── readme.md ├── LICENSE └── .gitignore /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pistolet" 3 | version = "0.1.0" 4 | authors = ["MisakaCenter "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | pest = "^2.1.0" 9 | pest_derive = "^2.1.0" 10 | lazy_static = "^1.4.0" 11 | colored = "^2" 12 | stacker = "0.1" -------------------------------------------------------------------------------- /src/test/test_parser.pst: -------------------------------------------------------------------------------- 1 | fun foo (X: nat)(Y : bool) -> bool { 2 | let x: bool = true. 3 | return x. 4 | } 5 | 6 | loop { 7 | return foo(1, true). 8 | }~> (1 =? 1) 9 | 10 | if (b && true) 11 | {let x: nat = y. let x: nat = y. return 1.} 12 | {let x: nat = y. return x+y.} 13 | 14 | let y: bool = (true =? true) && true ~&& x. 15 | 16 | let x: int = 1 + xx - 1. 17 | 18 | let y: nat = -2.1 + 10 + 1 * 1 / 2 - 3. 19 | 20 | let b: bool = true && false || true. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Pistolet (WIP) 2 | 3 | 🔫 Elegant ML-like Imperative Programming Language 4 | 5 | ### Basic 6 | 7 | - [x] Abstract Syntax Tree 8 | - [x] Lexer 9 | - [x] Parser 10 | - [x] Interpreter 11 | - [x] Syntax 12 | - [x] Let (Var binding) 13 | - [x] If (control flow) 14 | - [x] Loop (control flow) 15 | - [x] Function Definition (Function binding) 16 | - [x] Evaluation 17 | - [x] Int, Float and Boolean Evaluation 18 | - [x] const 19 | - [x] var 20 | - [x] Function Call Evaluation 21 | - [ ] Compile to LLVM IR 22 | - [ ] Static Analysis (Visualize Control Flow Graph) 23 | - [ ] Compiler Optimization 24 | - [ ] Interpreter Optimization (Stack Overflow) 25 | 26 | ### Language Feature 27 | 28 | - [ ] Type Definition 29 | - [ ] Pattern Match 30 | 31 | ### Integrated Development Environment 32 | 33 | - [ ] Code Highlight in VS Code 34 | - [ ] Type Inference 35 | 36 | ### Document 37 | 38 | - [ ] Language BNF 39 | - [ ] Syntax & Grammar Tutorial 40 | - [ ] Examples -------------------------------------------------------------------------------- /src/test/test_eval.pst: -------------------------------------------------------------------------------- 1 | fun fib (n: int) -> int { 2 | if (n =? 0) { 3 | return 0. 4 | } { 5 | if (n =? 1) { 6 | return 1. 7 | } { 8 | return fib(n-1) + fib(n-2). 9 | } 10 | } 11 | } 12 | 13 | let i: int = 0. 14 | loop{ 15 | let i: int = i + 1. 16 | println(fib(i)). 17 | }~>(i =? 10) 18 | 19 | fun factorial (n: int) -> int { 20 | if (n =? 1) { 21 | return 1. 22 | } { 23 | return n * factorial(n - 1). 24 | } 25 | } 26 | 27 | println(factorial(10)). 28 | 29 | let if_dec : bool = false. 30 | 31 | let k : int = 0. 32 | loop{ 33 | let k : int = k + 1. 34 | let k1 : int = 0. 35 | loop{ 36 | let k1 : int = k1 + 1. 37 | println(k1). 38 | }~>(k1 =? 5) 39 | }~>(k =? 5) 40 | 41 | fun foo (xx: int)(yy : bool) -> bool { 42 | println(xx). 43 | return yy. 44 | } 45 | 46 | let y : int = 100. 47 | 48 | let x : bool = foo(y + 1, true). 49 | 50 | println(x). 51 | 52 | if if_dec { 53 | return(114). 54 | } { 55 | return(514). 56 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Hanzhi Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/ast.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | enum PistoletValue { 3 | Integer(i128), 4 | Float(f64), 5 | Boolean(bool), 6 | Var(String), 7 | Funcall(String, Vec), 8 | } 9 | 10 | #[derive(Debug, Clone)] 11 | enum PistoletExpr { 12 | Val(PistoletValue), 13 | Add(Box, Box), 14 | Sub(Box, Box), 15 | Mul(Box, Box), 16 | Div(Box, Box), 17 | And(Box, Box), 18 | Orb(Box, Box), 19 | Nand(Box, Box), 20 | Eq(Box, Box), 21 | Leq(Box, Box), 22 | Req(Box, Box), 23 | Left(Box, Box), 24 | Right(Box, Box) 25 | } 26 | 27 | #[derive(Debug, Clone)] 28 | enum PistoletAST { 29 | Seq(Vec), 30 | Let(String, String, PistoletExpr), 31 | If(PistoletExpr, Box, Box), 32 | While(Box, PistoletExpr), 33 | Return(PistoletExpr), 34 | Varbind(String, String), 35 | Paralist(Vec), 36 | Fun(String, Box, String, Box), 37 | PrintLine(PistoletExpr), 38 | EOI, 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,rust 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,rust 5 | 6 | ### Linux ### 7 | *~ 8 | 9 | # temporary files which can be created if a process still has a handle open of a deleted file 10 | .fuse_hidden* 11 | 12 | # KDE directory preferences 13 | .directory 14 | 15 | # Linux trash folder which might appear on any partition or disk 16 | .Trash-* 17 | 18 | # .nfs files are created when an open file is removed but is still being accessed 19 | .nfs* 20 | 21 | ### Rust ### 22 | # Generated by Cargo 23 | # will have compiled files and executables 24 | /target/ 25 | 26 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 27 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 28 | Cargo.lock 29 | 30 | ### VisualStudioCode ### 31 | .vscode/* 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | *.code-workspace 35 | 36 | ### VisualStudioCode Patch ### 37 | # Ignore all local history of files 38 | .history 39 | .ionide 40 | 41 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,rust 42 | 43 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 44 | 45 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | include!("parser.rs"); 2 | include!("interpreter.rs"); 3 | 4 | use colored::*; 5 | use std::fs; 6 | 7 | fn main() { 8 | println!("{}", "[Test] Parser Test Begin!".green()); 9 | let file_path = "src/test/test_parser.pst"; 10 | match parse_to_ast(&fs::read_to_string(file_path).expect("cannot read file")) { 11 | Ok(_) => println!("{}", "[Test] Parser Test Passed!".green()), 12 | Err(_) => { 13 | println!("{}", "[Failed] Parser Test Failed!".red()); 14 | return; 15 | } 16 | } 17 | println!("{}", "[Test] Interpreter Test Begin!".green()); 18 | let file_path = "src/test/test_eval.pst"; 19 | let eval_result; 20 | let unparsed_file = fs::read_to_string(file_path).expect("cannot read file"); 21 | let state = ProgStates::new(); 22 | let mut func_list = FuncDic::new(); 23 | eval_result = ast_eval(parse_to_ast(&unparsed_file).unwrap(), state, &mut func_list); 24 | 25 | match eval_result { 26 | Ok((result, _)) => result.print(), 27 | Err(err_code) => match err_code { 28 | RuntimeErr::ReturnValue(expr_value) => println!( 29 | "[Return] Exit with {} : {}", 30 | expr_value.get_type(), 31 | expr_value.get_value() 32 | ), 33 | _ => err_code.print(), 34 | }, 35 | } 36 | println!("{}", "[Test] Interpreter Test Passed!".green()); 37 | } 38 | -------------------------------------------------------------------------------- /src/pistolet.pest: -------------------------------------------------------------------------------- 1 | program = { SOI ~ sentence+ ~ EOI | SOI ~ EOI} 2 | 3 | sentence = { 4 | (FUN | LET | WHILE | IF | RETURN | PrintLine) 5 | } 6 | 7 | TERM = { 8 | "{" ~ 9 | (FUN | LET | WHILE | IF | RETURN | PrintLine)+ 10 | ~ "}" 11 | } 12 | 13 | PrintLine = { 14 | "println" ~ "(" ~ EXPR_Noty_A ~ ")" ~ "." 15 | } 16 | 17 | 18 | FUN_CALL = { 19 | FUN_NAME ~ "(" ~ EXPR_Noty_A ~ ("," ~ EXPR_Noty_A)* ~ ")" 20 | } 21 | 22 | EXPR_Noty_A = _{ 23 | EXPR_NoTy | NONE 24 | } 25 | 26 | EXPR_NoTy = { 27 | EQ_EXPR | (EXPR_NoTy_T ~ ((and | or | nand | add | sub | mul | div) ~ EXPR_NoTy_T)*) 28 | } 29 | 30 | EXPR_NoTy_T = _{ 31 | ( ("(" ~ EXPR_NoTy ~ ")") | (BOOL_VALUE | VALUE) | EQ_EXPR ) 32 | } 33 | 34 | EXPR_A = _{ 35 | BOOL_EXPR | EXPR | NONE 36 | } 37 | 38 | NONE = { 39 | "" 40 | } 41 | 42 | BOOL_EXPR = { 43 | EQ_EXPR | BOOL_EXPR_T ~ ((and | or | nand) ~ BOOL_EXPR_T)* 44 | } 45 | 46 | BOOL_EXPR_T = _{ 47 | ( ("(" ~ BOOL_EXPR ~ ")") | BOOL_VALUE | EQ_EXPR ) 48 | } 49 | 50 | EQ_EXPR = { 51 | EXPR ~ (eq | lefteq | left | righteq | righteq) ~ EXPR 52 | } 53 | 54 | EXPR = { 55 | EXPR_T ~ ((add | sub | mul | div) ~ EXPR_T)* 56 | } 57 | 58 | BOOL_VALUE = { 59 | FUN_CALL | BOOL | VAR_NAME 60 | } 61 | 62 | VALUE = { 63 | FUN_CALL | FLOAT | INTEGER | VAR_NAME 64 | } 65 | 66 | EXPR_T = _{ 67 | ("(" ~ EXPR ~ ")") | VALUE 68 | } 69 | 70 | PARA_LIST = { 71 | ("(" ~ VAR_BIND ~ ")")+ 72 | } 73 | 74 | VAR_BIND = { 75 | VAR_NAME ~ ":" ~ TYPE_NAME 76 | } 77 | 78 | RETURN = { 79 | "return" ~ EXPR_Noty_A ~ "." 80 | } 81 | 82 | FUN = { 83 | "fun" ~ FUN_NAME ~ PARA_LIST ~ "->" ~ TYPE_NAME ~ TERM 84 | } 85 | 86 | LET = { 87 | "let" ~ VAR_NAME ~ ":" ~ TYPE_NAME ~ "=" ~ EXPR_Noty_A ~ "." 88 | } 89 | 90 | WHILE = { 91 | "loop" ~ TERM ~ "~>" ~ BOOL_EXPR 92 | } 93 | 94 | IF = { 95 | "if" ~ BOOL_EXPR ~ TERM ~ TERM 96 | } 97 | 98 | BOOL = { "true" | "false" } 99 | 100 | alpha = { 'a'..'z' | 'A'..'Z' } 101 | 102 | digit = { '0'..'9' } 103 | 104 | int = @{ digit+ } 105 | 106 | add = { "+" } 107 | 108 | sub = { "-" } 109 | 110 | mul = { "*" } 111 | 112 | div = { "/" } 113 | 114 | and = { "&&" } 115 | 116 | or = { "||" } 117 | 118 | nand = { "~&&" } 119 | 120 | eq = { "=?" } 121 | 122 | lefteq = { "<=" } 123 | 124 | righteq = { ">=" } 125 | 126 | left = { "<" } 127 | 128 | right = { ">" } 129 | 130 | FUN_NAME = @{ (alpha | "_") ~ (alpha | digit | "_")* } 131 | 132 | TYPE_NAME = @{ (alpha | "_") ~ (alpha | digit | "_")* } 133 | 134 | VAR_NAME = @{ (alpha | "_") ~ (alpha | digit | "_")* } 135 | 136 | FLOAT = @{ ("-")? ~ int ~ ("." ~ int+) } 137 | 138 | INTEGER = @{ ("-")? ~ int } 139 | 140 | WHITESPACE = _{ " " | "\t" | "\r" | "\n" } 141 | 142 | COMMENT = _{ "(*" ~ (!"*)" ~ ANY)* ~ "*)" } -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | include!("ast.rs"); 2 | 3 | extern crate pest; 4 | #[macro_use] 5 | extern crate pest_derive; 6 | 7 | #[macro_use] 8 | extern crate lazy_static; 9 | 10 | use pest::error::Error; 11 | use pest::prec_climber::{Assoc, Operator, PrecClimber}; 12 | use pest::Parser; 13 | 14 | #[derive(Parser)] 15 | #[grammar = "pistolet.pest"] 16 | pub struct PistoletParser; 17 | 18 | lazy_static! { 19 | static ref PREC_CLIMBER: PrecClimber = { 20 | use Assoc::*; 21 | use Rule::*; 22 | PrecClimber::new(vec![ 23 | Operator::new(add, Left) | Operator::new(sub, Left), 24 | Operator::new(mul, Left) | Operator::new(div, Left), 25 | Operator::new(and, Left) | Operator::new(or, Left) | Operator::new(nand, Left), 26 | Operator::new(eq, Left) | Operator::new(lefteq, Left)|Operator::new(left, Left) |Operator::new(righteq, Left) | Operator::new(right, Left) , 27 | ]) 28 | }; 29 | } 30 | 31 | fn parse_to_ast(file: &str) -> Result> { 32 | let pistolet_prog = PistoletParser::parse(Rule::program, &file) 33 | .expect("unsuccessful parse") 34 | .next() 35 | .unwrap(); 36 | use pest::iterators::Pair; 37 | use pest::iterators::Pairs; 38 | 39 | fn parse_value(pair: Pair) -> PistoletValue { 40 | match pair.as_rule() { 41 | Rule::INTEGER => PistoletValue::Integer(pair.as_str().parse().unwrap()), 42 | Rule::FLOAT => PistoletValue::Float(pair.as_str().parse().unwrap()), 43 | Rule::BOOL => PistoletValue::Boolean(pair.as_str().parse().unwrap()), 44 | Rule::VAR_NAME => PistoletValue::Var(pair.as_str().to_string()), 45 | Rule::FUN_CALL => { 46 | let mut new_pair = pair.into_inner(); 47 | PistoletValue::Funcall( 48 | { 49 | let x = new_pair.next().unwrap(); 50 | match x.as_rule() { 51 | Rule::FUN_NAME => x.as_str().to_string(), 52 | _ => unreachable!(), 53 | } 54 | }, 55 | new_pair.map(unwarp_expr).map(parse_expr).collect(), 56 | ) 57 | } 58 | _ => unreachable!(), 59 | } 60 | } 61 | 62 | fn unwarp_expr(exp: Pair) -> Pairs { 63 | exp.into_inner() 64 | } 65 | 66 | fn parse_expr(exp: Pairs) -> PistoletExpr { 67 | PREC_CLIMBER.climb( 68 | exp, 69 | |pair: Pair| match pair.as_rule() { 70 | Rule::VALUE => PistoletExpr::Val(parse_value(pair.into_inner().peek().unwrap())), 71 | Rule::EXPR => parse_expr(pair.into_inner()), 72 | Rule::BOOL_VALUE => { 73 | PistoletExpr::Val(parse_value(pair.into_inner().peek().unwrap())) 74 | } 75 | Rule::BOOL_EXPR => parse_expr(pair.into_inner()), 76 | Rule::EXPR_NoTy => parse_expr(pair.into_inner()), 77 | Rule::EQ_EXPR => parse_expr(pair.into_inner()), 78 | _ => { 79 | println!("{:#?}", pair); 80 | unreachable!() 81 | } 82 | }, 83 | |lhs: PistoletExpr, op: Pair, rhs: PistoletExpr| match op.as_rule() { 84 | Rule::and => PistoletExpr::And(Box::new(lhs), Box::new(rhs)), 85 | Rule::or => PistoletExpr::Orb(Box::new(lhs), Box::new(rhs)), 86 | Rule::nand => PistoletExpr::Nand(Box::new(lhs), Box::new(rhs)), 87 | Rule::add => PistoletExpr::Add(Box::new(lhs), Box::new(rhs)), 88 | Rule::sub => PistoletExpr::Sub(Box::new(lhs), Box::new(rhs)), 89 | Rule::mul => PistoletExpr::Mul(Box::new(lhs), Box::new(rhs)), 90 | Rule::div => PistoletExpr::Div(Box::new(lhs), Box::new(rhs)), 91 | Rule::eq => PistoletExpr::Eq(Box::new(lhs), Box::new(rhs)), 92 | Rule::lefteq => PistoletExpr::Leq(Box::new(lhs), Box::new(rhs)), 93 | Rule::righteq => PistoletExpr::Req(Box::new(lhs), Box::new(rhs)), 94 | Rule::left => PistoletExpr::Left(Box::new(lhs), Box::new(rhs)), 95 | Rule::right => PistoletExpr::Right(Box::new(lhs), Box::new(rhs)), 96 | _ => unreachable!(), 97 | }, 98 | ) 99 | } 100 | 101 | fn parse_prog(pair: Pair) -> PistoletAST { 102 | match pair.as_rule() { 103 | Rule::program => PistoletAST::Seq(pair.into_inner().map(parse_prog).collect()), 104 | Rule::TERM => PistoletAST::Seq(pair.into_inner().map(parse_prog).collect()), 105 | Rule::sentence => parse_prog(pair.into_inner().peek().unwrap()), 106 | Rule::PARA_LIST => PistoletAST::Paralist(pair.into_inner().map(parse_prog).collect()), 107 | Rule::LET => { 108 | let mut new_pair = pair.into_inner(); 109 | PistoletAST::Let( 110 | { 111 | let x = new_pair.next().unwrap(); 112 | match x.as_rule() { 113 | Rule::VAR_NAME => x.as_str().to_string(), 114 | Rule::TYPE_NAME => x.as_str().to_string(), 115 | _ => unreachable!(), 116 | } 117 | }, 118 | { 119 | let x = new_pair.next().unwrap(); 120 | match x.as_rule() { 121 | Rule::VAR_NAME => x.as_str().to_string(), 122 | Rule::TYPE_NAME => x.as_str().to_string(), 123 | _ => unreachable!(), 124 | } 125 | }, 126 | match new_pair.peek().unwrap().as_rule() { 127 | Rule::EXPR_NoTy => parse_expr(new_pair.peek().unwrap().into_inner()), 128 | _ => unreachable!(), 129 | }, 130 | ) 131 | } 132 | Rule::IF => { 133 | let mut new_pair = pair.into_inner(); 134 | PistoletAST::If( 135 | { 136 | let x = new_pair.next().unwrap(); 137 | match x.as_rule() { 138 | Rule::BOOL_EXPR => parse_expr(x.into_inner()), 139 | _ => unreachable!(), 140 | } 141 | }, 142 | { 143 | let x = new_pair.next().unwrap(); 144 | match x.as_rule() { 145 | Rule::TERM => Box::new(parse_prog(x)), 146 | _ => unreachable!(), 147 | } 148 | }, 149 | match new_pair.peek().unwrap().as_rule() { 150 | Rule::TERM => Box::new(parse_prog(new_pair.peek().unwrap())), 151 | _ => unreachable!(), 152 | }, 153 | ) 154 | } 155 | Rule::WHILE => { 156 | let mut new_pair = pair.into_inner(); 157 | PistoletAST::While( 158 | { 159 | let x = new_pair.next().unwrap(); 160 | match x.as_rule() { 161 | Rule::TERM => Box::new(parse_prog(x)), 162 | _ => unreachable!(), 163 | } 164 | }, 165 | { 166 | let x = new_pair.next().unwrap(); 167 | match x.as_rule() { 168 | Rule::BOOL_EXPR => parse_expr(x.into_inner()), 169 | _ => unreachable!(), 170 | } 171 | }, 172 | ) 173 | } 174 | Rule::RETURN => PistoletAST::Return(parse_expr(pair.into_inner())), 175 | Rule::VAR_BIND => { 176 | let mut new_pair = pair.into_inner(); 177 | PistoletAST::Varbind( 178 | { 179 | let x = new_pair.next().unwrap(); 180 | match x.as_rule() { 181 | Rule::VAR_NAME => x.as_str().to_string(), 182 | _ => unreachable!(), 183 | } 184 | }, 185 | match new_pair.peek().unwrap().as_rule() { 186 | Rule::TYPE_NAME => new_pair.as_str().to_string(), 187 | _ => unreachable!(), 188 | }, 189 | ) 190 | } 191 | Rule::FUN => { 192 | let mut new_pair = pair.into_inner(); 193 | PistoletAST::Fun( 194 | { 195 | let x = new_pair.next().unwrap(); 196 | match x.as_rule() { 197 | Rule::FUN_NAME => x.as_str().to_string(), 198 | _ => unreachable!(), 199 | } 200 | }, 201 | { 202 | let x = new_pair.next().unwrap(); 203 | match x.as_rule() { 204 | Rule::PARA_LIST => Box::new(parse_prog(x)), 205 | _ => unreachable!(), 206 | } 207 | }, 208 | { 209 | let x = new_pair.next().unwrap(); 210 | match x.as_rule() { 211 | Rule::TYPE_NAME => x.as_str().to_string(), 212 | _ => unreachable!(), 213 | } 214 | }, 215 | match new_pair.peek().unwrap().as_rule() { 216 | Rule::TERM => Box::new(parse_prog(new_pair.peek().unwrap())), 217 | _ => unreachable!(), 218 | }, 219 | ) 220 | } 221 | Rule::EOI => PistoletAST::EOI, 222 | Rule::PrintLine => { 223 | let new_pair = pair.into_inner(); 224 | match new_pair.peek().unwrap().as_rule() { 225 | Rule::EXPR_NoTy => PistoletAST::PrintLine(parse_expr(new_pair)), 226 | _ => unreachable!(), 227 | } 228 | } 229 | _ => { 230 | println!("{:#?}", pair); 231 | unimplemented!() 232 | } 233 | } 234 | } 235 | 236 | Ok(parse_prog(pistolet_prog)) 237 | } 238 | -------------------------------------------------------------------------------- /src/interpreter.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::collections::HashMap; 3 | use std::collections::VecDeque; 4 | use std::fmt; 5 | use std::rc::Rc; 6 | 7 | #[derive(Debug, Clone)] 8 | enum ValueBind { 9 | Vb(String, VarValue), /* type, value*/ 10 | } 11 | 12 | impl ValueBind { 13 | pub fn get_type(&self) -> String { 14 | match self { 15 | ValueBind::Vb(t, _) => t.to_string(), 16 | } 17 | } 18 | pub fn get_value(&self) -> VarValue { 19 | match self { 20 | ValueBind::Vb(_, v) => *v, 21 | } 22 | } 23 | } 24 | 25 | #[derive(Debug, Clone)] 26 | struct FuncDic { 27 | func_list: HashMap 28 | } 29 | 30 | impl FuncDic { 31 | pub fn new() -> FuncDic { 32 | let func_list = FuncDic{ 33 | func_list: HashMap::new() 34 | }; 35 | return func_list; 36 | } 37 | 38 | pub fn find_func( 39 | &self, 40 | name: String, 41 | ) -> Result<(PistoletAST, String, Vec<(String, String)>), RuntimeErr> { 42 | let fun = self.func_list.get(&name); 43 | match fun { 44 | Some(result) => { 45 | match result { 46 | (PistoletAST::Paralist(paralist), func_type, func_body) => { 47 | let para_vec = para_to_vec(paralist.clone()); 48 | Ok((func_body.clone(), func_type.clone(), para_vec)) 49 | } 50 | _ => unreachable!(), 51 | } 52 | } 53 | None => Err(RuntimeErr::FuncUsedBeforeDefine) 54 | } 55 | } 56 | 57 | pub fn func_insert( 58 | &mut self, 59 | func_name: String, 60 | para_list: PistoletAST, 61 | return_type: String, 62 | func_body: PistoletAST, 63 | ) { 64 | self.func_list 65 | .insert(func_name, (para_list, return_type, func_body)); 66 | } 67 | } 68 | 69 | #[derive(Debug)] 70 | struct ProgList { 71 | var_list: HashMap 72 | } 73 | 74 | #[derive(Debug)] 75 | struct ProgState(Rc>); 76 | 77 | #[derive(Debug)] 78 | struct StateVec { 79 | states: VecDeque, 80 | } 81 | 82 | #[derive(Debug, Clone)] 83 | struct ProgStates(Rc>); 84 | 85 | impl ProgStates { 86 | pub fn new() -> ProgStates { 87 | let main_state = ProgState(Rc::new(RefCell::new(ProgList { 88 | var_list: HashMap::new() 89 | }))); 90 | 91 | let state = ProgStates(Rc::new(RefCell::new(StateVec { 92 | states: VecDeque::new(), 93 | }))); 94 | 95 | state.push_back(main_state); 96 | return state; 97 | } 98 | pub fn push_front(&self, state: ProgState) { 99 | self.0.borrow_mut().states.push_front(state) 100 | } 101 | pub fn push_back(&self, state: ProgState) { 102 | self.0.borrow_mut().states.push_back(state) 103 | } 104 | pub fn pop_front(&self) { 105 | self.0.borrow_mut().states.pop_front(); 106 | } 107 | pub fn find_var(&self, name: String) -> Result { 108 | let mut r: ValueBind = ValueBind::Vb("foo".to_string(), VarValue::Bool(true)); // dummy useless initial value 109 | let mut find_var: bool = false; 110 | for state in self.0.borrow().states.iter() { 111 | match state.get(name.clone()) { 112 | Some(result) => { 113 | r = result.clone(); 114 | find_var = true; 115 | break; 116 | } 117 | None => continue, 118 | } 119 | } 120 | if find_var { 121 | Ok(r) 122 | } else { 123 | Err(RuntimeErr::VarUsedBeforeDefine) 124 | } 125 | } 126 | pub fn insert(&self, var_name: String, var_value: ValueBind) { 127 | self.0 128 | .borrow_mut() 129 | .states 130 | .get(0) 131 | .unwrap() 132 | .insert(var_name, var_value); 133 | } 134 | pub fn print(&self) { 135 | self.0.borrow_mut().states.get(0).unwrap().print(); 136 | } 137 | } 138 | 139 | impl ProgState { 140 | pub fn insert(&self, var_name: String, var_value: ValueBind) { 141 | self.0.borrow_mut().var_list.insert(var_name, var_value); 142 | } 143 | pub fn get(&self, var_name: String) -> Option { 144 | match self.0.borrow().var_list.get(&var_name) { 145 | Some(n) => Some(n.clone()), 146 | None => None, 147 | } 148 | } 149 | pub fn print(&self) { 150 | println!("------ PROGRAM STATE ------"); 151 | for var in &(self.0.borrow().var_list) { 152 | let (var_name, ValueBind::Vb(type_name, var_value)) = var; 153 | println!( 154 | "Var: {} Type: {} Value: {}", 155 | var_name, type_name, var_value 156 | ) 157 | } 158 | println!("------ PROGRAM STATE ------"); 159 | } 160 | } 161 | 162 | #[derive(Debug, Copy, Clone)] 163 | enum VarValue { 164 | Int(i128), 165 | Float(f64), 166 | Bool(bool), 167 | } 168 | 169 | impl fmt::Display for VarValue { 170 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 171 | match self { 172 | VarValue::Int(i) => write!(f, "{}", i), 173 | VarValue::Float(i) => write!(f, "{}", i), 174 | VarValue::Bool(i) => write!(f, "{}", i), 175 | } 176 | } 177 | } 178 | 179 | #[derive(Debug)] 180 | enum RuntimeErr { 181 | TypeMismatch, 182 | Unknown, 183 | VarUsedBeforeDefine, 184 | FuncUsedBeforeDefine, 185 | DivideByZero, 186 | FuncallParaNum, 187 | FunctionNoReturn, 188 | ReturnValue(ValueBind), 189 | } 190 | 191 | impl RuntimeErr { 192 | pub fn print(&self) { 193 | println!("------ Runtime Error ------"); 194 | match self { 195 | RuntimeErr::TypeMismatch => println!("[Error] Type mismatch in an expression"), 196 | RuntimeErr::VarUsedBeforeDefine => println!("[Error] Var used before defined"), 197 | RuntimeErr::Unknown => println!("[Error] An exception has occurred"), 198 | RuntimeErr::DivideByZero => println!("[Error] Attempt to divide by zero "), 199 | RuntimeErr::FuncUsedBeforeDefine => println!("[Error] Function used before defined"), 200 | RuntimeErr::FuncallParaNum => println!("[Error] wrong number function call"), 201 | RuntimeErr::FunctionNoReturn => println!("[Error] function no return"), 202 | _ => unreachable!(), 203 | } 204 | println!("------ Runtime Error ------"); 205 | } 206 | } 207 | 208 | fn type_dec(v1: VarValue, v2: VarValue) -> bool { 209 | match v1 { 210 | VarValue::Int(_) => match v2 { 211 | VarValue::Int(_) => true, 212 | _ => false, 213 | }, 214 | VarValue::Float(_) => match v2 { 215 | VarValue::Float(_) => true, 216 | _ => false, 217 | }, 218 | VarValue::Bool(_) => match v2 { 219 | VarValue::Bool(_) => true, 220 | _ => false, 221 | }, 222 | } 223 | } 224 | 225 | fn para_to_vec(paralist: Vec) -> Vec<(String, String)> { 226 | let mut result: Vec<(String, String)> = Vec::new(); 227 | for bind in paralist.iter() { 228 | match bind { 229 | PistoletAST::Varbind(v, t) => { 230 | result.push((v.to_string(), t.to_string())); 231 | } 232 | _ => unreachable!(), 233 | } 234 | } 235 | result 236 | } 237 | 238 | fn var_eval(name: String, states: ProgStates) -> Result { 239 | states.find_var(name) 240 | } 241 | 242 | fn func_eval( 243 | name: String, 244 | expr_list: Vec, 245 | states: ProgStates, 246 | func_list: FuncDic 247 | 248 | ) -> Result { 249 | let (func_body, func_type, para_list) = func_list.find_func(name)?; 250 | let mut val_list: Vec = Vec::new(); 251 | for expr in expr_list.iter() { 252 | let expr_val = expr_eval(expr.clone(), states.clone(), func_list.clone()).unwrap(); 253 | val_list.push(expr_val); 254 | } 255 | if val_list.len() == para_list.len() { 256 | let sub_state = ProgState(Rc::new(RefCell::new(ProgList { 257 | var_list: HashMap::new() 258 | }))); 259 | states.push_front(sub_state); 260 | for (index, val) in val_list.iter().enumerate() { 261 | let (para_name, para_type) = para_list.get(index).unwrap(); 262 | if val.get_type().eq_ignore_ascii_case(¶_type) { 263 | states.insert(para_name.clone(), val.clone()); 264 | } else { 265 | states.pop_front(); 266 | return Err(RuntimeErr::TypeMismatch); 267 | } 268 | } 269 | let result = ast_eval(func_body, states.clone(), &mut func_list.clone()); 270 | let func_result: Result; 271 | match result { 272 | Err(some_err) => match some_err { 273 | RuntimeErr::ReturnValue(expr_value) => { 274 | if expr_value.get_type().eq_ignore_ascii_case(&func_type) { 275 | func_result = Ok(expr_value); 276 | } else { 277 | func_result = Err(RuntimeErr::TypeMismatch); 278 | } 279 | } 280 | _ => func_result = Err(some_err), 281 | }, 282 | Ok(_) => func_result = Err(RuntimeErr::FunctionNoReturn), 283 | } 284 | states.pop_front(); 285 | return func_result; 286 | } else { 287 | return Err(RuntimeErr::FuncallParaNum); 288 | } 289 | } 290 | 291 | fn expr_eval(expr: PistoletExpr, state: ProgStates, func_list: FuncDic) -> Result { 292 | match expr { 293 | PistoletExpr::Val(value) => match value { 294 | PistoletValue::Integer(n) => Ok(ValueBind::Vb("int".to_string(), VarValue::Int(n))), 295 | PistoletValue::Float(n) => Ok(ValueBind::Vb("float".to_string(), VarValue::Float(n))), 296 | PistoletValue::Boolean(n) => Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n))), 297 | PistoletValue::Var(n) => var_eval(n, state), 298 | PistoletValue::Funcall(func_name, expr_list) => func_eval(func_name, expr_list, state, func_list.clone()), 299 | }, 300 | PistoletExpr::Add(e1, e2) => { 301 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 302 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 303 | let v1 = v1.get_value(); 304 | let v2 = v2.get_value(); 305 | 306 | if type_dec(v1, v2) { 307 | match v1 { 308 | VarValue::Int(n) => match v2 { 309 | VarValue::Int(m) => { 310 | Ok(ValueBind::Vb("int".to_string(), VarValue::Int(n + m))) 311 | } 312 | _ => unreachable!(), 313 | }, 314 | VarValue::Float(n) => match v2 { 315 | VarValue::Float(m) => { 316 | Ok(ValueBind::Vb("float".to_string(), VarValue::Float(n + m))) 317 | } 318 | _ => unreachable!(), 319 | }, 320 | _ => Err(RuntimeErr::TypeMismatch), 321 | } 322 | } else { 323 | Err(RuntimeErr::TypeMismatch) 324 | } 325 | } 326 | PistoletExpr::Sub(e1, e2) => { 327 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 328 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 329 | let v1 = v1.get_value(); 330 | let v2 = v2.get_value(); 331 | 332 | if type_dec(v1, v2) { 333 | match v1 { 334 | VarValue::Int(n) => match v2 { 335 | VarValue::Int(m) => { 336 | Ok(ValueBind::Vb("int".to_string(), VarValue::Int(n - m))) 337 | } 338 | _ => unreachable!(), 339 | }, 340 | VarValue::Float(n) => match v2 { 341 | VarValue::Float(m) => { 342 | Ok(ValueBind::Vb("float".to_string(), VarValue::Float(n - m))) 343 | } 344 | _ => unreachable!(), 345 | }, 346 | _ => Err(RuntimeErr::TypeMismatch), 347 | } 348 | } else { 349 | Err(RuntimeErr::TypeMismatch) 350 | } 351 | } 352 | PistoletExpr::Mul(e1, e2) => { 353 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 354 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 355 | let v1 = v1.get_value(); 356 | let v2 = v2.get_value(); 357 | 358 | if type_dec(v1, v2) { 359 | match v1 { 360 | VarValue::Int(n) => match v2 { 361 | VarValue::Int(m) => { 362 | Ok(ValueBind::Vb("int".to_string(), VarValue::Int(n * m))) 363 | } 364 | _ => unreachable!(), 365 | }, 366 | VarValue::Float(n) => match v2 { 367 | VarValue::Float(m) => { 368 | Ok(ValueBind::Vb("float".to_string(), VarValue::Float(n * m))) 369 | } 370 | _ => unreachable!(), 371 | }, 372 | _ => Err(RuntimeErr::TypeMismatch), 373 | } 374 | } else { 375 | Err(RuntimeErr::TypeMismatch) 376 | } 377 | } 378 | PistoletExpr::Div(e1, e2) => { 379 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 380 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 381 | let v1 = v1.get_value(); 382 | let v2 = v2.get_value(); 383 | 384 | if type_dec(v1, v2) { 385 | match v1 { 386 | VarValue::Int(n) => match v2 { 387 | VarValue::Int(m) => { 388 | if m == 0 { 389 | Err(RuntimeErr::DivideByZero) 390 | } else { 391 | Ok(ValueBind::Vb("int".to_string(), VarValue::Int(n / m))) 392 | } 393 | } 394 | _ => unreachable!(), 395 | }, 396 | VarValue::Float(n) => match v2 { 397 | VarValue::Float(m) => { 398 | let r = n / m; 399 | if r.is_infinite() { 400 | Err(RuntimeErr::DivideByZero) 401 | } else { 402 | Ok(ValueBind::Vb("float".to_string(), VarValue::Float(r))) 403 | } 404 | } 405 | _ => unreachable!(), 406 | }, 407 | _ => Err(RuntimeErr::TypeMismatch), 408 | } 409 | } else { 410 | Err(RuntimeErr::TypeMismatch) 411 | } 412 | } 413 | PistoletExpr::And(e1, e2) => { 414 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 415 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 416 | let v1 = v1.get_value(); 417 | let v2 = v2.get_value(); 418 | 419 | if type_dec(v1, v2) { 420 | match v1 { 421 | VarValue::Bool(n) => match v2 { 422 | VarValue::Bool(m) => { 423 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n && m))) 424 | } 425 | _ => unreachable!(), 426 | }, 427 | _ => Err(RuntimeErr::TypeMismatch), 428 | } 429 | } else { 430 | Err(RuntimeErr::TypeMismatch) 431 | } 432 | } 433 | PistoletExpr::Orb(e1, e2) => { 434 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 435 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 436 | let v1 = v1.get_value(); 437 | let v2 = v2.get_value(); 438 | 439 | if type_dec(v1, v2) { 440 | match v1 { 441 | VarValue::Bool(n) => match v2 { 442 | VarValue::Bool(m) => { 443 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n || m))) 444 | } 445 | _ => unreachable!(), 446 | }, 447 | _ => Err(RuntimeErr::TypeMismatch), 448 | } 449 | } else { 450 | Err(RuntimeErr::TypeMismatch) 451 | } 452 | } 453 | PistoletExpr::Nand(e1, e2) => { 454 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 455 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 456 | let v1 = v1.get_value(); 457 | let v2 = v2.get_value(); 458 | 459 | if type_dec(v1, v2) { 460 | match v1 { 461 | VarValue::Bool(n) => match v2 { 462 | VarValue::Bool(m) => { 463 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(!(n && m)))) 464 | } 465 | _ => unreachable!(), 466 | }, 467 | _ => Err(RuntimeErr::TypeMismatch), 468 | } 469 | } else { 470 | Err(RuntimeErr::TypeMismatch) 471 | } 472 | } 473 | PistoletExpr::Eq(e1, e2) => { 474 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 475 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 476 | let v1 = v1.get_value(); 477 | let v2 = v2.get_value(); 478 | 479 | if type_dec(v1, v2) { 480 | match v1 { 481 | VarValue::Int(n) => match v2 { 482 | VarValue::Int(m) => { 483 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n == m))) 484 | } 485 | _ => unreachable!(), 486 | }, 487 | VarValue::Float(n) => match v2 { 488 | VarValue::Float(m) => { 489 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n == m))) 490 | } 491 | _ => unreachable!(), 492 | }, 493 | _ => unreachable!(), 494 | } 495 | } else { 496 | Err(RuntimeErr::TypeMismatch) 497 | } 498 | } 499 | PistoletExpr::Leq(e1, e2) => { 500 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 501 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 502 | let v1 = v1.get_value(); 503 | let v2 = v2.get_value(); 504 | 505 | if type_dec(v1, v2) { 506 | match v1 { 507 | VarValue::Int(n) => match v2 { 508 | VarValue::Int(m) => { 509 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n <= m))) 510 | } 511 | _ => unreachable!(), 512 | }, 513 | VarValue::Float(n) => match v2 { 514 | VarValue::Float(m) => { 515 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n <= m))) 516 | } 517 | _ => unreachable!(), 518 | }, 519 | _ => unreachable!(), 520 | } 521 | } else { 522 | Err(RuntimeErr::TypeMismatch) 523 | } 524 | } 525 | PistoletExpr::Req(e1, e2) => { 526 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 527 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 528 | let v1 = v1.get_value(); 529 | let v2 = v2.get_value(); 530 | 531 | if type_dec(v1, v2) { 532 | match v1 { 533 | VarValue::Int(n) => match v2 { 534 | VarValue::Int(m) => { 535 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n >= m))) 536 | } 537 | _ => unreachable!(), 538 | }, 539 | VarValue::Float(n) => match v2 { 540 | VarValue::Float(m) => { 541 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n >= m))) 542 | } 543 | _ => unreachable!(), 544 | }, 545 | _ => unreachable!(), 546 | } 547 | } else { 548 | Err(RuntimeErr::TypeMismatch) 549 | } 550 | } 551 | PistoletExpr::Left(e1, e2) => { 552 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 553 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 554 | let v1 = v1.get_value(); 555 | let v2 = v2.get_value(); 556 | 557 | if type_dec(v1, v2) { 558 | match v1 { 559 | VarValue::Int(n) => match v2 { 560 | VarValue::Int(m) => { 561 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n < m))) 562 | } 563 | _ => unreachable!(), 564 | }, 565 | VarValue::Float(n) => match v2 { 566 | VarValue::Float(m) => { 567 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n < m))) 568 | } 569 | _ => unreachable!(), 570 | }, 571 | _ => unreachable!(), 572 | } 573 | } else { 574 | Err(RuntimeErr::TypeMismatch) 575 | } 576 | } 577 | PistoletExpr::Right(e1, e2) => { 578 | let v1 = expr_eval(*e1, state.clone(), func_list.clone())?; 579 | let v2 = expr_eval(*e2, state.clone(), func_list.clone())?; 580 | let v1 = v1.get_value(); 581 | let v2 = v2.get_value(); 582 | 583 | if type_dec(v1, v2) { 584 | match v1 { 585 | VarValue::Int(n) => match v2 { 586 | VarValue::Int(m) => { 587 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n > m))) 588 | } 589 | _ => unreachable!(), 590 | }, 591 | VarValue::Float(n) => match v2 { 592 | VarValue::Float(m) => { 593 | Ok(ValueBind::Vb("bool".to_string(), VarValue::Bool(n > m))) 594 | } 595 | _ => unreachable!(), 596 | }, 597 | _ => unreachable!(), 598 | } 599 | } else { 600 | Err(RuntimeErr::TypeMismatch) 601 | } 602 | } 603 | } 604 | } 605 | 606 | fn seq_eval(ast: PistoletAST, state: ProgStates, mut func_list: FuncDic) -> Option { 607 | let mut error: RuntimeErr = RuntimeErr::Unknown; 608 | let mut error_state = false; 609 | match ast { 610 | PistoletAST::Seq(term_list) => { 611 | for term in term_list { 612 | match ast_eval(term, state.clone(), &mut func_list) { 613 | Ok(_) => continue, 614 | Err(err) => { 615 | error = err; 616 | error_state = true; 617 | break; 618 | } 619 | } 620 | } 621 | } 622 | _ => unreachable!(), 623 | } 624 | if error_state { 625 | Some(error) 626 | } else { 627 | None 628 | } 629 | } 630 | 631 | fn ast_eval(ast: PistoletAST, state: ProgStates, func_list: &mut FuncDic) -> Result<(ProgStates, FuncDic), RuntimeErr> { 632 | match ast { 633 | PistoletAST::Seq(term_list) => match seq_eval(PistoletAST::Seq(term_list), state.clone(), func_list.clone()) { 634 | Some(err) => Err(err), 635 | None => Ok((state.clone(), func_list.clone())), 636 | }, 637 | PistoletAST::Let(var_name, var_type, var_expr) => { 638 | let var_value = expr_eval(var_expr, state.clone(), func_list.clone())?; 639 | if var_value.get_type().eq_ignore_ascii_case(&var_type) { 640 | state.insert(var_name, var_value); 641 | Ok((state.clone(), func_list.clone())) 642 | } else { 643 | Err(RuntimeErr::TypeMismatch) 644 | } 645 | } 646 | PistoletAST::If(expr, branch_true, branch_false) => { 647 | let expr_value = expr_eval(expr, state.clone(), func_list.clone())?; 648 | let sub_state = ProgState(Rc::new(RefCell::new(ProgList { 649 | var_list: HashMap::new() 650 | }))); 651 | state.push_front(sub_state); 652 | match expr_value.get_value() { 653 | VarValue::Bool(true) => match seq_eval(*branch_true, state.clone(), func_list.clone()) { 654 | Some(err) => { 655 | state.pop_front(); 656 | Err(err) 657 | } 658 | None => { 659 | state.pop_front(); 660 | Ok((state.clone(), func_list.clone())) 661 | } 662 | }, 663 | VarValue::Bool(false) => match seq_eval(*branch_false, state.clone(), func_list.clone()) { 664 | Some(err) => { 665 | state.pop_front(); 666 | Err(err) 667 | } 668 | None => { 669 | state.pop_front(); 670 | Ok((state.clone(), func_list.clone())) 671 | } 672 | }, 673 | _ => unreachable!(), 674 | } 675 | } 676 | PistoletAST::While(seq, expr) => { 677 | let info: Result<(ProgStates, FuncDic), RuntimeErr>; 678 | let sub_state = ProgState(Rc::new(RefCell::new(ProgList { 679 | var_list: HashMap::new() 680 | }))); 681 | state.push_front(sub_state); 682 | loop { 683 | match seq_eval(*seq.clone(), state.clone(), func_list.clone()) { 684 | Some(err) => { 685 | info = Err(err); 686 | break; 687 | } //Here can process break. in future... 688 | None => { 689 | let expr_value = expr_eval(expr.clone(), state.clone(), func_list.clone())?.get_value(); 690 | match expr_value { 691 | VarValue::Bool(true) => { 692 | info = Ok((state.clone(), func_list.clone())); 693 | break; 694 | } 695 | VarValue::Bool(false) => { 696 | continue; 697 | } 698 | _ => unreachable!(), 699 | } 700 | } 701 | } 702 | } 703 | state.pop_front(); 704 | info 705 | } 706 | PistoletAST::Fun(func_name, para_list, return_type, fun_body) => { 707 | func_list.func_insert(func_name, *para_list, return_type, *fun_body); 708 | Ok((state.clone(), func_list.clone())) 709 | } 710 | PistoletAST::Return(expr) => { 711 | let expr_value = expr_eval(expr, state, func_list.clone())?; 712 | Err(RuntimeErr::ReturnValue(expr_value)) 713 | } 714 | PistoletAST::PrintLine(expr) => { 715 | let expr_value = expr_eval(expr, state.clone(), func_list.clone())?; 716 | println!("{} : {}", expr_value.get_value(), expr_value.get_type()); 717 | Ok((state.clone(), func_list.clone())) 718 | } 719 | PistoletAST::EOI => Ok((state.clone(), func_list.clone())), 720 | _ => Err(RuntimeErr::Unknown), 721 | } 722 | } 723 | --------------------------------------------------------------------------------