Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
* You should have received a copy of the GNU General Public License
* along with Orion. If not, see <https://www.gnu.org/licenses/>.
*/
#![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)
Expand Down Expand Up @@ -51,6 +52,7 @@ impl Display for OpCode {
}
}
impl OpCode {
#[allow(unused)]
pub fn deserialize(ptr: &mut usize, bytes: &[u8]) -> Result<Self> {
*ptr += 1;
match bytes[*ptr - 1] {
Expand Down Expand Up @@ -126,13 +128,13 @@ impl OpCode {
}
}

#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Chunk {
pub instructions: Vec<OpCode>,
pub reference: Vec<u16>,
}

#[derive(PartialEq, Clone, Debug)]
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum BytecodePattern {
Var(u16), // (sym_idx)
Constr(u16, Vec<u16>), // (constr_id, [pat_idx])
Expand Down Expand Up @@ -167,14 +169,15 @@ impl Bytecode {
}
}
// All numbers here are big endian
#[allow(unused)]
pub fn deserialize(bytes: &[u8]) -> Result<Self> {
if &bytes[0..5] != "orion".chars().into_iter().map(|c| c as u8).collect::<Vec<u8>>() {
if bytes[0..5] != "orion".chars().into_iter().map(|c| c as u8).collect::<Vec<u8>>() {
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::<Result<Vec<String>>>()?;
let symbols = (0..sym_length).map(|_| string(&mut ptr, bytes)).collect::<Result<Vec<String>>>()?;
println!("Syms.");
let consts_length = len(&mut ptr, bytes)?;
println!("Consts length.");
Expand Down Expand Up @@ -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::<Result<Vec<OpCode>>>()?;
Ok((idx, instrs))
}).collect::<Result<Vec<(u16, Vec<OpCode>)>>>()?)
}).collect::<Result<Vec<(u16, Vec<OpCode>)>>>()
}).collect::<Result<Vec<Vec<(u16, Vec<OpCode>)>>>>()?;
println!("Matches.");

Expand Down Expand Up @@ -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);

Expand All @@ -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];
Expand All @@ -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) => {
Expand All @@ -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
}
}
Expand All @@ -414,7 +417,7 @@ fn string(ptr: &mut usize, bytes: &[u8]) -> Result<String> {
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 {
Expand Down
141 changes: 93 additions & 48 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,39 @@
* You should have received a copy of the GNU General Public License
* along with Orion. If not, see <https://www.gnu.org/licenses/>.
*/
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 <wafelack@protonmail.com>
;; 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();
let mut constructors = vec![];
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;
Expand All @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -184,43 +212,60 @@ 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::<u8>() {
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());
}
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),
};
Expand Down
Loading