diff --git a/src/bytecode.rs b/src/bytecode.rs index 0db30b6..05a9220 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -18,10 +18,11 @@ * You should have received a copy of the GNU General Public License * along with Orion. If not, see . */ +#![allow(clippy::approx_constant)] use crate::{parser::Literal, error, Result}; use std::fmt::{self, Formatter, Display}; -#[derive(PartialEq, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum OpCode { LoadConst(u16), // (const_id) LoadSym(u16), // (sym_id) @@ -51,6 +52,7 @@ impl Display for OpCode { } } impl OpCode { + #[allow(unused)] pub fn deserialize(ptr: &mut usize, bytes: &[u8]) -> Result { *ptr += 1; match bytes[*ptr - 1] { @@ -126,13 +128,13 @@ impl OpCode { } } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct Chunk { pub instructions: Vec, pub reference: Vec, } -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum BytecodePattern { Var(u16), // (sym_idx) Constr(u16, Vec), // (constr_id, [pat_idx]) @@ -167,14 +169,15 @@ impl Bytecode { } } // All numbers here are big endian + #[allow(unused)] pub fn deserialize(bytes: &[u8]) -> Result { - if &bytes[0..5] != "orion".chars().into_iter().map(|c| c as u8).collect::>() { + if bytes[0..5] != "orion".chars().into_iter().map(|c| c as u8).collect::>() { error!(=> "Invalid bytecode.") } else { let mut ptr = 5; // Skip timestamp let sym_length = len(&mut ptr, bytes)?; println!("Sym length."); - let mut symbols = (0..sym_length).map(|_| string(&mut ptr, bytes)).collect::>>()?; + let symbols = (0..sym_length).map(|_| string(&mut ptr, bytes)).collect::>>()?; println!("Syms."); let consts_length = len(&mut ptr, bytes)?; println!("Consts length."); @@ -263,14 +266,14 @@ impl Bytecode { println!("Matches length."); let matches = (0..matches_length).map(|_| { let match_length = len(&mut ptr, bytes)?; - Ok((0..match_length).map(|_| { + (0..match_length).map(|_| { let idx = len(&mut ptr, bytes)?; let instrs_len = len(&mut ptr, bytes)?; let instrs = (0..instrs_len).map(|_| { OpCode::deserialize(&mut ptr, bytes) }).collect::>>()?; Ok((idx, instrs)) - }).collect::)>>>()?) + }).collect::)>>>() }).collect::)>>>>()?; println!("Matches."); @@ -334,17 +337,17 @@ impl Bytecode { to_ret.extend(&link.to_be_bytes()); }); - let serialized = chunk.instructions.iter().map(|instr| { + let serialized = chunk.instructions.iter().flat_map(|instr| { instr.serialize() - }).flatten(); + }); to_ret.extend(&(chunk.instructions.len() as u16).to_be_bytes()); to_ret.extend(serialized) }); // Instructions - let serialized = self.instructions.iter().map(|instr| { + let serialized = self.instructions.iter().flat_map(|instr| { instr.serialize() - }).flatten(); + }); to_ret.extend(&(self.instructions.len() as u16).to_be_bytes()); to_ret.extend(serialized); @@ -359,7 +362,7 @@ impl Bytecode { // Patterns to_ret.extend(&(self.patterns.len() as u16).to_be_bytes()); - to_ret.extend(self.patterns.iter().map(|p| { + to_ret.extend(self.patterns.iter().flat_map(|p| { match p { BytecodePattern::Var(idx) => { let mut to_ret = vec![0]; @@ -370,17 +373,17 @@ impl Bytecode { let mut to_ret = vec![1]; to_ret.extend(&id.to_be_bytes()); to_ret.extend(&(pats.len() as u16).to_be_bytes()); - to_ret.extend(pats.into_iter().map(|p| { + to_ret.extend(pats.iter().flat_map(|p| { p.to_be_bytes().to_vec() - }).flatten()); + })); to_ret } BytecodePattern::Tuple(pats) => { let mut to_ret = vec![2]; to_ret.extend(&(pats.len() as u16).to_be_bytes()); - to_ret.extend(pats.into_iter().map(|p| { + to_ret.extend(pats.iter().flat_map(|p| { p.to_be_bytes().to_vec() - }).flatten()); + })); to_ret } BytecodePattern::Literal(idx) => { @@ -390,20 +393,20 @@ impl Bytecode { } BytecodePattern::Any => vec![4], } - }).flatten()); + })); // Matches to_ret.extend(&(self.matches.len() as u16).to_be_bytes()); - to_ret.extend(self.matches.iter().map(|patterns| { + to_ret.extend(self.matches.iter().flat_map(|patterns| { let mut to_ret = (patterns.len() as u16).to_be_bytes().to_vec(); - to_ret.extend(patterns.into_iter().map(|(idx, instrs)| { + to_ret.extend(patterns.iter().flat_map(|(idx, instrs)| { let mut to_ret = idx.to_be_bytes().to_vec(); to_ret.extend(&(instrs.len() as u16).to_be_bytes()); - to_ret.extend(instrs.into_iter().map(|instr| instr.serialize()).flatten()); + to_ret.extend(instrs.iter().flat_map(|instr| instr.serialize())); to_ret - }).flatten()); + })); to_ret - }).flatten()); + })); to_ret } } @@ -414,7 +417,7 @@ fn string(ptr: &mut usize, bytes: &[u8]) -> Result { to_ret.push(bytes[*ptr] as char); *ptr += 1; } - if bytes.iter().nth(*ptr) == Some(&0) { + if bytes.get(*ptr) == Some(&0) { *ptr += 1; Ok(to_ret) } else { diff --git a/src/cli.rs b/src/cli.rs index d5025c1..59d3ba1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -18,20 +18,31 @@ * You should have received a copy of the GNU General Public License * along with Orion. If not, see . */ +use crate::{ + bytecode::Bytecode, + compiler::Compiler, + error, + lexer::Lexer, + parser::Parser, + print_err, + vm::{Value, VM}, + Result, +}; use clap::{App, Arg}; use rustyline::{error::ReadlineError, Editor}; -use std::{rc::Rc, time::Instant, path::Path, fs, io::Write}; -use crate::{Result, print_err, error, lexer::{Lexer, Token}, parser::{Parser, Expr}, bytecode::Bytecode, compiler::{Compiler, Macro}, vm::{VM, Value}}; +use std::{fs, io::Write, path::Path, rc::Rc, time::Instant}; + fn repl(dbg_level: u8, lib: String) -> Result<()> { println!( - ";; Orion REPL v{}.\n +r#";; Orion REPL v{}. + ;; Copyright (C) 2021 Wafelack ;; This program comes with ABSOLUTELY NO WARRANTY. ;; This is free software, and you are welcome to redistribute it -;; under certain conditions.", -env!("CARGO_PKG_VERSION") -); +;; under certain conditions."#, + env!("CARGO_PKG_VERSION") + ); let mut ctx = vec![]; let mut symbols = vec![]; let mut bytecode = Bytecode::new(); @@ -39,7 +50,7 @@ env!("CARGO_PKG_VERSION") let mut sym_ref = vec![]; let mut saves = vec![]; let mut macros = vec![]; - let mut vm = VM::new(Bytecode::new(), vec![]); + // let mut vm = VM::new(Bytecode::new(), vec![]); let mut rl = Editor::<()>::new(); let mut i = 0; @@ -62,33 +73,44 @@ env!("CARGO_PKG_VERSION") continue; } }; - + let expressions = match Parser::new(tokens, "REPL").parse() { - Ok(e) => e, - Err(e) => { - print_err(e); - continue; - } - }; - let (new_bytecode, new_syms, new_constructors, new_macros) = match (match Compiler::new(expressions, "REPL", bytecode.clone(), constructors.clone(), i > 1, lib.clone(), true, macros.clone()) { - Ok(c) => c, + Ok(e) => e, Err(e) => { - if i == 1 { - i = 0; - } print_err(e); continue; } - }).compile(symbols.clone()) { - Ok(b) => b, + }; + let mut compiler = match Compiler::new( + expressions, + "REPL", + bytecode.clone(), + constructors.clone(), + i > 1, + lib.clone(), + true, + macros.clone(), + ) { + Ok(c) => c, Err(e) => { if i == 1 { i = 0; - } + } print_err(e); continue; } }; + let (new_bytecode, new_syms, new_constructors, new_macros) = + match compiler.compile(symbols.clone()) { + Ok(b) => b, + Err(e) => { + if i == 1 { + i = 0; + } + print_err(e); + continue; + } + }; bytecode = new_bytecode; symbols = new_syms; constructors = new_constructors; @@ -97,29 +119,35 @@ env!("CARGO_PKG_VERSION") if dbg_level > 1 { println!("{} Compiled in {}ms.", STAR, elapsed.as_millis()); } - vm = VM::<16000>::new(bytecode.clone(), saves.clone()); - let (new_ctx, new_ref, new_saves) = match vm.eval(sym_ref.clone(), ctx.clone(), dbg_level > 2) { - Ok(v) => v, - Err(e) => { - print_err(e); - continue; - } - }; + let mut vm = VM::<16000>::new(bytecode.clone(), saves.clone()); + let (new_ctx, new_ref, new_saves) = + match vm.eval(sym_ref.clone(), ctx.clone(), dbg_level > 2) { + Ok(v) => v, + Err(e) => { + print_err(e); + continue; + } + }; ctx = new_ctx; sym_ref = new_ref; saves = new_saves; - let top = &vm.stack.iter().nth(match vm.stack.len() as isize - 1 { - x if x < 0 => 0, - x => x as usize, - }).and_then(|v| Some((**v).clone())); + let top = &vm + .stack + .get(match vm.stack.len() as isize - 1 { + x if x < 0 => 0, + x => x as usize, + }) + .map(|v| (**v).clone()); if let Some(Value::Tuple(v)) = top { if !v.is_empty() { - println!("=> {}", vm.display_value(Rc::new(top.clone().unwrap()), true)) + println!( + "=> {}", + vm.display_value(Rc::new(top.clone().unwrap()), true) + ) } } else if let Some(v) = top.clone() { println!("=> {}", vm.display_value(Rc::new(v), true)); } - } Err(ReadlineError::Interrupted) => { println!(";; User break"); @@ -184,34 +212,49 @@ pub fn cli() -> Result<()> { let lib = match matches.value_of("lib") { Some(l) => l.to_string(), None => match env::var("ORION_LIB") { - Ok(v) => v.to_string(), + Ok(v) => v, Err(_) => return error!(=> "No such environment variable: ORION_LIB."), - } + }, }; let dbg_level = match matches.value_of("debug-level") { Some(lvl) => match lvl.parse::() { - Ok(u) => if u > 3 { - 3 - } else { - u + Ok(u) => { + if u > 3 { + 3 + } else { + u + } } Err(_) => 0, - } + }, None => 0, }; if let Some(file) = matches.value_of("file") { let output = match matches.value_of("output") { Some(f) => f.to_string(), - None => format!("{}.orc", Path::new(file).file_stem().unwrap().to_str().unwrap()), + None => format!( + "{}.orc", + Path::new(file).file_stem().unwrap().to_str().unwrap() + ), }; let content = match fs::read_to_string(file) { Ok(s) => s, - Err(e) => return error!(=> "Failed to read file: {}: {}.", file, e) + Err(e) => return error!(=> "Failed to read file: {}: {}.", file, e), }; let start = Instant::now(); let tokens = Lexer::new(content, file).proc_tokens()?; let expressions = Parser::new(tokens, file).parse()?; - let (bytecode, ..) = Compiler::new(expressions, file, Bytecode::new(), vec![], false, lib, false, vec![])?.compile(vec![])?; + let (bytecode, ..) = Compiler::new( + expressions, + file, + Bytecode::new(), + vec![], + false, + lib, + false, + vec![], + )? + .compile(vec![])?; let elapsed = start.elapsed(); if dbg_level > 0 { println!("{} Compiled in {}ms.", STAR, elapsed.as_millis()); @@ -219,8 +262,10 @@ pub fn cli() -> Result<()> { let to_write = bytecode.serialize(); match (match fs::File::create(&output) { Ok(f) => f, - Err(e) => return error!(=> "Failed to create file: {}: {}.", output, e) - }).write_all(to_write.as_slice()) { + Err(e) => return error!(=> "Failed to create file: {}: {}.", output, e), + }) + .write_all(to_write.as_slice()) + { Ok(()) => {} Err(e) => return error!(=> "Failed to write file: {}: {}.", output, e), }; diff --git a/src/compiler.rs b/src/compiler.rs index 2cc6ae3..ae85630 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -110,7 +110,7 @@ impl Compiler { &name, self.constructors .iter() - .position(|var| var.to_string() == name) + .position(|var| *var == name) .unwrap() ) } else { @@ -126,7 +126,7 @@ impl Compiler { let idx = self .constructors .iter() - .position(|variant| name == variant.to_string()) + .position(|variant| name == *variant) .unwrap(); Ok((self.output.constructors[idx].0, idx as u16)) } else { @@ -290,10 +290,7 @@ impl Compiler { } ExprT::Call(func, args) => { if let ExprT::Var(v) = func.clone().exprt { - match self.macros.iter().position(|(name, ..)| &v == name) { - Some(i) => return self.r#macro(i, args, symbols, impure, expr.line), - None => {} - } + if let Some(i) = self.macros.iter().position(|(name, ..)| &v == name) { return self.r#macro(i, args, symbols, impure, expr.line) } } let (mut to_ret, mut symbols) = self.compile_expr(*func, symbols, impure)?; // The λ to execute. let argc = args.len() as u16; @@ -386,7 +383,7 @@ impl Compiler { .builtins .iter() .position(|builtin| builtin.0 == name) - .map_or(error!(self.file, expr.line => "No such builtin: {}.", name), |i| Ok(i))?; + .map_or(error!(self.file, expr.line => "No such builtin: {}.", name), Ok)?; let impure_builtin = self.builtins[idx as usize].1; if !impure && impure_builtin { return error!(self.file, expr.line => "Impure builtin used out of an `impure` function: {}.", name); @@ -397,12 +394,10 @@ impl Compiler { ExprT::Enum(name, constructors) => { let start = self.output.constructors.len() as u16; constructors - .into_iter() - .map(|(k, v)| { + .into_iter().try_for_each(|(k, v)| { symbols = self.register_constructor(k, symbols.clone(), v, expr.line)?; Ok(()) - }) - .collect::>()?; + })?; let end = self.output.constructors.len() as u16 - 1; self.output.types.push((name, start, end)); Ok((vec![], symbols)) @@ -457,7 +452,7 @@ impl Compiler { Ok((to_ret, symbols)) } ExprT::Match(expr, patterns) => { - let (mut compiled, mut symbols) = self.compile_expr(*expr.clone(), symbols, impure)?; + let (mut compiled, mut symbols) = self.compile_expr(*expr, symbols, impure)?; let match_content = patterns.into_iter().map(|(pat, expr)| { let (pat_id, new_symbols) = self.declare_pat(pat, symbols.clone(), impure, expr.line)?; symbols = new_symbols; diff --git a/src/errors.rs b/src/errors.rs index 90f3724..6ac888b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -33,7 +33,7 @@ macro_rules! error { let _file = std::option::Option::Some($file.to_string()); let _line = std::option::Option::Some($line); )? - std::result::Result::Err(crate::errors::OrionError(_file, _line, format_args!($($arg)*).to_string())) + std::result::Result::Err($crate::errors::OrionError(_file, _line, format_args!($($arg)*).to_string())) } } diff --git a/src/lexer.rs b/src/lexer.rs index d9565f0..06b4176 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with Orion. If not, see . */ +#![allow(clippy::approx_constant)] use crate::{error, Result}; #[derive(Clone, PartialEq, Debug)] @@ -87,7 +88,7 @@ pub struct Lexer { impl Lexer { pub fn new(input: impl ToString, file: impl ToString) -> Self { Self { - input: input.to_string().replace("λ", "\\").to_string(), + input: input.to_string().replace('λ', "\\"), output: vec![], current: 0, line: 1, @@ -161,11 +162,9 @@ impl Lexer { } else if !self.is_at_end() && self.peek() == '|' { self.advance(); while !self.is_at_end() { - if self.peek() == '|' { - if !self.is_at_end() && self.peek() == '#' { - self.advance(); - break; - } + if self.peek() == '|' && !self.is_at_end() && self.peek() == '#' { + self.advance(); + break; } self.advance(); } @@ -179,7 +178,7 @@ impl Lexer { } } _ => { - if c.is_digit(10) { + if c.is_ascii_digit() { self.number(); } else { self.identifier(); @@ -193,7 +192,7 @@ impl Lexer { self.builtins.push(builtin.to_string()); } fn number(&mut self) { - while !self.is_at_end() && self.peek().is_digit(10) { + while !self.is_at_end() && self.peek().is_ascii_digit() { self.advance(); } @@ -201,7 +200,7 @@ impl Lexer { self.advance(); // Decimal part delimiter } - while !self.is_at_end() && self.peek().is_digit(10) { + while !self.is_at_end() && self.peek().is_ascii_digit() { self.advance(); } @@ -280,7 +279,7 @@ fn apply_ansi_codes(input: &str) -> String { .replace("\\t", "\t") .replace("\\0", "\0") .replace("\\\\", "\\") - .to_string() + } #[cfg(test)] @@ -317,7 +316,7 @@ mod test { let ttypes = get_ttypes(Lexer::new("42 3.1415926535897932", "").proc_tokens()?); assert_eq!( ttypes, - vec![TType::Number(42), TType::Float(3.1415926535897932)] + vec![TType::Number(42), TType::Float(3.141_592_7)] ); Ok(()) } diff --git a/src/main.rs b/src/main.rs index 2862c08..d5a9c26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with Orion. If not, see . */ + mod bytecode; mod compiler; mod errors; diff --git a/src/parser.rs b/src/parser.rs index dca84d2..8e5378a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with Orion. If not, see . */ +#![allow(clippy::approx_constant)] use crate::{ bug, error, lexer::{TType, Token}, @@ -91,7 +92,7 @@ pub enum Pattern { Literal(Literal), } fn first_char(s: impl ToString) -> char { - s.to_string().chars().nth(0).unwrap() + s.to_string().chars().next().unwrap() } pub struct Parser { @@ -141,10 +142,7 @@ impl Parser { } } fn peek(&self) -> Option { - self.input - .iter() - .nth(self.current) - .and_then(|t| Some(t.clone())) + self.input.get(self.current).cloned() } fn is_at_end(&self) -> bool { self.input.len() != 1 && self.current >= self.input.len() @@ -266,7 +264,7 @@ impl Parser { while !self.is_at_end() && self.peek().unwrap().ttype != TType::RBracket { exprs.push(self.parse_expr()?); } - let constr = if exprs.len() >= 1 { + let constr = if !exprs.is_empty() { exprs.into_iter().rev().fold(ExprT::Constr("Nil".to_string(), vec![]), |acc, e| ExprT::Constr("Cons".to_string(), vec![e, Expr::new(acc).line(root.line)])) } else { ExprT::Constr("Nil".to_string(), vec![]) @@ -323,14 +321,10 @@ impl Parser { } TType::Def => { let impure = - if self.peek().and_then(|t| Some(t.ttype)) == Some(TType::Quote) { + if self.peek().map(|t| t.ttype) == Some(TType::Quote) { self.advance(TType::Quote)?; let got = self.advance(TType::Ident("".to_string()))?; - if got.ttype == TType::Ident("impure".to_string()) { - true - } else { - false - } + got.ttype == TType::Ident("impure".to_string()) } else { false }; @@ -556,7 +550,7 @@ mod test { vec![ Expr::new(ExprT::Literal(Literal::String("foo".to_string()))).line(1), Expr::new(ExprT::Literal(Literal::Integer(42))).line(1), - Expr::new(ExprT::Literal(Literal::Single(3.1415926535897932))).line(1), + Expr::new(ExprT::Literal(Literal::Single(3.141_592_7))).line(1), ] ); diff --git a/src/string.rs b/src/string.rs index 9dc547f..4107f01 100644 --- a/src/string.rs +++ b/src/string.rs @@ -51,7 +51,7 @@ impl VM { Ok(Rc::new(Value::String(if i < 0 { "".to_string() } else { - s.chars().nth(i as usize).and_then(|c| Some(format!("{}", c))).unwrap_or("".to_string()) + s.chars().nth(i as usize).map(|c| format!("{}", c)).unwrap_or_else(|| "".to_string()) }))) } else { error!(=> "Expected a String, found a {}.", self.val_type(&string)?) diff --git a/src/vm.rs b/src/vm.rs index 59f4f1c..df63917 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -99,13 +99,13 @@ impl VM { Value::Lambda(u, ..) => format!("λ{}", u), Value::Constructor(id, args) => { let name = self.input.symbols[self.input.constructors[*id as usize].1 as usize].clone(); - if args.len() == 0 { + if args.is_empty() { name } else { - format!( "({} {})", self.input.symbols[self.input.constructors[*id as usize].1 as usize], args.into_iter().map(|a| format!("{}", self.display_value(a.clone(), true))).fold("".to_string(), |acc, c| format!("{}{}{}", acc, if acc.as_str() == "" { "" } else { " " }, c)).trim()) + format!( "({} {})", self.input.symbols[self.input.constructors[*id as usize].1 as usize], args.iter().map(|a| self.display_value(a.clone(), true)).fold("".to_string(), |acc, c| format!("{}{}{}", acc, if acc.as_str() == "" { "" } else { " " }, c)).trim()) } } - Value::Tuple(args) => format!("({})", args.into_iter().map(|a| format!("{}", self.display_value(a.clone(), true))).fold("".to_string(), |acc, c| format!("{}{}{}", acc, if acc.as_str() == "" { "" } else { " " }, c)).trim()), + Value::Tuple(args) => format!("({})", args.iter().map(|a| self.display_value(a.clone(), true)).fold("".to_string(), |acc, c| format!("{}{}{}", acc, if acc.as_str() == "" { "" } else { " " }, c)).trim()), } } fn _cmp(&mut self, lhs: &Value, rhs: &Value) -> Result { @@ -113,54 +113,52 @@ impl VM { match lhs { Value::Single(lhs) => match rhs { Value::Single(rhs) => { - Ok(lhs.partial_cmp(&rhs).unwrap()) + Ok(lhs.partial_cmp(rhs).unwrap()) } - _ => error!(=> "Expected a Single, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected a Single, found a {}.", self.val_type(rhs)?), } Value::Integer(lhs) => match rhs { Value::Integer(rhs) => { - Ok(lhs.cmp(&rhs)) + Ok(lhs.cmp(rhs)) } - _ => error!(=> "Expected an Integer, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected an Integer, found a {}.", self.val_type(rhs)?), } Value::String(lhs) => match rhs { Value::String(rhs) => { - Ok(lhs.cmp(&rhs)) + Ok(lhs.cmp(rhs)) } - _ => error!(=> "Expected a String, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected a String, found a {}.", self.val_type(rhs)?), } Value::Constructor(lid, vlhs) => match &rhs { Value::Constructor(rid, vrhs) => { - let tlhs = self.val_type(&lhs)?; - let trhs = self.val_type(&rhs)?; + let tlhs = self.val_type(lhs)?; + let trhs = self.val_type(rhs)?; if tlhs != trhs { error!(=> "Expected a {}, found a {}.", tlhs, trhs) + } else if lid != rid { + error!(=> "Not the same enum variants, expected 0x{:04x}, found 0x{:04x}", lid, rid) } else { - if lid != rid { - error!(=> "Not the same enum variants, expected 0x{:04x}, found 0x{:04x}", lid, rid) - } else { - let mut to_ret = Ordering::Equal; + let mut to_ret = Ordering::Equal; - for idx in 0..vlhs.len() { - let lhs = &vlhs[idx]; - let rhs = &vrhs[idx]; - let res = self._cmp(lhs, rhs)?; - if res != Ordering::Equal { - to_ret = res; - break; - } + for idx in 0..vlhs.len() { + let lhs = &vlhs[idx]; + let rhs = &vrhs[idx]; + let res = self._cmp(lhs, rhs)?; + if res != Ordering::Equal { + to_ret = res; + break; } - Ok(to_ret) } + Ok(to_ret) } } - _ => error!(=> "Expected a Constructor, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected a Constructor, found a {}.", self.val_type(rhs)?), } Value::Tuple(vlhs) => match rhs { Value::Tuple(vrhs) => { - let tlhs = self.val_type(&lhs)?; - let trhs = self.val_type(&rhs)?; + let tlhs = self.val_type(lhs)?; + let trhs = self.val_type(rhs)?; if tlhs != trhs { error!(=> "Expected a {}, found a {}.", tlhs, trhs) } else { @@ -177,9 +175,9 @@ impl VM { Ok(to_ret) } } - _ => error!(=> "Expected a Tuple, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected a Tuple, found a {}.", self.val_type(rhs)?), } - _ => error!(=> "Expected a String, found a {}.", self.val_type(&rhs)?), + _ => error!(=> "Expected a String, found a {}.", self.val_type(rhs)?), } } @@ -193,12 +191,12 @@ impl VM { } fn r#type(&mut self) -> Result> { let popped = self.pop()?; - let to_ret = Ok(Rc::new(Value::String(self.val_type(&popped)?))); - to_ret + + Ok(Rc::new(Value::String(self.val_type(&popped)?))) } pub fn val_type(&mut self, popped: &Value) -> Result { let to_ret = Ok(match popped { - Value::Constructor(idx, _) => self.input.types[self.input.types.iter().position(|(_, start, end)| (start..=end).contains(&&idx)).unwrap()].0.clone(), + Value::Constructor(idx, _) => self.input.types[self.input.types.iter().position(|(_, start, end)| (start..=end).contains(&idx)).unwrap()].0.clone(), Value::Tuple(content) => format!("({})", content.iter().map(|v|{ let to_ret = self.val_type(v)?; Ok(to_ret) @@ -260,7 +258,7 @@ impl VM { while self.ip < saved + instr_length as usize { self.ip += 1; let instr = instructions[self.ip]; - self.eval_opcode(instr, ctx, sym_ref, &instructions)?; + self.eval_opcode(instr, ctx, sym_ref, instructions)?; } let popped = self.pop()?; let id = if !sym_ref.contains(&sym_id) { @@ -307,10 +305,9 @@ impl VM { args.len() ); } - for idx in 0..chunk.reference.len() { + for (idx, &sym_id) in chunk.reference.iter().enumerate() { // Fetch arguments and replace the symbol table. let val = args[idx].clone(); - let sym_id = chunk.reference[idx]; self.decl(sym_id, val, &mut ctx, &mut sym_ref); } let prev_ip = self.ip; @@ -341,8 +338,8 @@ impl VM { let saved = self.ip; while self.ip < saved + to_eval as usize { self.ip += 1; - let instruction = instructions[self.ip].clone(); - self.eval_opcode(instruction, ctx, sym_ref, instructions.clone())?; + let instruction = instructions[self.ip]; + self.eval_opcode(instruction, ctx, sym_ref, instructions)?; } let mut vals = (0..amount) .map(|_| self.pop()) @@ -366,34 +363,31 @@ impl VM { OpCode::Match(idx) => { let to_match = self.pop()?; let patterns = self.input.matches[idx as usize].clone(); - let plausible = patterns.into_iter().map(|(pat, to_exec)| { + let plausibles: Vec<_> = patterns.into_iter().filter_map(|(pat, to_exec)| { if self.is_plausible(pat, &to_match) { Some((pat, to_exec)) } else { None } - }).filter(|p| !p.is_none()).map(|p| p.unwrap()).collect::)>>(); - for plausible in plausible.into_iter() { - match self.match_and_bound(&to_match, plausible.0) { - Some(to_bind) => { - let mut new_ctx = ctx.clone(); - let mut new_ref = sym_ref.clone(); - let mut new_stack = (0..to_bind.len()).map(|_| self.pop()).rev().collect::>>()?; - to_bind.into_iter().for_each(|sym_id| { - let val = new_stack.pop().unwrap(); - self.decl(sym_id, val, &mut new_ctx, &mut new_ref); - }); - let saved = self.ip; - self.ip = 0; - while self.ip < plausible.1.len() { - let instr = plausible.1[self.ip]; - self.eval_opcode(instr, &mut new_ctx, &mut new_ref, &plausible.1)?; - self.ip += 1; - } - self.ip = saved; - return Ok(()); - }, - None => {}, + }).collect(); + for plausible in plausibles { + if let Some(to_bind) = self.match_and_bound(&to_match, plausible.0) { + let mut new_ctx = ctx.clone(); + let mut new_ref = sym_ref.clone(); + let mut new_stack = (0..to_bind.len()).map(|_| self.pop()).rev().collect::>>()?; + to_bind.into_iter().for_each(|sym_id| { + let val = new_stack.pop().unwrap(); + self.decl(sym_id, val, &mut new_ctx, &mut new_ref); + }); + let saved = self.ip; + self.ip = 0; + while self.ip < plausible.1.len() { + let instr = plausible.1[self.ip]; + self.eval_opcode(instr, &mut new_ctx, &mut new_ref, &plausible.1)?; + self.ip += 1; + } + self.ip = saved; + return Ok(()); } } return error!(=> "No pattern to be matched."); @@ -474,32 +468,16 @@ impl VM { } fn is_plausible(&self, pat: u16, to_match: &Value) -> bool { let pat = self.input.patterns[pat as usize].clone(); - match pat { - BytecodePattern::Var(_) | BytecodePattern::Any => true, - BytecodePattern::Constr(_, _) => if let Value::Constructor(_, _) = to_match { - true - } else { - false - } - BytecodePattern::Tuple(_) => if let Value::Tuple(_) = to_match { - true - } else { - false - } - BytecodePattern::Literal(lid) => match &self.input.constants[lid as usize] { - Literal::Integer(_) => match to_match { - Value::Integer(_) => true, - _ => false, - } - Literal::Single(_) => match to_match { - Value::Single(_) => true, - _ => false - } - Literal::String(_) => match to_match { - Value::String(_) => true, - _ => false, - } + match (pat, to_match) { + (BytecodePattern::Var(_) | BytecodePattern::Any, _) => true, + (BytecodePattern::Constr(_, _), Value::Constructor(_, _)) => true, + (BytecodePattern::Tuple(_), Value::Tuple(_)) => true, + (BytecodePattern::Literal(lid), _) => match &self.input.constants[lid as usize] { + Literal::Integer(_) => matches!(to_match, Value::Integer(_)), + Literal::Single(_) => matches!(to_match, Value::Single(_)), + Literal::String(_) => matches!(to_match, Value::String(_)), } + _ => false } } pub fn eval(&mut self, mut sym_ref: Vec, mut ctx: Vec>, mut step: bool) -> Result<(Vec>, Vec, Vec>>)> { @@ -535,7 +513,7 @@ i\tDisplay the 15 instructions around the instruction pointer."; "n" => return true, "q" => return false, "c" => println!("{}", self.input.instructions[self.ip]), - "s" => println!("[{}]", self.stack.iter().skip(1).fold(self.stack.iter().nth(0).and_then(|e| Some(self.display_value(e.clone(), true))).unwrap_or("".to_string()), |acc, x| format!("{}, {}", acc, self.display_value(x.clone(), true)))), + "s" => println!("[{}]", self.stack.iter().skip(1).fold(self.stack.get(0).map(|e| self.display_value(e.clone(), true)).unwrap_or_else(|| "".to_string()), |acc, x| format!("{}, {}", acc, self.display_value(x.clone(), true)))), "i" => { let start = if 7 > self.ip { (0, -(self.ip as i32)) @@ -545,7 +523,7 @@ i\tDisplay the 15 instructions around the instruction pointer."; let end = if self.ip + 7 > self.input.instructions.len() { (self.input.instructions.len(), self.input.instructions.len() as i32 - self.ip as i32) } else { - (self.ip + 7, 7 as i32) + (self.ip + 7, 7_i32) }; let indices = (start.1..end.1).collect::>(); self.input.instructions[start.0..end.0].iter().enumerate().for_each(|(idx, i)| { @@ -561,11 +539,11 @@ i\tDisplay the 15 instructions around the instruction pointer."; #[cfg(test)] mod test { - use super::*; - use crate::lexer::Lexer; - use crate::parser::Parser; - use crate::compiler::Compiler; - use std::time::Instant; + + + + + #[cfg(not(debug_assertions))] // Run only in Release #[test]