diff --git a/examples/brainfuck.fml b/examples/brainfuck.fml index a9d5ea7..9a228e0 100644 --- a/examples/brainfuck.fml +++ b/examples/brainfuck.fml @@ -810,4 +810,4 @@ interpreter(program(), false).eval(); // > mogami river // > // > -- yukko -// > \ No newline at end of file +// > diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..2a35f02 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +use_small_heuristics = "Max" diff --git a/src/bytecode/bytecode.rs b/src/bytecode/bytecode.rs index 801d11e..fc24364 100644 --- a/src/bytecode/bytecode.rs +++ b/src/bytecode/bytecode.rs @@ -1,4 +1,4 @@ -use std::io::{Write, Read}; +use std::io::{Read, Write}; use super::serializable; use super::serializable::*; @@ -30,7 +30,7 @@ pub enum OpCode { * [ProgramObject::Integer]: ../objects/enum.ProgramObject.html#variant.Integer * [ProgramObject::Null]: ../objects/enum.ProgramObject.html#variant.Null */ - Literal { index: /*Integer|Null|Boolean*/ ConstantPoolIndex }, // rename to constant + Literal { index: ConstantPoolIndex }, // rename to constant /** * ## Push the value of local variable onto stack @@ -43,7 +43,7 @@ pub enum OpCode { * [LocalFrame]: ../interpreter/struct.LocalFrame.html * [OperandStack]: ../interpreter/struct.OperandStack.html */ - // FIXME writing out all those links in each variant is not sustainable... + // FIXME writing out all those links in each variant is not sustainable... GetLocal { index: LocalFrameIndex }, /** @@ -64,7 +64,7 @@ pub enum OpCode { * * Serialized as opcode `0x0C`. */ - GetGlobal { name: /*String*/ ConstantPoolIndex }, + GetGlobal { name: ConstantPoolIndex }, /** * ## Set the value of global variable to the top value from stack @@ -74,7 +74,7 @@ pub enum OpCode { * * Serialized as opcode `0x0B`. */ - SetGlobal { name: /*String*/ ConstantPoolIndex }, + SetGlobal { name: ConstantPoolIndex }, /** * ## Create a new (runtime) object @@ -95,7 +95,7 @@ pub enum OpCode { * * Serialized as opcode `0x04`. */ - Object { class: /*ProgramObject::Class*/ ConstantPoolIndex }, + Object { class: ConstantPoolIndex }, /** * ## Create a new array (runtime) object @@ -140,7 +140,7 @@ pub enum OpCode { * ## Call a member method * * Pops `arguments` values from the `OperandStack` for the arguments to the call. The last popped - *`RuntimeObject` from the `OperandStack` will be used as the method call's receiver. + *`RuntimeObject` from the `OperandStack` will be used as the method call's receiver. * Afterwards, a `ProgramObject::String` object representing the name of the method to call is * retrieved from the `ConstantPool` from the index specified by `name`. * @@ -187,7 +187,7 @@ pub enum OpCode { * * Serialized as opcode `0x00`. */ - Label { name: /*String*/ ConstantPoolIndex }, + Label { name: ConstantPoolIndex }, /** * ## Print a formatted string @@ -202,7 +202,7 @@ pub enum OpCode { * * Serialized as opcode `0x02`. */ - Print { format: /*String*/ ConstantPoolIndex, arguments: Arity }, + Print { format: ConstantPoolIndex, arguments: Arity }, /** * ## Jump to a label @@ -212,7 +212,7 @@ pub enum OpCode { * * Serialized as opcode `0x0E`. */ - Jump { label: /*String*/ ConstantPoolIndex }, + Jump { label: ConstantPoolIndex }, /** * ## Conditionally jump to a label @@ -223,7 +223,7 @@ pub enum OpCode { * * Serialized as opcode `0x0D`. */ - Branch { label: /*String*/ ConstantPoolIndex }, + Branch { label: ConstantPoolIndex }, /** * ## Return from the current function or method @@ -249,41 +249,38 @@ pub enum OpCode { Drop, } - - impl Serializable for OpCode { - - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u8(sink, self.to_hex())?; use OpCode::*; match self { - Label { name } => { name.serialize(sink) }, - Literal { index } => { index.serialize(sink) }, + Label { name } => name.serialize(sink), + Literal { index } => index.serialize(sink), Print { format, arguments } => { format.serialize(sink)?; arguments.serialize(sink) - }, - Array => { Ok(()) }, - Object { class } => { class.serialize(sink) }, - GetField { name } => { name.serialize(sink) }, - SetField { name } => { name.serialize(sink) }, + } + Array => Ok(()), + Object { class } => class.serialize(sink), + GetField { name } => name.serialize(sink), + SetField { name } => name.serialize(sink), CallMethod { name, arguments } => { name.serialize(sink)?; arguments.serialize(sink) - }, + } CallFunction { name: function, arguments } => { function.serialize(sink)?; arguments.serialize(sink) - }, - SetLocal { index } => { index.serialize(sink) }, - GetLocal { index } => { index.serialize(sink) }, - SetGlobal { name } => { name.serialize(sink) }, - GetGlobal { name } => { name.serialize(sink) }, - Branch { label } => { label.serialize(sink) }, - Jump { label } => { label.serialize(sink) }, - Return => { Ok(()) }, - Drop => { Ok(()) }, + } + SetLocal { index } => index.serialize(sink), + GetLocal { index } => index.serialize(sink), + SetGlobal { name } => name.serialize(sink), + GetGlobal { name } => name.serialize(sink), + Branch { label } => label.serialize(sink), + Jump { label } => label.serialize(sink), + Return => Ok(()), + Drop => Ok(()), // Skip => { Ok(()) }, } } @@ -293,52 +290,58 @@ impl Serializable for OpCode { use OpCode::*; match tag { - 0x00 => Label { name: ConstantPoolIndex::from_bytes(input) }, - 0x01 => Literal { index: ConstantPoolIndex::from_bytes(input) }, - 0x02 => Print { format: ConstantPoolIndex::from_bytes(input), - arguments: Arity::from_bytes(input) }, - 0x03 => Array { }, - 0x04 => Object { class: ConstantPoolIndex::from_bytes(input) }, - 0x05 => GetField { name: ConstantPoolIndex::from_bytes(input) }, - 0x06 => SetField { name: ConstantPoolIndex::from_bytes(input) }, - 0x07 => CallMethod { name: ConstantPoolIndex::from_bytes(input), - arguments: Arity::from_bytes(input) }, - 0x08 => CallFunction { name: ConstantPoolIndex::from_bytes(input), - arguments: Arity::from_bytes(input) }, - 0x09 => SetLocal { index: LocalFrameIndex::from_bytes(input) }, - 0x0A => GetLocal { index: LocalFrameIndex::from_bytes(input) }, - 0x0B => SetGlobal { name: ConstantPoolIndex::from_bytes(input) }, - 0x0C => GetGlobal { name: ConstantPoolIndex::from_bytes(input) }, - 0x0D => Branch { label: ConstantPoolIndex::from_bytes(input) }, - 0x0E => Jump { label: ConstantPoolIndex::from_bytes(input) }, + 0x00 => Label { name: ConstantPoolIndex::from_bytes(input) }, + 0x01 => Literal { index: ConstantPoolIndex::from_bytes(input) }, + 0x02 => Print { + format: ConstantPoolIndex::from_bytes(input), + arguments: Arity::from_bytes(input), + }, + 0x03 => Array {}, + 0x04 => Object { class: ConstantPoolIndex::from_bytes(input) }, + 0x05 => GetField { name: ConstantPoolIndex::from_bytes(input) }, + 0x06 => SetField { name: ConstantPoolIndex::from_bytes(input) }, + 0x07 => CallMethod { + name: ConstantPoolIndex::from_bytes(input), + arguments: Arity::from_bytes(input), + }, + 0x08 => CallFunction { + name: ConstantPoolIndex::from_bytes(input), + arguments: Arity::from_bytes(input), + }, + 0x09 => SetLocal { index: LocalFrameIndex::from_bytes(input) }, + 0x0A => GetLocal { index: LocalFrameIndex::from_bytes(input) }, + 0x0B => SetGlobal { name: ConstantPoolIndex::from_bytes(input) }, + 0x0C => GetGlobal { name: ConstantPoolIndex::from_bytes(input) }, + 0x0D => Branch { label: ConstantPoolIndex::from_bytes(input) }, + 0x0E => Jump { label: ConstantPoolIndex::from_bytes(input) }, 0x0F => Return, 0x10 => Drop, - tag => panic!("Cannot deserialize opcode: unknown tag {}", tag) + tag => panic!("Cannot deserialize opcode: unknown tag {}", tag), } } } impl OpCode { - pub fn to_hex(&self) -> u8 { + pub fn to_hex(self) -> u8 { use OpCode::*; match self { - Label { name: _ } => 0x00, - Literal { index: _ } => 0x01, - Print { format: _, arguments: _ } => 0x02, - Array { } => 0x03, - Object { class: _ } => 0x04, - GetField { name: _ } => 0x05, - SetField { name: _ } => 0x06, - CallMethod { name: _, arguments: _ } => 0x07, + Label { name: _ } => 0x00, + Literal { index: _ } => 0x01, + Print { format: _, arguments: _ } => 0x02, + Array {} => 0x03, + Object { class: _ } => 0x04, + GetField { name: _ } => 0x05, + SetField { name: _ } => 0x06, + CallMethod { name: _, arguments: _ } => 0x07, CallFunction { name: _, arguments: _ } => 0x08, - SetLocal { index: _ } => 0x09, - GetLocal { index: _ } => 0x0A, - SetGlobal { name: _ } => 0x0B, - GetGlobal { name: _ } => 0x0C, - Branch { label: _ } => 0x0D, - Jump { label: _ } => 0x0E, - Return => 0x0F, - Drop => 0x10, + SetLocal { index: _ } => 0x09, + GetLocal { index: _ } => 0x0A, + SetGlobal { name: _ } => 0x0B, + GetGlobal { name: _ } => 0x0C, + Branch { label: _ } => 0x0D, + Jump { label: _ } => 0x0E, + Return => 0x0F, + Drop => 0x10, // Skip => 0xFF, } } @@ -352,7 +355,10 @@ impl OpCode { opcodes } - pub fn write_opcode_vector(sink: &mut W, vector: &Vec<&OpCode>) -> anyhow::Result<()> { + pub fn write_opcode_vector( + sink: &mut W, + vector: &Vec<&OpCode>, + ) -> anyhow::Result<()> { serializable::write_usize_as_u32(sink, vector.len())?; for opcode in vector { opcode.serialize(sink)?; @@ -364,40 +370,23 @@ impl OpCode { impl std::fmt::Display for OpCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - OpCode::Literal { index } => - write!(f, "lit {}", index), - OpCode::GetLocal { index } => - write!(f, "get local {}", index), - OpCode::SetLocal { index } => - write!(f, "set local {}", index), - OpCode::GetGlobal { name } => - write!(f, "get global {}", name), - OpCode::SetGlobal { name } => - write!(f, "set global {}", name), - OpCode::Object { class } => - write!(f, "object {}", class), - OpCode::Array => - write!(f, "array"), - OpCode::GetField { name } => - write!(f, "get slot {}", name), - OpCode::SetField { name } => - write!(f, "set slot {}", name), - OpCode::CallMethod { name, arguments } => - write!(f, "call slot {} {}", name, arguments), - OpCode::CallFunction { name, arguments } => - write!(f, "call {} {}", name, arguments), - OpCode::Print { format, arguments } => - write!(f, "printf {} {}", format, arguments), - OpCode::Label { name } => - write!(f, "label {}", name), - OpCode::Jump { label } => - write!(f, "goto {}", label), - OpCode::Branch { label } => - write!(f, "branch {}", label), - OpCode::Return => - write!(f, "return"), - OpCode::Drop => - write!(f, "drop"), + OpCode::Literal { index } => write!(f, "lit {}", index), + OpCode::GetLocal { index } => write!(f, "get local {}", index), + OpCode::SetLocal { index } => write!(f, "set local {}", index), + OpCode::GetGlobal { name } => write!(f, "get global {}", name), + OpCode::SetGlobal { name } => write!(f, "set global {}", name), + OpCode::Object { class } => write!(f, "object {}", class), + OpCode::Array => write!(f, "array"), + OpCode::GetField { name } => write!(f, "get slot {}", name), + OpCode::SetField { name } => write!(f, "set slot {}", name), + OpCode::CallMethod { name, arguments } => write!(f, "call slot {} {}", name, arguments), + OpCode::CallFunction { name, arguments } => write!(f, "call {} {}", name, arguments), + OpCode::Print { format, arguments } => write!(f, "printf {} {}", format, arguments), + OpCode::Label { name } => write!(f, "label {}", name), + OpCode::Jump { label } => write!(f, "goto {}", label), + OpCode::Branch { label } => write!(f, "branch {}", label), + OpCode::Return => write!(f, "return"), + OpCode::Drop => write!(f, "drop"), } } -} \ No newline at end of file +} diff --git a/src/bytecode/compiler.rs b/src/bytecode/compiler.rs index 3b1d801..6fb5a6a 100644 --- a/src/bytecode/compiler.rs +++ b/src/bytecode/compiler.rs @@ -46,43 +46,62 @@ impl ProgramGenerator { } pub struct LabelGenerator { - names: HashSet, groups: usize + names: HashSet, + groups: usize, } impl LabelGenerator { - pub fn new() -> Self { LabelGenerator { names: HashSet::new(), groups: 0 } } - pub(crate) fn generate_name_within_group(&self, prefix: S, group: usize) -> Result where S: Into { + pub fn new() -> Self { + LabelGenerator { names: HashSet::new(), groups: 0 } + } + pub(crate) fn generate_name_within_group(&self, prefix: S, group: usize) -> Result + where + S: Into, + { let name = format!("{}:{}", prefix.into(), group); bail_if!(self.names.contains(&name), "Label `{}` already exists.", name); Ok(name) } - pub fn generate_name(&mut self, prefix: S) -> Result where S: Into { + pub fn generate_name(&mut self, prefix: S) -> Result + where + S: Into, + { let name = self.generate_name_within_group(prefix, self.groups)?; - self.groups = self.groups + 1; + self.groups += 1; Ok(name) } #[allow(dead_code)] - pub fn generate(&mut self, prefix: S) -> Result where S: Into { - self.generate_name(prefix) - .map(|name| ProgramObject::String(name)) + pub fn generate(&mut self, prefix: S) -> Result + where + S: Into, + { + self.generate_name(prefix).map(ProgramObject::String) } pub fn create_group(&mut self) -> LabelGroup<'_> { let group = self.groups; - self.groups = self.groups + 1; + self.groups += 1; LabelGroup { labels: self, group } } } -pub struct LabelGroup<'a> { labels: &'a LabelGenerator, group: usize } +pub struct LabelGroup<'a> { + labels: &'a LabelGenerator, + group: usize, +} impl LabelGroup<'_> { - pub fn generate_name(&self, prefix: S) -> Result where S: Into { + pub fn generate_name(&self, prefix: S) -> Result + where + S: Into, + { self.labels.generate_name_within_group(prefix, self.group) } #[allow(dead_code)] - pub fn generate(&self, prefix: S) -> Result where S: Into { - self.labels.generate_name_within_group(prefix, self.group) - .map(|name| ProgramObject::String(name)) + pub fn generate(&self, prefix: S) -> Result + where + S: Into, + { + self.labels.generate_name_within_group(prefix, self.group).map(ProgramObject::String) } } @@ -92,7 +111,13 @@ pub fn compile(ast: &AST) -> Result { let mut current_frame = Frame::Top; let mut active_buffer = Code::new(); - ast.compile_into(&mut program, &mut active_buffer, &mut global_environment, &mut current_frame, true)?; + ast.compile_into( + &mut program, + &mut active_buffer, + &mut global_environment, + &mut current_frame, + true, + )?; program.completed_code.extend(active_buffer); program.materialize() @@ -100,7 +125,7 @@ pub fn compile(ast: &AST) -> Result { type Scope = usize; -#[derive(PartialEq,Debug,Clone)] +#[derive(PartialEq, Debug, Clone)] pub enum Frame { Local(Environment), Top, @@ -121,7 +146,7 @@ impl Frame { } } -#[derive(PartialEq,Debug,Clone)] +#[derive(PartialEq, Debug, Clone)] pub struct Environment { locals: HashMap<(Scope, String), LocalFrameIndex>, scopes: Vec, @@ -131,7 +156,7 @@ pub struct Environment { impl Environment { pub fn new() -> Self { - Environment { locals: HashMap::new(), scopes: vec!(0), scope_sequence: 0, unique_number: 0 } + Environment { locals: HashMap::new(), scopes: vec![0], scope_sequence: 0, unique_number: 0 } } pub fn from_locals(locals: Vec) -> Self { @@ -141,10 +166,9 @@ impl Environment { local_map.insert((0, local), LocalFrameIndex::from_usize(i)); } - Environment { locals: local_map, scopes: vec!(0), scope_sequence: 0, unique_number: 0 } + Environment { locals: local_map, scopes: vec![0], scope_sequence: 0, unique_number: 0 } } - pub fn from_locals_at(locals: Vec, level: usize) -> Self { let mut local_map: HashMap<(Scope, String), LocalFrameIndex> = HashMap::new(); @@ -152,7 +176,12 @@ impl Environment { local_map.insert((level, local), LocalFrameIndex::from_usize(i)); } - Environment { locals: local_map, scopes: vec!(0), scope_sequence: level + 1, unique_number: 0 } + Environment { + locals: local_map, + scopes: vec![0], + scope_sequence: level + 1, + unique_number: 0, + } } fn current_scope(&self) -> Scope { @@ -161,7 +190,7 @@ impl Environment { pub fn generate_unique_number(&mut self) -> usize { let number = self.unique_number; - self.unique_number +=1 ; + self.unique_number += 1; number } @@ -169,8 +198,10 @@ impl Environment { let key = (self.current_scope(), id.to_string()); if let Some(index) = self.locals.get(&key) { - return Err(format!("Local {} already exist (at index {:?}) and cannot be redefined", - id, index)) + return Err(format!( + "Local {} already exist (at index {:?}) and cannot be redefined", + id, index + )); } let index = LocalFrameIndex::from_usize(self.locals.len()); @@ -199,7 +230,7 @@ impl Environment { return true; } } - return false; + false } fn in_outermost_scope(&self) -> bool { @@ -217,24 +248,47 @@ impl Environment { } pub fn leave_scope(&mut self) { - self.scopes.pop() - .expect("Cannot leave scope: the scope stack is empty"); + self.scopes.pop().expect("Cannot leave scope: the scope stack is empty"); } } pub trait Compiled { - fn compile_into(&self, program: &mut ProgramGenerator, active_buffer: &mut Code, global_environment: &mut Environment, current_frame: &mut Frame, keep_result: bool) -> Result<()>; - fn compile(&self, global_environment: &mut Environment, current_frame: &mut Frame) -> Result { + fn compile_into( + &self, + program: &mut ProgramGenerator, + active_buffer: &mut Code, + global_environment: &mut Environment, + current_frame: &mut Frame, + keep_result: bool, + ) -> Result<()>; + fn compile( + &self, + global_environment: &mut Environment, + current_frame: &mut Frame, + ) -> Result { let mut program = ProgramGenerator::new(); let mut active_buffer: Code = Code::new(); - self.compile_into(&mut program, &mut active_buffer, global_environment, current_frame, true)?; + self.compile_into( + &mut program, + &mut active_buffer, + global_environment, + current_frame, + true, + )?; program.completed_code.extend(active_buffer); program.materialize() } } impl Compiled for AST { - fn compile_into(&self, program: &mut ProgramGenerator, active_buffer: &mut Code, global_environment: &mut Environment, current_frame: &mut Frame, keep_result: bool) -> Result<()> { + fn compile_into( + &self, + program: &mut ProgramGenerator, + active_buffer: &mut Code, + global_environment: &mut Environment, + current_frame: &mut Frame, + keep_result: bool, + ) -> Result<()> { match self { AST::Integer(value) => { let constant = ProgramObject::Integer(*value); @@ -258,66 +312,98 @@ impl Compiled for AST { } AST::Variable { name: Identifier(name), value } => { - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; match current_frame { Frame::Local(environment) => { - let index = environment.register_new_local(name) - .expect(&format!("Cannot register new variable {}", &name)) - .clone(); + let index = environment + .register_new_local(name) + .unwrap_or_else(|_| panic!("Cannot register new variable {}", &name)); active_buffer.emit(OpCode::SetLocal { index }); - }, + } Frame::Top if !global_environment.in_outermost_scope() => { - let index = global_environment.register_new_local(name) - .expect(&format!("Cannot register new variable {}", &name)) - .clone(); + let index = global_environment + .register_new_local(name) + .unwrap_or_else(|_| panic!("Cannot register new variable {}", &name)); active_buffer.emit(OpCode::SetLocal { index }); - }, + } _ => { - let name_index = program.constant_pool.register(ProgramObject::from_str(name)); - let slot_index = - program.constant_pool.register(ProgramObject::Slot { name: name_index }); - program.globals.register(slot_index) - .expect(&format!("Cannot register new global {}", name)); + let name_index = + program.constant_pool.register(ProgramObject::from_str(name)); + let slot_index = program + .constant_pool + .register(ProgramObject::Slot { name: name_index }); + program + .globals + .register(slot_index) + .unwrap_or_else(|_| panic!("Cannot register new global {}", name)); active_buffer.emit(OpCode::SetGlobal { name: name_index }); - }, + } } active_buffer.emit_unless(OpCode::Drop, keep_result); } - AST::AccessVariable { name: Identifier(name) } => { - match current_frame { - Frame::Local(environment) if environment.has_local(name) => { - let index = environment.register_local(name).clone(); - active_buffer.emit(OpCode::GetLocal { index }); - }, - Frame::Top if !global_environment.in_outermost_scope() && global_environment.has_local(name) => { - let index = global_environment.register_local(name).clone(); - active_buffer.emit(OpCode::GetLocal { index }); - }, - _ => { - let index = program.constant_pool.register(ProgramObject::from_str(name)); - active_buffer.emit(OpCode::GetGlobal { name: index }); - }, + AST::AccessVariable { name: Identifier(name) } => match current_frame { + Frame::Local(environment) if environment.has_local(name) => { + let index = environment.register_local(name); + active_buffer.emit(OpCode::GetLocal { index }); } - } + Frame::Top + if !global_environment.in_outermost_scope() + && global_environment.has_local(name) => + { + let index = global_environment.register_local(name); + active_buffer.emit(OpCode::GetLocal { index }); + } + _ => { + let index = program.constant_pool.register(ProgramObject::from_str(name)); + active_buffer.emit(OpCode::GetGlobal { name: index }); + } + }, AST::AssignVariable { name: Identifier(name), value } => { match current_frame { Frame::Local(environment) if environment.has_local(name) => { - let index = environment.register_local(name).clone(); // FIXME error if does not exists - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; // FIXME scoping!!! + let index = environment.register_local(name); // FIXME error if does not exists + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; // FIXME scoping!!! active_buffer.emit(OpCode::SetLocal { index }); - }, - Frame::Top if !global_environment.in_outermost_scope() && global_environment.has_local(name) => { - let index = global_environment.register_local(name).clone(); // FIXME error if does not exists - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; // FIXME scoping!!! + } + Frame::Top + if !global_environment.in_outermost_scope() + && global_environment.has_local(name) => + { + let index = global_environment.register_local(name); // FIXME error if does not exists + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; // FIXME scoping!!! active_buffer.emit(OpCode::SetLocal { index }); - }, + } _ => { let index = program.constant_pool.register(ProgramObject::from_str(name)); - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; active_buffer.emit(OpCode::SetGlobal { name: index }); - }, + } } active_buffer.emit_unless(OpCode::Drop, keep_result); } @@ -332,13 +418,31 @@ impl Compiled for AST { let end_label_index = program.constant_pool.register(ProgramObject::from_str(&end_label)); - (**condition).compile_into(program, active_buffer, global_environment, current_frame, true)?; - active_buffer.emit(OpCode::Branch { label: consequent_label_index } ); - (**alternative).compile_into(program, active_buffer, global_environment, current_frame, keep_result)?; - active_buffer.emit(OpCode::Jump { label: end_label_index } ); + (**condition).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + active_buffer.emit(OpCode::Branch { label: consequent_label_index }); + (**alternative).compile_into( + program, + active_buffer, + global_environment, + current_frame, + keep_result, + )?; + active_buffer.emit(OpCode::Jump { label: end_label_index }); active_buffer.emit(OpCode::Label { name: consequent_label_index }); //program.labels.set(consequent_label, program.code.current_address())?; - (**consequent).compile_into(program, active_buffer, global_environment, current_frame, keep_result)?; + (**consequent).compile_into( + program, + active_buffer, + global_environment, + current_frame, + keep_result, + )?; active_buffer.emit(OpCode::Label { name: end_label_index }); //program.labels.set(end_label, program.code.current_address())?; } @@ -356,10 +460,22 @@ impl Compiled for AST { active_buffer.emit(OpCode::Jump { label: condition_label_index }); active_buffer.emit(OpCode::Label { name: body_label_index }); //program.labels.set(body_label, program.code.current_address())?; - (**body).compile_into(program, active_buffer, global_environment, current_frame, false)?; + (**body).compile_into( + program, + active_buffer, + global_environment, + current_frame, + false, + )?; active_buffer.emit(OpCode::Label { name: condition_label_index }); //program.labels.set(condition_label, program.code.current_address())?; - (**condition).compile_into(program, active_buffer, global_environment, current_frame, true)?; + (**condition).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; active_buffer.emit(OpCode::Branch { label: body_label_index }); if keep_result { @@ -371,13 +487,28 @@ impl Compiled for AST { AST::Array { size, value } => { match value.deref() { - AST::Boolean(_) | AST::Integer(_) | AST::Null | - AST::AccessVariable { name:_ } | AST::AccessField { object:_, field:_ } => { - size.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + AST::Boolean(_) + | AST::Integer(_) + | AST::Null + | AST::AccessVariable { name: _ } + | AST::AccessField { object: _, field: _ } => { + size.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; active_buffer.emit(OpCode::Array); active_buffer.emit_unless(OpCode::Drop, keep_result); - }, + } _ => { let unique_number = global_environment.generate_unique_number(); let i_id = Identifier::from(format!("::i_{}", unique_number)); @@ -385,25 +516,23 @@ impl Compiled for AST { let array_id = Identifier::from(format!("::array_{}", unique_number)); // let ::size = eval SIZE; - let size_definition = - AST::variable(size_id.clone(), *size.clone()); + let size_definition = AST::variable(size_id.clone(), *size.clone()); // let ::array = array(::size, null); let array_definition = AST::variable( array_id.clone(), - AST::array( - AST::access_variable(size_id.clone()), - AST::null())); + AST::array(AST::access_variable(size_id.clone()), AST::null()), + ); // let ::i = 0; - let i_definition = AST::variable( - i_id.clone(), AST::integer(0)); + let i_definition = AST::variable(i_id.clone(), AST::integer(0)); // ::array[::i] <- eval VALUE; let set_array = AST::assign_array( AST::access_variable(array_id.clone()), AST::access_variable(i_id.clone()), - *value.clone()); + *value.clone(), + ); // ::i <- ::i + 1; let increment_i = AST::assign_variable( @@ -411,22 +540,24 @@ impl Compiled for AST { AST::operation( Operator::Addition, AST::access_variable(i_id.clone()), - AST::Integer(1))); + AST::Integer(1), + ), + ); // ::i < ::size let comparison = AST::operation( Operator::Less, AST::access_variable(i_id), - AST::access_variable(size_id)); + AST::access_variable(size_id), + ); // while ::i < ::size do // begin // ::array[::i] <- eval VALUE; // ::i <- ::i + 1; // end; - let loop_de_loop = AST::loop_de_loop( - comparison, - AST::block(vec![set_array, increment_i])); + let loop_de_loop = + AST::loop_de_loop(comparison, AST::block(vec![set_array, increment_i])); // ::array let array = AST::access_variable(array_id); @@ -440,18 +571,60 @@ impl Compiled for AST { // ::i <- ::i + 1; // end; // ::array - size_definition.compile_into(program, active_buffer, global_environment, current_frame, false)?; - array_definition.compile_into(program, active_buffer, global_environment, current_frame, false)?; - i_definition.compile_into(program, active_buffer, global_environment, current_frame, false)?; - loop_de_loop.compile_into(program, active_buffer, global_environment, current_frame, false)?; - array.compile_into(program, active_buffer, global_environment, current_frame, keep_result)?; + size_definition.compile_into( + program, + active_buffer, + global_environment, + current_frame, + false, + )?; + array_definition.compile_into( + program, + active_buffer, + global_environment, + current_frame, + false, + )?; + i_definition.compile_into( + program, + active_buffer, + global_environment, + current_frame, + false, + )?; + loop_de_loop.compile_into( + program, + active_buffer, + global_environment, + current_frame, + false, + )?; + array.compile_into( + program, + active_buffer, + global_environment, + current_frame, + keep_result, + )?; } } } AST::AccessArray { array, index } => { - (**array).compile_into(program, active_buffer, global_environment, current_frame, true)?; - (**index).compile_into(program, active_buffer, global_environment, current_frame, true)?; + array.compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + (**index).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; let name = program.constant_pool.register(ProgramObject::String("get".to_string())); @@ -460,9 +633,27 @@ impl Compiled for AST { } AST::AssignArray { array, index, value } => { - (**array).compile_into(program, active_buffer, global_environment, current_frame, true)?; - (**index).compile_into(program, active_buffer, global_environment, current_frame, true)?; - (**value).compile_into(program, active_buffer, global_environment, current_frame, true)?; + (**array).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + (**index).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + (**value).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; let name = program.constant_pool.register(ProgramObject::String("set".to_string())); @@ -475,7 +666,13 @@ impl Compiled for AST { program.constant_pool.register(ProgramObject::String(format.to_string())); for argument in arguments.iter() { - argument.compile_into(program, active_buffer, global_environment, current_frame, true)?; + argument.compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; } let arguments = Arity::from_usize(arguments.len()); @@ -488,18 +685,23 @@ impl Compiled for AST { // let end_label_index = // program.constant_pool.register(ProgramObject::from_str(&end_label)); - let mut function_buffer = Code::new(); // function_buffer.emit(OpCode::Jump { label: end_label_index }); - let mut child_environment = Environment::new(); - for parameter in parameters.into_iter() { // TODO Environment::from + for parameter in parameters { + // TODO Environment::from child_environment.register_local(parameter.as_str()); } - let mut child_frame = &mut Frame::Local(child_environment); + let child_frame = &mut Frame::Local(child_environment); - (**body).compile_into(program, &mut function_buffer, global_environment, &mut child_frame, true)?; + (**body).compile_into( + program, + &mut function_buffer, + global_environment, + child_frame, + true, + )?; let locals_in_frame = match child_frame { Frame::Local(child_environment) => child_environment.count_locals(), @@ -511,7 +713,8 @@ impl Compiled for AST { // function_buffer.emit(OpCode::Label { name: end_label_index }); //program.labels.set(end_label, program.code.current_address())?; - let (start_address, function_length) = program.completed_code.extend(function_buffer); + let (start_address, function_length) = + program.completed_code.extend(function_buffer); // XXX finish slab @@ -532,7 +735,13 @@ impl Compiled for AST { AST::CallFunction { name: Identifier(name), arguments } => { let index = program.constant_pool.register(ProgramObject::String(name.to_string())); for argument in arguments.iter() { - argument.compile_into(program, active_buffer, global_environment, current_frame, true)?; + argument.compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; } let arity = Arity::from_usize(arguments.len()); active_buffer.emit(OpCode::CallFunction { name: index, arguments: arity }); @@ -540,21 +749,43 @@ impl Compiled for AST { } AST::Object { extends, members } => { - (**extends).compile_into(program, active_buffer, global_environment, current_frame, true)?; - - let slots: Result> = members.iter().map(|m| m.deref()).map(|m| match m { - AST::Function { name, parameters, body } => { - compile_function_definition(name.as_str(), true, parameters, body.deref(), - program, global_environment, current_frame) - - } - AST::Variable { name: Identifier(name), value } => { - (*value).compile_into(program, active_buffer, global_environment, current_frame, true)?; - let index = program.constant_pool.register(ProgramObject::from_str(name)); - Ok(program.constant_pool.register(ProgramObject::slot_from_index(index))) - }, - _ => panic!("Object definition: cannot define a member from {:?}", m) - }).collect(); + (**extends).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + + let slots: Result> = members + .iter() + .map(|m| match m { + AST::Function { name, parameters, body } => compile_function_definition( + name.as_str(), + true, + parameters, + body.deref(), + program, + global_environment, + current_frame, + ), + AST::Variable { name: Identifier(name), value } => { + (*value).compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + let index = + program.constant_pool.register(ProgramObject::from_str(name)); + Ok(program + .constant_pool + .register(ProgramObject::slot_from_index(index))) + } + _ => panic!("Object definition: cannot define a member from {:?}", m), + }) + .collect(); let class = ProgramObject::Class(slots?); let class_index = program.constant_pool.register(class); @@ -572,7 +803,13 @@ impl Compiled for AST { let length = children.len(); for (i, child) in children.iter().enumerate() { let last = i + 1 == length; - child.deref().compile_into(program, active_buffer, global_environment, current_frame, last && keep_result)?; + child.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + last && keep_result, + )?; } match current_frame { @@ -582,15 +819,33 @@ impl Compiled for AST { } AST::AccessField { object, field: Identifier(name) } => { - object.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + object.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; let index = program.constant_pool.register(ProgramObject::from_str(name)); active_buffer.emit(OpCode::GetField { name: index }); active_buffer.emit_unless(OpCode::Drop, keep_result); } AST::AssignField { object, field: Identifier(name), value } => { - object.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; - value.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + object.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; + value.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; let index = program.constant_pool.register(ProgramObject::from_str(name)); active_buffer.emit(OpCode::SetField { name: index }); active_buffer.emit_unless(OpCode::Drop, keep_result); @@ -598,17 +853,29 @@ impl Compiled for AST { AST::CallMethod { object, name: Identifier(name), arguments } => { let index = program.constant_pool.register(ProgramObject::from_str(name)); - object.deref().compile_into(program, active_buffer, global_environment, current_frame, true)?; + object.deref().compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; for argument in arguments.iter() { - argument.compile_into(program, active_buffer, global_environment, current_frame, true)?; + argument.compile_into( + program, + active_buffer, + global_environment, + current_frame, + true, + )?; } let arity = Arity::from_usize(arguments.len() + 1); active_buffer.emit(OpCode::CallMethod { name: index, arguments: arity }); active_buffer.emit_unless(OpCode::Drop, keep_result); } - AST::Top (children) => { - let function_name_index= + AST::Top(children) => { + let function_name_index = program.constant_pool.register(ProgramObject::from_string("λ:".to_owned())); let mut top_buffer = Code::new(); @@ -616,8 +883,14 @@ impl Compiled for AST { let children_count = children.len(); for (i, child) in children.iter().enumerate() { let last = children_count == i + 1; - child.deref().compile_into(program, &mut top_buffer, global_environment, current_frame, last)?; // TODO uggo - // TODO could be cute to pop exit status off of stack + child.deref().compile_into( + program, + &mut top_buffer, + global_environment, + current_frame, + last, + )?; // TODO uggo + // TODO could be cute to pop exit status off of stack } let (start_address, function_length) = program.completed_code.extend(top_buffer); @@ -641,14 +914,15 @@ impl Compiled for AST { } } -fn compile_function_definition(name: &str, - receiver: bool, - parameters: &Vec, - body: &AST, - program: &mut ProgramGenerator, - global_environment: &mut Environment, - _current_frame: &mut Frame) -> Result { - +fn compile_function_definition( + name: &str, + receiver: bool, + parameters: &Vec, + body: &AST, + program: &mut ProgramGenerator, + global_environment: &mut Environment, + _current_frame: &mut Frame, +) -> Result { // let end_label = program.labels.generate_name(format!("λ:{}", name))?; // let end_label_index = // program.constant_pool.register(ProgramObject::from_str(&end_label)); @@ -656,18 +930,19 @@ fn compile_function_definition(name: &str, let mut function_buffer = Code::new(); // function_buffer.emit(OpCode::Jump { label: end_label_index }); - let expected_arguments = parameters.len() + if receiver { 1 } else { 0 }; + let expected_arguments = parameters.len() + receiver as usize; let mut child_environment = Environment::new(); if receiver { child_environment.register_local("this"); } - for parameter in parameters.into_iter() { // TODO Environment::from + for parameter in parameters { + // TODO Environment::from child_environment.register_local(parameter.as_str()); } - let mut child_frame = &mut Frame::Local(child_environment); + let child_frame = &mut Frame::Local(child_environment); - body.compile_into(program, &mut function_buffer, global_environment, &mut child_frame, true)?; + body.compile_into(program, &mut function_buffer, global_environment, child_frame, true)?; let locals_in_frame = match child_frame { Frame::Local(child_environment) => child_environment.count_locals(), diff --git a/src/bytecode/debug.rs b/src/bytecode/debug.rs index 58428a0..590daa5 100644 --- a/src/bytecode/debug.rs +++ b/src/bytecode/debug.rs @@ -1,7 +1,7 @@ use std::io::Write; use super::bytecode::OpCode; -use super::program::{Program, Code}; +use super::program::{Code, Program}; use crate::bytecode::program::*; pub trait PrettyPrint: UglyPrint { @@ -29,7 +29,12 @@ pub trait PrettyPrintWithContext: UglyPrintWithContext { fn pretty_print_no_indent(&self, sink: &mut W, code: &Code) { self.ugly_print(sink, code, 0, false); } - fn pretty_print_no_first_line_indent(&self, sink: &mut W, code: &Code, indent: usize) { + fn pretty_print_no_first_line_indent( + &self, + sink: &mut W, + code: &Code, + indent: usize, + ) { self.ugly_print(sink, code, indent, false); } } @@ -48,7 +53,13 @@ pub trait UglyPrint { } pub trait UglyPrintWithContext { - fn ugly_print(&self, sink: &mut W, code: &Code, indent: usize, indent_first_line: bool); + fn ugly_print( + &self, + sink: &mut W, + code: &Code, + indent: usize, + indent_first_line: bool, + ); } macro_rules! write_string { @@ -56,17 +67,23 @@ macro_rules! write_string { if ($indent == 0) { $sink.write_all(format!("{}", $value).as_bytes()).unwrap() } else { - $sink.write_all(format!("{:indent$}{}"," ", $value, indent=$indent).as_bytes()).unwrap() + $sink + .write_all(format!("{:indent$}{}", " ", $value, indent = $indent).as_bytes()) + .unwrap() } }; ($sink: expr, $indent: expr, $fmt: expr, $value: expr) => { if ($indent == 0) { $sink.write_all(format!($fmt, $value).as_bytes()).unwrap() } else { - $sink.write_all(format!("{:indent$}{}"," ", format!($fmt, $value), - indent=$indent).as_bytes()).unwrap() + $sink + .write_all( + format!("{:indent$}{}", " ", format!($fmt, $value), indent = $indent) + .as_bytes(), + ) + .unwrap() } - } + }; } macro_rules! in_margin { @@ -76,20 +93,29 @@ macro_rules! in_margin { } else { $indent - 3 } - } + }; } macro_rules! further { - ($indent: expr) => {$indent + 4} + ($indent: expr) => { + $indent + 4 + }; } macro_rules! big_further { - ($indent: expr) => {$indent + 6} + ($indent: expr) => { + $indent + 6 + }; } - macro_rules! first { - ($indent: expr, $condition: expr) => {if $condition {$indent} else {0}} + ($indent: expr, $condition: expr) => { + if $condition { + $indent + } else { + 0 + } + }; } impl UglyPrint for ConstantPoolIndex { @@ -123,39 +149,50 @@ impl UglyPrint for Address { } impl UglyPrintWithContext for ProgramObject { - fn ugly_print(&self, sink: &mut W, code: &Code, indent: usize, prefix_first_line: bool) { + fn ugly_print( + &self, + sink: &mut W, + code: &Code, + indent: usize, + prefix_first_line: bool, + ) { match self { - ProgramObject::Null => - write_string!(sink, first!(indent, prefix_first_line), "Null"), + ProgramObject::Null => write_string!(sink, first!(indent, prefix_first_line), "Null"), - ProgramObject::Integer(value) => - write_string!(sink, first!(indent, prefix_first_line), "Int({})", value), + ProgramObject::Integer(value) => { + write_string!(sink, first!(indent, prefix_first_line), "Int({})", value) + } - ProgramObject::Boolean(value) => - write_string!(sink, first!(indent, prefix_first_line), "Bool({})", value), + ProgramObject::Boolean(value) => { + write_string!(sink, first!(indent, prefix_first_line), "Bool({})", value) + } ProgramObject::String(value) => { let string = value.escape_default().to_string(); write_string!(sink, first!(indent, prefix_first_line), "String(\"{}\")", string) } - ProgramObject::Slot {name} => { + ProgramObject::Slot { name } => { write_string!(sink, first!(indent, prefix_first_line), "Slot("); name.pretty_print_no_indent(sink); write_string!(sink, 0, ")"); - }, + } ProgramObject::Class(slots) => { write_string!(sink, first!(indent, prefix_first_line), "Class("); let mut first = true; for slot in slots { - if !first { write_string!(sink, 0, ", "); } else { first = false; } + if !first { + write_string!(sink, 0, ", "); + } else { + first = false; + } slot.pretty_print_no_indent(sink) } write_string!(sink, 0, ")"); - }, + } - ProgramObject::Method {name, parameters: arguments, locals, code: range} => { + ProgramObject::Method { name, parameters: arguments, locals, code: range } => { write_string!(sink, first!(indent, prefix_first_line), "Method("); name.pretty_print_no_indent(sink); write_string!(sink, 0, ", nargs:"); @@ -164,12 +201,13 @@ impl UglyPrintWithContext for ProgramObject { locals.pretty_print_no_indent(sink); write_string!(sink, 0, ") :"); - for opcode in code.materialize(range).unwrap() { // TODO error handling + for opcode in code.materialize(range).unwrap() { + // TODO error handling write_string!(sink, 0, "\n"); //println!("indent {:?} {} -> {} ", self, indent, further!(indent)); opcode.pretty_print_indent(sink, further!(indent)) } - }, + } } } } @@ -180,71 +218,71 @@ impl UglyPrint for OpCode { OpCode::Literal { index } => { write_string!(sink, indent, "lit "); index.pretty_print_no_indent(sink); - }, + } OpCode::GetLocal { index } => { write_string!(sink, indent, "get local "); index.pretty_print_no_indent(sink); - }, + } OpCode::SetLocal { index } => { write_string!(sink, indent, "set local "); index.pretty_print_no_indent(sink); - }, + } OpCode::GetGlobal { name } => { write_string!(sink, indent, "get global "); name.pretty_print_no_indent(sink); - }, + } OpCode::SetGlobal { name } => { write_string!(sink, indent, "set global "); name.pretty_print_no_indent(sink); - }, + } OpCode::Object { class } => { write_string!(sink, indent, "object "); class.pretty_print_no_indent(sink); - }, + } OpCode::Array => { write_string!(sink, indent, "array"); - }, + } OpCode::GetField { name } => { write_string!(sink, indent, "get slot "); name.pretty_print_no_indent(sink); - }, + } OpCode::SetField { name } => { write_string!(sink, indent, "set slot "); name.pretty_print_no_indent(sink); - }, + } OpCode::CallMethod { name, arguments } => { write_string!(sink, indent, "call slot "); name.pretty_print_no_indent(sink); arguments.pretty_print_indent(sink, 1); - }, + } OpCode::CallFunction { name, arguments } => { write_string!(sink, indent, "call "); name.pretty_print_no_indent(sink); arguments.pretty_print_indent(sink, 1); - }, + } OpCode::Print { format, arguments } => { write_string!(sink, indent, "printf "); format.pretty_print_no_indent(sink); arguments.pretty_print_indent(sink, 1); - }, + } OpCode::Label { name } => { write_string!(sink, in_margin!(indent), "label "); name.pretty_print_no_indent(sink); - }, + } OpCode::Jump { label } => { write_string!(sink, indent, "goto "); label.pretty_print_no_indent(sink); - }, + } OpCode::Branch { label } => { write_string!(sink, indent, "branch "); label.pretty_print_no_indent(sink); - }, + } OpCode::Return => { write_string!(sink, indent, "return"); - }, + } OpCode::Drop => { write_string!(sink, indent, "drop"); - }, + } } } } @@ -264,6 +302,6 @@ impl UglyPrint for Program { write_string!(sink, 0, "\n"); } write_string!(sink, indent, "Entry : "); - self.entry.get().unwrap().pretty_print_no_indent(sink); // TODO error handling + self.entry.get().unwrap().pretty_print_no_indent(sink); // TODO error handling } } diff --git a/src/bytecode/heap.rs b/src/bytecode/heap.rs index a32b47d..5a0beb1 100644 --- a/src/bytecode/heap.rs +++ b/src/bytecode/heap.rs @@ -1,38 +1,46 @@ use anyhow::*; use indexmap::IndexMap; +use crate::bytecode::program::{AddressRange, Arity, ConstantPoolIndex, ProgramObject, Size}; use crate::bytecode::state::OperandStack; -use crate::bytecode::program::{ProgramObject, ConstantPoolIndex, AddressRange, Arity, Size}; -use std::path::PathBuf; -use std::fs::{File, create_dir_all}; -use std::time::SystemTime; +use std::fs::{create_dir_all, File}; use std::io::Write; use std::mem::size_of; +use std::path::PathBuf; +use std::time::SystemTime; macro_rules! heap_log { (START -> $file:expr) => { if let Some(file) = &mut $file { - let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + let timestamp = + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); write!(file, "{},S,0\n", timestamp).unwrap(); } }; (ALLOCATE -> $file:expr, $memory:expr) => { if let Some(file) = &mut $file { - let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + let timestamp = + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); write!(file, "{},A,{}\n", timestamp, $memory).unwrap(); } }; (GC -> $file:expr, $memory:expr) => { if let Some(file) = &mut $file { - let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + let timestamp = + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); write!(file, "{},G,{}\n", timestamp, $memory).unwrap(); } - } + }; } #[derive(Debug)] -pub struct Heap{ max_size: usize, size: usize, log: Option, memory: Vec } +pub struct Heap { + max_size: usize, + size: usize, + log: Option, + memory: Vec, +} impl Eq for Heap {} impl PartialEq for Heap { @@ -46,13 +54,12 @@ impl Heap { self.max_size = size * 1024 * 1024 /* in B */ } pub fn set_log(&mut self, path: PathBuf) { - let mut dir = path.clone(); dir.pop(); create_dir_all(dir).unwrap(); let mut file = File::create(path).unwrap(); - write!(file, "timestamp,event,heap\n").unwrap(); + writeln!(file, "timestamp,event,heap").unwrap(); heap_log!(START -> Some(&mut file)); self.log = Some(file) @@ -68,14 +75,14 @@ impl Heap { index } pub fn dereference(&self, index: &HeapIndex) -> Result<&HeapObject> { - self.memory.get(index.as_usize()) - .with_context(|| - format!("Cannot dereference object from the heap at index: `{}`", index)) + self.memory.get(index.as_usize()).with_context(|| { + format!("Cannot dereference object from the heap at index: `{}`", index) + }) } pub fn dereference_mut(&mut self, index: &HeapIndex) -> Result<&mut HeapObject> { - self.memory.get_mut(index.as_usize()) - .with_context(|| - format!("Cannot dereference object from the heap at index: `{}`", index)) + self.memory.get_mut(index.as_usize()).with_context(|| { + format!("Cannot dereference object from the heap at index: `{}`", index) + }) } } @@ -85,7 +92,7 @@ impl From> for Heap { size: objects.iter().map(|o| o.size()).sum(), max_size: 0, log: None, - memory: objects + memory: objects, } } } @@ -93,12 +100,16 @@ impl From> for Heap { #[derive(Eq, PartialEq, Debug, Clone)] pub enum HeapObject { Array(ArrayInstance), - Object(ObjectInstance) + Object(ObjectInstance), } impl HeapObject { #[allow(dead_code)] - pub fn new_object(parent: Pointer, fields: IndexMap, methods: IndexMap) -> Self { + pub fn new_object( + parent: Pointer, + fields: IndexMap, + methods: IndexMap, + ) -> Self { HeapObject::Object(ObjectInstance { parent, fields, methods }) } pub fn as_object_instance(&self) -> Result<&ObjectInstance> { @@ -125,7 +136,11 @@ impl HeapObject { HeapObject::Array(ArrayInstance::from(v)) } #[allow(dead_code)] - pub fn from(parent: Pointer, fields: IndexMap, methods: IndexMap) -> Self { + pub fn from( + parent: Pointer, + fields: IndexMap, + methods: IndexMap, + ) -> Self { HeapObject::Object(ObjectInstance { parent, fields, methods }) } pub fn evaluate_as_string(&self, heap: &Heap) -> Result { @@ -141,17 +156,27 @@ impl HeapObject { } HeapObject::Object(object) => { let header = size_of::(); - let fields: usize = - object.fields.iter().map(|(string, _pointer)| string.len() + size_of::()).sum(); - let methods: usize = - object.methods.iter().map(|(string, program_object)| string.len() + match program_object { - ProgramObject::Method { .. } => - size_of::() + - size_of::() + - size_of::() + - size_of::(), - _ => unreachable!() - }).sum(); + let fields: usize = object + .fields + .iter() + .map(|(string, _pointer)| string.len() + size_of::()) + .sum(); + let methods: usize = object + .methods + .iter() + .map(|(string, program_object)| { + string.len() + + match program_object { + ProgramObject::Method { .. } => { + size_of::() + + size_of::() + + size_of::() + + size_of::() + } + _ => unreachable!(), + } + }) + .sum(); header + fields + methods } } @@ -167,7 +192,6 @@ impl std::fmt::Display for HeapObject { } } - #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] pub struct ArrayInstance(Vec); @@ -177,7 +201,7 @@ impl ArrayInstance { ArrayInstance(vec![]) } #[allow(dead_code)] - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn iter(&self) -> impl Iterator + '_ { self.0.iter() } #[allow(dead_code)] @@ -186,21 +210,31 @@ impl ArrayInstance { } pub fn get_element(&self, index: usize) -> Result<&Pointer> { let length = self.0.len(); - bail_if!(index >= length, - "Index out of range {} for array `{}` with length {}", - index, self, length); + bail_if!( + index >= length, + "Index out of range {} for array `{}` with length {}", + index, + self, + length + ); Ok(&self.0[index]) } pub fn set_element(&mut self, index: usize, value_pointer: Pointer) -> Result<&Pointer> { let length = self.0.len(); - bail_if!(index >= length, - "Index out of range {} for array `{}` with length {}", - index, self, length); + bail_if!( + index >= length, + "Index out of range {} for array `{}` with length {}", + index, + self, + length + ); self.0[index] = value_pointer; Ok(&self.0[index]) } pub fn evaluate_as_string(&self, heap: &Heap) -> Result { - let elements = self.0.iter() + let elements = self + .0 + .iter() .map(|element| element.evaluate_as_string(heap)) .collect::>>()?; Ok(format!("[{}]", elements.join(", "))) @@ -215,10 +249,11 @@ impl From> for ArrayInstance { impl std::fmt::Display for ArrayInstance { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[{}]", self.0.iter() - .map(|pointer| format!("{}", pointer)) - .collect::>() - .join(", ")) + write!( + f, + "[{}]", + self.0.iter().map(|pointer| format!("{}", pointer)).collect::>().join(", ") + ) } } @@ -226,24 +261,22 @@ impl std::fmt::Display for ArrayInstance { pub struct ObjectInstance { pub parent: Pointer, pub fields: IndexMap, // TODO make private - pub methods: IndexMap // TODO make private + pub methods: IndexMap, // TODO make private } impl ObjectInstance { #[allow(dead_code)] pub fn new() -> Self { - ObjectInstance { - parent: Pointer::Null, - fields: IndexMap::new(), - methods: IndexMap::new(), - } + ObjectInstance { parent: Pointer::Null, fields: IndexMap::new(), methods: IndexMap::new() } } pub fn get_field(&self, name: &str) -> Result<&Pointer> { - self.fields.get(name) + self.fields + .get(name) .with_context(|| format!("There is no field named `{}` in object `{}`", name, self)) } pub fn set_field(&mut self, name: &str, pointer: Pointer) -> Result { - self.fields.insert(name.to_owned(), pointer) + self.fields + .insert(name.to_owned(), pointer) .with_context(|| format!("There is no field named `{}` in object `{}`", name, self)) } pub fn evaluate_as_string(&self, heap: &Heap) -> Result { @@ -256,17 +289,18 @@ impl ObjectInstance { let mut sorted_fields: Vec<(&String, &Pointer)> = self.fields.iter().collect(); sorted_fields.sort_by_key(|(name, _)| *name); - let fields = sorted_fields.into_iter() + let fields = sorted_fields + .into_iter() .map(|(name, value)| { value.evaluate_as_string(heap).map(|value| format!("{}={}", name, value)) }) .collect::>>()?; match parent { - Some(parent) if fields.len() > 0 => - Ok(format!("object(..={}, {})", parent, fields.join(", "))), - Some(parent) => - Ok(format!("object(..={})", parent)), + Some(parent) if !fields.is_empty() => { + Ok(format!("object(..={}, {})", parent, fields.join(", "))) + } + Some(parent) => Ok(format!("object(..={})", parent)), None => Ok(format!("object({})", fields.join(", "))), } } @@ -279,10 +313,10 @@ impl std::fmt::Display for ObjectInstance { parent => Some(parent.to_string()), }; - let fields = self.fields.iter() - .map(|(name, value)| { - format!("{}={}", name, value) - }) + let fields = self + .fields + .iter() + .map(|(name, value)| format!("{}={}", name, value)) .collect::>(); match parent { @@ -304,10 +338,14 @@ impl From for HeapIndex { impl From<&Pointer> for HeapIndex { fn from(p: &Pointer) -> Self { match p { - Pointer::Reference(p) => p.clone(), + Pointer::Reference(p) => *p, Pointer::Null => panic!("Cannot create heap reference from a null-tagged pointer"), - Pointer::Integer(_) => panic!("Cannot create heap reference from an integer-tagged pointer"), - Pointer::Boolean(_) => panic!("Cannot create heap reference from a boolean-tagged pointer"), + Pointer::Integer(_) => { + panic!("Cannot create heap reference from an integer-tagged pointer") + } + Pointer::Boolean(_) => { + panic!("Cannot create heap reference from a boolean-tagged pointer") + } } } } @@ -315,16 +353,22 @@ impl From<&Pointer> for HeapIndex { impl From for HeapIndex { fn from(p: Pointer) -> Self { match p { - Pointer::Reference(p) => p.clone(), + Pointer::Reference(p) => p, Pointer::Null => panic!("Cannot create heap reference from a null-tagged pointer"), - Pointer::Integer(_) => panic!("Cannot create heap reference from an integer-tagged pointer"), - Pointer::Boolean(_) => panic!("Cannot create heap reference from a boolean-tagged pointer"), + Pointer::Integer(_) => { + panic!("Cannot create heap reference from an integer-tagged pointer") + } + Pointer::Boolean(_) => { + panic!("Cannot create heap reference from a boolean-tagged pointer") + } } } } impl HeapIndex { - pub fn as_usize(&self) -> usize { self.0 } + pub fn as_usize(&self) -> usize { + self.0 + } } impl std::fmt::Display for HeapIndex { @@ -360,7 +404,10 @@ impl Pointer { ProgramObject::Null => Ok(Self::Null), ProgramObject::Integer(value) => Ok(Self::Integer(*value)), ProgramObject::Boolean(value) => Ok(Self::Boolean(*value)), - _ => bail!("Expecting either a null, an integer, or a boolean, but found `{}`.", program_object), + _ => bail!( + "Expecting either a null, an integer, or a boolean, but found `{}`.", + program_object + ), } } #[allow(dead_code)] @@ -440,7 +487,8 @@ impl Pointer { } } - pub fn evaluate_as_string(&self, heap: &Heap) -> Result { // TODO trait candidate + pub fn evaluate_as_string(&self, heap: &Heap) -> Result { + // TODO trait candidate match self { Pointer::Null => Ok("null".to_owned()), Pointer::Integer(i) => Ok(i.to_string()), @@ -492,7 +540,7 @@ impl From for Pointer { impl From<&HeapIndex> for Pointer { fn from(p: &HeapIndex) -> Self { - Pointer::Reference(p.clone()) + Pointer::Reference(*p) } } @@ -529,4 +577,4 @@ impl std::fmt::Display for Pointer { Pointer::Reference(p) => write!(f, "{}", p), } } -} \ No newline at end of file +} diff --git a/src/bytecode/helpers.rs b/src/bytecode/helpers.rs index c944718..f0c9e0c 100644 --- a/src/bytecode/helpers.rs +++ b/src/bytecode/helpers.rs @@ -9,15 +9,26 @@ macro_rules! bail_if { #[macro_export] macro_rules! veccat { - ($a:expr, $b:expr) => { $a.into_iter().chain($b.into_iter()).collect() }; - ($a:expr, $b:expr, $c:expr) => { $a.into_iter().chain($b.into_iter()).chain($c.into_iter()).collect() }; + ($a:expr, $b:expr) => { + $a.into_iter().chain($b.into_iter()).collect() + }; + ($a:expr, $b:expr, $c:expr) => { + $a.into_iter().chain($b.into_iter()).chain($c.into_iter()).collect() + }; } -pub trait Pairable where T: Copy + Default { +pub trait Pairable +where + T: Copy + Default, +{ fn pairs(self) -> PairIterator; } -impl Pairable for I where I: Iterator, T: Copy + Default { +impl Pairable for I +where + I: Iterator, + T: Copy + Default, +{ fn pairs(self) -> PairIterator { PairIterator { previous: T::default(), iter: self } } @@ -28,7 +39,11 @@ pub struct PairIterator { iter: I, } -impl Iterator for PairIterator where I: Iterator, T: Copy { +impl Iterator for PairIterator +where + I: Iterator, + T: Copy, +{ type Item = (T, T); fn next(&mut self) -> Option { let next = self.iter.next().map(|current| (self.previous, current)); @@ -39,22 +54,23 @@ impl Iterator for PairIterator where I: Iterator, T: Copy { } } - pub trait MapResult { type IntoIter; fn into_result(self) -> Result; } -impl MapResult for I where I: Iterator> + Clone { +impl MapResult for I +where + I: Iterator> + Clone, +{ type IntoIter = std::iter::Map) -> T>; fn into_result(self) -> Result { - let error = self.clone() - .filter(|e| e.is_err()) - .take(1) - .last(); + let error = self.clone().filter(|e| e.is_err()).take(1).last(); - if let Some(error) = error { error?; } + if let Some(error) = error { + error?; + } Ok(self.map(|e| e.unwrap())) } @@ -87,4 +103,4 @@ impl MapResult for I where I: Iterator> + Clone { // self.0.insert(position, (key, value)) // // } -// } \ No newline at end of file +// } diff --git a/src/bytecode/interpreter.rs b/src/bytecode/interpreter.rs index c7bd166..b0e9263 100644 --- a/src/bytecode/interpreter.rs +++ b/src/bytecode/interpreter.rs @@ -3,8 +3,8 @@ use std::fmt::Write; use crate::bytecode::bytecode::OpCode; use crate::bytecode::heap::*; -use anyhow::*; use anyhow::Context; +use anyhow::*; use std::iter::repeat; use crate::bail_if; @@ -15,7 +15,6 @@ use crate::bytecode::state::*; use indexmap::map::IndexMap; use std::path::PathBuf; - trait OpCodeEvaluationResult { fn attach(self, opcode: &OpCode) -> Result; } @@ -34,7 +33,11 @@ pub fn evaluate(program: &Program) -> Result<()> { evaluate_with(program, &mut state, &mut output) } -pub fn evaluate_with_memory_config(program: &Program, heap_size: usize, heap_log: Option) -> Result<()> { +pub fn evaluate_with_memory_config( + program: &Program, + heap_size: usize, + heap_log: Option, +) -> Result<()> { let mut state = State::from(program)?; state.heap.set_size(heap_size); if let Some(log) = heap_log { @@ -44,7 +47,10 @@ pub fn evaluate_with_memory_config(program: &Program, heap_size: usize, heap_log evaluate_with(program, &mut state, &mut output) } -pub fn evaluate_with(program: &Program, state: &mut State, output: &mut W) -> Result<()> where W: Write { +pub fn evaluate_with(program: &Program, state: &mut State, output: &mut W) -> Result<()> +where + W: Write, +{ // eprintln!("Program:"); // eprintln!("{}", program); while let Some(address) = state.instruction_pointer.get() { @@ -55,13 +61,24 @@ pub fn evaluate_with(program: &Program, state: &mut State, output: &mut W) -> } #[allow(dead_code)] -pub fn step_with(program: &Program, state: &mut State, output: &mut W) -> Result<()> where W: Write { +pub fn step_with(program: &Program, state: &mut State, output: &mut W) -> Result<()> +where + W: Write, +{ let address = state.instruction_pointer.get().with_context(|| "Nothing to execute.")?; let opcode = program.code.get(address)?; eval_opcode(program, state, output, opcode) } -pub fn eval_opcode(program: &Program, state: &mut State, output: &mut W, opcode: &OpCode) -> Result<()> where W: Write { +pub fn eval_opcode( + program: &Program, + state: &mut State, + output: &mut W, + opcode: &OpCode, +) -> Result<()> +where + W: Write, +{ match opcode { OpCode::Literal { index } => eval_literal(program, state, index), OpCode::GetLocal { index } => eval_get_local(program, state, index), @@ -73,14 +90,19 @@ pub fn eval_opcode(program: &Program, state: &mut State, output: &mut W, opco OpCode::GetField { name } => eval_get_field(program, state, name), OpCode::SetField { name } => eval_set_field(program, state, name), OpCode::CallMethod { name, arguments } => eval_call_method(program, state, name, arguments), - OpCode::CallFunction { name, arguments } => eval_call_function(program, state, name, arguments), + OpCode::CallFunction { name, arguments } => { + eval_call_function(program, state, name, arguments) + } OpCode::Label { .. } => eval_label(program, state), - OpCode::Print { format, arguments } => eval_print(program, state, output, format, arguments), + OpCode::Print { format, arguments } => { + eval_print(program, state, output, format, arguments) + } OpCode::Jump { label } => eval_jump(program, state, label), OpCode::Branch { label } => eval_branch(program, state, label), OpCode::Return => eval_return(program, state), OpCode::Drop => eval_drop(program, state), - }.attach(opcode) + } + .attach(opcode) } #[inline(always)] @@ -93,7 +115,8 @@ pub fn eval_literal(program: &Program, state: &mut State, index: &ConstantPoolIn } #[inline(always)] -pub fn eval_get_local(program: &Program, state: &mut State, index: &LocalFrameIndex) -> Result<()> { // TODO rename LocalFrameIndex to FrameIndex +pub fn eval_get_local(program: &Program, state: &mut State, index: &LocalFrameIndex) -> Result<()> { + // TODO rename LocalFrameIndex to FrameIndex let frame = state.frame_stack.get_locals()?; let pointer = *frame.get(index)?; state.operand_stack.push(pointer); @@ -111,7 +134,11 @@ pub fn eval_set_local(program: &Program, state: &mut State, index: &LocalFrameIn } #[inline(always)] -pub fn eval_get_global(program: &Program, state: &mut State, index: &ConstantPoolIndex) -> Result<()> { +pub fn eval_get_global( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, +) -> Result<()> { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?; let pointer = *state.frame_stack.globals.get(name)?; @@ -121,7 +148,11 @@ pub fn eval_get_global(program: &Program, state: &mut State, index: &ConstantPoo } #[inline(always)] -pub fn eval_set_global(program: &Program, state: &mut State, index: &ConstantPoolIndex) -> Result<()> { +pub fn eval_set_global( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, +) -> Result<()> { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?.to_owned(); let pointer = *state.operand_stack.peek()?; @@ -133,28 +164,35 @@ pub fn eval_set_global(program: &Program, state: &mut State, index: &ConstantPoo #[inline(always)] pub fn eval_object(program: &Program, state: &mut State, index: &ConstantPoolIndex) -> Result<()> { let program_object = program.constant_pool.get(index)?; - let members = program_object.as_class_definition()?.iter() - .map(| index | program.constant_pool.get(index)) + let members = program_object + .as_class_definition()? + .iter() + .map(|index| program.constant_pool.get(index)) .collect::>>()?; let mut slots = Vec::new(); let mut methods = IndexMap::new(); - for member in members { // TODO this could probably be a method in ProgramObject, something like: `create prototype object om class` + for member in members { + // TODO this could probably be a method in ProgramObject, something like: `create prototype object om class` match member { ProgramObject::Slot { name: index } => { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?; slots.push(name); } - ProgramObject::Method { name: index, .. } => { // TODO, probably don't need to store methods, tbh, just the class, which would simplify this a lot + ProgramObject::Method { name: index, .. } => { + // TODO, probably don't need to store methods, tbh, just the class, which would simplify this a lot let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?.to_owned(); let previous = methods.insert(name.clone(), member.clone()); - ensure!(previous.is_none(), - "Member method `{}` has a non-unique name within object.", name) + ensure!( + previous.is_none(), + "Member method `{}` has a non-unique name within object.", + name + ) } - _ => bail!("Class members must be either Methods or Slots, but found `{}`.", member) + _ => bail!("Class members must be either Methods or Slots, but found `{}`.", member), } } @@ -192,7 +230,11 @@ pub fn eval_array(program: &Program, state: &mut State) -> Result<()> { } #[inline(always)] -pub fn eval_get_field(program: &Program, state: &mut State, index: &ConstantPoolIndex) -> Result<()> { +pub fn eval_get_field( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, +) -> Result<()> { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?; let pointer = state.operand_stack.pop()?; @@ -207,7 +249,11 @@ pub fn eval_get_field(program: &Program, state: &mut State, index: &ConstantPool } #[inline(always)] -pub fn eval_set_field(program: &Program, state: &mut State, index: &ConstantPoolIndex) -> Result<()> { +pub fn eval_set_field( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, +) -> Result<()> { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?; let value_pointer = state.operand_stack.pop()?; @@ -216,28 +262,45 @@ pub fn eval_set_field(program: &Program, state: &mut State, index: &ConstantPool let object = state.heap.dereference_mut(&heap_pointer)?; let object_instance = object.as_object_instance_mut()?; - object_instance.set_field(name, value_pointer.clone())?; + object_instance.set_field(name, value_pointer)?; state.operand_stack.push(value_pointer); state.instruction_pointer.bump(program); Ok(()) } #[inline(always)] -pub fn eval_call_method(program: &Program, state: &mut State, index: &ConstantPoolIndex, arguments: &Arity) -> Result<()> { - bail_if!(arguments.to_usize() == 0, "All method calls require at least {} parameter (receiver)", 1); +pub fn eval_call_method( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, + arguments: &Arity, +) -> Result<()> { + bail_if!( + arguments.to_usize() == 0, + "All method calls require at least {} parameter (receiver)", + 1 + ); let program_object = program.constant_pool.get(index)?; let method_name = program_object.as_str()?; - ensure!(arguments.to_usize() > 0, - "Method arity is zero, which does not account for a receiver object."); + ensure!( + arguments.to_usize() > 0, + "Method arity is zero, which does not account for a receiver object." + ); let argument_pointers = state.operand_stack.pop_sequence(arguments.to_usize() - 1)?; let receiver_pointer = state.operand_stack.pop()?; dispatch_method(program, state, receiver_pointer, method_name, argument_pointers) } -fn dispatch_method(program: &Program, state: &mut State, receiver_pointer: Pointer, method_name: &str, argument_pointers: Vec) -> Result<()> { +fn dispatch_method( + program: &Program, + state: &mut State, + receiver_pointer: Pointer, + method_name: &str, + argument_pointers: Vec, +) -> Result<()> { match receiver_pointer { Pointer::Null => { dispatch_null_method(method_name, argument_pointers)? @@ -254,76 +317,106 @@ fn dispatch_method(program: &Program, state: &mut State, receiver_pointer: Point .push_onto(&mut state.operand_stack); state.instruction_pointer.bump(program); } - Pointer::Reference(index) => - match state.heap.dereference_mut(&index)? { - HeapObject::Array(array) => { - dispatch_array_method(array, method_name, argument_pointers)? - .push_onto(&mut state.operand_stack); - state.instruction_pointer.bump(program); - } - HeapObject::Object(_) => - dispatch_object_method(program, state, receiver_pointer, - method_name, argument_pointers)?, + Pointer::Reference(index) => match state.heap.dereference_mut(&index)? { + HeapObject::Array(array) => { + dispatch_array_method(array, method_name, argument_pointers)? + .push_onto(&mut state.operand_stack); + state.instruction_pointer.bump(program); } + HeapObject::Object(_) => dispatch_object_method( + program, + state, + receiver_pointer, + method_name, + argument_pointers, + )?, + }, } Ok(()) } fn dispatch_null_method(method_name: &str, argument_pointers: Vec) -> Result { - bail_if!(argument_pointers.len() != 1, - "Invalid number of arguments for method `{}` in object `null`", method_name); + bail_if!( + argument_pointers.len() != 1, + "Invalid number of arguments for method `{}` in object `null`", + method_name + ); let argument = argument_pointers.last().unwrap(); - let result = match (method_name, argument) { - ("==", Pointer::Null) | ("eq", Pointer::Null) => Pointer::from(true), - ("==", _) | ("eq", _) => Pointer::from(false), + let result = match (method_name, argument) { + ("==", Pointer::Null) | ("eq", Pointer::Null) => Pointer::from(true), + ("==", _) | ("eq", _) => Pointer::from(false), ("!=", Pointer::Null) | ("neq", Pointer::Null) => Pointer::from(false), - ("!=", _) | ("neq", _) => Pointer::from(true), + ("!=", _) | ("neq", _) => Pointer::from(true), _ => bail!("Call method error: no method `{}` in object `null`", method_name), }; Ok(result) } -fn dispatch_integer_method(receiver: &i32, method_name: &str, argument_pointers: Vec) -> Result { - bail_if!(argument_pointers.len() != 1, - "Invalid number of arguments for method `{}` in object `{}`", method_name, receiver); +fn dispatch_integer_method( + receiver: &i32, + method_name: &str, + argument_pointers: Vec, +) -> Result { + bail_if!( + argument_pointers.len() != 1, + "Invalid number of arguments for method `{}` in object `{}`", + method_name, + receiver + ); let argument_pointer = argument_pointers.last().unwrap(); let result = match (method_name, argument_pointer) { - ("+", Pointer::Integer(argument)) => Pointer::from(receiver + argument), - ("-", Pointer::Integer(argument)) => Pointer::from(receiver - argument), - ("*", Pointer::Integer(argument)) => Pointer::from(receiver * argument), - ("/", Pointer::Integer(argument)) => Pointer::from(receiver / argument), - ("%", Pointer::Integer(argument)) => Pointer::from(receiver % argument), + ("+", Pointer::Integer(argument)) => Pointer::from(receiver + argument), + ("-", Pointer::Integer(argument)) => Pointer::from(receiver - argument), + ("*", Pointer::Integer(argument)) => Pointer::from(receiver * argument), + ("/", Pointer::Integer(argument)) => Pointer::from(receiver / argument), + ("%", Pointer::Integer(argument)) => Pointer::from(receiver % argument), ("<=", Pointer::Integer(argument)) => Pointer::from(receiver <= argument), (">=", Pointer::Integer(argument)) => Pointer::from(receiver >= argument), - ("<", Pointer::Integer(argument)) => Pointer::from(receiver < argument), - (">", Pointer::Integer(argument)) => Pointer::from(receiver > argument), + ("<", Pointer::Integer(argument)) => Pointer::from(receiver < argument), + (">", Pointer::Integer(argument)) => Pointer::from(receiver > argument), ("==", Pointer::Integer(argument)) => Pointer::from(receiver == argument), ("!=", Pointer::Integer(argument)) => Pointer::from(receiver != argument), ("==", _) => Pointer::from(false), ("!=", _) => Pointer::from(true), - ("add", Pointer::Integer(argument)) => Pointer::from(receiver + argument), - ("sub", Pointer::Integer(argument)) => Pointer::from(receiver - argument), - ("mul", Pointer::Integer(argument)) => Pointer::from(receiver * argument), - ("div", Pointer::Integer(argument)) => Pointer::from(receiver / argument), - ("mod", Pointer::Integer(argument)) => Pointer::from(receiver % argument), - ("le", Pointer::Integer(argument)) => Pointer::from(receiver <= argument), - ("ge", Pointer::Integer(argument)) => Pointer::from(receiver >= argument), - ("lt", Pointer::Integer(argument)) => Pointer::from(receiver < argument), - ("gt", Pointer::Integer(argument)) => Pointer::from(receiver > argument), - ("eq", Pointer::Integer(argument)) => Pointer::from(receiver == argument), + ("add", Pointer::Integer(argument)) => Pointer::from(receiver + argument), + ("sub", Pointer::Integer(argument)) => Pointer::from(receiver - argument), + ("mul", Pointer::Integer(argument)) => Pointer::from(receiver * argument), + ("div", Pointer::Integer(argument)) => Pointer::from(receiver / argument), + ("mod", Pointer::Integer(argument)) => Pointer::from(receiver % argument), + ("le", Pointer::Integer(argument)) => Pointer::from(receiver <= argument), + ("ge", Pointer::Integer(argument)) => Pointer::from(receiver >= argument), + ("lt", Pointer::Integer(argument)) => Pointer::from(receiver < argument), + ("gt", Pointer::Integer(argument)) => Pointer::from(receiver > argument), + ("eq", Pointer::Integer(argument)) => Pointer::from(receiver == argument), ("neq", Pointer::Integer(argument)) => Pointer::from(receiver != argument), ("eq", _) => Pointer::from(false), ("neq", _) => Pointer::from(true), - (method, argument) if method == "+" || method == "-" || method == "*" || method == "/" - || method == "%" || method == "<=" || method == ">=" || method == "<" || method == ">" - || method == "add" || method == "sub" || method == "mul" || method == "div" - || method == "mod" || method == "le" || method == "ge" || method == "lt" || method == "le" => { + (method, argument) + if method == "+" + || method == "-" + || method == "*" + || method == "/" + || method == "%" + || method == "<=" + || method == ">=" + || method == "<" + || method == ">" + || method == "add" + || method == "sub" + || method == "mul" + || method == "div" + || method == "mod" + || method == "le" + || method == "ge" + || method == "lt" + || method == "le" => + { bail!("Call method error: method {} is not defined in object `{}` for argument `{}` (expecting integer argument)", method, receiver, argument) } @@ -333,59 +426,87 @@ fn dispatch_integer_method(receiver: &i32, method_name: &str, argument_pointers: Ok(result) } -fn dispatch_boolean_method(receiver: &bool, method_name: &str, argument_pointers: Vec) -> Result { - bail_if!(argument_pointers.len() != 1, - "Invalid number of arguments for method `{}` in object `{}`", method_name, receiver); +fn dispatch_boolean_method( + receiver: &bool, + method_name: &str, + argument_pointers: Vec, +) -> Result { + bail_if!( + argument_pointers.len() != 1, + "Invalid number of arguments for method `{}` in object `{}`", + method_name, + receiver + ); let argument_pointer = argument_pointers.last().unwrap(); let result = match (method_name, argument_pointer) { - ("&", Pointer::Boolean(argument)) => Pointer::from(*receiver && *argument), - ("|", Pointer::Boolean(argument)) => Pointer::from(*receiver || *argument), + ("&", Pointer::Boolean(argument)) => Pointer::from(*receiver && *argument), + ("|", Pointer::Boolean(argument)) => Pointer::from(*receiver || *argument), ("==", Pointer::Boolean(argument)) => Pointer::from(*receiver == *argument), ("!=", Pointer::Boolean(argument)) => Pointer::from(*receiver != *argument), ("==", _) => Pointer::from(false), ("!=", _) => Pointer::from(true), ("and", Pointer::Boolean(argument)) => Pointer::from(*receiver && *argument), - ("or", Pointer::Boolean(argument)) => Pointer::from(*receiver || *argument), - ("eq", Pointer::Boolean(argument)) => Pointer::from(*receiver == *argument), + ("or", Pointer::Boolean(argument)) => Pointer::from(*receiver || *argument), + ("eq", Pointer::Boolean(argument)) => Pointer::from(*receiver == *argument), ("neq", Pointer::Boolean(argument)) => Pointer::from(*receiver != *argument), - ("eq", _) => Pointer::from(false), + ("eq", _) => Pointer::from(false), ("neq", _) => Pointer::from(true), - (method, argument) if method == "&" || method == "|" || method == "and" || method == "or" => { + (method, argument) + if method == "&" || method == "|" || method == "and" || method == "or" => + { bail!("Call method error: method {} is not defined in object `{}` for argument `{}` (expecting boolean argument)", method, receiver, argument) } - _ => bail!("Call method error: no method `{}` in object `{}`", method_name, receiver), + _ => bail!("Call method error: no method `{}` in object `{}`", method_name, receiver), }; Ok(result) } -fn dispatch_array_method(array: &mut ArrayInstance, method_name: &str, argument_pointers: Vec) -> Result { +fn dispatch_array_method( + array: &mut ArrayInstance, + method_name: &str, + argument_pointers: Vec, +) -> Result { match method_name { "get" => dispatch_array_get_method(array, method_name, argument_pointers), "set" => dispatch_array_set_method(array, method_name, argument_pointers), - _ => bail!("Call method error: no method `{}` in array `{}`", method_name, array), + _ => bail!("Call method error: no method `{}` in array `{}`", method_name, array), } } -fn dispatch_array_get_method(array: &mut ArrayInstance, method_name: &str, argument_pointers: Vec) -> Result { - bail_if!(argument_pointers.len() != 1, - "Invalid number of arguments for method `{}` in array `{}`, expecting 1", - method_name, array); +fn dispatch_array_get_method( + array: &mut ArrayInstance, + method_name: &str, + argument_pointers: Vec, +) -> Result { + bail_if!( + argument_pointers.len() != 1, + "Invalid number of arguments for method `{}` in array `{}`, expecting 1", + method_name, + array + ); let index_pointer = argument_pointers.first().unwrap(); let index = index_pointer.as_usize()?; array.get_element(index).map(|e| *e) } -fn dispatch_array_set_method(array: &mut ArrayInstance, method_name: &str, argument_pointers: Vec) -> Result { - bail_if!(argument_pointers.len() != 2, - "Invalid number of arguments for method `{}` in array `{}`, expecting 2", - method_name, array); +fn dispatch_array_set_method( + array: &mut ArrayInstance, + method_name: &str, + argument_pointers: Vec, +) -> Result { + bail_if!( + argument_pointers.len() != 2, + "Invalid number of arguments for method `{}` in array `{}`, expecting 2", + method_name, + array + ); let index_pointer = argument_pointers.first().unwrap(); let value_pointer = argument_pointers.last().unwrap(); @@ -393,102 +514,167 @@ fn dispatch_array_set_method(array: &mut ArrayInstance, method_name: &str, argum array.set_element(index, *value_pointer).map(|e| *e) } -fn dispatch_object_method(program: &Program, state: &mut State, - receiver_pointer: Pointer, method_name: &str, - argument_pointers: Vec) -> Result<()> { - +fn dispatch_object_method( + program: &Program, + state: &mut State, + receiver_pointer: Pointer, + method_name: &str, + argument_pointers: Vec, +) -> Result<()> { let heap_reference = receiver_pointer.into_heap_reference()?; // Should never fail. let heap_object = state.heap.dereference_mut(&heap_reference)?; // Should never fail. let object_instance = heap_object.as_object_instance_mut()?; // Should never fail. - let parent_pointer = object_instance.parent.clone(); + let parent_pointer = object_instance.parent; - let method_option = object_instance.methods - .get(&method_name.to_string()) - .map(|method| method.clone()); + let method_option = + object_instance.methods.get(&method_name.to_string()).cloned(); match method_option { - Some(method) => - eval_call_object_method(program, state, method, method_name, receiver_pointer, argument_pointers), - None if object_instance.parent.is_null() => - bail!("Call method error: no method `{}` in object `{}`", method_name, object_instance), - None => - dispatch_method(program, state, parent_pointer, method_name, argument_pointers) + Some(method) => eval_call_object_method( + program, + state, + method, + method_name, + receiver_pointer, + argument_pointers, + ), + None if object_instance.parent.is_null() => { + bail!("Call method error: no method `{}` in object `{}`", method_name, object_instance) + } + None => dispatch_method(program, state, parent_pointer, method_name, argument_pointers), } } -fn eval_call_object_method(program: &Program, state: &mut State, - method: ProgramObject, method_name: &str, - pointer: Pointer, argument_pointers: Vec) -> Result<()> { - - let parameters = method.get_method_parameters()?; // FIXME perhaps the thing to do here is to have a Method struct inside the ProgramObject::Method constructor +fn eval_call_object_method( + program: &Program, + state: &mut State, + method: ProgramObject, + method_name: &str, + pointer: Pointer, + argument_pointers: Vec, +) -> Result<()> { + let parameters = method.get_method_parameters()?; // FIXME perhaps the thing to do here is to have a Method struct inside the ProgramObject::Method constructor let locals = method.get_method_locals()?; let address = method.get_method_start_address()?; - bail_if!(argument_pointers.len() != parameters.to_usize() - 1, - "Method `{}` requires {} arguments, but {} were supplied", - method_name, parameters, argument_pointers.len()); + bail_if!( + argument_pointers.len() != parameters.to_usize() - 1, + "Method `{}` requires {} arguments, but {} were supplied", + method_name, + parameters, + argument_pointers.len() + ); let local_pointers = locals.make_vector(Pointer::Null); state.instruction_pointer.bump(program); - let frame = Frame::from(state.instruction_pointer.get(), veccat!(vec![pointer], argument_pointers, local_pointers)); + let frame = Frame::from( + state.instruction_pointer.get(), + veccat!(vec![pointer], argument_pointers, local_pointers), + ); state.frame_stack.push(frame); state.instruction_pointer.set(Some(*address)); Ok(()) } #[inline(always)] -pub fn eval_call_function(program: &Program, state: &mut State, index: &ConstantPoolIndex, arguments: &Arity) -> Result<()> { +pub fn eval_call_function( + program: &Program, + state: &mut State, + index: &ConstantPoolIndex, + arguments: &Arity, +) -> Result<()> { let program_object = program.constant_pool.get(index)?; let name = program_object.as_str()?; let function_index = state.frame_stack.functions.get(name)?; let function = program.constant_pool.get(function_index)?; - let parameters = function.get_method_parameters()?; // FIXME perhaps the thing to do here is to have a Method struct inside the ProgramObject::Method constructor + let parameters = function.get_method_parameters()?; // FIXME perhaps the thing to do here is to have a Method struct inside the ProgramObject::Method constructor let locals = function.get_method_locals()?; let address = function.get_method_start_address()?; - bail_if!(arguments != parameters, - "Function `{}` requires {} arguments, but {} were supplied", - name, parameters, arguments); + bail_if!( + arguments != parameters, + "Function `{}` requires {} arguments, but {} were supplied", + name, + parameters, + arguments + ); let argument_pointers = state.operand_stack.pop_sequence(arguments.to_usize())?; let local_pointers = locals.make_vector(Pointer::Null); state.instruction_pointer.bump(program); - let frame = Frame::from(state.instruction_pointer.get(), veccat!(argument_pointers, local_pointers)); + let frame = + Frame::from(state.instruction_pointer.get(), veccat!(argument_pointers, local_pointers)); state.frame_stack.push(frame); state.instruction_pointer.set(Some(*address)); Ok(()) } #[inline(always)] -pub fn eval_print(program: &Program, state: &mut State, output: &mut W, index: &ConstantPoolIndex, arguments: &Arity) -> Result<()> where W: Write { +pub fn eval_print( + program: &Program, + state: &mut State, + output: &mut W, + index: &ConstantPoolIndex, + arguments: &Arity, +) -> Result<()> +where + W: Write, +{ let program_object = program.constant_pool.get(index)?; let format = program_object.as_str()?; let mut argument_pointers = state.operand_stack.pop_reverse_sequence(arguments.to_usize())?; let mut escaped = false; - for character in format.chars(){ + for character in format.chars() { match (escaped, character) { - (true, '~' ) => { output.write_char('~')?; escaped = false; }, - (true, '\\') => { output.write_char('\\')?; escaped = false; }, - (true, '"' ) => { output.write_char('"')?; escaped = false; }, - (true, 'n' ) => { output.write_char('\n')?; escaped = false; }, - (true, 't' ) => { output.write_char('\t')?; escaped = false; }, - (true, 'r' ) => { output.write_char('\r')?; escaped = false; }, - (true, chr ) => { bail!("Unknown control sequence \\{}", chr) }, - (false, '\\') => { escaped = true; }, - (_, '~' ) => { - let argument = argument_pointers.pop() + (true, '~') => { + output.write_char('~')?; + escaped = false; + } + (true, '\\') => { + output.write_char('\\')?; + escaped = false; + } + (true, '"') => { + output.write_char('"')?; + escaped = false; + } + (true, 'n') => { + output.write_char('\n')?; + escaped = false; + } + (true, 't') => { + output.write_char('\t')?; + escaped = false; + } + (true, 'r') => { + output.write_char('\r')?; + escaped = false; + } + (true, chr) => { + bail!("Unknown control sequence \\{}", chr) + } + (false, '\\') => { + escaped = true; + } + (_, '~') => { + let argument = argument_pointers + .pop() .with_context(|| "Not enough arguments for format `{}`")?; output.write_str(argument.evaluate_as_string(&state.heap)?.as_str())? - }, - (_, chr ) => { output.write_char(chr)? }, + } + (_, chr) => output.write_char(chr)?, } } - bail_if!(!argument_pointers.is_empty(), - "{} unused arguments for format `{}`", argument_pointers.len(), format); + bail_if!( + !argument_pointers.is_empty(), + "{} unused arguments for format `{}`", + argument_pointers.len(), + format + ); state.operand_stack.push(Pointer::Null); state.instruction_pointer.bump(program); @@ -537,5 +723,3 @@ pub fn eval_drop(program: &Program, state: &mut State) -> Result<()> { state.instruction_pointer.bump(program); Ok(()) } - - diff --git a/src/bytecode/mod.rs b/src/bytecode/mod.rs index 1e23d25..5602d05 100644 --- a/src/bytecode/mod.rs +++ b/src/bytecode/mod.rs @@ -3,10 +3,11 @@ use crate::parser::AST; pub(crate) mod bytecode; pub(crate) mod compiler; pub(crate) mod debug; +pub mod interpreter; pub mod program; pub mod serializable; -pub mod interpreter; -#[macro_use] mod helpers; +#[macro_use] +mod helpers; pub mod heap; pub mod state; @@ -14,4 +15,4 @@ use anyhow::Result; pub fn compile(ast: &AST) -> Result { compiler::compile(ast) -} \ No newline at end of file +} diff --git a/src/bytecode/program.rs b/src/bytecode/program.rs index 7d79955..35fdfd9 100644 --- a/src/bytecode/program.rs +++ b/src/bytecode/program.rs @@ -1,5 +1,5 @@ -use std::io::{Write, Read}; use std::collections::HashMap; +use std::io::{Read, Write}; use super::bytecode::OpCode; @@ -24,7 +24,12 @@ pub struct Program { impl Program { #[allow(dead_code)] - pub fn from(code: Code, constant_pool: ConstantPool, globals: Globals, entry: Entry) -> Result { + pub fn from( + code: Code, + constant_pool: ConstantPool, + globals: Globals, + entry: Entry, + ) -> Result { let label_names = code.labels(); let label_constants = constant_pool.get_all(label_names)?.into_iter(); let label_addresses = code.label_addresses().into_iter(); @@ -50,15 +55,20 @@ impl std::fmt::Display for Program { #[derive(Eq, PartialEq, Debug)] pub struct Globals(Vec); impl Globals { - pub fn new() -> Self { Globals(Vec::new()) } + pub fn new() -> Self { + Globals(Vec::new()) + } pub fn register(&mut self, name_index: ConstantPoolIndex) -> Result<()> { - bail_if!(self.0.contains(&name_index), - "Cannot register global `{}`, index is already registered as a global.", - name_index); - Ok(self.0.push(name_index)) + bail_if!( + self.0.contains(&name_index), + "Cannot register global `{}`, index is already registered as a global.", + name_index + ); + self.0.push(name_index); + Ok(()) } - pub fn iter<'a>(&'a self) -> impl Iterator + 'a{ - self.0.iter().map(|index| index.clone()) + pub fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.0.iter().copied() } } @@ -80,10 +90,15 @@ impl std::fmt::Display for Globals { #[derive(Eq, PartialEq, Debug)] pub struct Entry(Option); impl Entry { - pub fn new() -> Self { Entry(None) } + pub fn new() -> Self { + Entry(None) + } pub fn get(&self) -> Result { - bail_if!(self.0.is_none(), "Entry point was read, but it was not set yet.", /*bad macro*/); - Ok(self.0.as_ref().unwrap().clone()) + bail_if!( + self.0.is_none(), + "Entry point was read, but it was not set yet.", /*bad macro*/ + ); + Ok(*self.0.as_ref().unwrap()) } pub fn set(&mut self, index: ConstantPoolIndex) { self.0 = Some(index) @@ -95,7 +110,9 @@ impl From for Entry { } } impl From for Entry { - fn from(index: u16) -> Self { Entry(Some(ConstantPoolIndex::from(index))) } + fn from(index: u16) -> Self { + Entry(Some(ConstantPoolIndex::from(index))) + } } impl std::fmt::Display for Entry { @@ -105,17 +122,25 @@ impl std::fmt::Display for Entry { } #[derive(Eq, PartialEq, Debug)] -pub struct Labels { names: HashMap } // FIXME clean up +pub struct Labels { + names: HashMap, +} // FIXME clean up impl Labels { #[allow(dead_code)] - pub fn new() -> Self { Labels { names: HashMap::new() } } + pub fn new() -> Self { + Labels { names: HashMap::new() } + } pub fn get(&self, label: &str) -> Result<&Address> { - self.names.get(label) + self.names + .get(label) .with_context(|| format!("Label `{}` was not previously register.", label)) } pub fn from<'a, I>(labels: I) -> Result - where I: IntoIterator { - let names = labels.into_iter() + where + I: IntoIterator, + { + let names = labels + .into_iter() .map(|(program_object, address)| { program_object.as_str().map(|name| (name.to_owned(), address)) }) @@ -127,25 +152,26 @@ impl Labels { #[derive(Eq, PartialEq, Debug)] pub struct ConstantPool(Vec); impl ConstantPool { - pub fn new() -> Self { ConstantPool(Vec::new()) } + pub fn new() -> Self { + ConstantPool(Vec::new()) + } pub fn get(&self, index: &ConstantPoolIndex) -> Result<&ProgramObject> { - self.0.get(index.as_usize()) - .with_context(|| - format!("Cannot dereference object from the constant pool at index: `{}`", index)) + self.0.get(index.as_usize()).with_context(|| { + format!("Cannot dereference object from the constant pool at index: `{}`", index) + }) } pub fn get_all(&self, indices: Vec<&ConstantPoolIndex>) -> Result> { - indices.iter() - .map(|index| self.get(index)) - .collect() + indices.iter().map(|index| self.get(index)).collect() } pub fn push(&mut self, program_object: ProgramObject) -> ConstantPoolIndex { self.0.push(program_object); ConstantPoolIndex::from_usize(self.0.len() - 1) } pub fn find(&self, program_object: &ProgramObject) -> Option { - self.0.iter() + self.0 + .iter() .position(|c| c == program_object) - .map(|position| ConstantPoolIndex::from_usize(position)) + .map(ConstantPoolIndex::from_usize) } pub fn register(&mut self, program_object: ProgramObject) -> ConstantPoolIndex { let index = self.find(&program_object); @@ -154,7 +180,7 @@ impl ConstantPool { None => self.push(program_object), } } - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.0.iter() } #[allow(dead_code)] @@ -180,19 +206,19 @@ impl From> for ConstantPool { impl From> for ConstantPool { fn from(vector: Vec) -> Self { - ConstantPool(vector.into_iter().map(|n| ProgramObject::from_i32(n)).collect()) + ConstantPool(vector.into_iter().map(ProgramObject::from_i32).collect()) } } impl From> for ConstantPool { fn from(vector: Vec<&str>) -> Self { - ConstantPool(vector.into_iter().map(|s| ProgramObject::from_str(s)).collect()) + ConstantPool(vector.into_iter().map(ProgramObject::from_str).collect()) } } impl From> for ConstantPool { fn from(vector: Vec) -> Self { - ConstantPool(vector.into_iter().map(|b| ProgramObject::from_bool(b)).collect()) + ConstantPool(vector.into_iter().map(ProgramObject::from_bool).collect()) } } @@ -254,12 +280,7 @@ pub enum ProgramObject { * * Serialized with tag `0x03`. */ - Method { - name: ConstantPoolIndex, - parameters: Arity, - locals: Size, - code: AddressRange, - }, + Method { name: ConstantPoolIndex, parameters: Arity, locals: Size, code: AddressRange }, /** * Represents an object structure consisting of field (aka slot) and method members for each @@ -288,13 +309,15 @@ impl ProgramObject { pub fn as_str(&self) -> anyhow::Result<&str> { match self { ProgramObject::String(string) => Ok(string), - _ => anyhow::bail!("Expecting a program object representing a String, found `{}`", self) + _ => { + anyhow::bail!("Expecting a program object representing a String, found `{}`", self) + } } } pub fn as_class_definition(&self) -> anyhow::Result<&Vec> { match self { ProgramObject::Class(members) => Ok(members), - _ => anyhow::bail!("Expecting a program object representing a Class, found `{}`", self) + _ => anyhow::bail!("Expecting a program object representing a Class, found `{}`", self), } } pub fn is_slot(&self) -> bool { @@ -310,31 +333,36 @@ impl ProgramObject { } } pub fn get_method_parameters(&self) -> anyhow::Result<&Arity> { - match self { // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? + match self { + // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? ProgramObject::Method { parameters, .. } => Ok(parameters), pointer => Err(anyhow::anyhow!("Expected a Method but found `{}`", pointer)), } } pub fn get_method_name(&self) -> anyhow::Result<&ConstantPoolIndex> { - match self { // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? + match self { + // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? ProgramObject::Method { name, .. } => Ok(name), pointer => Err(anyhow::anyhow!("Expected a Method but found `{}`", pointer)), } } pub fn get_method_locals(&self) -> anyhow::Result<&Size> { - match self { // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? + match self { + // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? ProgramObject::Method { locals, .. } => Ok(locals), pointer => Err(anyhow::anyhow!("Expected a Method but found `{}`", pointer)), } } pub fn get_method_start_address(&self) -> anyhow::Result<&Address> { - match self { // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? + match self { + // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? ProgramObject::Method { code, .. } => Ok(code.start()), pointer => Err(anyhow::anyhow!("Expected a Method but found `{}`", pointer)), } } pub fn get_method_length(&self) -> anyhow::Result { - match self { // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? + match self { + // FIXME there's gotta be a way to do this cleaner. perhaps locally defined function? ProgramObject::Method { code, .. } => Ok(code.length), pointer => Err(anyhow::anyhow!("Expected a Method but found `{}`", pointer)), } @@ -342,7 +370,7 @@ impl ProgramObject { pub fn as_slot_index(&self) -> anyhow::Result<&ConstantPoolIndex> { match self { ProgramObject::Slot { name } => Ok(name), - _ => anyhow::bail!("Expecting a program object representing a Slot, found `{}`", self) + _ => anyhow::bail!("Expecting a program object representing a Slot, found `{}`", self), } } // pub fn as_method(&self) -> bool { @@ -357,13 +385,13 @@ impl ProgramObject { fn tag(&self) -> u8 { use ProgramObject::*; match &self { - Integer(_) => 0x00, - Null => 0x01, - String(_) => 0x02, - Method {name: _, parameters: _, locals: _, code: _} => 0x03, - Slot {name:_} => 0x04, - Class(_) => 0x05, - Boolean(_) => 0x06, + Integer(_) => 0x00, + Null => 0x01, + String(_) => 0x02, + Method { name: _, parameters: _, locals: _, code: _ } => 0x03, + Slot { name: _ } => 0x04, + Class(_) => 0x05, + Boolean(_) => 0x06, } } } @@ -378,14 +406,12 @@ impl std::fmt::Display for ProgramObject { ProgramObject::Slot { name } => write!(f, "slot {}", name), ProgramObject::Method { name, locals, parameters: arguments, code } => { write!(f, "method {} args:{} locals:{} {}", name, arguments, locals, code) - }, + } ProgramObject::Class(members) => { - let members = members.iter() - .map(|i| i.to_string()) - .collect::>() - .join(","); + let members = + members.iter().map(|i| i.to_string()).collect::>().join(","); write!(f, "class {}", members) - }, + } } } } @@ -395,14 +421,14 @@ impl SerializableWithContext for ProgramObject { serializable::write_u8(sink, self.tag())?; use ProgramObject::*; match &self { - Null => Ok(()), - Integer(n) => serializable::write_i32(sink, *n), - Boolean(b) => serializable::write_bool(sink, *b), - String(s) => serializable::write_utf8(sink, s), - Class(v) => ConstantPoolIndex::write_cpi_vector(sink, v), - Slot {name} => name.serialize(sink), - - Method {name, parameters, locals, code: range} => { + Null => Ok(()), + Integer(n) => serializable::write_i32(sink, *n), + Boolean(b) => serializable::write_bool(sink, *b), + String(s) => serializable::write_utf8(sink, s), + Class(v) => ConstantPoolIndex::write_cpi_vector(sink, v), + Slot { name } => name.serialize(sink), + + Method { name, parameters, locals, code: range } => { name.serialize(sink)?; parameters.serialize(sink)?; locals.serialize(sink)?; @@ -411,27 +437,29 @@ impl SerializableWithContext for ProgramObject { } } - fn from_bytes(input: &mut R, code: &mut Code) -> Self { // TODO error handling + fn from_bytes(input: &mut R, code: &mut Code) -> Self { + // TODO error handling let tag = serializable::read_u8(input); match tag { 0x00 => ProgramObject::Integer(serializable::read_i32(input)), 0x01 => ProgramObject::Null, 0x02 => ProgramObject::String(serializable::read_utf8(input)), - 0x03 => ProgramObject::Method { name: ConstantPoolIndex::from_bytes(input), + 0x03 => ProgramObject::Method { + name: ConstantPoolIndex::from_bytes(input), parameters: Arity::from_bytes(input), locals: Size::from_bytes(input), - code: code.append(OpCode::read_opcode_vector(input))}, + code: code.append(OpCode::read_opcode_vector(input)), + }, 0x04 => ProgramObject::Slot { name: ConstantPoolIndex::from_bytes(input) }, 0x05 => ProgramObject::Class(ConstantPoolIndex::read_cpi_vector(input)), 0x06 => ProgramObject::Boolean(serializable::read_bool(input)), - _ => panic!("Cannot deserialize value: unrecognized value tag: {}", tag) + _ => panic!("Cannot deserialize value: unrecognized value tag: {}", tag), } } } // FIXME error message should include parameter list: // Call method error: no method `*` in object `2`', src/main.rs:158:14 impl ProgramObject { - #[allow(dead_code)] pub fn null() -> Self { ProgramObject::Null @@ -479,7 +507,9 @@ impl ProgramObject { #[derive(Eq, PartialEq, Debug)] pub struct Code(Vec); impl Code { - pub fn new() -> Self { Code(Vec::new()) } + pub fn new() -> Self { + Code(Vec::new()) + } pub fn upcoming_address(&self) -> Address { Address::from_usize(self.0.len()) } @@ -495,10 +525,14 @@ impl Code { } #[allow(dead_code)] pub fn emit_if(&mut self, opcode: OpCode, condition: bool) { - if condition { self.emit(opcode) } + if condition { + self.emit(opcode) + } } pub fn emit_unless(&mut self, opcode: OpCode, condition: bool) { - if !condition { self.emit(opcode) } + if !condition { + self.emit(opcode) + } } #[allow(dead_code)] pub fn length(&self) -> usize { @@ -510,9 +544,13 @@ impl Code { //println!("start: {}, end: {}", start, end); - bail_if!(end > self.0.len(), - "Address range exceeds code size: {} + {} >= {}.", - start, range.length, self.0.len()); + bail_if!( + end > self.0.len(), + "Address range exceeds code size: {} + {} >= {}.", + start, + range.length, + self.0.len() + ); Ok((start..end).map(|index| &self.0[index]).collect()) } @@ -523,16 +561,23 @@ impl Code { AddressRange::new(Address::from_usize(start), length) } pub fn labels(&self) -> Vec<&ConstantPoolIndex> { - self.0.iter().flat_map(|opcode| match opcode { - OpCode::Label { name } => Some(name), - _ => None - }).collect() + self.0 + .iter() + .flat_map(|opcode| match opcode { + OpCode::Label { name } => Some(name), + _ => None, + }) + .collect() } pub fn label_addresses(&self) -> Vec
{ - self.0.iter().enumerate().flat_map(|(address, opcode)| match opcode { - OpCode::Label { .. } => Some(Address::from_usize(address)), - _ => None - }).collect() + self.0 + .iter() + .enumerate() + .flat_map(|(address, opcode)| match opcode { + OpCode::Label { .. } => Some(Address::from_usize(address)), + _ => None, + }) + .collect() } pub fn next(&self, address: Address) -> Option
{ let index = address.value_usize() + 1; @@ -677,7 +722,6 @@ impl std::fmt::Display for Code { // } // - impl Serializable for Program { fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { self.constant_pool.serialize(sink, &self.code)?; @@ -693,7 +737,7 @@ impl Serializable for Program { let entry = Entry::from_bytes(input); let label_names = code.labels(); - let label_constants = constant_pool.get_all(label_names).unwrap().into_iter(); // TODO error handling + let label_constants = constant_pool.get_all(label_names).unwrap().into_iter(); // TODO error handling let label_addresses = code.label_addresses().into_iter(); let labels = Labels::from(label_constants.zip(label_addresses)).unwrap(); @@ -704,9 +748,7 @@ impl Serializable for Program { impl SerializableWithContext for ConstantPool { fn serialize(&self, sink: &mut W, code: &Code) -> Result<()> { serializable::write_usize_as_u16(sink, self.0.len())?; - self.0.iter() - .map(|program_object| program_object.serialize(sink, code)) - .collect() + self.0.iter().try_for_each(|program_object| program_object.serialize(sink, code)) } fn from_bytes(input: &mut R, code: &mut Code) -> Self { @@ -738,15 +780,24 @@ impl Serializable for Entry { } } -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct Arity(u8); -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct Size(u16); -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct Address(u32); -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct ConstantPoolIndex(u16); -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct LocalFrameIndex(u16); -#[derive(PartialEq,Debug,Copy,Clone,Eq,PartialOrd,Ord,Hash)] pub struct AddressRange { start: Address, length: usize } +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct Arity(u8); +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct Size(u16); +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct Address(u32); +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct ConstantPoolIndex(u16); +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct LocalFrameIndex(u16); +#[derive(PartialEq, Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] +pub struct AddressRange { + start: Address, + length: usize, +} impl Arity { - pub fn new(value: u8) -> Arity { + pub fn new(value: u8) -> Arity { Arity(value) } } @@ -758,7 +809,7 @@ impl Size { } impl LocalFrameIndex { #[allow(dead_code)] - pub fn new(value: u16) -> LocalFrameIndex { + pub fn new(value: u16) -> LocalFrameIndex { LocalFrameIndex(value) } } @@ -819,16 +870,16 @@ impl From for ConstantPoolIndex { } impl AddressRange { - pub fn new (start: Address, length: usize) -> Self { + pub fn new(start: Address, length: usize) -> Self { AddressRange { start, length } } #[allow(dead_code)] - pub fn from (start: usize, length: usize) -> Self { + pub fn from(start: usize, length: usize) -> Self { AddressRange { start: Address::from_usize(start), length } } #[allow(dead_code)] - pub fn from_addresses (start: Address, end: Address) -> Self { + pub fn from_addresses(start: Address, end: Address) -> Self { AddressRange { start, length: end.value_usize() - start.value_usize() + 1 } } @@ -843,22 +894,38 @@ impl AddressRange { impl ConstantPoolIndex { pub fn read_cpi_vector(input: &mut R) -> Vec { - serializable::read_u16_vector(input) - .into_iter() - .map(ConstantPoolIndex::new) - .collect() + serializable::read_u16_vector(input).into_iter().map(ConstantPoolIndex::new).collect() } - pub fn write_cpi_vector(sink: &mut R, vector: &Vec) -> anyhow::Result<()> { + pub fn write_cpi_vector( + sink: &mut R, + vector: &Vec, + ) -> anyhow::Result<()> { let vector_of_u16s: Vec = vector.iter().map(|cpi| cpi.0).collect(); serializable::write_u16_vector(sink, &vector_of_u16s) } } -impl ConstantPoolIndex { pub fn value(&self) -> u16 { self.0 } } -impl LocalFrameIndex { pub fn value(&self) -> u16 { self.0 } } -impl Size { pub fn value(&self) -> u16 { self.0 } } -impl Arity { pub fn value(&self) -> u8 { self.0 } } +impl ConstantPoolIndex { + pub fn value(&self) -> u16 { + self.0 + } +} +impl LocalFrameIndex { + pub fn value(&self) -> u16 { + self.0 + } +} +impl Size { + pub fn value(&self) -> u16 { + self.0 + } +} +impl Arity { + pub fn value(&self) -> u8 { + self.0 + } +} impl Address { #[allow(dead_code)] @@ -882,8 +949,7 @@ impl Address { } impl Serializable for Arity { - - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u8(sink, self.0) } @@ -893,9 +959,8 @@ impl Serializable for Arity { } impl Arity { - #[allow(dead_code)] - pub fn serialize_plus_one (&self, sink: &mut W) -> Result<()> { + pub fn serialize_plus_one(&self, sink: &mut W) -> Result<()> { assert!(self.0 < 255u8); serializable::write_u8(sink, self.0 + 1) } @@ -909,8 +974,7 @@ impl Arity { } impl Serializable for Size { - - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u16(sink, self.0) } @@ -920,7 +984,7 @@ impl Serializable for Size { } impl Serializable for Address { - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u32(sink, self.0) } fn from_bytes(input: &mut R) -> Self { @@ -929,7 +993,7 @@ impl Serializable for Address { } impl Serializable for ConstantPoolIndex { - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u16(sink, self.0) } fn from_bytes(input: &mut R) -> Self { @@ -938,7 +1002,7 @@ impl Serializable for ConstantPoolIndex { } impl Serializable for LocalFrameIndex { - fn serialize (&self, sink: &mut W) -> anyhow::Result<()> { + fn serialize(&self, sink: &mut W) -> anyhow::Result<()> { serializable::write_u16(sink, self.0) } fn from_bytes(input: &mut R) -> Self { @@ -948,7 +1012,7 @@ impl Serializable for LocalFrameIndex { impl std::fmt::Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{number:>0width$}", number=self.0, width=4) + write!(f, "{number:>0width$}", number = self.0, width = 4) } } @@ -981,14 +1045,21 @@ impl std::fmt::Display for AddressRange { if self.length == 0 { write!(f, "{}-∅", self.start) } else { - write!(f, "{}-{}", self.start, - Address::from_usize(self.start.value_usize() + self.length - 1)) + write!( + f, + "{}-{}", + self.start, + Address::from_usize(self.start.value_usize() + self.length - 1) + ) } } } impl Size { - pub fn make_vector(&self, element: T) -> Vec where T: Clone { + pub fn make_vector(&self, element: T) -> Vec + where + T: Clone, + { repeat(element).take(self.to_usize()).collect::>() } -} \ No newline at end of file +} diff --git a/src/bytecode/serializable.rs b/src/bytecode/serializable.rs index 88b3747..9f1395c 100644 --- a/src/bytecode/serializable.rs +++ b/src/bytecode/serializable.rs @@ -5,12 +5,12 @@ use super::program::Code; use anyhow::*; pub trait SerializableWithContext { - fn serialize (&self, sink: &mut W, code: &Code) -> Result<()>; + fn serialize(&self, sink: &mut W, code: &Code) -> Result<()>; fn from_bytes(input: &mut R, code: &mut Code) -> Self; } pub trait Serializable { - fn serialize (&self, sink: &mut W) -> Result<()>; + fn serialize(&self, sink: &mut W) -> Result<()>; fn from_bytes(input: &mut R) -> Self; } @@ -52,8 +52,9 @@ pub fn read_utf8(reader: &mut R) -> String { for i in 0..length { bytes[i] = read_u8(reader); } - String::from_utf8(bytes).expect(&format!("Problem reading UTF-8 string of size {} \ - from data sink", length)) + String::from_utf8(bytes).unwrap_or_else(|_| panic!("Problem reading UTF-8 string of size {} \ + from data sink", + length)) } pub fn read_u16_vector(reader: &mut R) -> Vec { @@ -86,31 +87,31 @@ pub fn read_u32_as_usize(reader: &mut R) -> usize { } pub fn write_u8(writer: &mut W, value: u8) -> Result<()> { - writer.write(&[value])?;//.expect(&format!("Problem writing u8 to data sink: {}", value)?; + writer.write_all(&[value])?; //.expect(&format!("Problem writing u8 to data sink: {}", value)?; Ok(()) } pub fn write_bool(writer: &mut W, value: bool) -> Result<()> { let byte = if value { 1 } else { 0 }; - writer.write(&[byte])?;//.expect(&format!("Problem writing bool to data sink: {}", value))?; + writer.write_all(&[byte])?; //.expect(&format!("Problem writing bool to data sink: {}", value))?; Ok(()) } pub fn write_u16(writer: &mut W, value: u16) -> Result<()> { let buf = value.to_le_bytes(); - writer.write(&buf)?;//.expect(&format!("Problem writing u16 to data sink: {}", value))?; + writer.write_all(&buf)?; //.expect(&format!("Problem writing u16 to data sink: {}", value))?; Ok(()) } pub fn write_u32(writer: &mut W, value: u32) -> Result<()> { let buf = value.to_le_bytes(); - writer.write(&buf)?;//.expect(&format!("Problem writing u32 to data sink: {}", value)); + writer.write_all(&buf)?; //.expect(&format!("Problem writing u32 to data sink: {}", value)); Ok(()) } pub fn write_i32(writer: &mut W, value: i32) -> Result<()> { let buf = value.to_le_bytes(); - writer.write(&buf)?;//.expect(&format!("Problem writing i32 to data sink: {}", value)); + writer.write_all(&buf)?; //.expect(&format!("Problem writing i32 to data sink: {}", value)); Ok(()) } @@ -118,9 +119,9 @@ pub fn write_utf8(writer: &mut R, string: &str) -> Result<()> { let byte_vector: Vec = string.bytes().collect(); let bytes = byte_vector.as_slice(); write_usize_as_u32(writer, bytes.len())?; - writer.write(bytes)?; + writer.write_all(bytes)?; Ok(()) - //.expect(&format!("Problem writing UTF-8 string to data sink: {}", string)); + //.expect(&format!("Problem writing UTF-8 string to data sink: {}", string)); } pub fn write_u16_vector(writer: &mut R, vector: &Vec) -> Result<()> { diff --git a/src/bytecode/state.rs b/src/bytecode/state.rs index 184ad5a..0419614 100644 --- a/src/bytecode/state.rs +++ b/src/bytecode/state.rs @@ -1,5 +1,5 @@ -use crate::bytecode::program::*; use crate::bytecode::heap::*; +use crate::bytecode::program::*; use std::collections::{HashMap, HashSet}; use anyhow::*; @@ -10,7 +10,9 @@ use std::io::Write as IOWrite; #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] pub struct InstructionPointer(Option
); impl InstructionPointer { - pub fn new() -> Self { InstructionPointer(None) } + pub fn new() -> Self { + InstructionPointer(None) + } pub fn bump(&mut self, program: &Program) { if let Some(address) = self.0 { self.0 = program.code.next(address) @@ -24,35 +26,48 @@ impl InstructionPointer { } } impl From
for InstructionPointer { - fn from(address: Address) -> Self { InstructionPointer(Some(address)) } + fn from(address: Address) -> Self { + InstructionPointer(Some(address)) + } } impl From<&Address> for InstructionPointer { - fn from(address: &Address) -> Self { InstructionPointer(Some(address.clone())) } + fn from(address: &Address) -> Self { + InstructionPointer(Some(*address)) + } } impl From for InstructionPointer { - fn from(n: u32) -> Self { InstructionPointer(Some(Address::from_u32(n))) } + fn from(n: u32) -> Self { + InstructionPointer(Some(Address::from_u32(n))) + } } impl From for InstructionPointer { - fn from(n: usize) -> Self { InstructionPointer(Some(Address::from_usize(n))) } + fn from(n: usize) -> Self { + InstructionPointer(Some(Address::from_usize(n))) + } } #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] pub struct OperandStack(Vec); impl OperandStack { - pub fn new() -> Self { OperandStack(Vec::new()) } + pub fn new() -> Self { + OperandStack(Vec::new()) + } pub fn push(&mut self, pointer: Pointer) { self.0.push(pointer) } pub fn pop(&mut self) -> Result { - self.0.pop().with_context(|| format!("Cannot pop from an empty operand stack.")) + self.0.pop().with_context(|| "Cannot pop from an empty operand stack.".to_string()) } pub fn peek(&self) -> Result<&Pointer> { - self.0.last().with_context(|| format!("Cannot peek from an empty operand stack.")) + self.0.last().with_context(|| "Cannot peek from an empty operand stack.".to_string()) } #[allow(dead_code)] pub fn pop_sequence(&mut self, n: usize) -> Result> { let result = (0..n).map(|_| self.pop()).collect::>>(); - result.map(|mut sequence| {sequence.reverse(); sequence}) + result.map(|mut sequence| { + sequence.reverse(); + sequence + }) } pub fn pop_reverse_sequence(&mut self, n: usize) -> Result> { (0..n).map(|_| self.pop()).collect::>>() @@ -66,13 +81,16 @@ impl From> for OperandStack { } #[derive(Eq, PartialEq, Debug)] -pub struct Frame { pub(crate) return_address: Option
, locals: Vec } +pub struct Frame { + pub(crate) return_address: Option
, + locals: Vec, +} impl Frame { pub fn new() -> Self { Frame { locals: Vec::new(), return_address: None } } pub fn with_capacity(return_address: Option
, size: usize, initial: Pointer) -> Self { - Frame { locals: (0..size).map(|_| initial.clone()).collect(), return_address } + Frame { locals: (0..size).map(|_| initial).collect(), return_address } } pub fn from(return_address: Option
, locals: Vec) -> Self { Frame { locals, return_address } @@ -95,27 +113,32 @@ impl Frame { } #[derive(Eq, PartialEq, Debug)] -pub struct FrameStack { pub globals: GlobalFrame, pub functions: GlobalFunctions, frames: Vec } +pub struct FrameStack { + pub globals: GlobalFrame, + pub functions: GlobalFunctions, + frames: Vec, +} impl FrameStack { pub fn new() -> Self { FrameStack { globals: GlobalFrame::new(), functions: GlobalFunctions::new(), - frames: Vec::new()} + frames: Vec::new(), + } } pub fn pop(&mut self) -> Result { - self.frames.pop().with_context(|| format!("Attempting to pop frame from empty stack.")) + self.frames.pop().with_context(|| "Attempting to pop frame from empty stack.".to_string()) } pub fn push(&mut self, frame: Frame) { self.frames.push(frame) } pub fn get_locals(&self) -> Result<&Frame> { - self.frames.last() - .with_context(|| format!("Attempting to access frame from empty stack.")) + self.frames.last().with_context(|| "Attempting to access frame from empty stack.".to_string()) } pub fn get_locals_mut(&mut self) -> Result<&mut Frame> { - self.frames.last_mut() - .with_context(|| format!("Attempting to access frame from empty stack.")) + self.frames + .last_mut() + .with_context(|| "Attempting to access frame from empty stack.".to_string()) } } @@ -130,7 +153,7 @@ impl From for FrameStack { FrameStack { globals: GlobalFrame::new(), functions: GlobalFunctions::new(), - frames: vec![frame] + frames: vec![frame], } } } @@ -138,10 +161,11 @@ impl From for FrameStack { #[derive(Eq, PartialEq, Debug)] pub struct GlobalFunctions(HashMap); impl GlobalFunctions { - pub fn new() -> Self { GlobalFunctions(HashMap::new()) } + pub fn new() -> Self { + GlobalFunctions(HashMap::new()) + } pub fn get(&self, name: &str) -> Result<&ConstantPoolIndex> { - self.0.get(name) - .with_context(|| format!("No such function `{}`.", name)) + self.0.get(name).with_context(|| format!("No such function `{}`.", name)) } #[allow(dead_code)] pub fn update(&mut self, name: String, index: ConstantPoolIndex) -> Result<()> { @@ -157,7 +181,8 @@ impl GlobalFunctions { } pub fn from(methods: Vec<(String, ConstantPoolIndex)>) -> Result { let mut unique = HashSet::new(); - let functions = methods.into_iter() + let functions = methods + .into_iter() .map(|(name, index)| { if unique.insert(name.clone()) { Ok((name, index)) @@ -173,10 +198,11 @@ impl GlobalFunctions { #[derive(Eq, PartialEq, Debug)] pub struct GlobalFrame(HashMap); impl GlobalFrame { - pub fn new() -> Self { GlobalFrame(HashMap::new()) } + pub fn new() -> Self { + GlobalFrame(HashMap::new()) + } pub fn get(&self, name: &str) -> Result<&Pointer> { - self.0.get(name) - .with_context(|| format!("No such global `{}`.", name)) + self.0.get(name).with_context(|| format!("No such global `{}`.", name)) } #[allow(dead_code)] pub fn update(&mut self, name: String, pointer: Pointer) -> Result<()> { @@ -192,10 +218,11 @@ impl GlobalFrame { } pub fn from(names: Vec, initial: Pointer) -> Result { let mut unique = HashSet::new(); - let globals = names.into_iter() + let globals = names + .into_iter() .map(|name| { if unique.insert(name.clone()) { - Ok((name, initial.clone())) + Ok((name, initial)) } else { Err(anyhow!("Global is a duplicate: {}", name)) } @@ -210,7 +237,7 @@ pub struct State { pub operand_stack: OperandStack, pub frame_stack: FrameStack, pub instruction_pointer: InstructionPointer, - pub heap: Heap + pub heap: Heap, } // pub struct State { @@ -231,30 +258,35 @@ impl State { // self.heap.set_log(heap_log); // self // } - pub fn from(program: &Program) -> Result { // TODO error handling is a right mess here. - - let entry_index = program.entry.get() - .with_context(|| format!("Cannot find entry method."))?; - let entry_method = program.constant_pool.get(&entry_index) - .with_context(|| format!("Cannot find entry method."))?; + pub fn from(program: &Program) -> Result { + // TODO error handling is a right mess here. + + let entry_index = + program.entry.get().with_context(|| "Cannot find entry method.".to_string())?; + let entry_method = program + .constant_pool + .get(&entry_index) + .with_context(|| "Cannot find entry method.".to_string())?; let entry_address = entry_method.get_method_start_address()?; let entry_length = entry_method.get_method_length()?; let entry_locals = entry_method.get_method_locals()?; - let instruction_pointer = if entry_length > 0 { - InstructionPointer::from(*entry_address) - } else { + let instruction_pointer = if entry_length > 0 { + InstructionPointer::from(*entry_address) + } else { InstructionPointer::new() }; - let global_objects = program.globals.iter() - .map(|index| { - program.constant_pool.get(&index).map(|object| (index, object)) - }) + let global_objects = program + .globals + .iter() + .map(|index| program.constant_pool.get(&index).map(|object| (index, object))) .collect::>>()?; - ensure!(global_objects.iter().all(|(_, object)| object.is_slot() || object.is_method()), - "Illegal global constant: expecting Method or Slot."); + ensure!( + global_objects.iter().all(|(_, object)| object.is_slot() || object.is_method()), + "Illegal global constant: expecting Method or Slot." + ); fn extract_slot(program: &Program, slot: &ProgramObject) -> Result { let name_index = slot.as_slot_index()?; @@ -263,19 +295,25 @@ impl State { Ok(name.to_owned()) } - let globals = global_objects.iter() + let globals = global_objects + .iter() .filter(|(_, program_object)| program_object.is_slot()) .map(|(_, slot)| extract_slot(program, slot)) .collect::>>()?; - fn extract_function(program: &Program, index: &ConstantPoolIndex, method: &ProgramObject) -> Result<(String, ConstantPoolIndex)> { + fn extract_function( + program: &Program, + index: &ConstantPoolIndex, + method: &ProgramObject, + ) -> Result<(String, ConstantPoolIndex)> { let name_index = method.get_method_name()?; let name_object = program.constant_pool.get(name_index)?; let name = name_object.as_str()?; - Ok((name.to_owned(), index.clone())) + Ok((name.to_owned(), *index)) } - let functions = global_objects.iter() + let functions = global_objects + .iter() .filter(|(_, program_object)| program_object.is_method()) .map(|(index, method)| extract_function(program, index, method)) .collect::>>()?; @@ -297,7 +335,7 @@ impl State { operand_stack: OperandStack::new(), frame_stack: FrameStack::new(), instruction_pointer: InstructionPointer::new(), - heap: Heap::new() + heap: Heap::new(), } } @@ -307,7 +345,7 @@ impl State { operand_stack: OperandStack::new(), frame_stack: FrameStack::from(Frame::new()), instruction_pointer: InstructionPointer::from(Address::from_usize(0)), - heap: Heap::new() + heap: Heap::new(), } } @@ -436,7 +474,6 @@ impl State { // } } - // #[derive(PartialEq,Debug)] // pub struct LocalFrame { // locals: Vec, /* ProgramObject::Slot */ @@ -492,7 +529,9 @@ impl State { pub struct Output(); impl Output { - pub fn new() -> Self { Output() } + pub fn new() -> Self { + Output() + } } impl std::fmt::Write for Output { @@ -502,4 +541,4 @@ impl std::fmt::Write for Output { Err(_) => Err(std::fmt::Error), } } -} \ No newline at end of file +} diff --git a/src/fml.lalrpop b/src/fml.lalrpop index 74be565..496084b 100644 --- a/src/fml.lalrpop +++ b/src/fml.lalrpop @@ -1,5 +1,4 @@ use std::str::FromStr; -use std::collections::VecDeque; use crate::parser::AST; use crate::parser::Operator; @@ -67,13 +66,7 @@ pub TopLevel: AST = { => AST::top(vec![AST::null()]), } -TopLevelExpressions: Vec = { - > >)*> SEMICOLON? => { - let mut all = VecDeque::from(elements); - all.push_front(element); - Vec::from(all) - } -} +TopLevelExpressions = SeparatedOnePlus, SEMICOLON>; TopLevelExpression: AST = { FunctionDefinition => <>, // Feeny-style function definition, returns unit? @@ -87,13 +80,7 @@ TopLevelExpression: AST = { Operation => <>, // operations, but this also leads to Accessible } -Expressions: Vec = { - > >)*> SEMICOLON? => { - let mut all = VecDeque::from(elements); - all.push_front(element); - Vec::from(all) - } -} +Expressions = SeparatedOnePlus, SEMICOLON>; Expression: AST = { //FunctionDefinition => <>, // Feeny-style function definition, returns unit? @@ -221,10 +208,6 @@ Conditional: AST = { Print: AST = { // TODO format string check PRINT LPAREN )?> RPAREN => { - // let boxed_arguments: Vec> = match arguments { - // Some(arguments) => arguments.into_iter().map( | e | Box::new(e)).collect(), - // None => vec!(), - // }; AST::print(format, arguments.unwrap_or(vec![])) } } @@ -234,12 +217,7 @@ ObjectDefinition: AST = { AST::object(extends.unwrap_or(AST::Null), members) } -Members: Vec = { - BEGIN SEMICOLON)*> END => match element { - None => elements, - Some(e) => { let mut elements = elements; elements.push(e); elements } - } -} +Members = BEGIN > END; Field: AST = { DOT DOT)*> => { @@ -280,13 +258,7 @@ OperatorDefinition: AST = { AST::operator(operator, parameters, body) } -Parameters: Vec = { - LPAREN COMMA)*> RPAREN => - match element { - None => elements, - Some(e) => { let mut elements = elements; elements.push(e); elements } - } -} +Parameters = LPAREN > RPAREN; IdentOrPrint: Identifier = { Ident => <>, @@ -295,30 +267,21 @@ IdentOrPrint: Identifier = { Application: AST = { LPAREN RPAREN => { - // let boxed_arguments: Vec> = - // arguments.into_iter().map(|e| Box::new(e)).collect(); AST::call_function(function, arguments) }, DOT DOT)*> LPAREN RPAREN => { let tail = Vec::from(fields); let host: AST = tail.into_iter().fold(object, |left, right| AST::access_field(left, right)); - // let boxed_arguments: Vec> = arguments.into_iter().map(|e| Box::new(e)).collect(); AST::call_method(host, method, arguments) }, DOT DOT)*> LPAREN RPAREN => { let tail = Vec::from(fields); let host: AST = tail.into_iter().fold(object, |left, right| AST::access_field (left, right)); - //let boxed_arguments: Vec> = arguments.into_iter().map(|e| Box::new(e)).collect(); AST::call_operator(host, operator, arguments) } } -Arguments: Vec = { - > COMMA)*> ?> => match element { - None => elements, - Some(e) => { let mut elements = elements; elements.push(e); elements } - } -} +Arguments = Separated, COMMA>; Assignment: AST = { LET BE > => @@ -364,3 +327,15 @@ Boolean: AST = { Unit: AST = { UNIT => AST::null(), } + +// Macros +Separated: Vec = { + S)*> => match e { + None => v, + Some(e) => { v.push(e); v } + } +} + +SeparatedOnePlus: Vec = { + S)*> S? => { v.push(e); v } +}; diff --git a/src/main.rs b/src/main.rs index 2fc32cd..f6a0a78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,29 @@ -#[macro_use] extern crate lalrpop_util; +#[macro_use] +extern crate lalrpop_util; lalrpop_mod!(pub fml); // load module synthesized by LALRPOP -mod parser; mod bytecode; +mod parser; -#[cfg(test)] mod tests; +#[cfg(test)] +mod tests; -use std::path::PathBuf; use std::fs::File; -use std::io::{Read, BufReader, BufRead, Write, BufWriter}; +use std::io::{BufRead, BufReader, BufWriter, Read, Write}; +use std::path::PathBuf; -use clap::Clap; -use clap::crate_version; -use clap::crate_authors; use anyhow::*; +use clap::crate_authors; +use clap::crate_version; +use clap::Clap; -use crate::parser::AST; use crate::fml::TopLevelParser; +use crate::parser::AST; +use crate::bytecode::interpreter::evaluate_with_memory_config; use crate::bytecode::program::Program; use crate::bytecode::serializable::Serializable; -use crate::bytecode::interpreter::evaluate_with_memory_config; #[derive(Clap, Debug)] #[clap(version = crate_version!(), author = crate_authors!())] @@ -48,29 +50,50 @@ impl Action { #[derive(Clap, Debug)] #[clap(about = "Run an FML program")] struct RunAction { - #[clap(name="FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] pub input: Option, - #[clap(long="heap-size", name="MBs", about = "Maximum heap size in megabytes", default_value = "0")] + #[clap( + long = "heap-size", + name = "MBs", + about = "Maximum heap size in megabytes", + default_value = "0" + )] pub heap_size: usize, - #[clap(long="heap-log", name="LOG_FILE", about = "Path to heap log, if none, the log is not produced", parse(from_os_str), parse(from_os_str))] + #[clap( + long = "heap-log", + name = "LOG_FILE", + about = "Path to heap log, if none, the log is not produced", + parse(from_os_str), + parse(from_os_str) + )] pub heap_log: Option, } #[derive(Clap, Debug)] #[clap(about = "Print FML bytecode in human-readable form")] struct BytecodeDisassemblyAction { - #[clap(name="FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] pub input: Option, } #[derive(Clap, Debug)] #[clap(about = "Interpret FML bytecode")] struct BytecodeInterpreterAction { - #[clap(name="FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] pub input: Option, - #[clap(long="heap-size", name="MBs", about = "Maximum heap size in megabytes", default_value = "0")] + #[clap( + long = "heap-size", + name = "MBs", + about = "Maximum heap size in megabytes", + default_value = "0" + )] pub heap_size: usize, - #[clap(long="heap-log", name="LOG_FILE", about = "Path to heap log, if none, the log is not produced", parse(from_os_str))] + #[clap( + long = "heap-log", + name = "LOG_FILE", + about = "Path to heap log, if none, the log is not produced", + parse(from_os_str) + )] pub heap_log: Option, } @@ -80,15 +103,23 @@ struct CompilerAction { #[clap(short = 'o', long = "output-path", alias = "output-dir", parse(from_os_str))] pub output: Option, - #[clap(name="FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] pub input: Option, - #[clap(long = "output-format", alias = "bc", name = "AST_FORMAT", - about = "The output format for the bytecode: bytes or string")] + #[clap( + long = "output-format", + alias = "bc", + name = "AST_FORMAT", + about = "The output format for the bytecode: bytes or string" + )] pub output_format: Option, - #[clap(long = "input-format", alias = "ast", name = "BC_FORMAT", - about = "The output format of the AST: JSON, LISP, YAML")] + #[clap( + long = "input-format", + alias = "ast", + name = "BC_FORMAT", + about = "The output format of the AST: JSON, LISP, YAML" + )] pub input_format: Option, } @@ -98,11 +129,15 @@ struct ParserAction { #[clap(short = 'o', long = "output-path", alias = "output-dir", parse(from_os_str))] pub output: Option, - #[clap(name="FILE", parse(from_os_str))] + #[clap(name = "FILE", parse(from_os_str))] pub input: Option, - #[clap(long = "format", alias = "ast", name = "FORMAT", - about = "The output format of the AST: JSON, LISP, YAML, or Rust")] + #[clap( + long = "format", + alias = "ast", + name = "FORMAT", + about = "The output format of the AST: JSON, LISP, YAML, or Rust" + )] pub format: Option, } @@ -113,12 +148,9 @@ macro_rules! prepare_file_path_from_input_and_serializer { let mut file = path.clone(); let filename = match $self.selected_input().unwrap().name { Stream::File(file) => { - PathBuf::from(file) - .file_name().unwrap() - .to_str().unwrap() - .to_owned() + PathBuf::from(file).file_name().unwrap().to_str().unwrap().to_owned() } - Stream::Console => { "ast".to_owned() } + Stream::Console => "ast".to_owned(), }; let extension = $self.selected_output_format().extension(); file.push(filename); @@ -128,22 +160,18 @@ macro_rules! prepare_file_path_from_input_and_serializer { path.clone() } }) - } + }; } - impl RunAction { pub fn run(&self) { - let source = self.selected_input() - .expect("Cannot open FML program."); + let source = self.selected_input().expect("Cannot open FML program."); let ast: AST = TopLevelParser::new() - .parse(&source.into_string() - .expect("Error reading input")) + .parse(&source.into_string().expect("Error reading input")) .expect("Parse error"); - let program = bytecode::compile(&ast) - .expect("Compiler error"); + let program = bytecode::compile(&ast).expect("Compiler error"); evaluate_with_memory_config(&program, self.heap_size, self.heap_log.clone()) .expect("Interpreter error") @@ -156,10 +184,11 @@ impl RunAction { impl BytecodeInterpreterAction { pub fn interpret(&self) { - let mut source = self.selected_input() - .expect("Cannot open an input for the bytecode interpreter."); + let mut source = + self.selected_input().expect("Cannot open an input for the bytecode interpreter."); - let program = BCSerializer::BYTES.deserialize(&mut source) + let program = BCSerializer::BYTES + .deserialize(&mut source) .expect("Cannot parse bytecode from input."); evaluate_with_memory_config(&program, self.heap_size, self.heap_log.clone()) @@ -173,10 +202,11 @@ impl BytecodeInterpreterAction { impl BytecodeDisassemblyAction { pub fn debug(&self) { - let mut source = self.selected_input() - .expect("Cannot open an input for the bytecode interpreter."); + let mut source = + self.selected_input().expect("Cannot open an input for the bytecode interpreter."); - let program = BCSerializer::BYTES.deserialize(&mut source) + let program = BCSerializer::BYTES + .deserialize(&mut source) .expect("Cannot parse bytecode from input."); println!("{}", program); @@ -189,23 +219,20 @@ impl BytecodeDisassemblyAction { impl CompilerAction { pub fn compile(&self) { - let source = self.selected_input() - .expect("Cannot open an input for the compiler."); - let mut sink = self.selected_output() - .expect("Cannot open an output for the compiler."); - let input_serializer = self.selected_input_format() + let source = self.selected_input().expect("Cannot open an input for the compiler."); + let mut sink = self.selected_output().expect("Cannot open an output for the compiler."); + let input_serializer = self + .selected_input_format() .expect("Cannot derive input format from file path. Consider setting it explicitly."); let output_serializer = self.selected_output_format(); - let source = source.into_string() - .expect("Error reading input file"); - let ast = input_serializer.deserialize(&source) - .expect("Error parsing AST from input file"); + let source = source.into_string().expect("Error reading input file"); + let ast = input_serializer.deserialize(&source).expect("Error parsing AST from input file"); - let program = bytecode::compile(&ast) - .expect("Compiler Error"); + let program = bytecode::compile(&ast).expect("Compiler Error"); - output_serializer.serialize(&program, &mut sink) + output_serializer + .serialize(&program, &mut sink) .expect("Cannot serialize program to output."); } @@ -221,9 +248,10 @@ impl CompilerAction { if self.input_format.is_some() { self.input_format } else { - self.selected_input().unwrap().extension().map(|s| { - ASTSerializer::from_extension(s.as_str()) - }).flatten() + self.selected_input() + .unwrap() + .extension() + .and_then(|s| ASTSerializer::from_extension(s.as_str())) } } @@ -235,22 +263,17 @@ impl CompilerAction { impl ParserAction { pub fn parse(&self) { - let source = self.selected_input() - .expect("Cannot open an input for the parser."); - let mut sink = self.selected_output() - .expect("Cannot open an output for the parser."); + let source = self.selected_input().expect("Cannot open an input for the parser."); + let mut sink = self.selected_output().expect("Cannot open an output for the parser."); let serializer = self.selected_output_format(); let ast: AST = TopLevelParser::new() - .parse(&source.into_string() - .expect("Error reading input")) + .parse(&source.into_string().expect("Error reading input")) .expect("Parse error"); - let result = serializer.serialize(&ast) - .expect("Cannot serialize AST"); + let result = serializer.serialize(&ast).expect("Cannot serialize AST"); - write!(sink, "{}", result) - .expect("Cannot write to output"); + write!(sink, "{}", result).expect("Cannot write to output"); } pub fn selected_input(&self) -> Result { @@ -259,13 +282,11 @@ impl ParserAction { pub fn selected_output_format(&self) -> ASTSerializer { self.format.unwrap_or_else(|| { - self.output.as_ref() - .map(|path| path.extension()) - .flatten() - .map(|extension| extension.to_str().map(|s| s.to_owned())) - .flatten() - .map(|extension| ASTSerializer::from_extension(extension.as_str())) - .flatten() + self.output + .as_ref() + .and_then(|path| path.extension()) + .and_then(|extension| extension.to_str().map(|s| s.to_owned())) + .and_then(|extension| ASTSerializer::from_extension(extension.as_str())) .unwrap_or(ASTSerializer::INTERNAL) }) } @@ -278,13 +299,14 @@ impl ParserAction { #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Copy, Clone, Hash)] enum BCSerializer { - BYTES, STRING + BYTES, + STRING, } impl BCSerializer { pub fn serialize(&self, program: &Program, sink: &mut NamedSink) -> Result<()> { match self { - BCSerializer::BYTES => program.serialize(sink), + BCSerializer::BYTES => program.serialize(sink), BCSerializer::STRING => unimplemented!(), } } @@ -295,7 +317,7 @@ impl BCSerializer { pub fn extension(&self) -> &'static str { match self { - BCSerializer::BYTES => "bc", + BCSerializer::BYTES => "bc", BCSerializer::STRING => "bc.txt", } } @@ -306,23 +328,26 @@ impl std::str::FromStr for BCSerializer { fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { - "bytes" | "bc" | "bytecode" => Ok(Self::BYTES), + "bytes" | "bc" | "bytecode" => Ok(Self::BYTES), "string" | "str" | "pp" | "pretty" | "print" => Ok(Self::STRING), - format => Err(anyhow::anyhow!("Unknown BC serialization format: {}", format)) + format => Err(anyhow::anyhow!("Unknown BC serialization format: {}", format)), } } } #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Copy, Clone, Hash)] enum ASTSerializer { - LISP, JSON, YAML, INTERNAL + LISP, + JSON, + YAML, + INTERNAL, } impl ASTSerializer { pub fn serialize(&self, ast: &AST) -> Result { let string = match self { - ASTSerializer::LISP => serde_lexpr::to_string(&ast)?, - ASTSerializer::JSON => serde_json::to_string(&ast)?, - ASTSerializer::YAML => serde_yaml::to_string(&ast)?, + ASTSerializer::LISP => serde_lexpr::to_string(&ast)?, + ASTSerializer::JSON => serde_json::to_string(&ast)?, + ASTSerializer::YAML => serde_yaml::to_string(&ast)?, ASTSerializer::INTERNAL => format!("{:?}", ast), }; Ok(format!("{}\n", string)) @@ -330,18 +355,20 @@ impl ASTSerializer { pub fn deserialize(&self, source: &str) -> Result { match self { - ASTSerializer::LISP => Ok(serde_lexpr::from_str(source)?), - ASTSerializer::JSON => Ok(serde_json::from_str(source)?), - ASTSerializer::YAML => Ok(serde_yaml::from_str(source)?), - ASTSerializer::INTERNAL => bail!("No deserializer implemented for Rust/INTERNAL format"), + ASTSerializer::LISP => Ok(serde_lexpr::from_str(source)?), + ASTSerializer::JSON => Ok(serde_json::from_str(source)?), + ASTSerializer::YAML => Ok(serde_yaml::from_str(source)?), + ASTSerializer::INTERNAL => { + bail!("No deserializer implemented for Rust/INTERNAL format") + } } } pub fn extension(&self) -> &'static str { match self { - ASTSerializer::LISP => "lisp", - ASTSerializer::JSON => "json", - ASTSerializer::YAML => "yaml", + ASTSerializer::LISP => "lisp", + ASTSerializer::JSON => "json", + ASTSerializer::YAML => "yaml", ASTSerializer::INTERNAL => "internal", } } @@ -360,17 +387,17 @@ impl std::str::FromStr for ASTSerializer { type Err = anyhow::Error; fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { - "json" => Ok(Self::JSON), - "lisp" | "sexp" | "sexpr" => Ok(Self::LISP), - "yaml" => Ok(Self::YAML), - "rust" | "internal" | "debug" => Ok(Self::INTERNAL), + "json" => Ok(Self::JSON), + "lisp" | "sexp" | "sexpr" => Ok(Self::LISP), + "yaml" => Ok(Self::YAML), + "rust" | "internal" | "debug" => Ok(Self::INTERNAL), - format => Err(anyhow::anyhow!("Unknown AST serialization format: {}", format)) + format => Err(anyhow::anyhow!("Unknown AST serialization format: {}", format)), } } } -#[derive(Clone,Hash,Debug,Eq,PartialEq,PartialOrd,Ord)] +#[derive(Clone, Hash, Debug, Eq, PartialEq, PartialOrd, Ord)] enum Stream { File(String), Console, @@ -389,7 +416,7 @@ impl Stream { struct NamedSource { name: Stream, - source: Box + source: Box, } impl NamedSource { @@ -408,10 +435,12 @@ impl NamedSource { } fn from_file(path: &PathBuf) -> Result { if let Some(name) = path.as_os_str().to_str() { - File::open(path).map(|file| NamedSource { - name: Stream::File(name.to_owned()), - source: Box::new(BufReader::new(file)), - }).map_err(|error| anyhow!("Cannot open file for reading \"{}\": {}", name, error)) + File::open(path) + .map(|file| NamedSource { + name: Stream::File(name.to_owned()), + source: Box::new(BufReader::new(file)), + }) + .map_err(|error| anyhow!("Cannot open file for reading \"{}\": {}", name, error)) // TODO maybe directories too? } else { bail!("Cannot convert path into UTF string: {:?}", path) @@ -425,10 +454,9 @@ impl NamedSource { fn extension(&self) -> Option { match &self.name { Stream::File(file) => { - PathBuf::from(file).extension() - .map(|s| s.to_str().unwrap().to_owned()) + PathBuf::from(file).extension().map(|s| s.to_str().unwrap().to_owned()) } - Stream::Console => None + Stream::Console => None, } } } @@ -452,7 +480,7 @@ impl std::fmt::Debug for NamedSource { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str("<")?; match &self.name { - Stream::File(file) => f.write_str(&file), + Stream::File(file) => f.write_str(file), Stream::Console => f.write_str("stdin"), }?; Ok(()) @@ -471,18 +499,17 @@ impl NamedSink { } } fn console() -> Result { - let named_sink = NamedSink { - name: Stream::Console, - sink: Box::new(std::io::stdout()), - }; + let named_sink = NamedSink { name: Stream::Console, sink: Box::new(std::io::stdout()) }; Ok(named_sink) } fn from_file(path: &PathBuf) -> Result { if let Some(name) = path.as_os_str().to_str() { - File::create(path).map(|file| NamedSink { - name: Stream::File(name.to_owned()), - sink: Box::new(BufWriter::new(file)), - }).map_err(|error| anyhow!("Cannot open file for writing \"{}\": {}", name, error)) + File::create(path) + .map(|file| NamedSink { + name: Stream::File(name.to_owned()), + sink: Box::new(BufWriter::new(file)), + }) + .map_err(|error| anyhow!("Cannot open file for writing \"{}\": {}", name, error)) } else { bail!("Cannot convert path into UTF string: {:?}", path) } @@ -492,10 +519,9 @@ impl NamedSink { fn extension(&self) -> Option { match &self.name { Stream::File(file) => { - PathBuf::from(file).extension() - .map(|s| s.to_str().unwrap().to_owned()) + PathBuf::from(file).extension().map(|s| s.to_str().unwrap().to_owned()) } - Stream::Console => None + Stream::Console => None, } } } @@ -503,7 +529,7 @@ impl Write for NamedSink { fn write(&mut self, buf: &[u8]) -> std::result::Result { self.sink.write(buf) } - fn flush(&mut self) -> std::result::Result<(), std::io::Error>{ + fn flush(&mut self) -> std::result::Result<(), std::io::Error> { self.sink.flush() } } @@ -512,7 +538,7 @@ impl std::fmt::Debug for NamedSink { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(">")?; match &self.name { - Stream::File(file) => f.write_str(&file), + Stream::File(file) => f.write_str(file), Stream::Console => f.write_str("stout"), }?; Ok(()) @@ -521,4 +547,4 @@ impl std::fmt::Debug for NamedSink { fn main() { Action::parse().execute(); -} \ No newline at end of file +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6f087c5..4a4c669 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,8 +1,8 @@ -use std::fmt::Debug; +use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; -use serde::{Serialize, Deserialize}; +use std::fmt::Debug; -#[derive(PartialEq,Debug,Serialize,Deserialize,Clone)] +#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)] pub enum AST { Integer(i32), Boolean(bool), @@ -10,7 +10,7 @@ pub enum AST { Variable { name: Identifier, value: Box }, Array { size: Box, value: Box }, - Object { extends: Box, members: Vec> }, + Object { extends: Box, members: Vec }, AccessVariable { name: Identifier }, AccessField { object: Box, field: Identifier }, @@ -22,24 +22,21 @@ pub enum AST { Function { name: Identifier, parameters: Vec, body: Box }, //Operator { operator: Operator, parameters: Vec, body: Box }, // TODO Consider merging with function - - CallFunction { name: Identifier, arguments: Vec> }, - CallMethod { object: Box, name: Identifier, arguments: Vec> }, + CallFunction { name: Identifier, arguments: Vec }, + CallMethod { object: Box, name: Identifier, arguments: Vec }, //CallOperator { object: Box, operator: Operator, arguments: Vec> }, // TODO Consider removing //Operation { operator: Operator, left: Box, right: Box }, // TODO Consider removing - - Top (Vec>), - Block (Vec>), + Top(Vec), + Block(Vec), Loop { condition: Box, body: Box }, Conditional { condition: Box, consequent: Box, alternative: Box }, - Print { format: String, arguments: Vec> }, + Print { format: String, arguments: Vec }, } impl AST { pub fn integer(i: i32) -> Self { Self::Integer(i) - } pub fn boolean(b: bool) -> Self { Self::Boolean(b) @@ -50,15 +47,15 @@ impl AST { } pub fn variable(name: Identifier, value: AST) -> Self { - Self::Variable { name, value: value.into_boxed() } + Self::Variable { name, value: Box::new(value) } } pub fn array(size: AST, value: AST) -> Self { - Self::Array { size: size.into_boxed(), value: value.into_boxed() } + Self::Array { size: Box::new(size), value: Box::new(value) } } pub fn object(extends: AST, members: Vec) -> Self { - Self::Object { extends: extends.into_boxed(), members: members.into_boxed() } + Self::Object { extends: Box::new(extends), members } } pub fn access_variable(name: Identifier) -> Self { @@ -66,95 +63,80 @@ impl AST { } pub fn access_field(object: AST, field: Identifier) -> Self { - Self::AccessField { object: object.into_boxed(), field } + Self::AccessField { object: Box::new(object), field } } pub fn access_array(array: AST, index: AST) -> Self { - Self::AccessArray { array: array.into_boxed(), index: index.into_boxed() } + Self::AccessArray { array: Box::new(array), index: Box::new(index) } } pub fn assign_variable(name: Identifier, value: AST) -> Self { - Self::AssignVariable { name, value: value.into_boxed() } + Self::AssignVariable { name, value: Box::new(value) } } pub fn assign_field(object: AST, field: Identifier, value: AST) -> Self { - Self::AssignField { - object: object.into_boxed(), - field, - value: value.into_boxed() - } + Self::AssignField { object: Box::new(object), field, value: Box::new(value) } } pub fn assign_array(array: AST, index: AST, value: AST) -> Self { - Self::AssignArray { - array: array.into_boxed(), - index: index.into_boxed(), - value: value.into_boxed() - } + Self::AssignArray { array: Box::new(array), index: Box::new(index), value: Box::new(value) } } pub fn function(name: Identifier, parameters: Vec, body: AST) -> Self { - Self::Function { name, parameters, body: body.into_boxed() } + Self::Function { name, parameters, body: Box::new(body) } } pub fn operator(operator: Operator, parameters: Vec, body: AST) -> Self { - Self::Function { name: Identifier::from(operator), parameters, body: body.into_boxed() } + Self::Function { name: Identifier::from(operator), parameters, body: Box::new(body) } } pub fn call_function(name: Identifier, arguments: Vec) -> Self { - Self::CallFunction { name, arguments: arguments.into_boxed() } + Self::CallFunction { name, arguments } } pub fn call_method(object: AST, name: Identifier, arguments: Vec) -> Self { - Self::CallMethod { - object: object.into_boxed(), - name, - arguments: arguments.into_boxed() } + Self::CallMethod { object: Box::new(object), name, arguments } } pub fn call_operator(object: AST, operator: Operator, arguments: Vec) -> Self { - Self::CallMethod { - object: object.into_boxed(), - name: Identifier::from(operator), - arguments: arguments.into_boxed() - } + Self::CallMethod { object: Box::new(object), name: Identifier::from(operator), arguments } } pub fn operation(operator: Operator, left: AST, right: AST) -> Self { - //Self::Operation { operator, left: left.into_boxed(), right: right.into_boxed() } + //Self::Operation { operator, left: left, right: right } Self::CallMethod { - object: left.into_boxed(), + object: Box::new(left), name: Identifier::from(operator), - arguments: vec![right.into_boxed()] + arguments: vec![right], } } - pub fn top (statements: Vec) -> Self { - Self::Top(statements.into_boxed()) + pub fn top(statements: Vec) -> Self { + Self::Top(statements) } pub fn block(statements: Vec) -> Self { - Self::Block(statements.into_boxed()) + Self::Block(statements) } pub fn loop_de_loop(condition: AST, body: AST) -> Self { - Self::Loop { condition: condition.into_boxed(), body: body.into_boxed() } + Self::Loop { condition: Box::new(condition), body: Box::new(body) } } pub fn conditional(condition: AST, consequent: AST, alternative: AST) -> Self { Self::Conditional { - condition: condition.into_boxed(), - consequent: consequent.into_boxed(), - alternative: alternative.into_boxed() + condition: Box::new(condition), + consequent: Box::new(consequent), + alternative: Box::new(alternative), } } pub fn print(format: String, arguments: Vec) -> Self { - Self::Print { format, arguments: arguments.into_boxed() } + Self::Print { format, arguments } } } -#[derive(PartialEq,Eq,Hash,Debug,Clone,Serialize,Deserialize)] +#[derive(PartialEq, Eq, Hash, Debug, Clone, Serialize, Deserialize)] pub struct Identifier(pub String); impl From for Identifier { @@ -182,10 +164,12 @@ impl std::fmt::Display for Identifier { } impl Identifier { - pub fn as_str(&self) -> &str { &self.0 } + pub fn as_str(&self) -> &str { + &self.0 + } } -#[derive(PartialEq,Debug,Copy,Clone,Serialize,Deserialize)] +#[derive(PartialEq, Debug, Copy, Clone, Serialize, Deserialize)] pub enum Operator { Multiplication, Division, @@ -206,18 +190,18 @@ impl Operator { pub fn as_str(&self) -> &str { match self { Operator::Multiplication => "*", - Operator::Division => "/", - Operator::Module => "%", - Operator::Addition => "+", - Operator::Subtraction => "-", - Operator::Inequality => "!=", - Operator::Equality => "==", - Operator::Less => "<", - Operator::LessEqual => "<=", - Operator::Greater => ">", - Operator::GreaterEqual => ">=", - Operator::Disjunction => "|", - Operator::Conjunction => "&", + Operator::Division => "/", + Operator::Module => "%", + Operator::Addition => "+", + Operator::Subtraction => "-", + Operator::Inequality => "!=", + Operator::Equality => "==", + Operator::Less => "<", + Operator::LessEqual => "<=", + Operator::Greater => ">", + Operator::GreaterEqual => ">=", + Operator::Disjunction => "|", + Operator::Conjunction => "&", } } } @@ -225,19 +209,19 @@ impl Operator { impl From<&str> for Operator { fn from(s: &str) -> Self { match s { - "*" => Operator::Multiplication, - "/" => Operator::Division, - "%" => Operator::Module, - "+" => Operator::Addition, - "-" => Operator::Subtraction, + "*" => Operator::Multiplication, + "/" => Operator::Division, + "%" => Operator::Module, + "+" => Operator::Addition, + "-" => Operator::Subtraction, "!=" => Operator::Inequality, "==" => Operator::Equality, - "<" => Operator::Less, + "<" => Operator::Less, "<=" => Operator::LessEqual, - ">" => Operator::Greater, + ">" => Operator::Greater, ">=" => Operator::GreaterEqual, - "|" => Operator::Disjunction, - "&" => Operator::Conjunction, + "|" => Operator::Disjunction, + "&" => Operator::Conjunction, other => panic!("Cannot parse {} as Operator", other), } @@ -261,45 +245,18 @@ macro_rules! make_operator_ast { ( $head:expr, $tail:expr ) => { ($tail).into_iter().fold($head, |left, right| { let (operator, value) = right; - AST::Operation { - operator: operator, - left: Box::new(left), - right: Box::new(value)} + AST::Operation { operator: operator, left: Box::new(left), right: Box::new(value) } }) - } + }; } impl AST { - pub fn from_binary_expression(first_operand: AST, other_operators_and_operands: Vec<(Operator, AST)>) -> Self { - other_operators_and_operands.into_iter() - .fold(first_operand, |left, (operator, right)| { - AST::operation(operator, left, right) - }) - } -} - -pub trait IntoBoxed { - type Into; - fn into_boxed(self) -> Self::Into; -} - -impl IntoBoxed for AST { - type Into = Box; - fn into_boxed(self) -> Self::Into { - Box::new(self) - } -} - -impl IntoBoxed for Vec { - type Into = Vec>; - fn into_boxed(self) -> Self::Into { - self.into_iter().map(|ast| ast.into_boxed()).collect() + pub fn from_binary_expression( + first_operand: AST, + other_operators_and_operands: Vec<(Operator, AST)>, + ) -> Self { + other_operators_and_operands + .into_iter() + .fold(first_operand, |left, (operator, right)| AST::operation(operator, left, right)) } } - -impl IntoBoxed for Option { - type Into = Option>; - fn into_boxed(self) -> Self::Into { - self.map(|ast| ast.into_boxed()) - } -} \ No newline at end of file diff --git a/src/tests/bytecode.rs b/src/tests/bytecode.rs index 998e012..2407940 100644 --- a/src/tests/bytecode.rs +++ b/src/tests/bytecode.rs @@ -1,287 +1,331 @@ use std::io::Cursor; use crate::bytecode::bytecode::*; -use crate::bytecode::serializable::*; use crate::bytecode::program::*; +use crate::bytecode::serializable::*; fn deserialize_test(expected: OpCode, input: Vec) { assert_eq!(OpCode::from_bytes(&mut Cursor::new(input)), expected); } -fn deserialize_with_context_test(expected_object: ProgramObject, expected_code: Code, input: Vec) { +fn deserialize_with_context_test( + expected_object: ProgramObject, + expected_code: Code, + input: Vec, +) { let mut code = Code::new(); let object = ProgramObject::from_bytes(&mut Cursor::new(input), &mut code); assert_eq!(object, expected_object); assert_eq!(code, expected_code); } -fn serialize_test(expected: Vec, object: S) where S: Serializable { +fn serialize_test(expected: Vec, object: S) +where + S: Serializable, +{ let mut actual: Vec = Vec::new(); object.serialize(&mut actual).unwrap(); assert_eq!(actual, expected); } -fn serialize_with_context_test(expected: Vec, object: S, code: Code) where S: SerializableWithContext { +fn serialize_with_context_test(expected: Vec, object: S, code: Code) +where + S: SerializableWithContext, +{ let mut actual: Vec = Vec::new(); object.serialize(&mut actual, &code).unwrap(); assert_eq!(actual, expected); } -#[test] fn deserialize_label () { +#[test] +fn deserialize_label() { let expected = OpCode::Label { name: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x00, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x00, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_literal () { +#[test] +fn deserialize_literal() { let expected = OpCode::Literal { index: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x01, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x01, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_get_local () { +#[test] +fn deserialize_get_local() { let expected = OpCode::GetLocal { index: LocalFrameIndex::new(1) }; - let bytes = vec!(0x0A, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x0A, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_set_local () { +#[test] +fn deserialize_set_local() { let expected = OpCode::SetLocal { index: LocalFrameIndex::new(1) }; - let bytes = vec!(0x09, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x09, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_get_global () { +#[test] +fn deserialize_get_global() { let expected = OpCode::GetGlobal { name: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x0C, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x0C, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_set_global () { +#[test] +fn deserialize_set_global() { let expected = OpCode::SetGlobal { name: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x0B, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x0B, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_object () { +#[test] +fn deserialize_object() { let expected = OpCode::Object { class: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x04, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x04, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_array () { +#[test] +fn deserialize_array() { let expected = OpCode::Array; - let bytes = vec!(0x03); + let bytes = vec![0x03]; deserialize_test(expected, bytes); } -#[test] fn deserialize_get_slot () { +#[test] +fn deserialize_get_slot() { let expected = OpCode::GetField { name: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x05, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x05, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_set_slot () { +#[test] +fn deserialize_set_slot() { let expected = OpCode::SetField { name: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x06, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x06, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_call_method () { +#[test] +fn deserialize_call_method() { let expected = OpCode::CallMethod { name: ConstantPoolIndex::new(1), arguments: Arity::new(1) }; - let bytes = vec!(0x07, 0x01, 0x00, 0x01); + let bytes = vec![0x07, 0x01, 0x00, 0x01]; deserialize_test(expected, bytes); } -#[test] fn deserialize_call_function () { - let expected = OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(2) }; - let bytes = vec!(0x08, 0x01, 0x00, 0x02); +#[test] +fn deserialize_call_function() { + let expected = + OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(2) }; + let bytes = vec![0x08, 0x01, 0x00, 0x02]; deserialize_test(expected, bytes); } -#[test] fn deserialize_print () { +#[test] +fn deserialize_print() { let expected = OpCode::Print { format: ConstantPoolIndex::new(1), arguments: Arity::new(2) }; - let bytes = vec!(0x02, 0x01, 0x00, 0x02); + let bytes = vec![0x02, 0x01, 0x00, 0x02]; deserialize_test(expected, bytes); } -#[test] fn deserialize_jump () { +#[test] +fn deserialize_jump() { let expected = OpCode::Jump { label: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x0E, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x0E, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_branch () { +#[test] +fn deserialize_branch() { let expected = OpCode::Branch { label: ConstantPoolIndex::new(1) }; - let bytes = vec!(0x0D, 0x01, 0x00, 0x00, 0x00); + let bytes = vec![0x0D, 0x01, 0x00, 0x00, 0x00]; deserialize_test(expected, bytes); } -#[test] fn deserialize_return_op () { +#[test] +fn deserialize_return_op() { let expected = OpCode::Return; - let bytes = vec!(0x0F); + let bytes = vec![0x0F]; deserialize_test(expected, bytes); } -#[test] fn deserialize_drop () { +#[test] +fn deserialize_drop() { let expected = OpCode::Drop; - let bytes = vec!(0x10); + let bytes = vec![0x10]; deserialize_test(expected, bytes); } -#[test] fn serialize_label () { - let expected = vec!(0x00, 0x01, 0x00); +#[test] +fn serialize_label() { + let expected = vec![0x00, 0x01, 0x00]; let object = OpCode::Label { name: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_literal () { - let expected = vec!(0x01, 0x01, 0x00, ); +#[test] +fn serialize_literal() { + let expected = vec![0x01, 0x01, 0x00]; let object = OpCode::Literal { index: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_get_local () { - let expected = vec!(0x0A, 0x01, 0x00, ); +#[test] +fn serialize_get_local() { + let expected = vec![0x0A, 0x01, 0x00]; let object = OpCode::GetLocal { index: LocalFrameIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_set_local () { - let expected = vec!(0x09, 0x01, 0x00,); +#[test] +fn serialize_set_local() { + let expected = vec![0x09, 0x01, 0x00]; let object = OpCode::SetLocal { index: LocalFrameIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_get_global () { - let expected = vec!(0x0C, 0x01, 0x00, ); +#[test] +fn serialize_get_global() { + let expected = vec![0x0C, 0x01, 0x00]; let object = OpCode::GetGlobal { name: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_set_global () { - let expected = vec!(0x0B, 0x01, 0x00, ); +#[test] +fn serialize_set_global() { + let expected = vec![0x0B, 0x01, 0x00]; let object = OpCode::SetGlobal { name: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_object () { - let expected = vec!(0x04, 0x01, 0x00, ); +#[test] +fn serialize_object() { + let expected = vec![0x04, 0x01, 0x00]; let object = OpCode::Object { class: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_array () { - let expected = vec!(0x03); +#[test] +fn serialize_array() { + let expected = vec![0x03]; let object = OpCode::Array; serialize_test(expected, object); } -#[test] fn serialize_get_slot () { - let expected = vec!(0x05, 0x01, 0x00, ); +#[test] +fn serialize_get_slot() { + let expected = vec![0x05, 0x01, 0x00]; let object = OpCode::GetField { name: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_set_slot () { - let expected = vec!(0x06, 0x01, 0x00, ); +#[test] +fn serialize_set_slot() { + let expected = vec![0x06, 0x01, 0x00]; let object = OpCode::SetField { name: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_call_method () { - let expected = vec!(0x07, 0x01, 0x00, 0x01); +#[test] +fn serialize_call_method() { + let expected = vec![0x07, 0x01, 0x00, 0x01]; let object = OpCode::CallMethod { name: ConstantPoolIndex::new(1), arguments: Arity::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_call_function () { - let expected = vec!(0x08, 0x01, 0x00, 0x02); +#[test] +fn serialize_call_function() { + let expected = vec![0x08, 0x01, 0x00, 0x02]; let object = OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(2) }; serialize_test(expected, object); } -#[test] fn serialize_print () { - let expected = vec!(0x02, 0x01, 0x00, 0x02); +#[test] +fn serialize_print() { + let expected = vec![0x02, 0x01, 0x00, 0x02]; let object = OpCode::Print { format: ConstantPoolIndex::new(1), arguments: Arity::new(2) }; serialize_test(expected, object); } -#[test] fn serialize_jump () { - let expected = vec!(0x0E, 0x01, 0x00, ); +#[test] +fn serialize_jump() { + let expected = vec![0x0E, 0x01, 0x00]; let object = OpCode::Jump { label: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_branch () { - let expected = vec!(0x0D, 0x01, 0x00, ); +#[test] +fn serialize_branch() { + let expected = vec![0x0D, 0x01, 0x00]; let object = OpCode::Branch { label: ConstantPoolIndex::new(1) }; serialize_test(expected, object); } -#[test] fn serialize_return_op () { - let expected = vec!(0x0F); +#[test] +fn serialize_return_op() { + let expected = vec![0x0F]; let object = OpCode::Return; serialize_test(expected, object); } -#[test] fn serialize_drop () { - let expected = vec!(0x10); +#[test] +fn serialize_drop() { + let expected = vec![0x10]; let object = OpCode::Drop; serialize_test(expected, object); } -#[test] fn serialize_null () { - let expected = vec!(0x01); +#[test] +fn serialize_null() { + let expected = vec![0x01]; let object = ProgramObject::Null; serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_integer () { - let expected = vec!(0x00, 0x2A, 0x00, 0x00, 0x00); +#[test] +fn serialize_integer() { + let expected = vec![0x00, 0x2A, 0x00, 0x00, 0x00]; let object = ProgramObject::Integer(42); serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_boolean () { - let expected = vec!(0x06, 0x01); +#[test] +fn serialize_boolean() { + let expected = vec![0x06, 0x01]; let object = ProgramObject::Boolean(true); serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_string () { - let expected = vec!(0x02, - 0x0C, 0x00, 0x00, 0x00, - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x0A); +#[test] +fn serialize_string() { + let expected = vec![ + 0x02, 0x0C, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, + 0x64, 0x0A, + ]; let object = ProgramObject::String("Hello World\n".to_string()); serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_slot () { - let expected = vec!(0x04, 0x2A, 0x00); +#[test] +fn serialize_slot() { + let expected = vec![0x04, 0x2A, 0x00]; let object = ProgramObject::Slot { name: ConstantPoolIndex::new(42) }; serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_class () { - let expected = vec!(0x05, - 0x02, 0x00, - 0x2A, 0x00, - 0x9A, 0x02, ); - let object = ProgramObject::Class(vec!(ConstantPoolIndex::new(42), - ConstantPoolIndex::new(666))); +#[test] +fn serialize_class() { + let expected = vec![0x05, 0x02, 0x00, 0x2A, 0x00, 0x9A, 0x02]; + let object = + ProgramObject::Class(vec![ConstantPoolIndex::new(42), ConstantPoolIndex::new(666)]); serialize_with_context_test(expected, object, Code::new()); } -#[test] fn serialize_method () { - let expected = vec!(0x03, - 0xFF, 0x00, - 0x03, - 0x0F, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x01, - 0x2A, 0x00, - 0x0F); +#[test] +fn serialize_method() { + let expected = + vec![0x03, 0xFF, 0x00, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x2A, 0x00, 0x0F]; let object = ProgramObject::Method { name: ConstantPoolIndex::new(255), @@ -290,74 +334,74 @@ fn serialize_with_context_test(expected: Vec, object: S, code: Code) wher code: AddressRange::from(0, 2), }; - let code = Code::from( - vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(42) }, - /* 1 */ OpCode::Return)); + let code = Code::from(vec![ + /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(42) }, + /* 1 */ OpCode::Return, + ]); serialize_with_context_test(expected, object, code); } -#[test] fn null () { +#[test] +fn null() { let expected = ProgramObject::Null; - let bytes = vec!(0x01); + let bytes = vec![0x01]; deserialize_with_context_test(expected, Code::new(), bytes); } -#[test] fn integer () { +#[test] +fn integer() { let expected = ProgramObject::Integer(42); - let bytes = vec!(0x00, 0x2A, 0x00, 0x00, 0x00); - deserialize_with_context_test(expected, Code::new(),bytes); + let bytes = vec![0x00, 0x2A, 0x00, 0x00, 0x00]; + deserialize_with_context_test(expected, Code::new(), bytes); } -#[test] fn boolean () { +#[test] +fn boolean() { let expected = ProgramObject::Boolean(true); - let bytes = vec!(0x06, 0x01); - deserialize_with_context_test(expected, Code::new(),bytes); + let bytes = vec![0x06, 0x01]; + deserialize_with_context_test(expected, Code::new(), bytes); } -#[test] fn string () { +#[test] +fn string() { let expected = ProgramObject::String("Hello World\0".to_string()); - let bytes = vec!(0x02, - 0x0C, 0x00, 0x00, 0x00, - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00); - deserialize_with_context_test(expected, Code::new(),bytes); + let bytes = vec![ + 0x02, 0x0C, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, + 0x64, 0x00, + ]; + deserialize_with_context_test(expected, Code::new(), bytes); } -#[test] fn slot () { +#[test] +fn slot() { let expected = ProgramObject::Slot { name: ConstantPoolIndex::new(42) }; - let bytes = vec!(0x04, 0x2A, 0x00, ); - deserialize_with_context_test(expected, Code::new(),bytes); + let bytes = vec![0x04, 0x2A, 0x00]; + deserialize_with_context_test(expected, Code::new(), bytes); } -#[test] fn class () { - let expected = ProgramObject::Class(vec!(ConstantPoolIndex::new(42), - ConstantPoolIndex::new(666))); - let bytes = vec!(0x05, - 0x02, 0x00, - 0x2A, 0x00, - 0x9A, 0x02, ); - deserialize_with_context_test(expected, Code::new(),bytes); +#[test] +fn class() { + let expected = + ProgramObject::Class(vec![ConstantPoolIndex::new(42), ConstantPoolIndex::new(666)]); + let bytes = vec![0x05, 0x02, 0x00, 0x2A, 0x00, 0x9A, 0x02]; + deserialize_with_context_test(expected, Code::new(), bytes); } +#[test] +fn method() { + let object = ProgramObject::Method { + name: ConstantPoolIndex::new(255), + parameters: Arity::new(3), + locals: Size::new(15), + code: AddressRange::from(0, 2), + }; -#[test] fn method () { - let object = ProgramObject::Method { name: ConstantPoolIndex::new(255), - parameters: Arity::new(3), - locals: Size::new(15), - code: AddressRange::from(0, 2)}; - - let code = Code::from(vec!(OpCode::Literal { index: ConstantPoolIndex::new(42) }, - OpCode::Return)); + let code = + Code::from(vec![OpCode::Literal { index: ConstantPoolIndex::new(42) }, OpCode::Return]); - let bytes = vec!(0x03, - 0xFF, 0x00, - 0x03, - 0x0F, 0x00, - 0x02, 0x00, 0x00, 0x00, - 0x01, - 0x2A, 0x00, - 0x0F); + let bytes = + vec![0x03, 0xFF, 0x00, 0x03, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x2A, 0x00, 0x0F]; deserialize_with_context_test(object, code, bytes); -} \ No newline at end of file +} diff --git a/src/tests/compiler.rs b/src/tests/compiler.rs index fb17ae6..82bc718 100644 --- a/src/tests/compiler.rs +++ b/src/tests/compiler.rs @@ -5,7 +5,8 @@ use crate::bytecode::program::*; use crate::bytecode::compiler::*; -#[test] fn number () { +#[test] +fn number() { let ast = AST::Integer(1); let mut global_environment = Environment::new(); @@ -16,13 +17,12 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) } - )); + let expected_code = + Code::from(vec![/* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }]); - let expected_constants = >>::from(vec!( - /* 0 */ ProgramObject::Integer(1) - )); + let expected_constants = >>::from(vec![ + /* 0 */ ProgramObject::Integer(1), + ]); let expected_globals = Globals::from(vec![]); let expected_entry = Entry::new(); @@ -44,7 +44,7 @@ use crate::bytecode::compiler::*; // // for ast in asts { // ast.compile(&mut program, &mut global_environment, &mut current_frame).unwrap(); - //let program = program.flatten(); +//let program = program.flatten(); // } // // let expected_global_environment = Environment::new(); @@ -74,7 +74,8 @@ use crate::bytecode::compiler::*; // assert_eq!(current_frame, expected_current_frame); // } -#[test] fn boolean () { +#[test] +fn boolean() { let ast = AST::Boolean(true); let mut global_environment = Environment::new(); @@ -85,12 +86,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) } - )); + let expected_code = + Code::from(vec![/* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }]); let expected_constants = >>::from(vec![ - /* 0 */ ProgramObject::Boolean(true) + /* 0 */ ProgramObject::Boolean(true), ]); let expected_globals = Globals::from(vec![]); @@ -104,7 +104,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn unit () { +#[test] +fn unit() { let ast = AST::Null; let mut global_environment = Environment::new(); @@ -115,13 +116,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) } - )); + let expected_code = + Code::from(vec![/* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }]); - let expected_constants = >>::from(vec![ - /* 0 */ ProgramObject::Null - ]); + let expected_constants = + >>::from(vec![/* 0 */ ProgramObject::Null]); let expected_globals = Globals::from(vec![]); let expected_entry = Entry::new(); @@ -134,9 +133,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn local_definition () { - let ast = AST::Variable { name: Identifier::from("x"), - value: Box::new(AST::Integer(1)) }; +#[test] +fn local_definition() { + let ast = AST::Variable { name: Identifier::from("x"), value: Box::new(AST::Integer(1)) }; let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -146,13 +145,13 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["x".to_owned()]); - let expected_code = Code::from(vec!( - OpCode::Literal { index: ConstantPoolIndex::new(0) }, // value - OpCode::SetLocal { index: LocalFrameIndex::new(0) } - )); + let expected_code = Code::from(vec![ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // value + OpCode::SetLocal { index: LocalFrameIndex::new(0) }, + ]); let expected_constants = >>::from(vec![ - /* 0 */ ProgramObject::Integer(1) + /* 0 */ ProgramObject::Integer(1), ]); let expected_globals = Globals::from(vec![]); @@ -166,9 +165,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn global_definition () { - let ast = AST::Variable { name: Identifier::from("x"), - value: Box::new(AST::Integer(1)) }; +#[test] +fn global_definition() { + let ast = AST::Variable { name: Identifier::from("x"), value: Box::new(AST::Integer(1)) }; let mut global_environment = Environment::new(); let mut current_frame = Frame::Top; @@ -178,15 +177,16 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::Top; - let expected_code = Code::from(vec!( - OpCode::Literal { index: ConstantPoolIndex::new(0) }, // value + let expected_code = Code::from(vec![ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // value OpCode::SetGlobal { name: ConstantPoolIndex::new(1) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_i32(1), /* 1 */ ProgramObject::from_str("x"), - /* 2 */ ProgramObject::Slot { name: ConstantPoolIndex::from_usize(1) }, + /* 2 */ + ProgramObject::Slot { name: ConstantPoolIndex::from_usize(1) }, ]); let expected_globals = Globals::from(vec![ConstantPoolIndex::from_usize(2)]); @@ -200,7 +200,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn local_access_x () { +#[test] +fn local_access_x() { let ast = AST::AccessVariable { name: Identifier::from("x") }; let mut global_environment = Environment::new(); @@ -211,9 +212,7 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["x".to_string(), "y".to_string()]); - let expected_code = Code::from(vec!( - OpCode::GetLocal { index: LocalFrameIndex::new(0) } - )); + let expected_code = Code::from(vec![OpCode::GetLocal { index: LocalFrameIndex::new(0) }]); let expected_constants = >>::from(vec![]); @@ -228,7 +227,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn local_access_y () { +#[test] +fn local_access_y() { let ast = AST::AccessVariable { name: Identifier::from("y") }; let mut global_environment = Environment::new(); @@ -239,9 +239,7 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["x".to_string(), "y".to_string()]); - let expected_code = Code::from(vec!( - OpCode::GetLocal { index: LocalFrameIndex::new(1) } - )); + let expected_code = Code::from(vec![OpCode::GetLocal { index: LocalFrameIndex::new(1) }]); let expected_constants = >>::from(vec![]); @@ -256,7 +254,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn global_access () { +#[test] +fn global_access() { let ast = AST::AccessVariable { name: Identifier::from("x") }; let mut global_environment = Environment::new(); @@ -267,13 +266,10 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - OpCode::GetGlobal { name: ConstantPoolIndex::new(0) } - )); + let expected_code = Code::from(vec![OpCode::GetGlobal { name: ConstantPoolIndex::new(0) }]); - let expected_constants = >>::from(vec![ - ProgramObject::from_str("x") - ]); + let expected_constants = + >>::from(vec![ProgramObject::from_str("x")]); let expected_globals = Globals::from(vec![]); let expected_entry = Entry::new(); @@ -286,7 +282,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn global_access_from_elsewhere () { +#[test] +fn global_access_from_elsewhere() { let ast = AST::AccessVariable { name: Identifier::from("z") }; let mut global_environment = Environment::from_locals(vec!["x".to_string()]); @@ -297,9 +294,7 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::from_locals(vec!["x".to_string()]); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - OpCode::GetGlobal { name: ConstantPoolIndex::new(0) } - )); + let expected_code = Code::from(vec![OpCode::GetGlobal { name: ConstantPoolIndex::new(0) }]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("z"), @@ -316,7 +311,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn loop_de_loop () { +#[test] +fn loop_de_loop() { let ast = AST::Loop { condition: Box::new(AST::Boolean(false)), body: Box::new(AST::Null) }; let mut global_environment = Environment::new(); @@ -327,7 +323,7 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::Jump { label: ConstantPoolIndex::new(1) }, /* 1 */ OpCode::Label { name: ConstantPoolIndex::new(0) }, /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, @@ -336,7 +332,7 @@ use crate::bytecode::compiler::*; /* 5 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, /* 6 */ OpCode::Branch { label: ConstantPoolIndex::new(0) }, /* 7 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("loop:body:0".to_string()), @@ -356,11 +352,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn conditional () { +#[test] +fn conditional() { let ast = AST::Conditional { condition: Box::new(AST::Boolean(true)), consequent: Box::new(AST::Integer(1)), - alternative: Box::new(AST::Integer(-1)) + alternative: Box::new(AST::Integer(-1)), }; let mut global_environment = Environment::new(); @@ -371,7 +368,7 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, /* 1 */ OpCode::Branch { label: ConstantPoolIndex::new(0) }, /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, @@ -379,7 +376,7 @@ use crate::bytecode::compiler::*; /* 4 */ OpCode::Label { name: ConstantPoolIndex::new(0) }, /* 5 */ OpCode::Literal { index: ConstantPoolIndex::new(4) }, /* 6 */ OpCode::Label { name: ConstantPoolIndex::new(1) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("if:consequent:0".to_string()), @@ -400,11 +397,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn array_definition_simple_test() { - let ast = AST::Array { - value: Box::new(AST::Null), - size: Box::new(AST::Integer(10)), - }; +#[test] +fn array_definition_simple_test() { + let ast = AST::Array { value: Box::new(AST::Null), size: Box::new(AST::Integer(10)) }; let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -414,11 +409,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, /* 2 */ OpCode::Array, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::Integer(10), @@ -436,13 +431,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn array_definition_complex_test() { // FIXME test is wrong +#[test] +fn array_definition_complex_test() { + // FIXME test is wrong let ast = AST::Array { size: Box::new(AST::Integer(10)), - value: Box::new(AST::CallFunction { - name: Identifier::from("f"), - arguments: vec!() - }), + value: Box::new(AST::CallFunction { name: Identifier::from("f"), arguments: vec![] }), }; let mut global_environment = Environment::new(); @@ -450,49 +444,44 @@ use crate::bytecode::compiler::*; let program = ast.compile(&mut global_environment, &mut current_frame).unwrap(); - let mut expected_global_environment = Environment::new(); + let mut expected_global_environment = Environment::new(); expected_global_environment.generate_unique_number(); let expected_current_frame = Frame::from_locals_at( - vec![ - "::size_0".to_string(), - "::array_0".to_string(), - "::i_0".to_string() - ], 0); - - let expected_code = Code::from(vec!( - OpCode::Literal { index: ConstantPoolIndex::new(0) }, // 10 - OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // size = 10 + vec!["::size_0".to_string(), "::array_0".to_string(), "::i_0".to_string()], + 0, + ); + + let expected_code = Code::from(vec![ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // 10 + OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // size = 10 OpCode::Drop, - OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // ?size = 10 - OpCode::Literal { index: ConstantPoolIndex::new(1) }, // null - OpCode::Array, // array(size = 10, null) - OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // arr = array(size = 10, null) + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // ?size = 10 + OpCode::Literal { index: ConstantPoolIndex::new(1) }, // null + OpCode::Array, // array(size = 10, null) + OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // arr = array(size = 10, null) OpCode::Drop, - - OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 - OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // i = 0 + OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 + OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // i = 0 OpCode::Drop, - OpCode::Jump { label: ConstantPoolIndex::new(4) }, // jump to loop_condition_0 - - OpCode::Label { name: ConstantPoolIndex::new(3) }, // label loop_body_0: - OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // arr - OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i - OpCode::CallFunction { name: ConstantPoolIndex::new(5),arguments: Arity::new(0)},// call f() -> result on stack - OpCode::CallMethod { name: ConstantPoolIndex::new(6), arguments: Arity::new(3) },// call arr.set(i, result of f()) + OpCode::Jump { label: ConstantPoolIndex::new(4) }, // jump to loop_condition_0 + OpCode::Label { name: ConstantPoolIndex::new(3) }, // label loop_body_0: + OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // arr + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i + OpCode::CallFunction { name: ConstantPoolIndex::new(5), arguments: Arity::new(0) }, // call f() -> result on stack + OpCode::CallMethod { name: ConstantPoolIndex::new(6), arguments: Arity::new(3) }, // call arr.set(i, result of f()) OpCode::Drop, - OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i - OpCode::Literal { index: ConstantPoolIndex::new(8) }, // 1 - OpCode::CallMethod { name: ConstantPoolIndex::new(7), arguments: Arity::new(2) },// i + 1 - OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // i = i + 1 + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i + OpCode::Literal { index: ConstantPoolIndex::new(8) }, // 1 + OpCode::CallMethod { name: ConstantPoolIndex::new(7), arguments: Arity::new(2) }, // i + 1 + OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // i = i + 1 OpCode::Drop, - - OpCode::Label { name: ConstantPoolIndex::new(4) }, // label loop_condition_0: - OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i - OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // size - OpCode::CallMethod { name: ConstantPoolIndex::new(9), arguments: Arity::new(2) },// i < size - OpCode::Branch { label: ConstantPoolIndex::new(3) }, // conditional jump to loop_body_0 - OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // arr - )); + OpCode::Label { name: ConstantPoolIndex::new(4) }, // label loop_condition_0: + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // i + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // size + OpCode::CallMethod { name: ConstantPoolIndex::new(9), arguments: Arity::new(2) }, // i < size + OpCode::Branch { label: ConstantPoolIndex::new(3) }, // conditional jump to loop_body_0 + OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // arr + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_i32(10), @@ -523,7 +512,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn array_access_test() { +#[test] +fn array_access_test() { let ast = AST::AccessArray { array: Box::new(AST::AccessVariable { name: Identifier("x".to_string()) }), index: Box::new(AST::Integer(1)), @@ -537,11 +527,12 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["x".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, - /* 2 */ OpCode::CallMethod { name: ConstantPoolIndex::new(1), arguments: Arity::new(2) }, - )); + /* 2 */ + OpCode::CallMethod { name: ConstantPoolIndex::new(1), arguments: Arity::new(2) }, + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::Integer(1), @@ -559,7 +550,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn array_mutation_test() { +#[test] +fn array_mutation_test() { let ast = AST::AssignArray { array: Box::new(AST::AccessVariable { name: Identifier("x".to_string()) }), index: Box::new(AST::Integer(1)), @@ -574,12 +566,13 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["x".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, - /* 3 */ OpCode::CallMethod { name: ConstantPoolIndex::new(2), arguments: Arity::new(3) }, - )); + /* 3 */ + OpCode::CallMethod { name: ConstantPoolIndex::new(2), arguments: Arity::new(3) }, + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::Integer(1), @@ -598,13 +591,11 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn print_test () { +#[test] +fn print_test() { let ast = AST::Print { format: "~ + ~".to_string(), - arguments: vec!( - Box::new(AST::Integer(2)), - Box::new(AST::Integer(5)), - ), + arguments: vec![AST::Integer(2), AST::Integer(5)], }; let mut global_environment = Environment::new(); @@ -615,11 +606,12 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, - /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, - /* 2 */ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, - )); + let expected_code = Code::from(vec![ + /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, + /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, + /* 2 */ + OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("~ + ~".to_string()), @@ -638,14 +630,11 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn function_application_test_three () { +#[test] +fn function_application_test_three() { let ast = AST::CallFunction { name: Identifier("f".to_string()), - arguments: vec!( - Box::new(AST::Null), - Box::new(AST::Integer(0)), - Box::new(AST::Boolean(true)), - ), + arguments: vec![AST::Null, AST::Integer(0), AST::Boolean(true)], }; let mut global_environment = Environment::new(); @@ -656,12 +645,13 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, - /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, - /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, - /* 3 */ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(3) }, - )); + let expected_code = Code::from(vec![ + /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, + /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, + /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, + /* 3 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(3) }, + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("f".to_string()), @@ -681,11 +671,10 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn function_application_test_one () { - let ast = AST::CallFunction { - name: Identifier("f".to_string()), - arguments: vec!(Box::new(AST::Integer(42))), - }; +#[test] +fn function_application_test_one() { + let ast = + AST::CallFunction { name: Identifier("f".to_string()), arguments: vec![AST::Integer(42)] }; let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -695,10 +684,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, - /* 1 */ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, - )); + let expected_code = Code::from(vec![ + /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, + /* 1 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("f".to_string()), @@ -716,11 +706,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn function_application_test_zero () { - let ast = AST::CallFunction { - name: Identifier("f".to_string()), - arguments: vec!() - }; +#[test] +fn function_application_test_zero() { + let ast = AST::CallFunction { name: Identifier("f".to_string()), arguments: vec![] }; let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -730,13 +718,15 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( - /* 0 */ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, - )); + let expected_code = Code::from(vec![/* 0 */ OpCode::CallFunction { + name: ConstantPoolIndex::new(0), + arguments: Arity::new(0), + }]); - let expected_constants = >>::from(vec![ - /* 0 */ ProgramObject::String("f".to_string()), - ]); + let expected_constants = + >>::from(vec![/* 0 */ ProgramObject::String( + "f".to_string(), + )]); let expected_globals = Globals::from(vec![]); let expected_entry = Entry::new(); @@ -749,13 +739,16 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn function_definition_three () { +#[test] +fn function_definition_three() { let ast = AST::Function { name: Identifier("project_right".to_string()), - parameters: vec!(Identifier::from("left"), - Identifier::from("middle"), - Identifier::from("right")), - body: Box::new(AST::AccessVariable { name: Identifier::from("left") }) + parameters: vec![ + Identifier::from("left"), + Identifier::from("middle"), + Identifier::from("right"), + ], + body: Box::new(AST::AccessVariable { name: Identifier::from("left") }), }; let mut global_environment = Environment::new(); @@ -766,14 +759,15 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, /* 1 */ OpCode::Return, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::String("project_right".to_string()), - /* 1 */ ProgramObject::Method { + /* 1 */ + ProgramObject::Method { name: ConstantPoolIndex::new(0), parameters: Arity::new(3), locals: Size::new(0), @@ -794,53 +788,49 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn object_with_methods_and_fields () { +#[test] +fn object_with_methods_and_fields() { let ast = AST::Object { extends: Box::new(AST::Boolean(true)), - members: vec!( - Box::new(AST::Function { + members: vec![ + AST::Function { name: Identifier::from("implies"), - parameters: vec!(Identifier::from("x")), - body: Box::new(AST::Boolean(true))}), - - Box::new(AST::Variable { - name: Identifier::from("id"), - value: Box::new(AST::Integer(1))}), - - Box::new(AST::Function { + parameters: vec![Identifier::from("x")], + body: Box::new(AST::Boolean(true)), + }, + AST::Variable { name: Identifier::from("id"), value: Box::new(AST::Integer(1)) }, + AST::Function { name: Identifier::from("identity"), - parameters: vec!(), - body: Box::new(AST::Boolean(true))}), - - Box::new(AST::Function { + parameters: vec![], + body: Box::new(AST::Boolean(true)), + }, + AST::Function { name: Identifier::from("or"), - parameters: vec!(Identifier::from("x")), - body: Box::new(AST::Boolean(true))}), - - Box::new(AST::Function { + parameters: vec![Identifier::from("x")], + body: Box::new(AST::Boolean(true)), + }, + AST::Function { name: Identifier::from("and"), - parameters: vec!(Identifier::from("x")), - body: Box::new(AST::AccessVariable { name: Identifier::from("x") })}), - - Box::new(AST::Variable { - name: Identifier::from("hash"), - value: Box::new(AST::Integer(1))}), - - Box::new(AST::Function { + parameters: vec![Identifier::from("x")], + body: Box::new(AST::AccessVariable { name: Identifier::from("x") }), + }, + AST::Variable { name: Identifier::from("hash"), value: Box::new(AST::Integer(1)) }, + AST::Function { name: Identifier::from(Operator::Addition), - parameters: vec!(Identifier::from("x")), - body: Box::new(AST::Boolean(true))}), - - Box::new(AST::Function { + parameters: vec![Identifier::from("x")], + body: Box::new(AST::Boolean(true)), + }, + AST::Function { name: Identifier::from(Operator::Multiplication), - parameters: vec!(Identifier::from("x")), - body: Box::new(AST::AccessVariable { name: Identifier::from("x") })}), - - Box::new(AST::Function { + parameters: vec![Identifier::from("x")], + body: Box::new(AST::AccessVariable { name: Identifier::from("x") }), + }, + AST::Function { name: Identifier::from("me"), - parameters: vec!(), - body: Box::new(AST::AccessVariable { name: Identifier::from("this") })}), - ) + parameters: vec![], + body: Box::new(AST::AccessVariable { name: Identifier::from("this") }), + }, + ], }; let mut global_environment = Environment::new(); @@ -851,109 +841,109 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::new(); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* implies (method) */ - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true + /* 0 */ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true /* 1 */ OpCode::Return, - /* identity (method) */ - /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true + /* 2 */ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true /* 3 */ OpCode::Return, - /* or (method) */ - /* 4 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true + /* 4 */ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true /* 5 */ OpCode::Return, - /* and (method) */ - /* 6 */ OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // x + /* 6 */ + OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // x /* 7 */ OpCode::Return, - /* + (method) */ - /* 8 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true + /* 8 */ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true /* 9 */ OpCode::Return, - /* * (method) */ - /* 10 */ OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // x + /* 10 */ + OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // x /* 11 */ OpCode::Return, - /* + (me) */ - /* 12 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // this + /* 12 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // this /* 13 */ OpCode::Return, - /* object parent, fields: id, hash */ - /* 14 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true - /* 15 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, // 1 - /* 16 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, // 1 - - /* 17 */ OpCode::Object { class: ConstantPoolIndex:: new(20) }, - )); + /* 14 */ + OpCode::Literal { index: ConstantPoolIndex::new(0) }, // true + /* 15 */ + OpCode::Literal { index: ConstantPoolIndex::new(3) }, // 1 + /* 16 */ + OpCode::Literal { index: ConstantPoolIndex::new(3) }, // 1 + /* 17 */ OpCode::Object { class: ConstantPoolIndex::new(20) }, + ]); let expected_constants = >>::from(vec![ /* 00 */ ProgramObject::from_bool(true), /* 01 */ ProgramObject::from_str("implies"), - /* 02 */ ProgramObject::Method { - name: ConstantPoolIndex::new(1), // "implies" - parameters: Arity::new(1+1), + /* 02 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(1), // "implies" + parameters: Arity::new(1 + 1), locals: Size::new(0), - code: AddressRange::from(0, 2), // opcodes: 0, 1 + code: AddressRange::from(0, 2), // opcodes: 0, 1 }, - /* 03 */ ProgramObject::from_i32(1), /* 04 */ ProgramObject::from_str("id"), /* 05 */ ProgramObject::slot_from_u16(4), // "id" - /* 06 */ ProgramObject::from_str("identity"), - /* 07 */ ProgramObject::Method { - name: ConstantPoolIndex::new(6), // identity - parameters: Arity::new(0+1), + /* 07 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(6), // identity + parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(2, 2), // addresses: 2, 3 + code: AddressRange::from(2, 2), // addresses: 2, 3 }, - /* 08 */ ProgramObject::from_str("or"), - /* 09 */ ProgramObject::Method { - name: ConstantPoolIndex::new(8), // or - parameters: Arity::new(1+1), + /* 09 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(8), // or + parameters: Arity::new(1 + 1), locals: Size::new(0), - code: AddressRange::from(4, 2), // addresses: 5, 6 + code: AddressRange::from(4, 2), // addresses: 5, 6 }, - /* 10 */ ProgramObject::from_str("and"), - /* 11 */ ProgramObject::Method { - name: ConstantPoolIndex::new(10), // and - parameters: Arity::new(1+1), + /* 11 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(10), // and + parameters: Arity::new(1 + 1), locals: Size::new(0), - code: AddressRange::from(6, 2), // addresses: 7, 8 + code: AddressRange::from(6, 2), // addresses: 7, 8 }, - /* 12 */ ProgramObject::from_str("hash"), /* 13 */ ProgramObject::slot_from_u16(12), - /* 14 */ ProgramObject::from_str("+"), - /* 15 */ ProgramObject::Method { - name: ConstantPoolIndex::new(14), // + - parameters: Arity::new(1+1), + /* 15 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(14), // + + parameters: Arity::new(1 + 1), locals: Size::new(0), - code: AddressRange::from(8, 2), // addresses: 7, 8 + code: AddressRange::from(8, 2), // addresses: 7, 8 }, - /* 16 */ ProgramObject::from_str("*"), - /* 17 */ ProgramObject::Method { - name: ConstantPoolIndex::new(16), // * - parameters: Arity::new(1+1), + /* 17 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(16), // * + parameters: Arity::new(1 + 1), locals: Size::new(0), - code: AddressRange::from(10, 2), // addresses: 9, 10 + code: AddressRange::from(10, 2), // addresses: 9, 10 }, - /* 18 */ ProgramObject::from_str("me"), - /* 19 */ ProgramObject::Method { - name: ConstantPoolIndex::new(18), // * + /* 19 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(18), // * parameters: Arity::new(1), locals: Size::new(0), code: AddressRange::from(12, 2), }, - - /* 20 */ ProgramObject::class_from_vec(vec!(2, 5, 7, 9, 11, 13, 15, 17, 19)), + /* 20 */ ProgramObject::class_from_vec(vec![2, 5, 7, 9, 11, 13, 15, 17, 19]), ]); let expected_globals = Globals::from(vec![]); @@ -969,14 +959,16 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn block_many () { - let ast = AST::Block(vec!( - Box::new(AST::Null), - Box::new(AST::Integer(1)), - Box::new(AST::Integer(42)), - Box::new(AST::Integer(0)), - Box::new(AST::Boolean(true)), - Box::new(AST::Integer(42)))); +#[test] +fn block_many() { + let ast = AST::Block(vec![ + AST::Null, + AST::Integer(1), + AST::Integer(42), + AST::Integer(0), + AST::Boolean(true), + AST::Integer(42), + ]); let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -993,7 +985,7 @@ use crate::bytecode::compiler::*; } } - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, /* 1 */ OpCode::Drop, /* 2 */ OpCode::Literal { index: ConstantPoolIndex::new(1) }, @@ -1005,7 +997,7 @@ use crate::bytecode::compiler::*; /* 8 */ OpCode::Literal { index: ConstantPoolIndex::new(4) }, /* 9 */ OpCode::Drop, /* 10 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::Null, @@ -1026,8 +1018,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn block_one () { - let ast = AST::Block(vec!(Box::new(AST::Null))); +#[test] +fn block_one() { + let ast = AST::Block(vec![AST::Null]); let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -1044,13 +1037,11 @@ use crate::bytecode::compiler::*; } } - let expected_code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, - )); + let expected_code = + Code::from(vec![/* 0 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }]); - let expected_constants = >>::from(vec![ - /* 0 */ ProgramObject::Null, - ]); + let expected_constants = + >>::from(vec![/* 0 */ ProgramObject::Null]); let expected_globals = Globals::from(vec![]); let expected_entry = Entry::new(); @@ -1063,8 +1054,9 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn block_zero () { - let ast = AST::Block(vec!()); +#[test] +fn block_zero() { + let ast = AST::Block(vec![]); let mut global_environment = Environment::new(); let mut current_frame = Frame::new(); @@ -1081,7 +1073,7 @@ use crate::bytecode::compiler::*; } } - let expected_code = Code::from(vec!()); + let expected_code = Code::from(vec![]); let expected_constants = >>::from(vec![]); @@ -1096,7 +1088,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn field_access_test () { +#[test] +fn field_access_test() { let ast = AST::AccessField { object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }), field: Identifier::from("x"), @@ -1110,10 +1103,10 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["obj".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, /* 1 */ OpCode::GetField { name: ConstantPoolIndex::new(0) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("x"), @@ -1130,7 +1123,8 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn field_mutation_test () { +#[test] +fn field_mutation_test() { let ast = AST::AssignField { object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }), field: Identifier::from("x"), @@ -1145,11 +1139,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["obj".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, /* 1 */ OpCode::Literal { index: ConstantPoolIndex::new(0) }, /* 2 */ OpCode::SetField { name: ConstantPoolIndex::new(1) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_i32(42), @@ -1167,13 +1161,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn method_call_test_three () { +#[test] +fn method_call_test_three() { let ast = AST::CallMethod { name: Identifier::from("f"), - arguments: vec!(Box::new(AST::Integer(1)), - Box::new(AST::Integer(2)), - Box::new(AST::Integer(3))), - object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }) + arguments: vec![AST::Integer(1), AST::Integer(2), AST::Integer(3)], + object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }), }; let mut global_environment = Environment::new(); @@ -1184,15 +1177,13 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["obj".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, - OpCode::Literal { index: ConstantPoolIndex::new(1) }, OpCode::Literal { index: ConstantPoolIndex::new(2) }, OpCode::Literal { index: ConstantPoolIndex::new(3) }, - OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(4) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("f"), @@ -1212,11 +1203,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn method_call_test_one () { +#[test] +fn method_call_test_one() { let ast = AST::CallMethod { name: Identifier::from("f"), - arguments: vec!(Box::new(AST::Integer(42))), - object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }) + arguments: vec![AST::Integer(42)], + object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }), }; let mut global_environment = Environment::new(); @@ -1227,11 +1219,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["obj".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, OpCode::Literal { index: ConstantPoolIndex::new(1) }, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("f"), @@ -1249,11 +1241,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn method_call_test_zero () { +#[test] +fn method_call_test_zero() { let ast = AST::CallMethod { name: Identifier::from("f"), - arguments: vec!(), - object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }) + arguments: vec![], + object: Box::new(AST::AccessVariable { name: Identifier::from("obj") }), }; let mut global_environment = Environment::new(); @@ -1264,10 +1257,10 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec!["obj".to_string()]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("f"), @@ -1284,10 +1277,11 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn operator_call_test () { +#[test] +fn operator_call_test() { let ast = AST::CallMethod { name: Identifier::from(Operator::Subtraction), - arguments: vec!(Box::new(AST::Integer(1))), + arguments: vec![AST::Integer(1)], object: Box::new(AST::Integer(7)), }; @@ -1299,11 +1293,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec![]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ OpCode::Literal { index: ConstantPoolIndex::new(1) }, OpCode::Literal { index: ConstantPoolIndex::new(2) }, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("-"), @@ -1322,11 +1316,12 @@ use crate::bytecode::compiler::*; assert_eq!(current_frame, expected_current_frame); } -#[test] fn operation_test () { +#[test] +fn operation_test() { let ast = AST::CallMethod { name: Identifier::from(Operator::Subtraction), object: Box::new(AST::Integer(1)), - arguments: vec![Box::new(AST::Integer(7))], + arguments: vec![AST::Integer(7)], }; let mut global_environment = Environment::new(); @@ -1337,11 +1332,11 @@ use crate::bytecode::compiler::*; let expected_global_environment = Environment::new(); let expected_current_frame = Frame::from_locals(vec![]); - let expected_code = Code::from(vec!( + let expected_code = Code::from(vec![ OpCode::Literal { index: ConstantPoolIndex::new(1) }, OpCode::Literal { index: ConstantPoolIndex::new(2) }, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, - )); + ]); let expected_constants = >>::from(vec![ /* 0 */ ProgramObject::from_str("-"), @@ -1358,4 +1353,4 @@ use crate::bytecode::compiler::*; assert_eq!(program, expected_program); assert_eq!(global_environment, expected_global_environment); assert_eq!(current_frame, expected_current_frame); -} \ No newline at end of file +} diff --git a/src/tests/feeny.rs b/src/tests/feeny.rs index e52726a..eb2c738 100644 --- a/src/tests/feeny.rs +++ b/src/tests/feeny.rs @@ -1,10 +1,10 @@ use std::io::Cursor; use crate::bytecode::bytecode::*; -use crate::bytecode::program::*; +use crate::bytecode::debug::*; use crate::bytecode::interpreter::*; +use crate::bytecode::program::*; use crate::bytecode::serializable::*; -use crate::bytecode::debug::*; use crate::bytecode::state::*; /* @@ -14,10 +14,10 @@ use crate::bytecode::state::*; * printf("~", a) * printf("~", b) * printf("~", c) - * + * * x.m(1, 2, 3) - * - * main() + * + * main() */ fn feeny_method_argument_order_source() -> &'static str { r#"Constants : @@ -58,62 +58,85 @@ fn feeny_method_argument_order_source() -> &'static str { return Globals : #9 -Entry : #11"#} +Entry : #11"# +} fn feeny_method_argument_order_program() -> Program { - let code = Code::from(vec!( - /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(1) }, - /* 1 */ OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, + let code = Code::from(vec![ + /* 0 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(1) }, + /* 1 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, /* 2 */ OpCode::Drop, - /* 3 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(2) }, - /* 4 */ OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, + /* 3 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(2) }, + /* 4 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, /* 5 */ OpCode::Drop, - /* 6 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(3) }, - /* 7 */ OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, + /* 6 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(3) }, + /* 7 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(1), arguments: Arity::from_usize(1) }, /* 8 */ OpCode::Return, - /* 9 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, - /* 10 */ OpCode::Object { class: ConstantPoolIndex::from_usize(4) }, - /* 11 */ OpCode::SetLocal { index: LocalFrameIndex::from_usize(0) }, + /* 9 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, + /* 10 */ + OpCode::Object { class: ConstantPoolIndex::from_usize(4) }, + /* 11 */ + OpCode::SetLocal { index: LocalFrameIndex::from_usize(0) }, /* 12 */ OpCode::Drop, - /* 13 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, - /* 14 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(5) }, - /* 15 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(6) }, - /* 16 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(7) }, - /* 17 */ OpCode::CallMethod { name: ConstantPoolIndex::from_usize(2), arguments: Arity::from_usize(4) }, + /* 13 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, + /* 14 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(5) }, + /* 15 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(6) }, + /* 16 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(7) }, + /* 17 */ + OpCode::CallMethod { + name: ConstantPoolIndex::from_usize(2), + arguments: Arity::from_usize(4), + }, /* 18 */ OpCode::Return, - /* 19 */ OpCode::CallFunction { name: ConstantPoolIndex::new(8), arguments: Arity::new(0) }, + /* 19 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(8), arguments: Arity::new(0) }, /* 20 */ OpCode::Drop, - /* 21 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, + /* 21 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, /* 22 */ OpCode::Return, - )); + ]); let constant_pool = ConstantPool::from(vec![ /* 0 */ ProgramObject::Null, /* 1 */ ProgramObject::from_str("~"), /* 2 */ ProgramObject::from_str("m"), - /* 3 */ ProgramObject::Method { + /* 3 */ + ProgramObject::Method { name: ConstantPoolIndex::from_usize(2), parameters: Arity::from_usize(4), locals: Size::from_usize(0), - code: AddressRange:: from(0, 9), + code: AddressRange::from(0, 9), }, /* 4 */ ProgramObject::Class(vec![ConstantPoolIndex::from_usize(3)]), /* 5 */ ProgramObject::from_i32(1), /* 6 */ ProgramObject::from_i32(2), /* 7 */ ProgramObject::from_i32(3), /* 8 */ ProgramObject::from_str("main"), - /* 9 */ ProgramObject::Method { + /* 9 */ + ProgramObject::Method { name: ConstantPoolIndex::from_usize(8), parameters: Arity::from_usize(0), locals: Size::from_usize(1), - code: AddressRange:: from(9, 10), + code: AddressRange::from(9, 10), }, /* 10 */ ProgramObject::from_str("entry38"), - /* 11 */ ProgramObject::Method { + /* 11 */ + ProgramObject::Method { name: ConstantPoolIndex::from_usize(10), parameters: Arity::from_usize(0), locals: Size::from_usize(0), - code: AddressRange:: from(19, 4), + code: AddressRange::from(19, 4), }, ]); @@ -123,47 +146,43 @@ fn feeny_method_argument_order_program() -> Program { } fn feeny_method_argument_order_bytes() -> Vec { - vec!( - 0x0C, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, - 0x7E, 0x02, 0x01, 0x00, 0x00, 0x00, 0x6D, 0x03, - 0x02, 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, - 0x00, 0x0A, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, - 0x10, 0x0A, 0x02, 0x00, 0x02, 0x01, 0x00, 0x01, - 0x10, 0x0A, 0x03, 0x00, 0x02, 0x01, 0x00, 0x01, - 0x0F, 0x05, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, - 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x08, - 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x09, 0x00, - 0x00, 0x10, 0x0A, 0x00, 0x00, 0x01, 0x05, 0x00, - 0x01, 0x06, 0x00, 0x01, 0x07, 0x00, 0x07, 0x02, - 0x00, 0x04, 0x0F, 0x02, 0x07, 0x00, 0x00, 0x00, - 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x38, 0x03, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, - 0x00, 0x0F, 0x01, 0x00, 0x09, 0x00, 0x0B, 0x00, - ) + vec![ + 0x0C, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x7E, 0x02, 0x01, 0x00, 0x00, 0x00, 0x6D, + 0x03, 0x02, 0x00, 0x04, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x00, 0x02, 0x01, + 0x00, 0x01, 0x10, 0x0A, 0x02, 0x00, 0x02, 0x01, 0x00, 0x01, 0x10, 0x0A, 0x03, 0x00, 0x02, + 0x01, 0x00, 0x01, 0x0F, 0x05, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, + 0x61, 0x69, 0x6E, 0x03, 0x08, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x04, 0x04, 0x00, 0x09, 0x00, 0x00, 0x10, 0x0A, 0x00, 0x00, 0x01, 0x05, 0x00, 0x01, + 0x06, 0x00, 0x01, 0x07, 0x00, 0x07, 0x02, 0x00, 0x04, 0x0F, 0x02, 0x07, 0x00, 0x00, 0x00, + 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x38, 0x03, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x09, 0x00, + 0x0B, 0x00, + ] } -#[test] fn feeny_method_argument_order_deserialize() { +#[test] +fn feeny_method_argument_order_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_method_argument_order_bytes())); assert_eq!(feeny_method_argument_order_program(), object); } -#[test] fn feeny_method_argument_order_serialize() { +#[test] +fn feeny_method_argument_order_serialize() { let mut output: Vec = Vec::new(); feeny_method_argument_order_program().serialize(&mut output).unwrap(); assert_eq!(feeny_method_argument_order_bytes(), output); } -#[test] fn feeny_method_argument_order_print() { +#[test] +fn feeny_method_argument_order_print() { let mut bytes: Vec = Vec::new(); feeny_method_argument_order_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_method_argument_order_source()); } -#[test] fn feeny_method_argument_order_eval() { +#[test] +fn feeny_method_argument_order_eval() { let program = feeny_method_argument_order_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); @@ -236,21 +255,31 @@ fn feeny_object_member_order_source() -> &'static str { return Globals : #15 -Entry : #17"#} +Entry : #17"# +} fn feeny_object_member_order_program() -> Program { - let code = Code::from(vec!( + let code = Code::from(vec![ OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, OpCode::GetField { name: ConstantPoolIndex::from_usize(4) }, - OpCode::Print { format: ConstantPoolIndex::from_usize(10), arguments: Arity::from_usize(1) }, + OpCode::Print { + format: ConstantPoolIndex::from_usize(10), + arguments: Arity::from_usize(1), + }, OpCode::Drop, OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, OpCode::GetField { name: ConstantPoolIndex::from_usize(6) }, - OpCode::Print { format: ConstantPoolIndex::from_usize(10), arguments: Arity::from_usize(1) }, + OpCode::Print { + format: ConstantPoolIndex::from_usize(10), + arguments: Arity::from_usize(1), + }, OpCode::Drop, OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, OpCode::GetField { name: ConstantPoolIndex::from_usize(8) }, - OpCode::Print { format: ConstantPoolIndex::from_usize(10), arguments: Arity::from_usize(1) }, + OpCode::Print { + format: ConstantPoolIndex::from_usize(10), + arguments: Arity::from_usize(1), + }, OpCode::Return, OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, OpCode::Literal { index: ConstantPoolIndex::from_usize(1) }, @@ -260,13 +289,19 @@ fn feeny_object_member_order_program() -> Program { OpCode::SetLocal { index: LocalFrameIndex::from_usize(0) }, OpCode::Drop, OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, - OpCode::CallMethod { name: ConstantPoolIndex::from_usize(11), arguments: Arity::from_usize(1) }, + OpCode::CallMethod { + name: ConstantPoolIndex::from_usize(11), + arguments: Arity::from_usize(1), + }, OpCode::Return, - OpCode::CallFunction { name: ConstantPoolIndex::from_usize(14), arguments: Arity::from_usize(0) }, + OpCode::CallFunction { + name: ConstantPoolIndex::from_usize(14), + arguments: Arity::from_usize(0), + }, OpCode::Drop, OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, - OpCode::Return - )); + OpCode::Return, + ]); let constant_pool = ConstantPool::from(vec![ ProgramObject::Null, @@ -285,25 +320,27 @@ fn feeny_object_member_order_program() -> Program { name: ConstantPoolIndex::from_usize(11), parameters: Arity::from_usize(1), locals: Size::from_usize(0), - code: AddressRange:: from(0, 12), + code: AddressRange::from(0, 12), }, - ProgramObject::Class(vec![ConstantPoolIndex::from_usize(5), - ConstantPoolIndex::from_usize(7), - ConstantPoolIndex::from_usize(9), - ConstantPoolIndex::from_usize(12)]), + ProgramObject::Class(vec![ + ConstantPoolIndex::from_usize(5), + ConstantPoolIndex::from_usize(7), + ConstantPoolIndex::from_usize(9), + ConstantPoolIndex::from_usize(12), + ]), ProgramObject::from_str("main"), ProgramObject::Method { name: ConstantPoolIndex::from_usize(14), parameters: Arity::from_usize(0), locals: Size::from_usize(1), - code: AddressRange:: from(12, 10), + code: AddressRange::from(12, 10), }, ProgramObject::from_str("entry38"), ProgramObject::Method { name: ConstantPoolIndex::from_usize(16), parameters: Arity::from_usize(0), locals: Size::from_usize(0), - code: AddressRange:: from(22, 4), + code: AddressRange::from(22, 4), }, ]); @@ -313,53 +350,45 @@ fn feeny_object_member_order_program() -> Program { } fn feeny_object_member_order_bytes() -> Vec { - vec!( - 0x12, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x61, - 0x04, 0x04, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, - 0x62, 0x04, 0x06, 0x00, 0x02, 0x01, 0x00, 0x00, - 0x00, 0x63, 0x04, 0x08, 0x00, 0x02, 0x01, 0x00, - 0x00, 0x00, 0x7E, 0x02, 0x01, 0x00, 0x00, 0x00, - 0x6D, 0x03, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x0C, - 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x04, - 0x00, 0x02, 0x0A, 0x00, 0x01, 0x10, 0x0A, 0x00, - 0x00, 0x05, 0x06, 0x00, 0x02, 0x0A, 0x00, 0x01, - 0x10, 0x0A, 0x00, 0x00, 0x05, 0x08, 0x00, 0x02, - 0x0A, 0x00, 0x01, 0x0F, 0x05, 0x04, 0x00, 0x05, - 0x00, 0x07, 0x00, 0x09, 0x00, 0x0C, 0x00, 0x02, - 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, - 0x03, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x02, 0x00, 0x01, 0x03, 0x00, 0x04, 0x0D, - 0x00, 0x09, 0x00, 0x00, 0x10, 0x0A, 0x00, 0x00, - 0x07, 0x0B, 0x00, 0x01, 0x0F, 0x02, 0x07, 0x00, - 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, - 0x38, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x08, 0x0E, 0x00, 0x00, 0x10, - 0x01, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x0F, 0x00, - 0x11, 0x00, - ) + vec![ + 0x12, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x61, 0x04, 0x04, 0x00, 0x02, 0x01, 0x00, + 0x00, 0x00, 0x62, 0x04, 0x06, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x63, 0x04, 0x08, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x00, 0x7E, 0x02, 0x01, 0x00, 0x00, 0x00, 0x6D, 0x03, 0x0B, 0x00, + 0x01, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x04, 0x00, 0x02, 0x0A, + 0x00, 0x01, 0x10, 0x0A, 0x00, 0x00, 0x05, 0x06, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x10, 0x0A, + 0x00, 0x00, 0x05, 0x08, 0x00, 0x02, 0x0A, 0x00, 0x01, 0x0F, 0x05, 0x04, 0x00, 0x05, 0x00, + 0x07, 0x00, 0x09, 0x00, 0x0C, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x03, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x01, 0x03, 0x00, 0x04, 0x0D, 0x00, 0x09, 0x00, 0x00, 0x10, 0x0A, + 0x00, 0x00, 0x07, 0x0B, 0x00, 0x01, 0x0F, 0x02, 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, + 0x72, 0x79, 0x33, 0x38, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, + 0x0E, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0F, 0x01, 0x00, 0x0F, 0x00, 0x11, 0x00, + ] } -#[test] fn feeny_object_member_order_deserialize() { +#[test] +fn feeny_object_member_order_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_object_member_order_bytes())); assert_eq!(feeny_object_member_order_program(), object); } -#[test] fn feeny_object_member_order_serialize() { +#[test] +fn feeny_object_member_order_serialize() { let mut output: Vec = Vec::new(); feeny_object_member_order_program().serialize(&mut output).unwrap(); assert_eq!(feeny_object_member_order_bytes(), output); } -#[test] fn feeny_object_member_order_print() { +#[test] +fn feeny_object_member_order_print() { let mut bytes: Vec = Vec::new(); feeny_object_member_order_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_object_member_order_source()); } -#[test] fn feeny_object_member_order_eval() { +#[test] +fn feeny_object_member_order_eval() { let program = feeny_object_member_order_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); @@ -397,20 +426,27 @@ fn feeny_print_argument_order_source() -> &'static str { return Globals : #5 -Entry : #8"#} +Entry : #8"# +} fn feeny_print_argument_order_program() -> Program { - let code = Code::from(vec!( - /* 0 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, - /* 1 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(1) }, - /* 2 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(2) }, - /* 3 */ OpCode::Print { format: ConstantPoolIndex::new(3), arguments: Arity::new(3) }, + let code = Code::from(vec![ + /* 0 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(0) }, + /* 1 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(1) }, + /* 2 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(2) }, + /* 3 */ + OpCode::Print { format: ConstantPoolIndex::new(3), arguments: Arity::new(3) }, /* 4 */ OpCode::Return, - /* 5 */ OpCode::CallFunction { name: ConstantPoolIndex::new(4), arguments: Arity::new(0) }, + /* 5 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(4), arguments: Arity::new(0) }, /* 6 */ OpCode::Drop, - /* 7 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(6) }, + /* 7 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(6) }, /* 8 */ OpCode::Return, - )); + ]); let constant_pool = ConstantPool::from(vec![ /* 0 */ ProgramObject::from_i32(1), @@ -418,7 +454,8 @@ fn feeny_print_argument_order_program() -> Program { /* 2 */ ProgramObject::from_i32(3), /* 3 */ ProgramObject::from_str("~~~"), /* 4 */ ProgramObject::from_str("main"), - /* 5 */ ProgramObject::Method { + /* 5 */ + ProgramObject::Method { name: ConstantPoolIndex::new(4), parameters: Arity::new(0), locals: Size::new(0), @@ -426,7 +463,8 @@ fn feeny_print_argument_order_program() -> Program { }, /* 6 */ ProgramObject::Null, /* 7 */ ProgramObject::from_str("entry35"), - /* 8 */ ProgramObject::Method { + /* 8 */ + ProgramObject::Method { name: ConstantPoolIndex::new(7), parameters: Arity::new(0), locals: Size::new(0), @@ -440,36 +478,39 @@ fn feeny_print_argument_order_program() -> Program { } fn feeny_print_argument_order_bytes() -> Vec { - vec!( - 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x7E, 0x7E, - 0x7E, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, - 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x03, 0x00, 0x03, 0x0F, 0x01, 0x02, - 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x35, 0x03, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, - 0x00, 0x10, 0x01, 0x06, 0x00, 0x0F, 0x01, 0x00, 0x05, 0x00, 0x08, 0x00, - ) + vec![ + 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x02, 0x04, 0x00, 0x00, 0x00, + 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x03, 0x00, 0x03, 0x0F, 0x01, 0x02, + 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x35, 0x03, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x01, 0x06, 0x00, 0x0F, + 0x01, 0x00, 0x05, 0x00, 0x08, 0x00, + ] } -#[test] fn feeny_print_argument_order_deserialize() { +#[test] +fn feeny_print_argument_order_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_print_argument_order_bytes())); assert_eq!(feeny_print_argument_order_program(), object); } -#[test] fn feeny_print_argument_order_serialize() { +#[test] +fn feeny_print_argument_order_serialize() { let mut output: Vec = Vec::new(); feeny_print_argument_order_program().serialize(&mut output).unwrap(); assert_eq!(feeny_print_argument_order_bytes(), output); } -#[test] fn feeny_print_argument_order_print() { +#[test] +fn feeny_print_argument_order_print() { let mut bytes: Vec = Vec::new(); feeny_print_argument_order_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_print_argument_order_source()); } -#[test] fn feeny_print_argument_order_eval() { +#[test] +fn feeny_print_argument_order_eval() { let program = feeny_print_argument_order_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); @@ -524,57 +565,73 @@ fn feeny_function_argument_order_source() -> &'static str { Globals : #2 #7 -Entry : #10"#} +Entry : #10"# +} fn feeny_function_argument_order_program() -> Program { - let code = Code::from(vec!( - /* 0 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, - /* 1 */ OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, + let code = Code::from(vec![ + /* 0 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(0) }, + /* 1 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, /* 2 */ OpCode::Drop, - /* 3 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(1) }, - /* 4 */ OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, + /* 3 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(1) }, + /* 4 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, /* 5 */ OpCode::Drop, - /* 6 */ OpCode::GetLocal { index: LocalFrameIndex::from_usize(2) }, - /* 7 */ OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, + /* 6 */ + OpCode::GetLocal { index: LocalFrameIndex::from_usize(2) }, + /* 7 */ + OpCode::Print { format: ConstantPoolIndex::from_usize(0), arguments: Arity::from_usize(1) }, /* 8 */ OpCode::Return, - /* 9 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(3) }, - /* 10 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(4) }, - /* 11 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(5) }, - /* 12 */ OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(3) }, + /* 9 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(3) }, + /* 10 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(4) }, + /* 11 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(5) }, + /* 12 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(3) }, /* 13 */ OpCode::Return, - /* 14 */ OpCode::CallFunction { name: ConstantPoolIndex::new(6), arguments: Arity::new(0) }, + /* 14 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(6), arguments: Arity::new(0) }, /* 15 */ OpCode::Drop, - /* 16 */ OpCode::Literal { index: ConstantPoolIndex::from_usize(8) }, + /* 16 */ + OpCode::Literal { index: ConstantPoolIndex::from_usize(8) }, /* 17 */ OpCode::Return, - )); + ]); let constant_pool = ConstantPool::from(vec![ /* 0 */ ProgramObject::from_str("~"), /* 1 */ ProgramObject::from_str("f"), - /* 2 */ ProgramObject::Method { - name: ConstantPoolIndex::new(1), - parameters: Arity::new(3), - locals: Size::new(0), - code: AddressRange::from(0, 9), - }, + /* 2 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(1), + parameters: Arity::new(3), + locals: Size::new(0), + code: AddressRange::from(0, 9), + }, /* 3 */ ProgramObject::from_i32(1), /* 4 */ ProgramObject::from_i32(2), /* 5 */ ProgramObject::from_i32(3), /* 6 */ ProgramObject::from_str("main"), - /* 7 */ ProgramObject::Method { - name: ConstantPoolIndex::new(6), - parameters: Arity::new(0), - locals: Size::new(0), - code: AddressRange::from(9, 5), - }, + /* 7 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(6), + parameters: Arity::new(0), + locals: Size::new(0), + code: AddressRange::from(9, 5), + }, /* 8 */ ProgramObject::Null, /* 9 */ ProgramObject::from_str("entry36"), - /* 10 */ ProgramObject::Method { - name: ConstantPoolIndex::new(9), - parameters: Arity::new(0), - locals: Size::new(0), - code: AddressRange::from(14, 4), - }, + /* 10 */ + ProgramObject::Method { + name: ConstantPoolIndex::new(9), + parameters: Arity::new(0), + locals: Size::new(0), + code: AddressRange::from(14, 4), + }, ]); let globals = Globals::from(vec![ConstantPoolIndex::new(2), ConstantPoolIndex::new(7)]); @@ -583,40 +640,42 @@ fn feeny_function_argument_order_program() -> Program { } fn feeny_function_argument_order_bytes() -> Vec { - vec!( - 0x0B, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x7E, 0x02, 0x01, 0x00, 0x00, - 0x00, 0x66, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x10, 0x0A, 0x01, 0x00, 0x02, - 0x00, 0x00, 0x01, 0x10, 0x0A, 0x02, 0x00, 0x02, 0x00, 0x00, 0x01, 0x0F, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, - 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x00, 0x01, 0x04, 0x00, 0x01, 0x05, 0x00, 0x08, 0x01, 0x00, 0x03, 0x0F, - 0x01, 0x02, 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, - 0x36, 0x03, 0x09, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, - 0x06, 0x00, 0x00, 0x10, 0x01, 0x08, 0x00, 0x0F, 0x02, 0x00, 0x02, 0x00, - 0x07, 0x00, 0x0A, 0x00, - ) + vec![ + 0x0B, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x7E, 0x02, 0x01, 0x00, 0x00, 0x00, 0x66, 0x03, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x01, 0x10, 0x0A, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x10, 0x0A, 0x02, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x01, 0x04, 0x00, 0x01, 0x05, + 0x00, 0x08, 0x01, 0x00, 0x03, 0x0F, 0x01, 0x02, 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, + 0x72, 0x79, 0x33, 0x36, 0x03, 0x09, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, + 0x06, 0x00, 0x00, 0x10, 0x01, 0x08, 0x00, 0x0F, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0A, + 0x00, + ] } -#[test] fn feeny_function_argument_order_deserialize() { +#[test] +fn feeny_function_argument_order_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_function_argument_order_bytes())); assert_eq!(feeny_function_argument_order_program(), object); } -#[test] fn feeny_function_argument_order_serialize() { +#[test] +fn feeny_function_argument_order_serialize() { let mut output: Vec = Vec::new(); feeny_function_argument_order_program().serialize(&mut output).unwrap(); assert_eq!(feeny_function_argument_order_bytes(), output); } -#[test] fn feeny_function_argument_order_print() { +#[test] +fn feeny_function_argument_order_print() { let mut bytes: Vec = Vec::new(); feeny_function_argument_order_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_function_argument_order_source()); } -#[test] fn feeny_function_argument_order_eval() { +#[test] +fn feeny_function_argument_order_eval() { let program = feeny_function_argument_order_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); @@ -642,22 +701,26 @@ fn feeny_hello_world_source() -> &'static str { return Globals : #2 -Entry : #5"#} +Entry : #5"# +} fn feeny_hello_world_program() -> Program { - let code = Code::from(vec!( - /* 0 */ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, + let code = Code::from(vec![ + /* 0 */ + OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, /* 1 */ OpCode::Return, - /* 2 */ OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(0) }, + /* 2 */ + OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(0) }, /* 3 */ OpCode::Drop, /* 4 */ OpCode::Literal { index: ConstantPoolIndex::new(3) }, /* 5 */ OpCode::Return, - )); + ]); let constant_pool = ConstantPool::from(vec![ /* #0 */ ProgramObject::String("Hello World\n".to_string()), /* #1 */ ProgramObject::String("main".to_string()), - /* #2 */ ProgramObject::Method { + /* #2 */ + ProgramObject::Method { name: ConstantPoolIndex::new(1), parameters: Arity::new(0), locals: Size::new(0), @@ -665,7 +728,8 @@ fn feeny_hello_world_program() -> Program { }, /* #3 */ ProgramObject::Null, /* #4 */ ProgramObject::String("entry35".to_string()), - /* #5 */ ProgramObject::Method { + /* #5 */ + ProgramObject::Method { name: ConstantPoolIndex::new(4), parameters: Arity::new(0), locals: Size::new(0), @@ -679,34 +743,38 @@ fn feeny_hello_world_program() -> Program { } fn feeny_hello_world_bytes() -> Vec { - vec!( - 0x06, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, - 0x6F, 0x72, 0x6C, 0x64, 0x0A, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, - 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0F, 0x01, 0x02, 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x35, - 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, - 0x10, 0x01, 0x03, 0x00, 0x0F, 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, - ) + vec![ + 0x06, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, + 0x72, 0x6C, 0x64, 0x0A, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x02, + 0x07, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x33, 0x35, 0x03, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x10, 0x01, 0x03, 0x00, 0x0F, + 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, + ] } -#[test] fn feeny_hello_world_deserialize() { +#[test] +fn feeny_hello_world_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_hello_world_bytes())); assert_eq!(feeny_hello_world_program(), object); } -#[test] fn feeny_hello_world_serialize() { +#[test] +fn feeny_hello_world_serialize() { let mut output: Vec = Vec::new(); feeny_hello_world_program().serialize(&mut output).unwrap(); assert_eq!(feeny_hello_world_bytes(), output); } -#[test] fn feeny_hello_world_print() { +#[test] +fn feeny_hello_world_print() { let mut bytes: Vec = Vec::new(); feeny_hello_world_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_hello_world_source()); } -#[test] fn feeny_hello_world_eval() { +#[test] +fn feeny_hello_world_eval() { let program = feeny_hello_world_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); @@ -821,7 +889,8 @@ fn feeny_fibonacci_source() -> &'static str { Globals : #15 #22 -Entry : #24"#} +Entry : #24"# +} fn feeny_fibonacci_expected_output() -> &'static str { r#"Fib(0) = 1 @@ -848,146 +917,222 @@ Fib(19) = 6765 } fn feeny_fibonacci_bytes() -> Vec { - vec!( - 0x19, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x71, 0x33, - 0x39, 0x02, 0x05, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x64, 0x34, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x65, 0x71, 0x02, 0x08, 0x00, 0x00, 0x00, - 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x71, 0x34, 0x31, 0x02, 0x05, 0x00, 0x00, 0x00, 0x65, - 0x6E, 0x64, 0x34, 0x32, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, - 0x74, 0x65, 0x73, 0x74, 0x34, 0x33, 0x02, 0x06, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x6F, - 0x70, 0x34, 0x34, 0x02, 0x03, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x02, 0x03, 0x00, - 0x00, 0x00, 0x73, 0x75, 0x62, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, - 0x00, 0x67, 0x65, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x66, 0x69, 0x62, 0x03, 0x0E, - 0x00, 0x01, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x07, 0x03, 0x00, 0x02, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x06, 0x00, 0x07, - 0x03, 0x00, 0x02, 0x0D, 0x04, 0x00, 0x01, 0x06, 0x00, 0x09, 0x01, 0x00, 0x10, 0x01, - 0x06, 0x00, 0x09, 0x02, 0x00, 0x10, 0x0E, 0x07, 0x00, 0x00, 0x08, 0x00, 0x0A, 0x01, - 0x00, 0x0A, 0x02, 0x00, 0x07, 0x09, 0x00, 0x02, 0x09, 0x03, 0x00, 0x10, 0x0A, 0x02, - 0x00, 0x09, 0x01, 0x00, 0x10, 0x0A, 0x03, 0x00, 0x09, 0x02, 0x00, 0x10, 0x0A, 0x00, - 0x00, 0x01, 0x06, 0x00, 0x07, 0x0A, 0x00, 0x02, 0x09, 0x00, 0x00, 0x10, 0x00, 0x07, - 0x00, 0x0A, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x07, 0x0C, 0x00, 0x02, 0x0D, 0x08, 0x00, - 0x01, 0x0D, 0x00, 0x10, 0x0A, 0x02, 0x00, 0x0E, 0x05, 0x00, 0x00, 0x04, 0x00, 0x01, - 0x06, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, - 0x00, 0x01, 0x00, 0x0F, 0x02, 0x06, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x34, - 0x35, 0x02, 0x06, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x6F, 0x70, 0x34, 0x36, 0x02, 0x0B, - 0x00, 0x00, 0x00, 0x46, 0x69, 0x62, 0x28, 0x7E, 0x29, 0x20, 0x3D, 0x20, 0x7E, 0x0A, - 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x6C, 0x74, 0x02, 0x04, - 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x15, 0x00, 0x00, 0x01, 0x00, 0x16, - 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x09, 0x00, 0x00, 0x10, 0x0E, 0x10, 0x00, 0x00, - 0x11, 0x00, 0x0A, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x08, 0x0E, 0x00, 0x01, 0x02, 0x12, - 0x00, 0x02, 0x10, 0x0A, 0x00, 0x00, 0x01, 0x06, 0x00, 0x07, 0x09, 0x00, 0x02, 0x09, - 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x13, 0x00, 0x07, 0x14, - 0x00, 0x02, 0x0D, 0x11, 0x00, 0x01, 0x0D, 0x00, 0x0F, 0x02, 0x07, 0x00, 0x00, 0x00, - 0x65, 0x6E, 0x74, 0x72, 0x79, 0x34, 0x37, 0x03, 0x17, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x10, 0x01, 0x0D, 0x00, 0x0F, 0x02, 0x00, - 0x0F, 0x00, 0x16, 0x00, 0x18, 0x00, - ) + vec![ + 0x19, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x71, 0x33, 0x39, + 0x02, 0x05, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x64, 0x34, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x65, 0x71, 0x02, 0x08, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, + 0x73, 0x65, 0x71, 0x34, 0x31, 0x02, 0x05, 0x00, 0x00, 0x00, 0x65, 0x6E, 0x64, 0x34, 0x32, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x34, + 0x33, 0x02, 0x06, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x6F, 0x70, 0x34, 0x34, 0x02, 0x03, 0x00, + 0x00, 0x00, 0x61, 0x64, 0x64, 0x02, 0x03, 0x00, 0x00, 0x00, 0x73, 0x75, 0x62, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x67, 0x65, 0x01, 0x02, 0x03, 0x00, 0x00, + 0x00, 0x66, 0x69, 0x62, 0x03, 0x0E, 0x00, 0x01, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0A, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x07, 0x03, 0x00, 0x02, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x00, + 0x01, 0x06, 0x00, 0x07, 0x03, 0x00, 0x02, 0x0D, 0x04, 0x00, 0x01, 0x06, 0x00, 0x09, 0x01, + 0x00, 0x10, 0x01, 0x06, 0x00, 0x09, 0x02, 0x00, 0x10, 0x0E, 0x07, 0x00, 0x00, 0x08, 0x00, + 0x0A, 0x01, 0x00, 0x0A, 0x02, 0x00, 0x07, 0x09, 0x00, 0x02, 0x09, 0x03, 0x00, 0x10, 0x0A, + 0x02, 0x00, 0x09, 0x01, 0x00, 0x10, 0x0A, 0x03, 0x00, 0x09, 0x02, 0x00, 0x10, 0x0A, 0x00, + 0x00, 0x01, 0x06, 0x00, 0x07, 0x0A, 0x00, 0x02, 0x09, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x0A, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x07, 0x0C, 0x00, 0x02, 0x0D, 0x08, 0x00, 0x01, 0x0D, + 0x00, 0x10, 0x0A, 0x02, 0x00, 0x0E, 0x05, 0x00, 0x00, 0x04, 0x00, 0x01, 0x06, 0x00, 0x00, + 0x05, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x0F, + 0x02, 0x06, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x34, 0x35, 0x02, 0x06, 0x00, 0x00, + 0x00, 0x6C, 0x6F, 0x6F, 0x70, 0x34, 0x36, 0x02, 0x0B, 0x00, 0x00, 0x00, 0x46, 0x69, 0x62, + 0x28, 0x7E, 0x29, 0x20, 0x3D, 0x20, 0x7E, 0x0A, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x6C, 0x74, 0x02, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, + 0x15, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x09, 0x00, 0x00, + 0x10, 0x0E, 0x10, 0x00, 0x00, 0x11, 0x00, 0x0A, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x08, 0x0E, + 0x00, 0x01, 0x02, 0x12, 0x00, 0x02, 0x10, 0x0A, 0x00, 0x00, 0x01, 0x06, 0x00, 0x07, 0x09, + 0x00, 0x02, 0x09, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x13, 0x00, + 0x07, 0x14, 0x00, 0x02, 0x0D, 0x11, 0x00, 0x01, 0x0D, 0x00, 0x0F, 0x02, 0x07, 0x00, 0x00, + 0x00, 0x65, 0x6E, 0x74, 0x72, 0x79, 0x34, 0x37, 0x03, 0x17, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x10, 0x01, 0x0D, 0x00, 0x0F, 0x02, 0x00, 0x0F, + 0x00, 0x16, 0x00, 0x18, 0x00, + ] } -fn feeny_fibonacci_program () -> Program { - let code = Code::from(vec!( +fn feeny_fibonacci_program() -> Program { + let code = Code::from(vec![ /* method fib: start: 0, length: 39 */ - /* 00 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 - /* 01 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 - /* 02 */ OpCode::CallMethod { // 0.eq(arg0) + /* 00 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 + /* 01 */ + OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 + /* 02 */ + OpCode::CallMethod { + // 0.eq(arg0) name: ConstantPoolIndex::new(3), - arguments: Arity::new(2) }, - /* 03 */ OpCode::Branch { label: ConstantPoolIndex::new(0) }, // branch conseq39 - /* 04 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // also x - /* 05 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 - /* 06 */ OpCode::CallMethod { // arg0.eq(1) + arguments: Arity::new(2), + }, + /* 03 */ + OpCode::Branch { label: ConstantPoolIndex::new(0) }, // branch conseq39 + /* 04 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // also x + /* 05 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 + /* 06 */ + OpCode::CallMethod { + // arg0.eq(1) name: ConstantPoolIndex::new(3), - arguments: Arity::new(2) }, - /* 07 */ OpCode::Branch { label: ConstantPoolIndex::new(4) }, // branch conseq41 - /* 08 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 - /* 09 */ OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // var1 = 1 + arguments: Arity::new(2), + }, + /* 07 */ + OpCode::Branch { label: ConstantPoolIndex::new(4) }, // branch conseq41 + /* 08 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 + /* 09 */ + OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // var1 = 1 /* 10 */ OpCode::Drop, - /* 11 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 - /* 12 */ OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // var2 = 1 + /* 11 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 + /* 12 */ + OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // var2 = 1 /* 13 */ OpCode::Drop, - /* 14 */ OpCode::Jump { label: ConstantPoolIndex::new(7) }, // goto test43 - - /* 15 */ OpCode::Label { name: ConstantPoolIndex::new(8) }, // label loop44 - /* 16 */ OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // var1 - /* 17 */ OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // var2 - /* 18 */ OpCode::CallMethod { // var1.add(var2) -> result1 + /* 14 */ + OpCode::Jump { label: ConstantPoolIndex::new(7) }, // goto test43 + /* 15 */ + OpCode::Label { name: ConstantPoolIndex::new(8) }, // label loop44 + /* 16 */ + OpCode::GetLocal { index: LocalFrameIndex::new(1) }, // var1 + /* 17 */ + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // var2 + /* 18 */ + OpCode::CallMethod { + // var1.add(var2) -> result1 name: ConstantPoolIndex::new(9), - arguments: Arity::new(2) }, - /* 19 */ OpCode::SetLocal { index: LocalFrameIndex::new(3) }, // var3 = result1 + arguments: Arity::new(2), + }, + /* 19 */ + OpCode::SetLocal { index: LocalFrameIndex::new(3) }, // var3 = result1 /* 20 */ OpCode::Drop, - /* 21 */ OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // var2 - /* 22 */ OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // var1 = var2 + /* 21 */ + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // var2 + /* 22 */ + OpCode::SetLocal { index: LocalFrameIndex::new(1) }, // var1 = var2 /* 23 */ OpCode::Drop, - /* 24 */ OpCode::GetLocal { index: LocalFrameIndex::new(3) }, // var3 - /* 25 */ OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // var2 = var3 + /* 24 */ + OpCode::GetLocal { index: LocalFrameIndex::new(3) }, // var3 + /* 25 */ + OpCode::SetLocal { index: LocalFrameIndex::new(2) }, // var2 = var3 /* 26 */ OpCode::Drop, - /* 27 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 - /* 28 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 - /* 29 */ OpCode::CallMethod { // arg0.sub(1) -> result2 + /* 27 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 + /* 28 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 + /* 29 */ + OpCode::CallMethod { + // arg0.sub(1) -> result2 name: ConstantPoolIndex::new(10), - arguments: Arity::new(2) }, - /* 30 */ OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // arg0 = result2 + arguments: Arity::new(2), + }, + /* 30 */ + OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // arg0 = result2 /* 31 */ OpCode::Drop, - /* 32 */ OpCode::Label { name: ConstantPoolIndex::new(7) }, // label test43 - /* 33 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 - /* 34 */ OpCode::Literal { index: ConstantPoolIndex::new(11) }, // 2 - /* 35 */ OpCode::CallMethod { // arg0.ge(2) -> result3 + /* 32 */ + OpCode::Label { name: ConstantPoolIndex::new(7) }, // label test43 + /* 33 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // arg0 + /* 34 */ + OpCode::Literal { index: ConstantPoolIndex::new(11) }, // 2 + /* 35 */ + OpCode::CallMethod { + // arg0.ge(2) -> result3 name: ConstantPoolIndex::new(12), - arguments: Arity::new(2) }, - /* 36 */ OpCode::Branch { label: ConstantPoolIndex::new(8) }, // loop44 - /* 37 */ OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null + arguments: Arity::new(2), + }, + /* 36 */ + OpCode::Branch { label: ConstantPoolIndex::new(8) }, // loop44 + /* 37 */ + OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null /* 38 */ OpCode::Drop, - /* 39 */ OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // arg2 (return arg2) - /* 40 */ OpCode::Jump { label: ConstantPoolIndex::new(5) }, // goto end42 - /* 41 */ OpCode::Label { name: ConstantPoolIndex::new(4) }, // label conseq41 - /* 42 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 (return 1) - /* 43 */ OpCode::Label { name: ConstantPoolIndex::new(5) }, // label end42 - /* 44 */ OpCode::Jump { label: ConstantPoolIndex::new(1) }, // goto end40 - /* 45 */ OpCode::Label { name: ConstantPoolIndex::new(0) }, // label conseq39 - /* 46 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 (return 1) - /* 47 */ OpCode::Label { name: ConstantPoolIndex::new(1) }, // label end40 + /* 39 */ + OpCode::GetLocal { index: LocalFrameIndex::new(2) }, // arg2 (return arg2) + /* 40 */ + OpCode::Jump { label: ConstantPoolIndex::new(5) }, // goto end42 + /* 41 */ + OpCode::Label { name: ConstantPoolIndex::new(4) }, // label conseq41 + /* 42 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 (return 1) + /* 43 */ + OpCode::Label { name: ConstantPoolIndex::new(5) }, // label end42 + /* 44 */ + OpCode::Jump { label: ConstantPoolIndex::new(1) }, // goto end40 + /* 45 */ + OpCode::Label { name: ConstantPoolIndex::new(0) }, // label conseq39 + /* 46 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 (return 1) + /* 47 */ + OpCode::Label { name: ConstantPoolIndex::new(1) }, // label end40 /* 48 */ OpCode::Return, - /* method main: start: 49, length: 22 */ - /* 49 */ OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 - /* 50 */ OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // var0 = 0 + /* 49 */ + OpCode::Literal { index: ConstantPoolIndex::new(2) }, // 0 + /* 50 */ + OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // var0 = 0 /* 51 */ OpCode::Drop, - /* 52 */ OpCode::Jump { label: ConstantPoolIndex::new(16) }, // goto loop45 - /* 53 */ OpCode::Label { name: ConstantPoolIndex::new(17) }, // label loop46 - /* 54 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 - /* 55 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 ... again? - /* 56 */ OpCode::CallFunction { // fib(var0) -> result1 + /* 52 */ + OpCode::Jump { label: ConstantPoolIndex::new(16) }, // goto loop45 + /* 53 */ + OpCode::Label { name: ConstantPoolIndex::new(17) }, // label loop46 + /* 54 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 + /* 55 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 ... again? + /* 56 */ + OpCode::CallFunction { + // fib(var0) -> result1 name: ConstantPoolIndex::new(14), - arguments: Arity::new(1) }, - /* 57 */ OpCode::Print { // printf "Fib(~) = ~\n" var0 result1 + arguments: Arity::new(1), + }, + /* 57 */ + OpCode::Print { + // printf "Fib(~) = ~\n" var0 result1 format: ConstantPoolIndex::new(18), - arguments: Arity::new(2) }, + arguments: Arity::new(2), + }, /* 58 */ OpCode::Drop, - /* 59 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 - /* 60 */ OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 - /* 61 */ OpCode::CallMethod { // var0.add(1) -> result2 + /* 59 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 + /* 60 */ + OpCode::Literal { index: ConstantPoolIndex::new(6) }, // 1 + /* 61 */ + OpCode::CallMethod { + // var0.add(1) -> result2 name: ConstantPoolIndex::new(9), - arguments: Arity::new(2) }, - /* 62 */ OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // var0 = result2 + arguments: Arity::new(2), + }, + /* 62 */ + OpCode::SetLocal { index: LocalFrameIndex::new(0) }, // var0 = result2 /* 63 */ OpCode::Drop, - /* 64 */ OpCode::Label { name: ConstantPoolIndex::new(16) }, // label test45 - /* 65 */ OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 - /* 66 */ OpCode::Literal { index: ConstantPoolIndex::new(19) }, // 20 - /* 67 */ OpCode::CallMethod { // var0.lt(20) -> result3 + /* 64 */ + OpCode::Label { name: ConstantPoolIndex::new(16) }, // label test45 + /* 65 */ + OpCode::GetLocal { index: LocalFrameIndex::new(0) }, // var0 + /* 66 */ + OpCode::Literal { index: ConstantPoolIndex::new(19) }, // 20 + /* 67 */ + OpCode::CallMethod { + // var0.lt(20) -> result3 name: ConstantPoolIndex::new(20), - arguments: Arity::new(2) }, - /* 68 */ OpCode::Branch { label: ConstantPoolIndex::new(17) }, // branch loop46 - /* 69 */ OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null + arguments: Arity::new(2), + }, + /* 68 */ + OpCode::Branch { label: ConstantPoolIndex::new(17) }, // branch loop46 + /* 69 */ + OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null /* 70 */ OpCode::Return, - /* method entry: start: 71, length: 4 */ - /* 71 */ OpCode::CallFunction { // main() -> result0 + /* 71 */ + OpCode::CallFunction { + // main() -> result0 name: ConstantPoolIndex::new(21), - arguments: Arity::new(0) }, + arguments: Arity::new(0), + }, /* 72 */ OpCode::Drop, - /* 73 */ OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null - /* 74 */ OpCode::Return - )); + /* 73 */ + OpCode::Literal { index: ConstantPoolIndex::new(13) }, // null + /* 74 */ OpCode::Return, + ]); let constants = ConstantPool::from(vec![ /* #0 0x00 */ ProgramObject::String("conseq39".to_string()), @@ -1005,7 +1150,9 @@ fn feeny_fibonacci_program () -> Program { /* #12 0x0C */ ProgramObject::String("ge".to_string()), /* #13 0x0D */ ProgramObject::Null, /* #14 0x0E */ ProgramObject::String("fib".to_string()), - /* #15 0x0F */ ProgramObject::Method { // fib + /* #15 0x0F */ + ProgramObject::Method { + // fib name: ConstantPoolIndex::new(14), parameters: Arity::new(1), locals: Size::new(3), @@ -1017,59 +1164,63 @@ fn feeny_fibonacci_program () -> Program { /* #19 0x12 */ ProgramObject::Integer(20), /* #20 0x13 */ ProgramObject::String("lt".to_string()), /* #21 0x14 */ ProgramObject::String("main".to_string()), - /* #22 0x15 */ ProgramObject::Method { // main + /* #22 0x15 */ + ProgramObject::Method { + // main name: ConstantPoolIndex::new(21), parameters: Arity::new(0), locals: Size::new(1), code: AddressRange::from(49, 22), }, /* #23 0x15 */ ProgramObject::String("entry47".to_string()), - /* #24 0x16 */ ProgramObject::Method { // entry47 + /* #24 0x16 */ + ProgramObject::Method { + // entry47 name: ConstantPoolIndex::new(23), parameters: Arity::new(0), locals: Size::new(0), - code: AddressRange::from(71,4), - } + code: AddressRange::from(71, 4), + }, ]); - let globals = Globals::from(vec![ - ConstantPoolIndex::new(15), - ConstantPoolIndex::new(22) - ]); + let globals = Globals::from(vec![ConstantPoolIndex::new(15), ConstantPoolIndex::new(22)]); let entry = Entry::from(24); Program::from(code, constants, globals, entry).unwrap() } -#[test] fn feeny_fibonacci_deserialize() { +#[test] +fn feeny_fibonacci_deserialize() { let object = Program::from_bytes(&mut Cursor::new(feeny_fibonacci_bytes())); assert_eq!(feeny_fibonacci_program(), object); } -#[test] fn feeny_fibonacci_serialize() { +#[test] +fn feeny_fibonacci_serialize() { let mut output: Vec = Vec::new(); feeny_fibonacci_program().serialize(&mut output).unwrap(); assert_eq!(feeny_fibonacci_bytes(), output); } -#[test] fn feeny_fibonacci_print() { +#[test] +fn feeny_fibonacci_print() { let mut bytes: Vec = Vec::new(); feeny_fibonacci_program().pretty_print(&mut bytes); assert_eq!(&String::from_utf8(bytes).unwrap(), feeny_fibonacci_source()); } -#[test] fn feeny_fibonacci_eval() { +#[test] +fn feeny_fibonacci_eval() { let program = feeny_fibonacci_program(); let mut state = State::from(&program).unwrap(); let mut output = String::new(); - - let mut source:Vec = Vec::new(); + let mut source: Vec = Vec::new(); program.pretty_print(&mut source); println!("{}", String::from_utf8(source).unwrap()); evaluate_with(&program, &mut state, &mut output).unwrap(); assert_eq!(output, feeny_fibonacci_expected_output()); -} \ No newline at end of file +} diff --git a/src/tests/interpreter.rs b/src/tests/interpreter.rs index 435a6bc..dcedcd9 100644 --- a/src/tests/interpreter.rs +++ b/src/tests/interpreter.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; use crate::bytecode::bytecode::*; -use crate::bytecode::program::*; -use crate::bytecode::interpreter::*; use crate::bytecode::heap::*; +use crate::bytecode::interpreter::*; +use crate::bytecode::program::*; use crate::bytecode::state::*; use indexmap::map::IndexMap; @@ -36,11 +36,10 @@ macro_rules! indexmap { }}; } -#[test] fn literal() { - let code = Code::from(vec!( - OpCode::Literal { index: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn literal() { + let code = + Code::from(vec![OpCode::Literal { index: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec![42]); let globals = Globals::new(); @@ -52,7 +51,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42)]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -64,11 +63,9 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn label() { - let code = Code::from(vec!( - OpCode::Label { name: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn label() { + let code = Code::from(vec![OpCode::Label { name: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec!["o.o"]); let globals = Globals::new(); @@ -92,11 +89,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn get_local() { - let code = Code::from(vec!( - OpCode::GetLocal { index: LocalFrameIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn get_local() { + let code = + Code::from(vec![OpCode::GetLocal { index: LocalFrameIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -110,9 +106,8 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42i32))); - let expected_frame_stack = - FrameStack::from(Frame::from(None, vec![Pointer::from(42i32)])); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42i32)]); + let expected_frame_stack = FrameStack::from(Frame::from(None, vec![Pointer::from(42i32)])); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -126,11 +121,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn set_local() { - let code = Code::from(vec!( - OpCode::SetLocal { index: LocalFrameIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn set_local() { + let code = + Code::from(vec![OpCode::SetLocal { index: LocalFrameIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -145,9 +139,8 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42))); - let expected_frame_stack = - FrameStack::from(Frame::from(None, vec![Pointer::from(42i32)])); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42)]); + let expected_frame_stack = FrameStack::from(Frame::from(None, vec![Pointer::from(42i32)])); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -158,11 +151,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn get_global() { - let code = Code::from(vec!( - OpCode::GetGlobal { name: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn get_global() { + let code = + Code::from(vec![OpCode::GetGlobal { name: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec!["skippy"]); let globals = Globals::from(vec![ConstantPoolIndex::from_usize(0)]); @@ -177,7 +169,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(666))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(666)]); let mut expected_frame_stack = FrameStack::from(Frame::new()); expected_frame_stack.globals = GlobalFrame::from(vec!["skippy".to_owned()], Pointer::from(666)).unwrap(); @@ -191,11 +183,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn set_global() { - let code = Code::from(vec!( - OpCode::SetGlobal { name: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn set_global() { + let code = + Code::from(vec![OpCode::SetGlobal { name: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec!["skippy"]); let globals = Globals::from(vec![ConstantPoolIndex::from_usize(0)]); @@ -211,7 +202,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42)]); let mut expected_frame_stack = FrameStack::from(Frame::new()); expected_frame_stack.globals = GlobalFrame::from(vec!["skippy".to_owned()], Pointer::from(42)).unwrap(); @@ -225,11 +216,9 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn drop() { - let code = Code::from(vec!( - OpCode::Drop, - OpCode::Return, - )); +#[test] +fn drop() { + let code = Code::from(vec![OpCode::Drop, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -258,13 +247,14 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn jump() { - let code = Code::from(vec!( +#[test] +fn jump() { + let code = Code::from(vec![ /*0*/ OpCode::Label { name: ConstantPoolIndex::new(0) }, /*1*/ OpCode::Return, /*2*/ OpCode::Jump { label: ConstantPoolIndex::new(0) }, /*3*/ OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["^.^"]); let globals = Globals::new(); @@ -290,13 +280,14 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn branch_true() { - let code = Code::from(vec!( +#[test] +fn branch_true() { + let code = Code::from(vec![ /*0*/ OpCode::Label { name: ConstantPoolIndex::new(0) }, /*1*/ OpCode::Return, /*2*/ OpCode::Branch { label: ConstantPoolIndex::new(0) }, /*3*/ OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["x.x"]); let globals = Globals::new(); @@ -323,13 +314,14 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn branch_false() { - let code = Code::from(vec!( +#[test] +fn branch_false() { + let code = Code::from(vec![ /*0*/ OpCode::Label { name: ConstantPoolIndex::new(0) }, /*1*/ OpCode::Return, /*2*/ OpCode::Branch { label: ConstantPoolIndex::new(0) }, /*3*/ OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["butt"]); let globals = Globals::new(); @@ -356,11 +348,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print() { - let code = Code::from(vec!( +#[test] +fn print() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["Ahoj przygodo!\n"]); let globals = Globals::new(); @@ -372,7 +365,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::Null)); + let expected_operand_stack = OperandStack::from(vec![Pointer::Null]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -384,11 +377,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_tilda() { - let code = Code::from(vec!( +#[test] +fn print_tilda() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~\\~!\n"]); let globals = Globals::new(); @@ -414,11 +408,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_one() { - let code = Code::from(vec!( +#[test] +fn print_one() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~!\n"]); let globals = Globals::new(); @@ -444,11 +439,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_two() { - let code = Code::from(vec!( +#[test] +fn print_two() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(2) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~x~!\n"]); let globals = Globals::new(); @@ -463,7 +459,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::Null)); + let expected_operand_stack = OperandStack::from(vec![Pointer::Null]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -475,11 +471,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_array() { - let code = Code::from(vec!( +#[test] +fn print_array() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~\n"]); let globals = Globals::new(); @@ -496,7 +493,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::Null)); + let expected_operand_stack = OperandStack::from(vec![Pointer::Null]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::from(vec![array]); @@ -508,11 +505,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_object_with_parent() { - let code = Code::from(vec!( +#[test] +fn print_object_with_parent() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~\n"]); let globals = Globals::new(); @@ -537,7 +535,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::Null)); + let expected_operand_stack = OperandStack::from(vec![Pointer::Null]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::from(vec![object]); @@ -549,11 +547,12 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn print_object_without_parent() { - let code = Code::from(vec!( +#[test] +fn print_object_without_parent() { + let code = Code::from(vec![ OpCode::Print { format: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["~\n"]); let globals = Globals::new(); @@ -578,7 +577,7 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::Null)); + let expected_operand_stack = OperandStack::from(vec![Pointer::Null]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::from(vec![object]); @@ -590,11 +589,9 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn array_zero() { - let code = Code::from(vec!( - OpCode::Array, - OpCode::Return, - )); +#[test] +fn array_zero() { + let code = Code::from(vec![OpCode::Array, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -609,11 +606,10 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = - OperandStack::from(vec!(Pointer::Reference(HeapIndex::from(0)))); + let expected_operand_stack = OperandStack::from(vec![Pointer::Reference(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec!(HeapObject::empty_array())); + let expected_heap = Heap::from(vec![HeapObject::empty_array()]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -622,11 +618,9 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn array_one() { - let code = Code::from(vec!( - OpCode::Array, - OpCode::Return - )); +#[test] +fn array_one() { + let code = Code::from(vec![OpCode::Array, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -641,11 +635,10 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = - OperandStack::from(vec!(Pointer::Reference(HeapIndex::from(0)))); + let expected_operand_stack = OperandStack::from(vec![Pointer::Reference(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec!(HeapObject::from_pointers(vec![Pointer::Null]))); + let expected_heap = Heap::from(vec![HeapObject::from_pointers(vec![Pointer::Null])]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -654,11 +647,9 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn array_three() { - let code = Code::from(vec!( - OpCode::Array, - OpCode::Return, - )); +#[test] +fn array_three() { + let code = Code::from(vec![OpCode::Array, OpCode::Return]); let constants = ConstantPool::new(); let globals = Globals::new(); @@ -673,13 +664,14 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = - OperandStack::from(vec!(Pointer::from(HeapIndex::from(0)))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec!(HeapObject::from_pointers(vec!(Pointer::from(0i32), - Pointer::from(0i32), - Pointer::from(0i32))))); + let expected_heap = Heap::from(vec![HeapObject::from_pointers(vec![ + Pointer::from(0i32), + Pointer::from(0i32), + Pointer::from(0i32), + ])]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -688,19 +680,24 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_function_zero() { - let code = Code::from(vec!( +#[test] +fn call_function_zero() { + let code = Code::from(vec![ /*0*/ OpCode::Return, - /*1*/ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, + /*1*/ + OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(0) }, /*2*/ OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec![ ProgramObject::String("bar".to_string()), - ProgramObject::Method { name: ConstantPoolIndex::new(0), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), parameters: Arity::new(0), locals: Size::new(0), - code: AddressRange::from(0,1) }]); + code: AddressRange::from(0, 1), + }, + ]); let globals = Globals::from(vec![ConstantPoolIndex::new(1)]); let entry = Entry::from(0); let program = Program::from(code, constants, globals, entry).unwrap(); @@ -738,19 +735,24 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_function_one() { - let code = Code::from(vec!( +#[test] +fn call_function_one() { + let code = Code::from(vec![ /*0*/ OpCode::Return, - /*1*/ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, + /*1*/ + OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, /*2*/ OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec![ ProgramObject::String("foo".to_string()), - ProgramObject::Method { name: ConstantPoolIndex::new(0), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0,1) }]); + code: AddressRange::from(0, 1), + }, + ]); let globals = Globals::from(vec![ConstantPoolIndex::new(1)]); let entry = Entry::from(0); let program = Program::from(code, constants, globals, entry).unwrap(); @@ -781,18 +783,24 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_function_three() { - let code = Code::from(vec!( +#[test] +fn call_function_three() { + let code = Code::from(vec![ /*0*/ OpCode::Return, - /*1*/ OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(3) }, + /*1*/ + OpCode::CallFunction { name: ConstantPoolIndex::new(0), arguments: Arity::new(3) }, /*2*/ OpCode::Return, - )); + ]); - let constants = ConstantPool::from(vec![ ProgramObject::String("fun".to_string()), - ProgramObject::Method { name: ConstantPoolIndex::new(0), - parameters: Arity::new(3), - locals: Size::new(0), - code: AddressRange::from(0,1) }]); + let constants = ConstantPool::from(vec![ + ProgramObject::String("fun".to_string()), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), + parameters: Arity::new(3), + locals: Size::new(0), + code: AddressRange::from(0, 1), + }, + ]); let globals = Globals::new(); let entry = Entry::from(0); let program = Program::from(code, constants, globals, entry).unwrap(); @@ -814,9 +822,10 @@ macro_rules! indexmap { let expected_operand_stack = OperandStack::new(); let mut expected_frame_stack = FrameStack::new(); expected_frame_stack.push(Frame::new()); - expected_frame_stack.push(Frame::from(Some(Address::from_usize(2)), vec![Pointer::from(1), - Pointer::from(2), - Pointer::from(3)])); + expected_frame_stack.push(Frame::from( + Some(Address::from_usize(2)), + vec![Pointer::from(1), Pointer::from(2), Pointer::from(3)], + )); expected_frame_stack.functions = GlobalFunctions::from(vec![("fun".to_string(), ConstantPoolIndex::from(1usize))]).unwrap(); @@ -830,19 +839,24 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn returns() { - let code = Code::from(vec!( +#[test] +fn returns() { + let code = Code::from(vec![ /*0*/ OpCode::Return, - /*1*/ OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(3) }, + /*1*/ + OpCode::CallFunction { name: ConstantPoolIndex::new(1), arguments: Arity::new(3) }, /*2*/ OpCode::Drop, - )); + ]); let constants = ConstantPool::from(vec![ ProgramObject::String("xxx".to_string()), - ProgramObject::Method { name: ConstantPoolIndex::new(0), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), parameters: Arity::new(3), locals: Size::new(0), - code: AddressRange::from(0,1) }]); + code: AddressRange::from(0, 1), + }, + ]); let globals = Globals::from(vec![ConstantPoolIndex::new(1)]); let entry = Entry::from(0); @@ -851,8 +865,10 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - state.frame_stack.push(Frame::from(Some(Address::from_usize(2)), - vec![Pointer::from(1), Pointer::from(2), Pointer::from(3)])); + state.frame_stack.push(Frame::from( + Some(Address::from_usize(2)), + vec![Pointer::from(1), Pointer::from(2), Pointer::from(3)], + )); step_with(&program, &mut state, &mut output).unwrap(); @@ -868,19 +884,24 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn object_zero() { - let code = Code::from(vec!( +#[test] +fn object_zero() { + let code = Code::from(vec![ /*0*/ OpCode::Object { class: ConstantPoolIndex::new(2) }, - /*1*/ OpCode::Return - )); + /*1*/ OpCode::Return, + ]); let constants = ConstantPool::from(vec![ - /*0*/ ProgramObject::String ("+".to_string()), - /*1*/ ProgramObject::Method { name: ConstantPoolIndex::new(0), + /*0*/ ProgramObject::String("+".to_string()), + /*1*/ + ProgramObject::Method { + name: ConstantPoolIndex::new(0), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1)}, - /*2*/ ProgramObject::Class(vec!(ConstantPoolIndex::new(1)))]); + code: AddressRange::from(0, 1), + }, + /*2*/ ProgramObject::Class(vec![ConstantPoolIndex::new(1)]), + ]); let globals = Globals::new(); let entry = Entry::from(0); @@ -898,14 +919,17 @@ macro_rules! indexmap { name: ConstantPoolIndex::new(0), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1) + code: AddressRange::from(0, 1), }; let expected_operand_stack = OperandStack::from(vec![Pointer::from(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from(Pointer::Null, IndexMap::new(), - indexmap!(("+".to_string(), method)))]); + let expected_heap = Heap::from(vec![HeapObject::from( + Pointer::Null, + IndexMap::new(), + indexmap!(("+".to_string(), method)), + )]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -914,24 +938,26 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn object_one() { - let code = Code::from(vec!( +#[test] +fn object_one() { + let code = Code::from(vec![ /*0*/ OpCode::Object { class: ConstantPoolIndex::new(4) }, - /*1*/ OpCode::Return - )); + /*1*/ OpCode::Return, + ]); let constants = ConstantPool::from(vec![ - /*0*/ ProgramObject::String ("x".to_string()), + /*0*/ ProgramObject::String("x".to_string()), /*1*/ ProgramObject::Slot { name: ConstantPoolIndex::new(0) }, - - /*2*/ ProgramObject::String ("+".to_string()), - /*3*/ ProgramObject::Method { name: ConstantPoolIndex::new(2), + /*2*/ ProgramObject::String("+".to_string()), + /*3*/ + ProgramObject::Method { + name: ConstantPoolIndex::new(2), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1)}, - - /*4*/ ProgramObject::Class(vec!(ConstantPoolIndex::new(1), - ConstantPoolIndex::new(3))) + code: AddressRange::from(0, 1), + }, + /*4*/ + ProgramObject::Class(vec![ConstantPoolIndex::new(1), ConstantPoolIndex::new(3)]), ]); let globals = Globals::new(); @@ -942,8 +968,8 @@ macro_rules! indexmap { let mut output: String = String::new(); state.instruction_pointer.set(Some(Address::from_usize(0))); - state.operand_stack.push(Pointer::Null); // parent - state.operand_stack.push(Pointer::from(0i32)); // x + state.operand_stack.push(Pointer::Null); // parent + state.operand_stack.push(Pointer::from(0i32)); // x step_with(&program, &mut state, &mut output).unwrap(); @@ -951,15 +977,17 @@ macro_rules! indexmap { name: ConstantPoolIndex::new(2), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1) + code: AddressRange::from(0, 1), }; let expected_operand_stack = OperandStack::from(vec![Pointer::from(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from(Pointer::Null, - indexmap!(("x".to_owned(), Pointer::from(0i32))), - indexmap!(("+".to_string(), method)))]); + let expected_heap = Heap::from(vec![HeapObject::from( + Pointer::Null, + indexmap!(("x".to_owned(), Pointer::from(0i32))), + indexmap!(("+".to_string(), method)), + )]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -968,28 +996,32 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn object_two() { - let code = Code::from(vec!( +#[test] +fn object_two() { + let code = Code::from(vec![ /*0*/ OpCode::Object { class: ConstantPoolIndex::new(6) }, - /*1*/ OpCode::Return - )); + /*1*/ OpCode::Return, + ]); let constants = ConstantPool::from(vec![ - /*0*/ ProgramObject::String ("x".to_string()), + /*0*/ ProgramObject::String("x".to_string()), /*1*/ ProgramObject::Slot { name: ConstantPoolIndex::new(0) }, - - /*2*/ ProgramObject::String ("y".to_string()), + /*2*/ ProgramObject::String("y".to_string()), /*3*/ ProgramObject::Slot { name: ConstantPoolIndex::new(2) }, - - /*4*/ ProgramObject::String ("+".to_string()), - /*5*/ ProgramObject::Method { name: ConstantPoolIndex::new(4), + /*4*/ ProgramObject::String("+".to_string()), + /*5*/ + ProgramObject::Method { + name: ConstantPoolIndex::new(4), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1)}, - - /*6*/ ProgramObject::Class(vec!(ConstantPoolIndex::new(1), - ConstantPoolIndex::new(3), - ConstantPoolIndex::new(5))), + code: AddressRange::from(0, 1), + }, + /*6*/ + ProgramObject::Class(vec![ + ConstantPoolIndex::new(1), + ConstantPoolIndex::new(3), + ConstantPoolIndex::new(5), + ]), ]); let globals = Globals::new(); let entry = Entry::from(0); @@ -999,9 +1031,9 @@ macro_rules! indexmap { let mut output: String = String::new(); state.instruction_pointer.set(Some(Address::from_usize(0))); - state.operand_stack.push(Pointer::Null); // parent - state.operand_stack.push(Pointer::from(0i32)); // x - state.operand_stack.push(Pointer::from(2i32)); // y + state.operand_stack.push(Pointer::Null); // parent + state.operand_stack.push(Pointer::from(0i32)); // x + state.operand_stack.push(Pointer::from(2i32)); // y step_with(&program, &mut state, &mut output).unwrap(); @@ -1009,16 +1041,17 @@ macro_rules! indexmap { name: ConstantPoolIndex::new(4), parameters: Arity::new(1), locals: Size::new(0), - code: AddressRange::from(0, 1) + code: AddressRange::from(0, 1), }; let expected_operand_stack = OperandStack::from(vec![Pointer::from(HeapIndex::from(0))]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from(Pointer::Null, - indexmap!(("x".to_owned(), Pointer::from(0)), - ("y".to_owned(), Pointer::from(2))), - indexmap!(("+".to_string(), method)))]); + let expected_heap = Heap::from(vec![HeapObject::from( + Pointer::Null, + indexmap!(("x".to_owned(), Pointer::from(0)), ("y".to_owned(), Pointer::from(2))), + indexmap!(("+".to_string(), method)), + )]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -1027,11 +1060,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn get_slot() { - let code = Code::from(vec!( - OpCode::GetField { name: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn get_slot() { + let code = + Code::from(vec![OpCode::GetField { name: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec!["value"]); let globals = Globals::new(); @@ -1041,21 +1073,24 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - let head_index = - state.heap.allocate(HeapObject::from(Pointer::Null, - indexmap!(("value".to_string(), Pointer::from(42i32))), - IndexMap::new())); + let head_index = state.heap.allocate(HeapObject::from( + Pointer::Null, + indexmap!(("value".to_string(), Pointer::from(42i32))), + IndexMap::new(), + )); state.operand_stack.push(Pointer::from(head_index)); step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42)]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from(Pointer::Null, - indexmap!(("value".to_owned(), Pointer::from(42))), - IndexMap::new())]); + let expected_heap = Heap::from(vec![HeapObject::from( + Pointer::Null, + indexmap!(("value".to_owned(), Pointer::from(42))), + IndexMap::new(), + )]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -1064,11 +1099,10 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn set_slot() { - let code = Code::from(vec!( - OpCode::SetField { name: ConstantPoolIndex::new(0) }, - OpCode::Return, - )); +#[test] +fn set_slot() { + let code = + Code::from(vec![OpCode::SetField { name: ConstantPoolIndex::new(0) }, OpCode::Return]); let constants = ConstantPool::from(vec!["value"]); let globals = Globals::new(); @@ -1078,9 +1112,11 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - let object = HeapObject::from(Pointer::Null, - indexmap!(("value".to_string(), Pointer::from(1))), - IndexMap::new()); + let object = HeapObject::from( + Pointer::Null, + indexmap!(("value".to_string(), Pointer::from(1))), + IndexMap::new(), + ); let head_index = state.heap.allocate(object); state.operand_stack.push(Pointer::from(head_index)); @@ -1088,12 +1124,14 @@ macro_rules! indexmap { step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(6))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(6)]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from(Pointer::Null, - indexmap!(("value".to_owned(), Pointer::from(6))), - IndexMap::new())]); + let expected_heap = Heap::from(vec![HeapObject::from( + Pointer::Null, + indexmap!(("value".to_owned(), Pointer::from(6))), + IndexMap::new(), + )]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -1102,12 +1140,13 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_method_zero() { - let code = Code::from(vec!( +#[test] +fn call_method_zero() { + let code = Code::from(vec![ OpCode::Return, - OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(0 + 1) }, + OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["f"]); let globals = Globals::new(); @@ -1117,12 +1156,19 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - let receiver = HeapObject::from(Pointer::Null, - IndexMap::new(), - indexmap!(("f".to_string(), ProgramObject::Method { name: ConstantPoolIndex::new(0), - parameters: Arity::new(0 + 1), - locals: Size::new(0), - code: AddressRange::from(0, 1) }))); + let receiver = HeapObject::from( + Pointer::Null, + IndexMap::new(), + indexmap!(( + "f".to_string(), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), + parameters: Arity::new(1), + locals: Size::new(0), + code: AddressRange::from(0, 1) + } + )), + ); state.instruction_pointer.set(Some(Address::from_usize(1))); @@ -1134,7 +1180,10 @@ macro_rules! indexmap { let expected_operand_stack = OperandStack::new(); let mut expected_frame_stack = FrameStack::new(); expected_frame_stack.push(Frame::from(None, vec![])); - expected_frame_stack.push(Frame::from(Some(Address::from_usize(2)), vec![Pointer::Reference(HeapIndex::from(0))])); + expected_frame_stack.push(Frame::from( + Some(Address::from_usize(2)), + vec![Pointer::Reference(HeapIndex::from(0))], + )); let expected_instruction_pointer = InstructionPointer::from(0u32); let expected_heap = Heap::from(vec![receiver]); @@ -1145,12 +1194,13 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_method_one() { - let code = Code::from(vec!( +#[test] +fn call_method_one() { + let code = Code::from(vec![ OpCode::Return, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(1 + 1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["+"]); let globals = Globals::new(); @@ -1160,12 +1210,19 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - let receiver = HeapObject::from(Pointer::from(0), - IndexMap::new(), - indexmap!(("+".to_string(), ProgramObject::Method { name: ConstantPoolIndex::new(0), - parameters: Arity::new(1 + 1), - locals: Size::new(0), - code: AddressRange::from(0, 1) }))); + let receiver = HeapObject::from( + Pointer::from(0), + IndexMap::new(), + indexmap!(( + "+".to_string(), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), + parameters: Arity::new(1 + 1), + locals: Size::new(0), + code: AddressRange::from(0, 1) + } + )), + ); state.instruction_pointer.set(Some(Address::from_usize(1))); @@ -1178,8 +1235,10 @@ macro_rules! indexmap { let expected_operand_stack = OperandStack::new(); let mut expected_frame_stack = FrameStack::new(); expected_frame_stack.push(Frame::from(None, vec![])); - expected_frame_stack.push(Frame::from(Some(Address::from_usize(2)), - vec![Pointer::Reference(HeapIndex::from(0)), Pointer::from(1)])); + expected_frame_stack.push(Frame::from( + Some(Address::from_usize(2)), + vec![Pointer::Reference(HeapIndex::from(0)), Pointer::from(1)], + )); let expected_instruction_pointer = InstructionPointer::from(0u32); let expected_heap = Heap::from(vec![receiver]); @@ -1190,12 +1249,13 @@ macro_rules! indexmap { assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_method_three() { - let code = Code::from(vec!( +#[test] +fn call_method_three() { + let code = Code::from(vec![ OpCode::Return, OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(3 + 1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["g"]); let globals = Globals::new(); @@ -1205,12 +1265,19 @@ macro_rules! indexmap { let mut state = State::minimal(); let mut output: String = String::new(); - let receiver = HeapObject::from(Pointer::from(0), - IndexMap::new(), - indexmap!(("g".to_string(), ProgramObject::Method { name: ConstantPoolIndex::new(0), - parameters: Arity::new(3 + 1), - locals: Size::new(0), - code: AddressRange::from(0, 1) }))); + let receiver = HeapObject::from( + Pointer::from(0), + IndexMap::new(), + indexmap!(( + "g".to_string(), + ProgramObject::Method { + name: ConstantPoolIndex::new(0), + parameters: Arity::new(3 + 1), + locals: Size::new(0), + code: AddressRange::from(0, 1) + } + )), + ); state.instruction_pointer.set(Some(Address::from_usize(1))); state.operand_stack.push(Pointer::from(state.heap.allocate(receiver.clone()))); @@ -1235,11 +1302,15 @@ macro_rules! indexmap { let expected_operand_stack = OperandStack::new(); let mut expected_frame_stack = FrameStack::new(); expected_frame_stack.push(Frame::from(None, vec![])); - expected_frame_stack.push(Frame::from(Some(Address::from_usize(2)), - vec![Pointer::Reference(HeapIndex::from(0)), - Pointer::from(1), - Pointer::from(2), - Pointer::from(3)])); + expected_frame_stack.push(Frame::from( + Some(Address::from_usize(2)), + vec![ + Pointer::Reference(HeapIndex::from(0)), + Pointer::from(1), + Pointer::from(2), + Pointer::from(3), + ], + )); let expected_instruction_pointer = InstructionPointer::from(0u32); let expected_heap = Heap::from(vec![receiver]); @@ -1295,10 +1366,10 @@ macro_rules! indexmap { // } fn call_method_on_pointers(receiver: Pointer, argument: Pointer, operation: &str, result: Pointer) { - let code = Code::from(vec!( + let code = Code::from(vec![ OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(1 + 1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec![operation]); let globals = Globals::new(); @@ -1309,8 +1380,8 @@ fn call_method_on_pointers(receiver: Pointer, argument: Pointer, operation: &str let mut output: String = String::new(); state.instruction_pointer.set(Some(Address::from_usize(0))); - state.operand_stack.push(Pointer::from(receiver)); - state.operand_stack.push(Pointer::from(argument)); + state.operand_stack.push(receiver); + state.operand_stack.push(argument); step_with(&program, &mut state, &mut output).unwrap(); @@ -1321,7 +1392,7 @@ fn call_method_on_pointers(receiver: Pointer, argument: Pointer, operation: &str // assert_eq!(state.frames, vec!(LocalFrame::empty()), "test frames"); // assert_eq!(state.memory, expected_memory) - let expected_operand_stack = OperandStack::from(vec!(result)); + let expected_operand_stack = OperandStack::from(vec![result]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::new(); @@ -1334,67 +1405,80 @@ fn call_method_on_pointers(receiver: Pointer, argument: Pointer, operation: &str } fn call_method_integer(receiver: i32, argument: i32, operation: &str, result: i32) { - call_method_on_pointers(Pointer::from(receiver), - Pointer::from(argument), - operation, - Pointer::from(result)); + call_method_on_pointers( + Pointer::from(receiver), + Pointer::from(argument), + operation, + Pointer::from(result), + ); } - fn call_method_integer_cmp(receiver: i32, argument: i32, operation: &str, result: bool) { - call_method_on_pointers(Pointer::from(receiver), - Pointer::from(argument), - operation, - Pointer::from(result)); + call_method_on_pointers( + Pointer::from(receiver), + Pointer::from(argument), + operation, + Pointer::from(result), + ); } fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: bool) { - call_method_on_pointers(Pointer::from(receiver), - Pointer::from(argument), - operation, - Pointer::from(result)); + call_method_on_pointers( + Pointer::from(receiver), + Pointer::from(argument), + operation, + Pointer::from(result), + ); } -#[test] fn call_method_integer_add() { +#[test] +fn call_method_integer_add() { call_method_integer(2, 5, "+", 7); call_method_integer(2, 5, "add", 7); } -#[test] fn call_method_integer_subtract() { +#[test] +fn call_method_integer_subtract() { call_method_integer(2, 5, "-", -3); call_method_integer(2, 5, "sub", -3); } -#[test] fn call_method_integer_multiply() { +#[test] +fn call_method_integer_multiply() { call_method_integer(2, 5, "*", 10); call_method_integer(2, 5, "mul", 10); } -#[test] fn call_method_integer_divide() { +#[test] +fn call_method_integer_divide() { call_method_integer(2, 5, "/", 0); call_method_integer(2, 5, "div", 0); } -#[test] fn call_method_integer_module() { +#[test] +fn call_method_integer_module() { call_method_integer(2, 5, "%", 2); call_method_integer(2, 5, "mod", 2); } -#[test] fn call_method_integer_equality() { +#[test] +fn call_method_integer_equality() { call_method_integer_cmp(2, 5, "==", false); call_method_integer_cmp(5, 5, "==", true); call_method_integer_cmp(2, 5, "eq", false); call_method_integer_cmp(5, 5, "eq", true); } -#[test] fn call_method_integer_inequality() { +#[test] +fn call_method_integer_inequality() { call_method_integer_cmp(2, 5, "!=", true); call_method_integer_cmp(2, 2, "!=", false); call_method_integer_cmp(2, 5, "neq", true); call_method_integer_cmp(2, 2, "neq", false); } -#[test] fn call_method_integer_less() { +#[test] +fn call_method_integer_less() { call_method_integer_cmp(2, 5, "<", true); call_method_integer_cmp(7, 5, "<", false); call_method_integer_cmp(5, 5, "<", false); @@ -1403,7 +1487,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_integer_cmp(5, 5, "lt", false); } -#[test] fn call_method_integer_less_equal() { +#[test] +fn call_method_integer_less_equal() { call_method_integer_cmp(2, 5, "<=", true); call_method_integer_cmp(7, 5, "<=", false); call_method_integer_cmp(5, 5, "<=", true); @@ -1412,7 +1497,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_integer_cmp(5, 5, "le", true); } -#[test] fn call_method_integer_more() { +#[test] +fn call_method_integer_more() { call_method_integer_cmp(2, 5, ">", false); call_method_integer_cmp(7, 5, ">", true); call_method_integer_cmp(5, 5, ">", false); @@ -1421,7 +1507,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_integer_cmp(5, 5, "gt", false); } -#[test] fn call_method_integer_more_equal() { +#[test] +fn call_method_integer_more_equal() { call_method_integer_cmp(2, 5, ">=", false); call_method_integer_cmp(7, 5, ">=", true); call_method_integer_cmp(5, 5, ">=", true); @@ -1430,43 +1517,48 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_integer_cmp(5, 5, "ge", true); } -#[test] fn call_method_boolean_conjunction() { - call_method_boolean(true, false, "&", false); - call_method_boolean(true, true, "&", true); +#[test] +fn call_method_boolean_conjunction() { + call_method_boolean(true, false, "&", false); + call_method_boolean(true, true, "&", true); call_method_boolean(true, false, "and", false); - call_method_boolean(true, true, "and", true); + call_method_boolean(true, true, "and", true); } -#[test] fn call_method_boolean_disjunction() { - call_method_boolean(true, false, "|", true); - call_method_boolean(false, false, "|", false); - call_method_boolean(true, false, "or", true); +#[test] +fn call_method_boolean_disjunction() { + call_method_boolean(true, false, "|", true); + call_method_boolean(false, false, "|", false); + call_method_boolean(true, false, "or", true); call_method_boolean(false, false, "or", false); } -#[test] fn call_method_boolean_equal() { - call_method_boolean(true, false, "==", false); - call_method_boolean(false, false, "==", true); - call_method_boolean(true, true, "==", true); - call_method_boolean(true, false, "eq", false); - call_method_boolean(false, false, "eq", true); - call_method_boolean(true, true, "eq", true); +#[test] +fn call_method_boolean_equal() { + call_method_boolean(true, false, "==", false); + call_method_boolean(false, false, "==", true); + call_method_boolean(true, true, "==", true); + call_method_boolean(true, false, "eq", false); + call_method_boolean(false, false, "eq", true); + call_method_boolean(true, true, "eq", true); } -#[test] fn call_method_boolean_unequal() { - call_method_boolean(true, false, "!=", true); - call_method_boolean(false, false, "!=", false); - call_method_boolean(true, true, "!=", false); - call_method_boolean(true, false, "neq", true); - call_method_boolean(false, false, "neq", false); - call_method_boolean(true, true, "neq", false); +#[test] +fn call_method_boolean_unequal() { + call_method_boolean(true, false, "!=", true); + call_method_boolean(false, false, "!=", false); + call_method_boolean(true, true, "!=", false); + call_method_boolean(true, false, "neq", true); + call_method_boolean(false, false, "neq", false); + call_method_boolean(true, true, "neq", false); } -#[test] fn call_method_array_get() { - let code = Code::from(vec!( +#[test] +fn call_method_array_get() { + let code = Code::from(vec![ OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(1 + 1) }, OpCode::Return, - )); + ]); let constants = ConstantPool::from(vec!["get"]); @@ -1487,7 +1579,7 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(666))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(666)]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); let expected_heap = Heap::from(vec![array]); @@ -1502,11 +1594,12 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: // before: array(1,2,3) // a.set(1, 42) // after: array(1,42,3) -#[test] fn call_method_array_set() { - let code = Code::from(vec!( +#[test] +fn call_method_array_set() { + let code = Code::from(vec![ OpCode::CallMethod { name: ConstantPoolIndex::new(0), arguments: Arity::new(3) }, - OpCode::Return - )); + OpCode::Return, + ]); let constants = ConstantPool::from(vec!["set"]); let globals = Globals::new(); @@ -1516,9 +1609,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: let mut state = State::minimal(); let mut output: String = String::new(); - let array = HeapObject::from_pointers(vec!(Pointer::from(0), - Pointer::from(1), - Pointer::from(2))); + let array = + HeapObject::from_pointers(vec![Pointer::from(0), Pointer::from(1), Pointer::from(2)]); state.instruction_pointer.set(Some(Address::from_usize(0))); @@ -1528,12 +1620,14 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: step_with(&program, &mut state, &mut output).unwrap(); - let expected_operand_stack = OperandStack::from(vec!(Pointer::from(42))); + let expected_operand_stack = OperandStack::from(vec![Pointer::from(42)]); let expected_frame_stack = FrameStack::from(Frame::new()); let expected_instruction_pointer = InstructionPointer::from(1u32); - let expected_heap = Heap::from(vec![HeapObject::from_pointers(vec!(Pointer::from(0), - Pointer::from(42), - Pointer::from(2)))]); + let expected_heap = Heap::from(vec![HeapObject::from_pointers(vec![ + Pointer::from(0), + Pointer::from(42), + Pointer::from(2), + ])]); assert_eq!(&output, "", "test output"); assert_eq!(state.operand_stack, expected_operand_stack, "test operands"); @@ -1542,7 +1636,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: assert_eq!(state.heap, expected_heap, "test memory"); } -#[test] fn call_method_null_equals() { +#[test] +fn call_method_null_equals() { call_method_on_pointers(Pointer::Null, Pointer::Null, "==", Pointer::from(true)); call_method_on_pointers(Pointer::Null, Pointer::from(1i32), "==", Pointer::from(false)); call_method_on_pointers(Pointer::from(1i32), Pointer::Null, "==", Pointer::from(false)); @@ -1552,7 +1647,8 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_on_pointers(Pointer::from(1i32), Pointer::Null, "eq", Pointer::from(false)); } -#[test] fn call_method_null_unequals() { +#[test] +fn call_method_null_unequals() { call_method_on_pointers(Pointer::Null, Pointer::Null, "!=", Pointer::from(false)); call_method_on_pointers(Pointer::Null, Pointer::from(1i32), "!=", Pointer::from(true)); call_method_on_pointers(Pointer::from(1i32), Pointer::Null, "!=", Pointer::from(true)); @@ -1561,4 +1657,3 @@ fn call_method_boolean(receiver: bool, argument: bool, operation: &str, result: call_method_on_pointers(Pointer::Null, Pointer::from(1i32), "neq", Pointer::from(true)); call_method_on_pointers(Pointer::from(1i32), Pointer::Null, "neq", Pointer::from(true)); } - diff --git a/src/tests/mod.rs b/src/tests/mod.rs index c61ae13..d23662e 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,7 +1,10 @@ -#[cfg(test)] mod parser; -#[cfg(test)] mod bytecode; -#[cfg(test)] mod interpreter; -#[cfg(test)] mod feeny; -#[cfg(test)] mod compiler; - - +#[cfg(test)] +mod bytecode; +#[cfg(test)] +mod compiler; +#[cfg(test)] +mod feeny; +#[cfg(test)] +mod interpreter; +#[cfg(test)] +mod parser; diff --git a/src/tests/parser.rs b/src/tests/parser.rs index 193c3fa..e006461 100644 --- a/src/tests/parser.rs +++ b/src/tests/parser.rs @@ -13,14 +13,14 @@ pub fn parse(input: &str) -> Result { fn parse_ok(input: &str, correct: AST) { println!("{}", input); for i in 0..input.len() { - if i%10 == 0 { + if i % 10 == 0 { print!(" "); } else { print!("{}", i % 10); } } println!(); - assert_eq!(TopLevelParser::new().parse(input), Ok(AST::Top(vec!(Box::new(correct))))); + assert_eq!(TopLevelParser::new().parse(input), Ok(AST::Top(vec!(correct)))); } #[allow(dead_code)] @@ -29,161 +29,230 @@ fn parse_err(input: &str) { assert!(TopLevelParser::new().parse(input).is_err()); } -#[test] fn test_unit() { parse_ok("null", AST::null()); } -#[test] fn test_nothing() { parse_ok("", AST::null()); } - -#[test] fn test_0() { parse_ok("0", AST::integer(0)); } -#[test] fn test_negative_0() { parse_ok("-0", AST::integer(0)); } -#[test] fn test_2() { parse_ok("2", AST::integer(2)); } -#[test] fn test_negative_2() { parse_ok("-2", AST::integer(-2)); } -#[test] fn test_42() { parse_ok("42", AST::integer(42)); } -#[test] fn test_042() { parse_ok("042", AST::integer(42)); } -#[test] fn test_00() { parse_ok("00", AST::integer(0)); } -#[test] fn test_negative_042() { parse_ok("-042", AST::integer(-42)); } -#[test] fn test_negative_00() { parse_ok("-00", AST::integer(0)); } - -#[test] fn test_underscore() { parse_ok("_", AST::access_variable(Identifier::from("_"))); } -#[test] fn test_underscore_identifier() { parse_ok("_x", AST::access_variable(Identifier::from("_x"))); } -#[test] fn test_identifier() { parse_ok("x", AST::access_variable(Identifier::from("x"))); } -#[test] fn test_identifier_with_number() { parse_ok("x1", AST::access_variable(Identifier::from("x1"))); } -#[test] fn test_multiple_underscores() { parse_ok("___", AST::access_variable(Identifier::from("___"))); } -#[test] fn test_long_identifier() { parse_ok("stuff", AST::access_variable(Identifier::from("stuff"))); } +#[test] +fn test_unit() { + parse_ok("null", AST::null()); +} +#[test] +fn test_nothing() { + parse_ok("", AST::null()); +} -#[test] fn test_true() { parse_ok("true", AST::boolean(true)); } -#[test] fn test_false() { parse_ok("false", AST::boolean(false)); } +#[test] +fn test_0() { + parse_ok("0", AST::integer(0)); +} +#[test] +fn test_negative_0() { + parse_ok("-0", AST::integer(0)); +} +#[test] +fn test_2() { + parse_ok("2", AST::integer(2)); +} +#[test] +fn test_negative_2() { + parse_ok("-2", AST::integer(-2)); +} +#[test] +fn test_42() { + parse_ok("42", AST::integer(42)); +} +#[test] +fn test_042() { + parse_ok("042", AST::integer(42)); +} +#[test] +fn test_00() { + parse_ok("00", AST::integer(0)); +} +#[test] +fn test_negative_042() { + parse_ok("-042", AST::integer(-42)); +} +#[test] +fn test_negative_00() { + parse_ok("-00", AST::integer(0)); +} -#[test] fn test_number_in_parens() { parse_ok("(1)", AST::integer(1)); } -#[test] fn test_number_in_two_parens() { parse_ok("((1))", AST::integer(1)); } -#[test] fn test_number_parens_with_whitespace() { parse_ok("( 1 )", AST::integer(1)); } +#[test] +fn test_underscore() { + parse_ok("_", AST::access_variable(Identifier::from("_"))); +} +#[test] +fn test_underscore_identifier() { + parse_ok("_x", AST::access_variable(Identifier::from("_x"))); +} +#[test] +fn test_identifier() { + parse_ok("x", AST::access_variable(Identifier::from("x"))); +} +#[test] +fn test_identifier_with_number() { + parse_ok("x1", AST::access_variable(Identifier::from("x1"))); +} +#[test] +fn test_multiple_underscores() { + parse_ok("___", AST::access_variable(Identifier::from("___"))); +} +#[test] +fn test_long_identifier() { + parse_ok("stuff", AST::access_variable(Identifier::from("stuff"))); +} -#[test] fn test_local_definition() { - parse_ok("let x = 1", - AST::variable(Identifier::from("x"),AST::integer(1))); +#[test] +fn test_true() { + parse_ok("true", AST::boolean(true)); +} +#[test] +fn test_false() { + parse_ok("false", AST::boolean(false)); } -#[test] fn test_mutation() { - parse_ok("x <- 1", - AST::assign_variable(Identifier::from("x"), AST::integer(1))); +#[test] +fn test_number_in_parens() { + parse_ok("(1)", AST::integer(1)); +} +#[test] +fn test_number_in_two_parens() { + parse_ok("((1))", AST::integer(1)); +} +#[test] +fn test_number_parens_with_whitespace() { + parse_ok("( 1 )", AST::integer(1)); } -#[test] fn test_function_no_args() { - parse_ok("function f () -> 1", - AST::function( - Identifier::from("f"), - vec!(), - AST::integer(1))); +#[test] +fn test_local_definition() { + parse_ok("let x = 1", AST::variable(Identifier::from("x"), AST::integer(1))); } -#[test] fn test_function_one_arg() { - parse_ok("function f (x) -> x", - AST::function( - Identifier::from("f"), - vec!(Identifier::from("x")), - AST::access_variable(Identifier::from("x")))); +#[test] +fn test_mutation() { + parse_ok("x <- 1", AST::assign_variable(Identifier::from("x"), AST::integer(1))); } -#[test] fn test_function_many_args() { - parse_ok("function f (x, y, z) -> x", - AST::function( - Identifier::from("f"), - vec!( - Identifier::from("x"), - Identifier::from("y"), - Identifier::from("z")), - AST::access_variable(Identifier::from("x")))); +#[test] +fn test_function_no_args() { + parse_ok("function f () -> 1", AST::function(Identifier::from("f"), vec![], AST::integer(1))); } -#[test] fn test_application_no_args() { - parse_ok("f ()", - AST::call_function( - Identifier::from("f"), - vec!())); +#[test] +fn test_function_one_arg() { + parse_ok( + "function f (x) -> x", + AST::function( + Identifier::from("f"), + vec![Identifier::from("x")], + AST::access_variable(Identifier::from("x")), + ), + ); } -#[test] fn test_application_one_arg() { - parse_ok("f (0)", - AST::call_function( - Identifier::from("f"), - vec!(AST::integer(0)))); +#[test] +fn test_function_many_args() { + parse_ok( + "function f (x, y, z) -> x", + AST::function( + Identifier::from("f"), + vec![Identifier::from("x"), Identifier::from("y"), Identifier::from("z")], + AST::access_variable(Identifier::from("x")), + ), + ); +} + +#[test] +fn test_application_no_args() { + parse_ok("f ()", AST::call_function(Identifier::from("f"), vec![])); +} + +#[test] +fn test_application_one_arg() { + parse_ok("f (0)", AST::call_function(Identifier::from("f"), vec![AST::integer(0)])); } -#[test] fn test_application_more_args() { - parse_ok("f (1, x, true)", - AST::call_function( - Identifier::from("f"), - vec!( - AST::integer(1), - AST::access_variable(Identifier::from("x")), - AST::boolean(true)))); +#[test] +fn test_application_more_args() { + parse_ok( + "f (1, x, true)", + AST::call_function( + Identifier::from("f"), + vec![AST::integer(1), AST::access_variable(Identifier::from("x")), AST::boolean(true)], + ), + ); } -#[test] fn test_application_no_spaces() { - parse_ok("f(0,-1)", - AST::call_function( - Identifier::from("f"), - vec!( - AST::integer(0), - AST::integer(-1)))); +#[test] +fn test_application_no_spaces() { + parse_ok( + "f(0,-1)", + AST::call_function(Identifier::from("f"), vec![AST::integer(0), AST::integer(-1)]), + ); } -#[test] fn test_application_more_spaces() { - parse_ok("f ( 0 , -1 )", - AST::call_function( - Identifier::from("f"), - vec!( - AST::integer(0), - AST::integer(-1)))); -} - -#[test] fn test_application_extra_comma() { - parse_ok("f(0,-1,)", - AST::call_function( - Identifier::from("f"), - vec!( - AST::integer(0), - AST::integer(-1)))); +#[test] +fn test_application_more_spaces() { + parse_ok( + "f ( 0 , -1 )", + AST::call_function(Identifier::from("f"), vec![AST::integer(0), AST::integer(-1)]), + ); } -#[test] fn test_application_just_a_comma() { parse_err("f(,)");} -#[test] fn test_application_many_extra_commas() { parse_err("f(x,,)");} +#[test] +fn test_application_extra_comma() { + parse_ok( + "f(0,-1,)", + AST::call_function(Identifier::from("f"), vec![AST::integer(0), AST::integer(-1)]), + ); +} -#[test] fn test_empty_block_is_unit() { +#[test] +fn test_application_just_a_comma() { + parse_err("f(,)"); +} +#[test] +fn test_application_many_extra_commas() { + parse_err("f(x,,)"); +} + +#[test] +fn test_empty_block_is_unit() { parse_ok("begin end", AST::null()); } -#[test] fn test_block_one_expression() { - parse_ok("begin 1 end", - AST::block(vec!(AST::integer(1)))) +#[test] +fn test_block_one_expression() { + parse_ok("begin 1 end", AST::block(vec![AST::integer(1)])) } -#[test] fn test_block_one_expression_and_semicolon() { - parse_ok("begin 1; end", - AST::block(vec!(AST::integer(1)))) +#[test] +fn test_block_one_expression_and_semicolon() { + parse_ok("begin 1; end", AST::block(vec![AST::integer(1)])) } -#[test] fn test_block_many_expressions() { - parse_ok("begin 1; 2; 3 end", - AST::block( - vec!( - AST::integer(1), - AST::integer(2), - AST::integer(3)))) +#[test] +fn test_block_many_expressions() { + parse_ok( + "begin 1; 2; 3 end", + AST::block(vec![AST::integer(1), AST::integer(2), AST::integer(3)]), + ) } -#[test] fn test_nested_block() { - parse_ok("begin 0; begin 1; 2; 3 end; 4; 5 end", - AST::block( - vec!( - AST::integer(0), - AST::block( - vec!( - AST::integer(1), - AST::integer(2), - AST::integer(3))), - AST::integer(4), - AST::integer(5)))) +#[test] +fn test_nested_block() { + parse_ok( + "begin 0; begin 1; 2; 3 end; 4; 5 end", + AST::block(vec![ + AST::integer(0), + AST::block(vec![AST::integer(1), AST::integer(2), AST::integer(3)]), + AST::integer(4), + AST::integer(5), + ]), + ) } -#[test] fn test_nested_block_two() { - parse_ok("begin \n\ +#[test] +fn test_nested_block_two() { + parse_ok( + "begin \n\ 0; \n\ begin \n\ 1; \n\ @@ -193,599 +262,624 @@ fn parse_err(input: &str) { 4; \n\ 5 \n\ end\n", - AST::block( - vec!( - AST::integer(0), - AST::block( - vec!( - AST::integer(1), - AST::integer(2), - AST::integer(3))), - AST::integer(4), - AST::integer(5)))) -} - -#[test] fn test_block_trailing_semicolon() { - parse_ok("begin 1; 2; 3; end", - AST::block( - vec!( - AST::integer(1), - AST::integer(2), - AST::integer(3)))) -} - -#[test] fn test_loop() { - parse_ok("while true do null", - AST::loop_de_loop( - AST::boolean(true), - AST::null())) -} - -#[test] fn test_conditional() { - parse_ok("if true then false else true", - AST::conditional( - AST::boolean(true), - AST::boolean(false), - AST::boolean(true))) -} - -#[test] fn test_conditional_no_alternative() { - parse_ok("if true then false", - AST::conditional( - AST::boolean(true), - AST::boolean(false), - AST::null())) -} - -#[test] fn test_conditional_so_many() { - parse_ok("if x then \ + AST::block(vec![ + AST::integer(0), + AST::block(vec![AST::integer(1), AST::integer(2), AST::integer(3)]), + AST::integer(4), + AST::integer(5), + ]), + ) +} + +#[test] +fn test_block_trailing_semicolon() { + parse_ok( + "begin 1; 2; 3; end", + AST::block(vec![AST::integer(1), AST::integer(2), AST::integer(3)]), + ) +} + +#[test] +fn test_loop() { + parse_ok("while true do null", AST::loop_de_loop(AST::boolean(true), AST::null())) +} + +#[test] +fn test_conditional() { + parse_ok( + "if true then false else true", + AST::conditional(AST::boolean(true), AST::boolean(false), AST::boolean(true)), + ) +} + +#[test] +fn test_conditional_no_alternative() { + parse_ok( + "if true then false", + AST::conditional(AST::boolean(true), AST::boolean(false), AST::null()), + ) +} + +#[test] +fn test_conditional_so_many() { + parse_ok( + "if x then \ if y then 3 else 2 \ else \ if y then 1 else 0", - AST::conditional( - AST::access_variable(Identifier::from("x")), - AST::conditional( - AST::access_variable(Identifier::from("y")), - AST::integer(3), - AST::integer(2)), - AST::conditional( - AST::access_variable(Identifier::from("y")), - AST::integer(1), - AST::integer(0)))) + AST::conditional( + AST::access_variable(Identifier::from("x")), + AST::conditional( + AST::access_variable(Identifier::from("y")), + AST::integer(3), + AST::integer(2), + ), + AST::conditional( + AST::access_variable(Identifier::from("y")), + AST::integer(1), + AST::integer(0), + ), + ), + ) } #[test] fn test_array_definition() { - parse_ok("array(10,0)", - AST::array(AST::integer(10),AST::integer(0))) + parse_ok("array(10,0)", AST::array(AST::integer(10), AST::integer(0))) } #[test] fn test_array_definition_spaces() { - parse_ok("array ( 10, 0 )", - AST::array(AST::integer(10), AST::integer(0))) + parse_ok("array ( 10, 0 )", AST::array(AST::integer(10), AST::integer(0))) } #[test] fn test_empty_object() { - parse_ok("object begin end", - AST::object(AST::null(),vec!())) + parse_ok("object begin end", AST::object(AST::null(), vec![])) } #[test] fn test_empty_object_with_superobject() { - parse_ok("object extends y begin end", - AST::object( - AST::access_variable(Identifier::from("y")), - vec!())) + parse_ok( + "object extends y begin end", + AST::object(AST::access_variable(Identifier::from("y")), vec![]), + ) } #[test] fn test_object_extending_expression() { - parse_ok("object extends if y then 1 else true begin end", - AST::object( - AST::conditional( - AST::access_variable(Identifier::from("y")), - AST::integer(1), - AST::boolean(true)), - vec!())) + parse_ok( + "object extends if y then 1 else true begin end", + AST::object( + AST::conditional( + AST::access_variable(Identifier::from("y")), + AST::integer(1), + AST::boolean(true), + ), + vec![], + ), + ) } #[test] fn test_object_extending_ad_hoc_object() { - parse_ok("object extends object begin end begin end", - AST::object( - AST::object( - AST::null(), - vec!()), - vec!())) + parse_ok( + "object extends object begin end begin end", + AST::object(AST::object(AST::null(), vec![]), vec![]), + ) } #[test] fn test_object_with_one_field() { - parse_ok("object begin let y = x; end", - AST::object( - AST::null(), - vec!( - AST::variable( - Identifier::from("y"), - AST::access_variable(Identifier::from("x")))))) + parse_ok( + "object begin let y = x; end", + AST::object( + AST::null(), + vec![AST::variable(Identifier::from("y"), AST::access_variable(Identifier::from("x")))], + ), + ) } #[test] fn test_object_with_one_method() { - parse_ok("object begin function m (x, y, z) -> y; end", - AST::object( - AST::null(), - vec!( - AST::function( - Identifier::from("m"), - vec!( - Identifier::from("x"), - Identifier::from("y"), - Identifier::from("z")), - AST::access_variable(Identifier::from("y")))))) + parse_ok( + "object begin function m (x, y, z) -> y; end", + AST::object( + AST::null(), + vec![AST::function( + Identifier::from("m"), + vec![Identifier::from("x"), Identifier::from("y"), Identifier::from("z")], + AST::access_variable(Identifier::from("y")), + )], + ), + ) } #[test] fn test_object_with_an_operator() { - parse_ok("object begin function + (y) -> y; end", - AST::object( - AST::null(), - vec!(AST::operator( - Operator::Addition, - vec!(Identifier::from("y")), - AST::access_variable(Identifier::from("y")))))) + parse_ok( + "object begin function + (y) -> y; end", + AST::object( + AST::null(), + vec![AST::operator( + Operator::Addition, + vec![Identifier::from("y")], + AST::access_variable(Identifier::from("y")), + )], + ), + ) } #[test] fn test_object_with_many_members() { - parse_ok("object begin \ + parse_ok( + "object begin \ let a = x; \ let b = true; \ function m (x, y, z) -> y; \ function id (x) -> x; \ function me () -> this; \ end", - AST::object( - AST::null(), - vec!( - AST::variable( - Identifier::from("a"), - AST::access_variable(Identifier::from("x"))), - AST::variable( - Identifier::from("b"), - AST::boolean(true)), - AST::function( - Identifier::from("m"), - vec!( - Identifier::from("x"), - Identifier::from("y"), - Identifier::from("z")), - AST::access_variable(Identifier::from("y"))), - AST::function( - Identifier::from("id"), - vec!(Identifier::from("x")), - AST::access_variable(Identifier::from("x"))), - AST::function( - Identifier::from("me"), - vec!(), - AST::access_variable(Identifier::from("this")))))); -} - -#[test] fn test_field_access_from_identifier () { - parse_ok("a.b", - AST::access_field( - AST::access_variable(Identifier::from("a")), - Identifier::from("b"))); -} - -#[test] fn test_field_access_from_number () { - parse_ok("1.b", - AST::access_field( - AST::integer(1), - Identifier::from("b"))); -} - -#[test] fn test_field_access_from_boolean () { - parse_ok("true.b", - AST::access_field( - AST::boolean(true), - Identifier::from("b"))); -} - -#[test] fn test_field_access_from_parenthesized_expression () { - parse_ok("(if x then 1 else 2).b", - AST::access_field( - AST::conditional( - AST::access_variable(Identifier::from("x")), - AST::integer(1), - AST::integer(2)), - Identifier::from("b"))); -} - -#[test] fn test_field_chain_access () { - parse_ok("a.b.c.d", - AST::access_field( - AST::access_field( - AST::access_field( - AST::access_variable(Identifier::from("a")), - Identifier::from("b")), - Identifier::from("c")), - Identifier::from("d"))); -} - -#[test] fn test_field_mutation_from_identifier () { - parse_ok("a.b <- 1", - AST::assign_field( - AST::access_variable(Identifier::from("a")), - Identifier::from("b"), - AST::integer(1))); -} - -#[test] fn test_method_call_from_identifier () { - parse_ok("a.b (1)", - AST::call_method( - AST::access_variable(Identifier::from("a")), - Identifier::from("b"), - vec!(AST::integer(1)))); -} - -#[test] fn test_method_call_to_operator () { - parse_ok("a.+(1)", - AST::call_operator( - AST::access_variable(Identifier::from("a")), - Operator::Addition, - vec!(AST::integer(1)))); -} - -#[test] fn test_array_access () { - parse_ok("a[1]", - AST::access_array( - AST::access_variable(Identifier::from("a")), - AST::integer(1))); -} - -#[test] fn test_array_access_from_object () { - parse_ok("a.b[1]", - AST::access_array( - AST::access_field( - AST::access_variable(Identifier::from("a")), - Identifier::from("b")), - AST::integer(1))); -} - -#[test] fn test_array_access_from_array () { - parse_ok("a[b][1]", - AST::access_array( - AST::access_array( - AST::access_variable(Identifier::from("a")), - AST::access_variable(Identifier::from("b"))), - AST::integer(1))); + AST::object( + AST::null(), + vec![ + AST::variable(Identifier::from("a"), AST::access_variable(Identifier::from("x"))), + AST::variable(Identifier::from("b"), AST::boolean(true)), + AST::function( + Identifier::from("m"), + vec![Identifier::from("x"), Identifier::from("y"), Identifier::from("z")], + AST::access_variable(Identifier::from("y")), + ), + AST::function( + Identifier::from("id"), + vec![Identifier::from("x")], + AST::access_variable(Identifier::from("x")), + ), + AST::function( + Identifier::from("me"), + vec![], + AST::access_variable(Identifier::from("this")), + ), + ], + ), + ); +} + +#[test] +fn test_field_access_from_identifier() { + parse_ok( + "a.b", + AST::access_field(AST::access_variable(Identifier::from("a")), Identifier::from("b")), + ); +} + +#[test] +fn test_field_access_from_number() { + parse_ok("1.b", AST::access_field(AST::integer(1), Identifier::from("b"))); +} + +#[test] +fn test_field_access_from_boolean() { + parse_ok("true.b", AST::access_field(AST::boolean(true), Identifier::from("b"))); +} + +#[test] +fn test_field_access_from_parenthesized_expression() { + parse_ok( + "(if x then 1 else 2).b", + AST::access_field( + AST::conditional( + AST::access_variable(Identifier::from("x")), + AST::integer(1), + AST::integer(2), + ), + Identifier::from("b"), + ), + ); } -#[test] fn test_array_call_method_on_member () { - parse_ok("a[b].c(1)", - AST::call_method( - AST::access_array( - AST::access_variable(Identifier::from("a")), - AST::access_variable(Identifier::from("b"))), - Identifier::from("c"), - vec!(AST::integer(1)))); +#[test] +fn test_field_chain_access() { + parse_ok( + "a.b.c.d", + AST::access_field( + AST::access_field( + AST::access_field( + AST::access_variable(Identifier::from("a")), + Identifier::from("b"), + ), + Identifier::from("c"), + ), + Identifier::from("d"), + ), + ); } -#[test] fn test_array_access_member_of_member () { - parse_ok("a[b].a", - AST::access_field( - AST::access_array( - AST::access_variable(Identifier::from("a")), - AST::access_variable(Identifier::from("b"))), - Identifier::from("a"))); +#[test] +fn test_field_mutation_from_identifier() { + parse_ok( + "a.b <- 1", + AST::assign_field( + AST::access_variable(Identifier::from("a")), + Identifier::from("b"), + AST::integer(1), + ), + ); } -#[test] fn test_array_access_with_array_access_as_index () { - parse_ok("a[b[c]]", - AST::access_array( - AST::access_variable(Identifier::from("a")), - AST::access_array( - AST::access_variable(Identifier::from("b")), - AST::access_variable(Identifier::from("c"))))); +#[test] +fn test_method_call_from_identifier() { + parse_ok( + "a.b (1)", + AST::call_method( + AST::access_variable(Identifier::from("a")), + Identifier::from("b"), + vec![AST::integer(1)], + ), + ); } -#[test] fn test_array_access_from_function_call () { - parse_ok("f(0,0)[x]", - AST::access_array( - AST::call_function( - Identifier::from("f"), - vec!( - AST::integer(0), - AST::integer(0))), - AST::access_variable(Identifier::from("x")))); +#[test] +fn test_method_call_to_operator() { + parse_ok( + "a.+(1)", + AST::call_operator( + AST::access_variable(Identifier::from("a")), + Operator::Addition, + vec![AST::integer(1)], + ), + ); } -#[test] fn test_print_call_with_arguments() { - parse_ok("print(\"~ ~ ~\", 1, true, x)", - AST::print( - "~ ~ ~".to_string(), - vec!( - AST::integer(1), - AST::boolean(true), - AST::access_variable(Identifier::from("x"))))); +#[test] +fn test_array_access() { + parse_ok( + "a[1]", + AST::access_array(AST::access_variable(Identifier::from("a")), AST::integer(1)), + ); } -#[test] fn test_print_call_without_arguments() { - parse_ok("print(\"~ ~ ~\")", - AST::print("~ ~ ~".to_string(),vec!())); +#[test] +fn test_array_access_from_object() { + parse_ok( + "a.b[1]", + AST::access_array( + AST::access_field(AST::access_variable(Identifier::from("a")), Identifier::from("b")), + AST::integer(1), + ), + ); +} + +#[test] +fn test_array_access_from_array() { + parse_ok( + "a[b][1]", + AST::access_array( + AST::access_array( + AST::access_variable(Identifier::from("a")), + AST::access_variable(Identifier::from("b")), + ), + AST::integer(1), + ), + ); +} + +#[test] +fn test_array_call_method_on_member() { + parse_ok( + "a[b].c(1)", + AST::call_method( + AST::access_array( + AST::access_variable(Identifier::from("a")), + AST::access_variable(Identifier::from("b")), + ), + Identifier::from("c"), + vec![AST::integer(1)], + ), + ); +} + +#[test] +fn test_array_access_member_of_member() { + parse_ok( + "a[b].a", + AST::access_field( + AST::access_array( + AST::access_variable(Identifier::from("a")), + AST::access_variable(Identifier::from("b")), + ), + Identifier::from("a"), + ), + ); +} + +#[test] +fn test_array_access_with_array_access_as_index() { + parse_ok( + "a[b[c]]", + AST::access_array( + AST::access_variable(Identifier::from("a")), + AST::access_array( + AST::access_variable(Identifier::from("b")), + AST::access_variable(Identifier::from("c")), + ), + ), + ); } -#[test] fn test_print_call_string() { - parse_ok("print(\"hello world\")", - AST::print("hello world".to_string(),vec!())); +#[test] +fn test_array_access_from_function_call() { + parse_ok( + "f(0,0)[x]", + AST::access_array( + AST::call_function(Identifier::from("f"), vec![AST::integer(0), AST::integer(0)]), + AST::access_variable(Identifier::from("x")), + ), + ); } -#[test] fn test_print_call_empty_string() { - parse_ok("print(\"\")", - AST::print(String::new(),vec!())); +#[test] +fn test_print_call_with_arguments() { + parse_ok( + "print(\"~ ~ ~\", 1, true, x)", + AST::print( + "~ ~ ~".to_string(), + vec![AST::integer(1), AST::boolean(true), AST::access_variable(Identifier::from("x"))], + ), + ); } -#[test] fn test_two_prints() { - parse_ok("begin print(\"\"); print(\"\"); end", - AST::block(vec!( - AST::print(String::new(),vec!()), - AST::print(String::new(),vec!()), - ))) +#[test] +fn test_print_call_without_arguments() { + parse_ok("print(\"~ ~ ~\")", AST::print("~ ~ ~".to_string(), vec![])); } -#[test] fn test_print_call_escape_newline() { - parse_ok("print(\"\\n\")", - AST::print("\\n".to_string(),vec!())); +#[test] +fn test_print_call_string() { + parse_ok("print(\"hello world\")", AST::print("hello world".to_string(), vec![])); } -#[test] fn test_print_call_escape_tab() { - parse_ok("print(\"\\t\")", - AST::print("\\t".to_string(),vec!())); +#[test] +fn test_print_call_empty_string() { + parse_ok("print(\"\")", AST::print(String::new(), vec![])); } -#[test] fn test_print_call_escape_return() { - parse_ok("print(\"\\r\")", - AST::print("\\r".to_string(),vec!())); +#[test] +fn test_two_prints() { + parse_ok( + "begin print(\"\"); print(\"\"); end", + AST::block(vec![AST::print(String::new(), vec![]), AST::print(String::new(), vec![])]), + ) } -#[test] fn test_print_call_escape_backslash() { - parse_ok("print(\"\\\\\")", - AST::print("\\\\".to_string(),vec!())); +#[test] +fn test_print_call_escape_newline() { + parse_ok("print(\"\\n\")", AST::print("\\n".to_string(), vec![])); } -#[test] fn test_print_call_botched_escape() { parse_err("print(\"\\\")"); } -#[test] fn test_print_call_invalid_escape() { parse_err("print(\"\\a\")"); } +#[test] +fn test_print_call_escape_tab() { + parse_ok("print(\"\\t\")", AST::print("\\t".to_string(), vec![])); +} +#[test] +fn test_print_call_escape_return() { + parse_ok("print(\"\\r\")", AST::print("\\r".to_string(), vec![])); +} -#[test] fn test_simple_disjunction() { - parse_ok("true | false", - AST::operation( - Operator::Disjunction, - AST::boolean(true), - AST::boolean(false))); +#[test] +fn test_print_call_escape_backslash() { + parse_ok("print(\"\\\\\")", AST::print("\\\\".to_string(), vec![])); } -#[test] fn test_double_disjunction() { - parse_ok("true | false | true", - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Disjunction, - AST::boolean(true), - AST::boolean(false)), - AST::boolean(true))); +#[test] +fn test_print_call_botched_escape() { + parse_err("print(\"\\\")"); +} +#[test] +fn test_print_call_invalid_escape() { + parse_err("print(\"\\a\")"); } -#[test] fn test_simple_conjunction() { - parse_ok("true & false", - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false))); +#[test] +fn test_simple_disjunction() { + parse_ok( + "true | false", + AST::operation(Operator::Disjunction, AST::boolean(true), AST::boolean(false)), + ); } -#[test] fn test_double_conjunction() { - parse_ok("true & false & true", - AST::operation( - Operator::Conjunction, - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)), - AST::boolean(true))); +#[test] +fn test_double_disjunction() { + parse_ok( + "true | false | true", + AST::operation( + Operator::Disjunction, + AST::operation(Operator::Disjunction, AST::boolean(true), AST::boolean(false)), + AST::boolean(true), + ), + ); } -#[test] fn test_simple_equality() { - parse_ok("true == false", - AST::operation( - Operator::Equality, - AST::boolean(true), - AST::boolean(false))); +#[test] +fn test_simple_conjunction() { + parse_ok( + "true & false", + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ); } +#[test] +fn test_double_conjunction() { + parse_ok( + "true & false & true", + AST::operation( + Operator::Conjunction, + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + AST::boolean(true), + ), + ); +} -#[test] fn test_simple_inequality() { - parse_ok("true != false", - AST::operation( - Operator::Inequality, - AST::boolean(true), - AST::boolean(false))); +#[test] +fn test_simple_equality() { + parse_ok( + "true == false", + AST::operation(Operator::Equality, AST::boolean(true), AST::boolean(false)), + ); } -#[test] fn test_disjunction_and_conjunction() { +#[test] +fn test_simple_inequality() { + parse_ok( + "true != false", + AST::operation(Operator::Inequality, AST::boolean(true), AST::boolean(false)), + ); +} + +#[test] +fn test_disjunction_and_conjunction() { //or (true, (true & false & false))) - parse_ok("true | true & false", - AST::operation( - Operator::Disjunction, - AST::boolean(true), - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)))); + parse_ok( + "true | true & false", + AST::operation( + Operator::Disjunction, + AST::boolean(true), + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ), + ); } -#[test] fn test_disjunction_and_conjunctions() { +#[test] +fn test_disjunction_and_conjunctions() { //or (true, (true & false & false))) - parse_ok("true & false | true & false", - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)), - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)))); -} - -#[test] fn test_disjunctions_and_conjunctions() { + parse_ok( + "true & false | true & false", + AST::operation( + Operator::Disjunction, + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ), + ); +} + +#[test] +fn test_disjunctions_and_conjunctions() { //or (true, (true & false & false))) - parse_ok("true & false | true & false | true & false", - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)), - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false))), - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)))); -} - -#[test] fn test_more_disjunctions_and_more_conjunctions() { + parse_ok( + "true & false | true & false | true & false", + AST::operation( + Operator::Disjunction, + AST::operation( + Operator::Disjunction, + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ), + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ), + ); +} + +#[test] +fn test_more_disjunctions_and_more_conjunctions() { //or (true, (true & false & false))) - parse_ok("true & false & true | true & true & false & true | true & false", - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Disjunction, - AST::operation( - Operator::Conjunction, - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)), - AST::boolean(true)), - AST::operation( - Operator::Conjunction, - AST::operation( - Operator::Conjunction, - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(true)), - AST::boolean(false)), - AST::boolean(true))), - AST::operation( - Operator::Conjunction, - AST::boolean(true), - AST::boolean(false)))); -} - -#[test] fn test_simple_addition() { - parse_ok("1 + 2", - AST::operation( - Operator::Addition, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_addition_to_field_object() { - parse_ok("a.x + 2", - AST::operation( - Operator::Addition, - AST::access_field( - AST::access_variable(Identifier::from("a")), - Identifier::from("x")), - AST::integer(2))); -} - -#[test] fn test_simple_subtraction() { - parse_ok("1 - 2", - AST::operation( - Operator::Subtraction, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_multiplication() { - parse_ok("1 * 2", - AST::operation( - Operator::Multiplication, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_module() { - parse_ok("1 % 2", - AST::operation( - Operator::Module, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_division() { - parse_ok("1 / 2", - AST::operation( - Operator::Division, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_less_than() { - parse_ok("1 < 2", - AST::operation( - Operator::Less, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_less_or_equal() { - parse_ok("1 <= 2", - AST::operation( - Operator::LessEqual, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_greater_than() { - parse_ok("1 > 2", - AST::operation( - Operator::Greater, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_simple_greater_or_equal() { - parse_ok("1 >= 2", - AST::operation( - Operator::GreaterEqual, - AST::integer(1), - AST::integer(2))); -} - -#[test] fn test_comment() { + parse_ok( + "true & false & true | true & true & false & true | true & false", + AST::operation( + Operator::Disjunction, + AST::operation( + Operator::Disjunction, + AST::operation( + Operator::Conjunction, + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + AST::boolean(true), + ), + AST::operation( + Operator::Conjunction, + AST::operation( + Operator::Conjunction, + AST::operation( + Operator::Conjunction, + AST::boolean(true), + AST::boolean(true), + ), + AST::boolean(false), + ), + AST::boolean(true), + ), + ), + AST::operation(Operator::Conjunction, AST::boolean(true), AST::boolean(false)), + ), + ); +} + +#[test] +fn test_simple_addition() { + parse_ok("1 + 2", AST::operation(Operator::Addition, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_addition_to_field_object() { + parse_ok( + "a.x + 2", + AST::operation( + Operator::Addition, + AST::access_field(AST::access_variable(Identifier::from("a")), Identifier::from("x")), + AST::integer(2), + ), + ); +} + +#[test] +fn test_simple_subtraction() { + parse_ok("1 - 2", AST::operation(Operator::Subtraction, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_multiplication() { + parse_ok("1 * 2", AST::operation(Operator::Multiplication, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_module() { + parse_ok("1 % 2", AST::operation(Operator::Module, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_division() { + parse_ok("1 / 2", AST::operation(Operator::Division, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_less_than() { + parse_ok("1 < 2", AST::operation(Operator::Less, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_less_or_equal() { + parse_ok("1 <= 2", AST::operation(Operator::LessEqual, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_greater_than() { + parse_ok("1 > 2", AST::operation(Operator::Greater, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_simple_greater_or_equal() { + parse_ok("1 >= 2", AST::operation(Operator::GreaterEqual, AST::integer(1), AST::integer(2))); +} + +#[test] +fn test_comment() { parse_ok("/* a */", AST::null()); } -#[test] fn test_comment_in_expression() { - parse_ok("1 + /* a */ 2", - AST::operation( - Operator::Addition, - AST::integer(1), - AST::integer(2))); +#[test] +fn test_comment_in_expression() { + parse_ok("1 + /* a */ 2", AST::operation(Operator::Addition, AST::integer(1), AST::integer(2))); } -#[test] fn test_multiline_comment() { +#[test] +fn test_multiline_comment() { parse_ok("/* \n\n\n */", AST::null()); -} \ No newline at end of file +} diff --git a/tests/bc_test_1/hello_world.fml b/tests/bc_test_1/hello_world.fml index a83c32f..90e1a2e 100644 --- a/tests/bc_test_1/hello_world.fml +++ b/tests/bc_test_1/hello_world.fml @@ -1 +1,2 @@ -print("Hello world!\n"); \ No newline at end of file +// > Hello world! +print("Hello world!\n"); diff --git a/tests/bc_test_1/push_pop.fml b/tests/bc_test_1/push_pop.fml index 4f15424..89d22dd 100644 --- a/tests/bc_test_1/push_pop.fml +++ b/tests/bc_test_1/push_pop.fml @@ -1,4 +1,8 @@ +// > 1 2 3 print("~ ~ ~\n", 1, 2, 3); +// > -1 -2 -3 print("~ ~ ~\n", -1, -2, -3); +// > null print("~\n", null); -print("~ ~\n", true, false); \ No newline at end of file +// > true false +print("~ ~\n", true, false); diff --git a/tests/bc_test_2/condition.fml b/tests/bc_test_2/condition.fml index 5e310b6..7815170 100644 --- a/tests/bc_test_2/condition.fml +++ b/tests/bc_test_2/condition.fml @@ -1,5 +1,7 @@ -let x = 1; -let y = true; -let z = null; +// > correct +if true then print("correct\n") +else print("incorrect\n"); -print("x=~ y=~ z=~\n", z, y, x); \ No newline at end of file +// > correct +if false then print("incorrect\n") +else print("correct\n"); diff --git a/tests/bc_test_2/function0.fml b/tests/bc_test_2/function0.fml index 5c0e746..9196326 100644 --- a/tests/bc_test_2/function0.fml +++ b/tests/bc_test_2/function0.fml @@ -1,2 +1,3 @@ function zero () -> 0; -print("~\n", zero()) \ No newline at end of file +// > 0 +print("~\n", zero()) diff --git a/tests/bc_test_2/function1.fml b/tests/bc_test_2/function1.fml index 1a0eac7..30c54ef 100644 --- a/tests/bc_test_2/function1.fml +++ b/tests/bc_test_2/function1.fml @@ -1,2 +1,3 @@ function one (x) -> x; -print("~\n", one(1)) \ No newline at end of file +// > 1 +print("~\n", one(1)) diff --git a/tests/bc_test_2/function2.fml b/tests/bc_test_2/function2.fml index e2119cc..63ac6dc 100644 --- a/tests/bc_test_2/function2.fml +++ b/tests/bc_test_2/function2.fml @@ -1,2 +1,3 @@ function one () -> 1; -print("~\n", one()) \ No newline at end of file +// > 1 +print("~\n", one()) diff --git a/tests/bc_test_2/function_globals.fml b/tests/bc_test_2/function_globals.fml index 3a0d682..2dc7944 100644 --- a/tests/bc_test_2/function_globals.fml +++ b/tests/bc_test_2/function_globals.fml @@ -1,7 +1,10 @@ +let d = null; + function f() -> let d = 5; let a = 1; let b = 2; let c = 3; + // > 1 2 3 null print("~ ~ ~ ~\n", a, b, c, d); -f() \ No newline at end of file +f() diff --git a/tests/bc_test_2/function_with_globals.fml b/tests/bc_test_2/function_with_globals.fml index d21ca4b..12a09b9 100644 --- a/tests/bc_test_2/function_with_globals.fml +++ b/tests/bc_test_2/function_with_globals.fml @@ -5,9 +5,13 @@ let z = 3; function f(y) -> begin let z = 5; + // > x=1 print("x=~\n", x); + // > y=4 print("y=~\n", y); + // > z=5 print("z=~\n", z); end; -print("~\n", f(4)) \ No newline at end of file +// > null +print("~\n", f(4)) diff --git a/tests/bc_test_2/function_with_locals.fml b/tests/bc_test_2/function_with_locals.fml index 1fc646e..2e56300 100644 --- a/tests/bc_test_2/function_with_locals.fml +++ b/tests/bc_test_2/function_with_locals.fml @@ -1,5 +1,7 @@ function left (x, y) -> x; function right (x, y) -> y; +// > true print("~\n", left(true, false)); -print("~\n", right(false, true)); \ No newline at end of file +// > true +print("~\n", right(false, true)); diff --git a/tests/bc_test_2/globals.fml b/tests/bc_test_2/globals.fml index 5e310b6..e2b77f1 100644 --- a/tests/bc_test_2/globals.fml +++ b/tests/bc_test_2/globals.fml @@ -2,4 +2,5 @@ let x = 1; let y = true; let z = null; -print("x=~ y=~ z=~\n", z, y, x); \ No newline at end of file +// > x=null y=true z=1 +print("x=~ y=~ z=~\n", z, y, x); diff --git a/tests/bc_test_2/locals.fml b/tests/bc_test_2/locals.fml index bf095f2..7b5da9a 100644 --- a/tests/bc_test_2/locals.fml +++ b/tests/bc_test_2/locals.fml @@ -3,5 +3,6 @@ let x = 1; let y = 2; let z = 3; +// > x=3 y=2 z=1 print("x=~ y=~ z=~\n", z, y, x); -end; \ No newline at end of file +end; diff --git a/tests/bc_test_2/loop.fml b/tests/bc_test_2/loop.fml index fff363c..3e53be7 100644 --- a/tests/bc_test_2/loop.fml +++ b/tests/bc_test_2/loop.fml @@ -1,2 +1,3 @@ while false do print("nothing\n"); +// > something print("something\n") diff --git a/tests/bc_test_2/recursive_function.fml b/tests/bc_test_2/recursive_function.fml index 5d8b388..96379ac 100644 --- a/tests/bc_test_2/recursive_function.fml +++ b/tests/bc_test_2/recursive_function.fml @@ -10,5 +10,11 @@ begin if x then decide(false) else decide(true) end; +// > decide(true) +// > invert(true) +// > decide(false) +// > false print("~\n", decide(true)); -print("~\n", decide(false)) \ No newline at end of file +// > decide(false) +// > false +print("~\n", decide(false)) diff --git a/tests/bc_test_3/arrays.fml b/tests/bc_test_3/arrays.fml index 6d83044..b941ea2 100644 --- a/tests/bc_test_3/arrays.fml +++ b/tests/bc_test_3/arrays.fml @@ -16,7 +16,7 @@ begin let index = 0; while index < length do begin - print("arr[~]: ~ \n", index, arr[index]); + print("arr[~]: ~\n", index, arr[index]); index <- index + 1; end; end; @@ -30,4 +30,4 @@ begin // > arr[7]: 128 // > arr[8]: 256 // > arr[9]: 512 -end; \ No newline at end of file +end; diff --git a/tests/bc_test_3/dispatch.fml b/tests/bc_test_3/dispatch.fml index 233c780..8adf084 100644 --- a/tests/bc_test_3/dispatch.fml +++ b/tests/bc_test_3/dispatch.fml @@ -26,7 +26,7 @@ begin print("~\n", cell); // > object(..=object(..=object(value=0))) cell.pretty_print(); - // > [!1] + // > [!0] cell.set(42); print("~\n", cell.get()); // > 42 @@ -43,6 +43,6 @@ begin print("~ == ~ => ~\n", cell, 43, cell == 43); // > object(..=object(..=object(value=43))) == 43 => true print("~ != ~ => ~\n", cell, 43, cell != 43); - // > object(..=object(..=object(value=43))) == 43 => false + // > object(..=object(..=object(value=43))) != 43 => false end; diff --git a/tests/bc_test_3/methods.fml b/tests/bc_test_3/methods.fml index 791563e..eb822d0 100644 --- a/tests/bc_test_3/methods.fml +++ b/tests/bc_test_3/methods.fml @@ -29,6 +29,6 @@ begin print("obj.y=~\n", obj.y); // > null=null // > obj.x=false - // > obj.x=null + // > obj.y=null end; diff --git a/tests/bc_test_3/object.fml b/tests/bc_test_3/object.fml index 7de0467..8189f12 100644 --- a/tests/bc_test_3/object.fml +++ b/tests/bc_test_3/object.fml @@ -26,4 +26,4 @@ begin end; print("~\n", objy); end; -// > object(..=object(), x=3, z=2, y=4) \ No newline at end of file +// > object(..=object(), x=3, y=4, z=2) diff --git a/tests/bc_test_3/operators.fml b/tests/bc_test_3/operators.fml index 49d7286..cf86f61 100644 --- a/tests/bc_test_3/operators.fml +++ b/tests/bc_test_3/operators.fml @@ -24,11 +24,11 @@ print("~ != ~ => ~\n", 1, -2, 1 != -2); // > 1 != -2 => true print("~ == ~ => ~\n", 1, null, 1 == null); // > 1 == null => false -print("~ != ~ => ~\n", 1, null, 1 == null); +print("~ != ~ => ~\n", 1, null, 1 != null); // > 1 != null => true print("~ == ~ => ~\n", 1, true, 1 == true); // > 1 == true => false -print("~ != ~ => ~\n", 1, true, 1 == true); +print("~ != ~ => ~\n", 1, true, 1 != true); // > 1 != true => true print("~ == ~ => ~\n", 1, (object begin end), 1 == (object begin end)); // > 1 == object() => false @@ -54,7 +54,7 @@ print("~ != ~ => ~\n", true, -2, true != -2); // > true != -2 => true print("~ == ~ => ~\n", true, null, true == null); // > true == null => false -print("~ != ~ => ~\n", true, null, true == null); +print("~ != ~ => ~\n", true, null, true != null); // > true != null => true print("~ == ~ => ~\n", true, (object begin end), true == (object begin end)); // > true == object() => false @@ -71,13 +71,13 @@ print("~ != ~ => ~\n", null, -2, null != -2); // > null != -2 => true print("~ == ~ => ~\n", null, null, null == null); // > null == null => true -print("~ != ~ => ~\n", null, null, null == null); +print("~ != ~ => ~\n", null, null, null != null); // > null != null => false print("~ == ~ => ~\n", null, (object begin end), null == (object begin end)); // > null == object() => false print("~ != ~ => ~\n", null, (object begin end), null != (object begin end)); -// > null != object() => null +// > null != object() => true print("~ == ~ => ~\n", null, array(1,null), null == array(1,null)); // > null == [null] => false print("~ != ~ => ~\n", null, array(1,null), null != array(1,null)); -// > null != [null] => true \ No newline at end of file +// > null != [null] => true diff --git a/tests/bc_test_3/operators_compat.fml b/tests/bc_test_3/operators_compat.fml deleted file mode 100644 index 58da94d..0000000 --- a/tests/bc_test_3/operators_compat.fml +++ /dev/null @@ -1,83 +0,0 @@ -print("~.add(~) => ~\n", 1, -2, 1.add(-2)); -// > 1.add(-2) => -1 -print("~.sub(~) => ~\n", 1, -2, 1.sub(-2)); -// > 1.sub(-2) => 3 -print("~.mul(~) => ~\n", 1, -2, 1.mul(-2)); -// > 1.mul(-2) => -2 -print("~.div(~) => ~\n", 1, -2, 1.div(-2)); -// > 1.div(-2) => 0 -print("~.mod(%) ~ => ~\n", 1, -2, 1.mod(-2)); -// > 1.mod(-2) => 1 - -print("~.le(~) => ~\n", 1, -2, 1.le(-2)); -// > 1.le(-2) => false -print("~.lt(~) => ~\n", 1, -2, 1.lt(-2)); -// > 1.lt(-2) => false -print("~.ge(~) => ~\n", 1, -2, 1.ge(-2)); -// > 1.ge(-2) => true -print("~.gt(~) => ~\n", 1, -2, 1.gt(-2)); -// > 1.gt(-2) => true - -print("~.eq(~) => ~\n", 1, -2, 1.eq(-2)); -// > 1.eq(-2) => false -print("~.neq(~) => ~\n", 1, -2, 1.neq(-2)); -// > 1.neq(-2) => true -print("~.eq(~) => ~\n", 1, null, 1.eq(null)); -// > 1.eq(null) => false -print("~.neq(~) => ~\n", 1, null, 1.eq(null)); -// > 1.neq(null) => true -print("~.eq(~) => ~\n", 1, true, 1.eq(true)); -// > 1.eq(true) => false -print("~.neq(~) => ~\n", 1, true, 1.eq(true)); -// > 1.neq(true) => true -print("~.eq(~) => ~\n", 1, (object begin end), 1.eq((object begin end))); -// > 1.eq(object()) => false -print("~.neq(~) => ~\n", 1, (object begin end), 1.neq((object begin end))); -// > 1.neq(object()) => true -print("~.eq(~) => ~\n", 1, array(1,1), 1.eq(array(1,1))); -// > 1.eq([1]) => false -print("~.neq(~) => ~\n", 1, array(1,1), 1.neq(array(1,1))); -// > 1.neq([1]) => true - -print("~.and(~) => ~\n", true, false, true.and(false)); -// > true.and(false) => false -print("~.or(~) => ~\n", true, false, true.or(false)); -// > true.or(false) => true -print("~.eq(~) => ~\n", true, false, true.eq(false)); -// > true.eq(false) => false -print("~.neq(~) => ~\n", true, false, true.neq(false)); -// > true.neq(false) => true - -print("~.eq(~) => ~\n", true, -2, true.eq(-2)); -// > true.eq(-2) => false -print("~.neq(~) => ~\n", true, -2, true.neq(-2)); -// > true.neq(-2) => true -print("~.eq(~) => ~\n", true, null, true.eq(null)); -// > true.eq(null) => false -print("~.neq(~) => ~\n", true, null, true.eq(null)); -// > true.neq(null) => true -print("~.eq(~) => ~\n", true, (object begin end), true.eq((object begin end))); -// > true.eq(object()) => false -print("~.neq(~) => ~\n", true, (object begin end), true.neq((object begin end))); -// > true.neq(object()) => true -print("~.eq(~) => ~\n", true, array(1,true), true.eq(array(1,true))); -// > true.eq([true]) => false -print("~.neq(~) => ~\n", true, array(1,true), true.neq(array(1,true))); -// > true.neq([true]) => true - -print("~.eq(~) => ~\n", null, -2, null.eq(-2)); -// > null.eq(-2) => false -print("~.neq(~) => ~\n", null, -2, null.neq(-2)); -// > null.neq(-2) => true -print("~.eq(~) => ~\n", null, null, null.eq(null)); -// > null.eq(null) => true -print("~.neq(~) => ~\n", null, null, null.eq(null)); -// > null.neq(null) => false -print("~.eq(~) => ~\n", null, (object begin end), null.eq((object begin end))); -// > null.eq(object()) => false -print("~.neq(~) => ~\n", null, (object begin end), null.neq((object begin end))); -// > null.neq(object()) => null -print("~.eq(~) => ~\n", null, array(1,null), null.eq(array(1,null))); -// > null.eq([null]) => false -print("~.neq(~) => ~\n", null, array(1,null), null.neq(array(1,null))); -// > null.neq([null]) => true \ No newline at end of file diff --git a/tests/misc/escape.fml b/tests/misc/escape.fml index 8ab1996..2303b6d 100644 --- a/tests/misc/escape.fml +++ b/tests/misc/escape.fml @@ -6,4 +6,4 @@ print("~\~~\n", 1, 2); print("~\\~\n", 3, 4); print("\"~\"\n", 5); -print("~\t~\n", 6, 7); \ No newline at end of file +print("~\t~\n", 6, 7); diff --git a/tests/misc/fibonacci.fml b/tests/misc/fibonacci.fml index 255b4e5..12c7355 100644 --- a/tests/misc/fibonacci.fml +++ b/tests/misc/fibonacci.fml @@ -28,4 +28,4 @@ end // > 12 => 144 // > 13 => 233 // > 14 => 377 -// > 15 => 610 \ No newline at end of file +// > 15 => 610 diff --git a/tests/misc/fizzbuzz_fun.fml b/tests/misc/fizzbuzz_fun.fml index 4f431ec..3a8e868 100644 --- a/tests/misc/fizzbuzz_fun.fml +++ b/tests/misc/fizzbuzz_fun.fml @@ -30,4 +30,4 @@ begin print("~ not considered\n", i); end; -fizzbuzz(1, 15) \ No newline at end of file +fizzbuzz(1, 15) diff --git a/tests/misc/fizzbuzz_loop.fml b/tests/misc/fizzbuzz_loop.fml index ae8ba8b..f4dcbc3 100644 --- a/tests/misc/fizzbuzz_loop.fml +++ b/tests/misc/fizzbuzz_loop.fml @@ -26,4 +26,4 @@ begin i <- i + 1; end; -print("~ not considered\n", i); \ No newline at end of file +print("~ not considered\n", i); diff --git a/tests/misc/functions.fml b/tests/misc/functions.fml index bcf097b..0cfde98 100644 --- a/tests/misc/functions.fml +++ b/tests/misc/functions.fml @@ -27,4 +27,4 @@ end; print("scope before: x=~, y=~, z=~\n", x, y, z); my_scope(6, 7); -print("scope after: x=~, y=~, z=~\n", x, y, z); \ No newline at end of file +print("scope after: x=~, y=~, z=~\n", x, y, z); diff --git a/tests/misc/hello_world.fml b/tests/misc/hello_world.fml index 27182c7..c5197c5 100644 --- a/tests/misc/hello_world.fml +++ b/tests/misc/hello_world.fml @@ -1,3 +1,3 @@ // Expected output: // > Hello world! -print("Hello world!\n"); \ No newline at end of file +print("Hello world!\n"); diff --git a/tests/misc/literals.fml b/tests/misc/literals.fml index 9c6587a..86b82f0 100644 --- a/tests/misc/literals.fml +++ b/tests/misc/literals.fml @@ -4,4 +4,4 @@ // > -42 -1 0 1 42 print("~\n", null); print("~ ~\n", false, true); -print("~ ~ ~ ~ ~\n", -42, -1, 0, 1, 42); \ No newline at end of file +print("~ ~ ~ ~ ~\n", -42, -1, 0, 1, 42); diff --git a/tests/misc/loops.fml b/tests/misc/loops.fml index 8cbcdbe..4f56913 100644 --- a/tests/misc/loops.fml +++ b/tests/misc/loops.fml @@ -1,3 +1,3 @@ // Expected output: -while false do print("nothing"); \ No newline at end of file +while false do print("nothing"); diff --git a/tests/misc/variables.fml b/tests/misc/variables.fml index ff253ae..2adfc4e 100644 --- a/tests/misc/variables.fml +++ b/tests/misc/variables.fml @@ -24,4 +24,4 @@ begin print("x=~, y=~, z=~\n", x, y, z); end; -print("x=~, y=~, z=~\n", x, y, z); \ No newline at end of file +print("x=~, y=~, z=~\n", x, y, z);