Add LoadBoolean; Refactor; Improve disassembly output
This commit is contained in:
parent
85b95a56aa
commit
915340fbdb
@ -262,7 +262,7 @@ impl Local {
|
||||
pub struct ChunkDisassembler<'a> {
|
||||
name: &'a str,
|
||||
chunk: &'a Chunk,
|
||||
width: usize,
|
||||
width: Option<usize>,
|
||||
styled: bool,
|
||||
}
|
||||
|
||||
@ -271,16 +271,16 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
"",
|
||||
"Instructions",
|
||||
"------------",
|
||||
"OFFSET OPERATION INFO POSITION",
|
||||
"------ -------------- ------------------------- --------",
|
||||
"INDEX OPERATION INFO POSITION",
|
||||
"----- -------------- ------------------------- --------",
|
||||
];
|
||||
|
||||
const CONSTANT_HEADER: [&'static str; 5] = [
|
||||
"",
|
||||
"Constants",
|
||||
"---------",
|
||||
"INDEX KIND VALUE",
|
||||
"----- ----- -----",
|
||||
"INDEX VALUE ",
|
||||
"----- ---------",
|
||||
];
|
||||
|
||||
const LOCAL_HEADER: [&'static str; 5] = [
|
||||
@ -291,21 +291,29 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
"----- ---------- ------- ----- --------",
|
||||
];
|
||||
|
||||
/// The default width of the disassembly output. To correctly align the output, this should be
|
||||
/// set to the width of the longest line that the disassembler is guaranteed to produce.
|
||||
const DEFAULT_WIDTH: usize = Self::INSTRUCTION_HEADER[4].len() + 1;
|
||||
/// The default width of the disassembly output. To correctly align the output, this should
|
||||
/// return the width of the longest line that the disassembler is guaranteed to produce.
|
||||
pub fn default_width(styled: bool) -> usize {
|
||||
let longest_line = Self::INSTRUCTION_HEADER[4];
|
||||
|
||||
if styled {
|
||||
longest_line.bold().chars().count()
|
||||
} else {
|
||||
longest_line.chars().count()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(name: &'a str, chunk: &'a Chunk) -> Self {
|
||||
Self {
|
||||
name,
|
||||
chunk,
|
||||
width: Self::DEFAULT_WIDTH,
|
||||
width: None,
|
||||
styled: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn width(&mut self, width: usize) -> &mut Self {
|
||||
self.width = width;
|
||||
self.width = Some(width);
|
||||
|
||||
self
|
||||
}
|
||||
@ -317,7 +325,11 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
}
|
||||
|
||||
pub fn disassemble(&self) -> String {
|
||||
let center = |line: &str| format!("{line:^width$}\n", width = self.width);
|
||||
let width = self
|
||||
.width
|
||||
.unwrap_or_else(|| Self::default_width(self.styled))
|
||||
+ 1;
|
||||
let center = |line: &str| format!("{line:^width$}\n");
|
||||
let style = |line: String| {
|
||||
if self.styled {
|
||||
line.bold().to_string()
|
||||
@ -326,10 +338,10 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut disassembled = String::with_capacity(self.predict_length());
|
||||
let mut disassembly = String::with_capacity(self.predict_length());
|
||||
let name_line = style(center(self.name));
|
||||
|
||||
disassembled.push_str(&name_line);
|
||||
disassembly.push_str(&name_line);
|
||||
|
||||
let info_line = center(&format!(
|
||||
"{} instructions, {} constants, {} locals",
|
||||
@ -339,52 +351,53 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
));
|
||||
let styled_info_line = {
|
||||
if self.styled {
|
||||
info_line.bold().dimmed().to_string()
|
||||
info_line.dimmed().to_string()
|
||||
} else {
|
||||
info_line
|
||||
}
|
||||
};
|
||||
|
||||
disassembled.push_str(&styled_info_line);
|
||||
disassembly.push_str(&styled_info_line);
|
||||
|
||||
for line in Self::INSTRUCTION_HEADER {
|
||||
disassembled.push_str(&style(center(line)));
|
||||
disassembly.push_str(&style(center(line)));
|
||||
}
|
||||
|
||||
for (offset, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
||||
for (index, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
||||
let position = position.to_string();
|
||||
let operation = instruction.operation().to_string();
|
||||
let info_option = instruction.disassembly_info(Some(self.chunk));
|
||||
|
||||
let instruction_display = if let Some(info) = info_option {
|
||||
format!("{offset:<6} {operation:14} {info:25} {position:8}")
|
||||
format!("{index:<5} {operation:14} {info:25} {position:8}")
|
||||
} else {
|
||||
format!("{offset:<6} {operation:14} {:25} {position:8}", " ")
|
||||
format!("{index:<5} {operation:14} {:25} {position:8}", " ")
|
||||
};
|
||||
|
||||
disassembled.push_str(¢er(&instruction_display));
|
||||
disassembly.push_str(¢er(&instruction_display));
|
||||
}
|
||||
|
||||
for line in Self::CONSTANT_HEADER {
|
||||
disassembled.push_str(&style(center(line)));
|
||||
disassembly.push_str(&style(center(line)));
|
||||
}
|
||||
|
||||
for (index, value_option) in self.chunk.constants.iter().enumerate() {
|
||||
let value_kind_display = if let Some(value) = value_option {
|
||||
value.kind().to_string()
|
||||
} else {
|
||||
"empty".to_string()
|
||||
};
|
||||
let value_display = value_option
|
||||
.as_ref()
|
||||
.map(|value| value.to_string())
|
||||
.unwrap_or_else(|| "empty".to_string());
|
||||
let constant_display = format!("{index:<5} {value_kind_display:<5} {value_display:<5}");
|
||||
.unwrap_or("empty".to_string());
|
||||
let elipsis = if value_display.len() > 9 { "..." } else { "" };
|
||||
let constant_display = if value_display.len() > 9 {
|
||||
format!("{index:<5} {value_display:^7.7}{elipsis}")
|
||||
} else {
|
||||
format!("{index:<5} {value_display:10}")
|
||||
};
|
||||
|
||||
disassembled.push_str(¢er(&constant_display));
|
||||
disassembly.push_str(¢er(&constant_display));
|
||||
}
|
||||
|
||||
for line in Self::LOCAL_HEADER {
|
||||
disassembled.push_str(&style(center(line)));
|
||||
disassembly.push_str(&style(center(line)));
|
||||
}
|
||||
|
||||
for (
|
||||
@ -403,14 +416,14 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
.unwrap_or_else(|| "empty".to_string());
|
||||
let identifier_display = identifier.as_str();
|
||||
let local_display = format!(
|
||||
"{index:<5} {identifier_display:<10} {mutable:<7} {depth:<5} {register_display:<8}"
|
||||
"{index:<5} {identifier_display:10} {mutable:7} {depth:<5} {register_display:8}"
|
||||
);
|
||||
|
||||
disassembled.push_str(¢er(&local_display));
|
||||
disassembly.push_str(¢er(&local_display));
|
||||
}
|
||||
|
||||
let expected_length = self.predict_length();
|
||||
let actual_length = disassembled.len();
|
||||
let actual_length = disassembly.len();
|
||||
|
||||
if !self.styled && expected_length != actual_length {
|
||||
log::debug!(
|
||||
@ -424,7 +437,7 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
disassembled
|
||||
disassembly
|
||||
}
|
||||
|
||||
/// Predicts the capacity of the disassembled output. This is used to pre-allocate the string
|
||||
@ -440,15 +453,21 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
/// the ANSI escape codes will make the result too low. It still works as a lower bound in that
|
||||
/// case.
|
||||
fn predict_length(&self) -> usize {
|
||||
const EXTRA_LINES: usize = 2; // There is one empty line after the name of the chunk
|
||||
const EXTRA_LINES: usize = 2; // There is one info line and one empty line after the name
|
||||
|
||||
let static_line_count =
|
||||
Self::INSTRUCTION_HEADER.len() + Self::CONSTANT_HEADER.len() + Self::LOCAL_HEADER.len();
|
||||
let static_line_count = Self::INSTRUCTION_HEADER.len()
|
||||
+ Self::CONSTANT_HEADER.len()
|
||||
+ Self::LOCAL_HEADER.len()
|
||||
+ EXTRA_LINES;
|
||||
let dynamic_line_count =
|
||||
self.chunk.instructions.len() + self.chunk.constants.len() + self.chunk.locals.len();
|
||||
let total_line_count = static_line_count + dynamic_line_count + EXTRA_LINES;
|
||||
let total_line_count = static_line_count + dynamic_line_count;
|
||||
let width = self
|
||||
.width
|
||||
.unwrap_or_else(|| Self::default_width(self.styled))
|
||||
+ 1;
|
||||
|
||||
total_line_count * (self.width + 1)
|
||||
total_line_count * width
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Chunk, Span};
|
||||
use crate::{Chunk, Operation, Span};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Instruction(u32);
|
||||
@ -24,6 +24,16 @@ impl Instruction {
|
||||
instruction
|
||||
}
|
||||
|
||||
pub fn load_boolean(to_register: u8, value: bool, skip: bool) -> Instruction {
|
||||
let mut instruction = Instruction(Operation::LoadBoolean as u32);
|
||||
|
||||
instruction.set_destination(to_register);
|
||||
instruction.set_first_argument(if value { 1 } else { 0 });
|
||||
instruction.set_second_argument(if skip { 1 } else { 0 });
|
||||
|
||||
instruction
|
||||
}
|
||||
|
||||
pub fn load_constant(to_register: u8, constant_index: u8) -> Instruction {
|
||||
let mut instruction = Instruction(Operation::LoadConstant as u32);
|
||||
|
||||
@ -251,6 +261,17 @@ impl Instruction {
|
||||
|
||||
format!("R({from_register})..=R({to_register})")
|
||||
}
|
||||
Operation::LoadBoolean => {
|
||||
let to_register = self.destination();
|
||||
let boolean = if self.first_argument() == 0 {
|
||||
"false"
|
||||
} else {
|
||||
"true"
|
||||
};
|
||||
let skip = self.second_argument() != 0;
|
||||
|
||||
format!("R({to_register}) = {boolean}; if {skip} ip++",)
|
||||
}
|
||||
Operation::LoadConstant => {
|
||||
let constant_index = self.first_argument();
|
||||
|
||||
@ -405,144 +426,6 @@ impl Display for Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
const MOVE: u8 = 0b0000_0000;
|
||||
const CLOSE: u8 = 0b000_0001;
|
||||
const LOAD_CONSTANT: u8 = 0b0000_0010;
|
||||
const LOAD_LIST: u8 = 0b0000_0011;
|
||||
const DECLARE_LOCAL: u8 = 0b0000_0100;
|
||||
const GET_LOCAL: u8 = 0b0000_0101;
|
||||
const SET_LOCAL: u8 = 0b0000_0110;
|
||||
const ADD: u8 = 0b0000_0111;
|
||||
const SUBTRACT: u8 = 0b0000_1000;
|
||||
const MULTIPLY: u8 = 0b0000_1001;
|
||||
const MODULO: u8 = 0b0000_1010;
|
||||
const AND: u8 = 0b0000_1011;
|
||||
const OR: u8 = 0b0000_1100;
|
||||
const DIVIDE: u8 = 0b0000_1101;
|
||||
const NEGATE: u8 = 0b0000_1110;
|
||||
const NOT: u8 = 0b0000_1111;
|
||||
const RETURN: u8 = 0b0001_0000;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Operation {
|
||||
// Stack manipulation
|
||||
Move = MOVE as isize,
|
||||
Close = CLOSE as isize,
|
||||
|
||||
// Value loading
|
||||
LoadConstant = LOAD_CONSTANT as isize,
|
||||
LoadList = LOAD_LIST as isize,
|
||||
|
||||
// Variables
|
||||
DefineLocal = DECLARE_LOCAL as isize,
|
||||
GetLocal = GET_LOCAL as isize,
|
||||
SetLocal = SET_LOCAL as isize,
|
||||
|
||||
// Binary operations
|
||||
Add = ADD as isize,
|
||||
Subtract = SUBTRACT as isize,
|
||||
Multiply = MULTIPLY as isize,
|
||||
Divide = DIVIDE as isize,
|
||||
Modulo = MODULO as isize,
|
||||
And = AND as isize,
|
||||
Or = OR as isize,
|
||||
|
||||
// Unary operations
|
||||
Negate = NEGATE as isize,
|
||||
Not = NOT as isize,
|
||||
|
||||
// Control flow
|
||||
Return = RETURN as isize,
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
pub fn is_binary(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Operation::Add
|
||||
| Operation::Subtract
|
||||
| Operation::Multiply
|
||||
| Operation::Divide
|
||||
| Operation::Modulo
|
||||
| Operation::And
|
||||
| Operation::Or
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Operation {
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
MOVE => Operation::Move,
|
||||
CLOSE => Operation::Close,
|
||||
LOAD_CONSTANT => Operation::LoadConstant,
|
||||
LOAD_LIST => Operation::LoadList,
|
||||
DECLARE_LOCAL => Operation::DefineLocal,
|
||||
GET_LOCAL => Operation::GetLocal,
|
||||
SET_LOCAL => Operation::SetLocal,
|
||||
ADD => Operation::Add,
|
||||
SUBTRACT => Operation::Subtract,
|
||||
MULTIPLY => Operation::Multiply,
|
||||
DIVIDE => Operation::Divide,
|
||||
MODULO => Operation::Modulo,
|
||||
AND => Operation::And,
|
||||
OR => Operation::Or,
|
||||
NEGATE => Operation::Negate,
|
||||
NOT => Operation::Not,
|
||||
RETURN => Operation::Return,
|
||||
_ => panic!("Invalid operation byte: {}", byte),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Operation> for u8 {
|
||||
fn from(operation: Operation) -> Self {
|
||||
match operation {
|
||||
Operation::Move => MOVE,
|
||||
Operation::Close => CLOSE,
|
||||
Operation::LoadConstant => LOAD_CONSTANT,
|
||||
Operation::LoadList => LOAD_LIST,
|
||||
Operation::DefineLocal => DECLARE_LOCAL,
|
||||
Operation::GetLocal => GET_LOCAL,
|
||||
Operation::SetLocal => SET_LOCAL,
|
||||
Operation::Add => ADD,
|
||||
Operation::Subtract => SUBTRACT,
|
||||
Operation::Multiply => MULTIPLY,
|
||||
Operation::Divide => DIVIDE,
|
||||
Operation::Modulo => MODULO,
|
||||
Operation::And => AND,
|
||||
Operation::Or => OR,
|
||||
Operation::Negate => NEGATE,
|
||||
Operation::Not => NOT,
|
||||
Operation::Return => RETURN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Operation {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Operation::Move => write!(f, "MOVE"),
|
||||
Operation::Close => write!(f, "CLOSE"),
|
||||
Operation::LoadConstant => write!(f, "LOAD_CONSTANT"),
|
||||
Operation::LoadList => write!(f, "LOAD_LIST"),
|
||||
Operation::DefineLocal => write!(f, "DEFINE_LOCAL"),
|
||||
Operation::GetLocal => write!(f, "GET_LOCAL"),
|
||||
Operation::SetLocal => write!(f, "SET_LOCAL"),
|
||||
Operation::Add => write!(f, "ADD"),
|
||||
Operation::Subtract => write!(f, "SUBTRACT"),
|
||||
Operation::Multiply => write!(f, "MULTIPLY"),
|
||||
Operation::Divide => write!(f, "DIVIDE"),
|
||||
Operation::Modulo => write!(f, "MODULO"),
|
||||
Operation::And => write!(f, "AND"),
|
||||
Operation::Or => write!(f, "OR"),
|
||||
Operation::Negate => write!(f, "NEGATE"),
|
||||
Operation::Not => write!(f, "NOT"),
|
||||
Operation::Return => write!(f, "RETURN"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -4,6 +4,7 @@ mod dust_error;
|
||||
mod identifier;
|
||||
mod instruction;
|
||||
mod lexer;
|
||||
mod operation;
|
||||
mod parser;
|
||||
mod token;
|
||||
mod r#type;
|
||||
@ -16,8 +17,9 @@ pub use chunk::{Chunk, ChunkError, Local};
|
||||
pub use constructor::Constructor;
|
||||
pub use dust_error::{AnnotatedError, DustError};
|
||||
pub use identifier::Identifier;
|
||||
pub use instruction::{Instruction, Operation};
|
||||
pub use instruction::Instruction;
|
||||
pub use lexer::{lex, LexError, Lexer};
|
||||
pub use operation::Operation;
|
||||
pub use parser::{parse, ParseError, Parser};
|
||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||
pub use token::{Token, TokenKind, TokenOwned};
|
||||
|
150
dust-lang/src/operation.rs
Normal file
150
dust-lang/src/operation.rs
Normal file
@ -0,0 +1,150 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
const MOVE: u8 = 0b0000_0000;
|
||||
const CLOSE: u8 = 0b000_0001;
|
||||
const LOAD_BOOLEAN: u8 = 0b0000_0010;
|
||||
const LOAD_CONSTANT: u8 = 0b0000_0011;
|
||||
const LOAD_LIST: u8 = 0b0000_0100;
|
||||
const DECLARE_LOCAL: u8 = 0b0000_0101;
|
||||
const GET_LOCAL: u8 = 0b0000_0110;
|
||||
const SET_LOCAL: u8 = 0b0000_0111;
|
||||
const ADD: u8 = 0b0000_1000;
|
||||
const SUBTRACT: u8 = 0b0000_1001;
|
||||
const MULTIPLY: u8 = 0b0000_1010;
|
||||
const MODULO: u8 = 0b0000_1011;
|
||||
const AND: u8 = 0b0000_1100;
|
||||
const OR: u8 = 0b0000_1101;
|
||||
const DIVIDE: u8 = 0b0000_1110;
|
||||
const NEGATE: u8 = 0b0000_1111;
|
||||
const NOT: u8 = 0b0001_0000;
|
||||
const RETURN: u8 = 0b0001_0001;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Operation {
|
||||
// Stack manipulation
|
||||
Move = MOVE as isize,
|
||||
Close = CLOSE as isize,
|
||||
|
||||
// Value loading
|
||||
LoadBoolean = LOAD_BOOLEAN as isize,
|
||||
LoadConstant = LOAD_CONSTANT as isize,
|
||||
LoadList = LOAD_LIST as isize,
|
||||
|
||||
// Variables
|
||||
DefineLocal = DECLARE_LOCAL as isize,
|
||||
GetLocal = GET_LOCAL as isize,
|
||||
SetLocal = SET_LOCAL as isize,
|
||||
|
||||
// Binary operations
|
||||
Add = ADD as isize,
|
||||
Subtract = SUBTRACT as isize,
|
||||
Multiply = MULTIPLY as isize,
|
||||
Divide = DIVIDE as isize,
|
||||
Modulo = MODULO as isize,
|
||||
And = AND as isize,
|
||||
Or = OR as isize,
|
||||
|
||||
// Unary operations
|
||||
Negate = NEGATE as isize,
|
||||
Not = NOT as isize,
|
||||
|
||||
// Control flow
|
||||
Return = RETURN as isize,
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
pub fn is_binary(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Operation::Add
|
||||
| Operation::Subtract
|
||||
| Operation::Multiply
|
||||
| Operation::Divide
|
||||
| Operation::Modulo
|
||||
| Operation::And
|
||||
| Operation::Or
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Operation {
|
||||
fn from(byte: u8) -> Self {
|
||||
match byte {
|
||||
MOVE => Operation::Move,
|
||||
CLOSE => Operation::Close,
|
||||
LOAD_BOOLEAN => Operation::LoadBoolean,
|
||||
LOAD_CONSTANT => Operation::LoadConstant,
|
||||
LOAD_LIST => Operation::LoadList,
|
||||
DECLARE_LOCAL => Operation::DefineLocal,
|
||||
GET_LOCAL => Operation::GetLocal,
|
||||
SET_LOCAL => Operation::SetLocal,
|
||||
ADD => Operation::Add,
|
||||
SUBTRACT => Operation::Subtract,
|
||||
MULTIPLY => Operation::Multiply,
|
||||
DIVIDE => Operation::Divide,
|
||||
MODULO => Operation::Modulo,
|
||||
AND => Operation::And,
|
||||
OR => Operation::Or,
|
||||
NEGATE => Operation::Negate,
|
||||
NOT => Operation::Not,
|
||||
RETURN => Operation::Return,
|
||||
_ => {
|
||||
if cfg!(test) {
|
||||
panic!("Invalid operation byte: {}", byte)
|
||||
} else {
|
||||
Operation::Return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Operation> for u8 {
|
||||
fn from(operation: Operation) -> Self {
|
||||
match operation {
|
||||
Operation::Move => MOVE,
|
||||
Operation::Close => CLOSE,
|
||||
Operation::LoadBoolean => LOAD_BOOLEAN,
|
||||
Operation::LoadConstant => LOAD_CONSTANT,
|
||||
Operation::LoadList => LOAD_LIST,
|
||||
Operation::DefineLocal => DECLARE_LOCAL,
|
||||
Operation::GetLocal => GET_LOCAL,
|
||||
Operation::SetLocal => SET_LOCAL,
|
||||
Operation::Add => ADD,
|
||||
Operation::Subtract => SUBTRACT,
|
||||
Operation::Multiply => MULTIPLY,
|
||||
Operation::Divide => DIVIDE,
|
||||
Operation::Modulo => MODULO,
|
||||
Operation::And => AND,
|
||||
Operation::Or => OR,
|
||||
Operation::Negate => NEGATE,
|
||||
Operation::Not => NOT,
|
||||
Operation::Return => RETURN,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Operation {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Operation::Move => write!(f, "MOVE"),
|
||||
Operation::Close => write!(f, "CLOSE"),
|
||||
Operation::LoadBoolean => write!(f, "LOAD_BOOLEAN"),
|
||||
Operation::LoadConstant => write!(f, "LOAD_CONSTANT"),
|
||||
Operation::LoadList => write!(f, "LOAD_LIST"),
|
||||
Operation::DefineLocal => write!(f, "DEFINE_LOCAL"),
|
||||
Operation::GetLocal => write!(f, "GET_LOCAL"),
|
||||
Operation::SetLocal => write!(f, "SET_LOCAL"),
|
||||
Operation::Add => write!(f, "ADD"),
|
||||
Operation::Subtract => write!(f, "SUBTRACT"),
|
||||
Operation::Multiply => write!(f, "MULTIPLY"),
|
||||
Operation::Divide => write!(f, "DIVIDE"),
|
||||
Operation::Modulo => write!(f, "MODULO"),
|
||||
Operation::And => write!(f, "AND"),
|
||||
Operation::Or => write!(f, "OR"),
|
||||
Operation::Negate => write!(f, "NEGATE"),
|
||||
Operation::Not => write!(f, "NOT"),
|
||||
Operation::Return => write!(f, "RETURN"),
|
||||
}
|
||||
}
|
||||
}
|
@ -148,9 +148,11 @@ impl<'src> Parser<'src> {
|
||||
self.advance()?;
|
||||
|
||||
let boolean = text.parse::<bool>().unwrap();
|
||||
let value = Value::boolean(boolean);
|
||||
|
||||
self.emit_constant(value)?;
|
||||
self.emit_instruction(
|
||||
Instruction::load_boolean(self.current_register, boolean, false),
|
||||
self.previous_position,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1287,7 +1287,7 @@ impl Display for ValueData {
|
||||
ValueData::Range(range_value) => {
|
||||
write!(f, "{range_value}")
|
||||
}
|
||||
ValueData::String(string) => write!(f, "\"{string}\""),
|
||||
ValueData::String(string) => write!(f, "{string}"),
|
||||
ValueData::Struct(r#struct) => write!(f, "{struct}"),
|
||||
ValueData::Tuple(fields) => {
|
||||
write!(f, "(")?;
|
||||
|
@ -50,12 +50,6 @@ impl Vm {
|
||||
vm.chunk
|
||||
.take_constant(instruction.second_argument(), position)?
|
||||
} else {
|
||||
if let Operation::GetLocal = instruction.operation() {
|
||||
println!("GetLocal: {}", instruction);
|
||||
}
|
||||
|
||||
println!("{}", instruction);
|
||||
|
||||
vm.clone(instruction.second_argument(), position)?
|
||||
};
|
||||
|
||||
@ -81,6 +75,18 @@ impl Vm {
|
||||
self.register_stack[register_index as usize] = None;
|
||||
}
|
||||
}
|
||||
Operation::LoadBoolean => {
|
||||
let to_register = instruction.destination();
|
||||
let boolean = instruction.first_argument() != 0;
|
||||
let skip = instruction.second_argument() != 0;
|
||||
let value = Value::boolean(boolean);
|
||||
|
||||
self.insert(value, to_register, position)?;
|
||||
|
||||
if skip {
|
||||
self.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LoadConstant => {
|
||||
let to_register = instruction.destination();
|
||||
let from_constant = instruction.first_argument();
|
||||
|
Loading…
Reference in New Issue
Block a user