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]