1
0

Continue function calls; Implement some built-in functions

This commit is contained in:
Jeff 2025-03-03 22:52:53 -05:00
parent 94179b6482
commit 72de66f5c1
13 changed files with 302 additions and 206 deletions

View File

@ -65,18 +65,18 @@ const LOCAL_BORDERS: [&str; 3] = [
"╰─────┴────────────────┴──────────────────────────┴────────────┴───────┴───────╯", "╰─────┴────────────────┴──────────────────────────┴────────────┴───────┴───────╯",
]; ];
const ARGUMENT_LIST_COLUMNS: [(&str, usize); 2] = [("i", 5), ("REGISTERS", 21)]; const ARGUMENT_LIST_COLUMNS: [(&str, usize); 3] = [("i", 5), ("REGISTERS", 21), ("TYPES", 21)];
const ARGUMENT_LIST_BORDERS: [&str; 3] = [ const ARGUMENT_LIST_BORDERS: [&str; 3] = [
"╭─────┬─────────────────────", "╭─────┬─────────────────────┬─────────────────────",
"├─────┼─────────────────────", "├─────┼─────────────────────┼─────────────────────",
"╰─────┴─────────────────────", "╰─────┴─────────────────────┴─────────────────────",
]; ];
const CONSTANT_COLUMNS: [(&str, usize); 3] = [("i", 5), ("TYPE", 26), ("VALUE", 26)]; const CONSTANT_COLUMNS: [(&str, usize); 3] = [("ADDRESS", 9), ("TYPE", 26), ("VALUE", 26)];
const CONSTANT_BORDERS: [&str; 3] = [ const CONSTANT_BORDERS: [&str; 3] = [
"╭─────┬──────────────────────────┬──────────────────────────╮", "╭─────────┬──────────────────────────┬──────────────────────────╮",
"├─────┼──────────────────────────┼──────────────────────────┤", "├─────────┼──────────────────────────┼──────────────────────────┤",
"╰─────┴──────────────────────────┴──────────────────────────╯", "╰─────────┴──────────────────────────┴──────────────────────────╯",
]; ];
const INDENTATION: &str = ""; const INDENTATION: &str = "";
@ -280,7 +280,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│'); column_name_line.push('│');
self.write_center_border_bold("Instructions")?; self.write_center_border_bold("Instructions")?;
self.write_center_border(INSTRUCTION_BORDERS[0])?; self.write_center_border(INSTRUCTION_BORDERS[0])?;
self.write_center_border(&column_name_line)?; self.write_center_border_bold(&column_name_line)?;
self.write_center_border(INSTRUCTION_BORDERS[1])?; self.write_center_border(INSTRUCTION_BORDERS[1])?;
for (index, instruction) in self.chunk.instructions.iter().enumerate() { for (index, instruction) in self.chunk.instructions.iter().enumerate() {
@ -312,7 +312,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│'); column_name_line.push('│');
self.write_center_border_bold("Locals")?; self.write_center_border_bold("Locals")?;
self.write_center_border(LOCAL_BORDERS[0])?; self.write_center_border(LOCAL_BORDERS[0])?;
self.write_center_border(&column_name_line)?; self.write_center_border_bold(&column_name_line)?;
self.write_center_border(LOCAL_BORDERS[1])?; self.write_center_border(LOCAL_BORDERS[1])?;
for ( for (
@ -367,7 +367,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│'); column_name_line.push('│');
self.write_center_border_bold("Constants")?; self.write_center_border_bold("Constants")?;
self.write_center_border(CONSTANT_BORDERS[0])?; self.write_center_border(CONSTANT_BORDERS[0])?;
self.write_center_border(&column_name_line)?; self.write_center_border_bold(&column_name_line)?;
self.write_center_border(CONSTANT_BORDERS[1])?; self.write_center_border(CONSTANT_BORDERS[1])?;
for (index, value) in self.chunk.character_constants.iter().enumerate() { for (index, value) in self.chunk.character_constants.iter().enumerate() {
@ -381,7 +381,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
value_string value_string
}; };
let constant_display = format!("{index:^5}{type_display:^26}{value_display:^26}"); let register_display = format!("C_CHAR_{index}");
let constant_display =
format!("{register_display:^9}{type_display:^26}{value_display:^26}");
self.write_center_border(&constant_display)?; self.write_center_border(&constant_display)?;
} }
@ -397,7 +399,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
value_string value_string
}; };
let constant_display = format!("{index:^5}{type_display:^26}{value_display:^26}"); let register_display = format!("C_FLOAT_{index}");
let constant_display =
format!("{register_display:^9}{type_display:^26}{value_display:^26}");
self.write_center_border(&constant_display)?; self.write_center_border(&constant_display)?;
} }
@ -413,7 +417,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
value_string value_string
}; };
let constant_display = format!("{index:^5}{type_display:^26}{value_display:^26}"); let register_display = format!("C_INT_{index}");
let constant_display =
format!("{register_display:^9}{type_display:^26}{value_display:^26}");
self.write_center_border(&constant_display)?; self.write_center_border(&constant_display)?;
} }
@ -429,7 +435,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
value_string value_string
}; };
let constant_display = format!("{index:^5}{type_display:^26}{value_display:^26}"); let register_display = format!("C_STR_{index}");
let constant_display =
format!("{register_display:^9}{type_display:^26}{value_display:^26}");
self.write_center_border(&constant_display)?; self.write_center_border(&constant_display)?;
} }
@ -449,16 +457,23 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│'); column_name_line.push('│');
self.write_center_border_bold("Argument Lists")?; self.write_center_border_bold("Argument Lists")?;
self.write_center_border(ARGUMENT_LIST_BORDERS[0])?; self.write_center_border(ARGUMENT_LIST_BORDERS[0])?;
self.write_center_border(&column_name_line)?; self.write_center_border_bold(&column_name_line)?;
self.write_center_border(ARGUMENT_LIST_BORDERS[1])?; self.write_center_border(ARGUMENT_LIST_BORDERS[1])?;
for (index, argument_list) in self.chunk.argument_lists.iter().enumerate() { for (index, (value_argument_list, type_argument_list)) in
self.chunk.argument_lists.iter().enumerate()
{
let argument_list_display = format!( let argument_list_display = format!(
"│{index:^5}│{:^21}│", "│{index:^5}│{:^21}│{:^21}│",
argument_list value_argument_list
.iter() .iter()
.map(|index| index.to_string()) .map(|index| index.to_string())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", "),
type_argument_list
.iter()
.map(|r#type| r#type.to_string())
.collect::<Vec<String>>()
.join(", ") .join(", ")
); );

View File

@ -24,7 +24,7 @@ use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{DustString, Function, FunctionType, Instruction, Span}; use crate::{DustString, Function, FunctionType, Instruction, Span, Type};
/// Representation of a Dust program or function. /// Representation of a Dust program or function.
/// ///
@ -42,7 +42,7 @@ pub struct Chunk {
pub string_constants: Vec<DustString>, pub string_constants: Vec<DustString>,
pub locals: Vec<Local>, pub locals: Vec<Local>,
pub prototypes: Vec<Arc<Chunk>>, pub prototypes: Vec<Arc<Chunk>>,
pub argument_lists: Vec<Vec<u16>>, pub argument_lists: Vec<(Vec<u16>, Vec<Type>)>,
pub boolean_register_count: u16, pub boolean_register_count: u16,
pub byte_register_count: u16, pub byte_register_count: u16,

View File

@ -110,7 +110,7 @@ pub struct Compiler<'src> {
/// Lists of arguments for each function call. The integers represent the register of each /// Lists of arguments for each function call. The integers represent the register of each
/// argument. Note that the type of each argument is not stored, so the caller must check the /// argument. Note that the type of each argument is not stored, so the caller must check the
/// function's type to determine the type of each argument. /// function's type to determine the type of each argument.
argument_lists: Vec<Vec<u16>>, argument_lists: Vec<(Vec<u16>, Vec<Type>)>,
/// The first boolean register index that the compiler should use. This is used to avoid reusing /// The first boolean register index that the compiler should use. This is used to avoid reusing
/// the registers that are used for the function's arguments. /// the registers that are used for the function's arguments.
@ -357,7 +357,7 @@ impl<'src> Compiler<'src> {
.find_map(|(instruction, r#type, _)| { .find_map(|(instruction, r#type, _)| {
if (instruction.operation() == Operation::LOAD_CONSTANT if (instruction.operation() == Operation::LOAD_CONSTANT
&& instruction.b_type() == TypeCode::INTEGER) && instruction.b_type() == TypeCode::INTEGER)
|| r#type == &Type::Integer || instruction.yields_value() && r#type == &Type::Integer
{ {
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
@ -402,7 +402,10 @@ impl<'src> Compiler<'src> {
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, _, _)| { .find_map(|(instruction, _, _)| {
if instruction.operation() == Operation::LOAD_FUNCTION { if matches!(
instruction.operation(),
Operation::LOAD_FUNCTION | Operation::LOAD_SELF
) {
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
None None
@ -862,6 +865,8 @@ impl<'src> Compiler<'src> {
Operation::LOAD_ENCODED Operation::LOAD_ENCODED
| Operation::LOAD_LIST | Operation::LOAD_LIST
| Operation::LOAD_SELF | Operation::LOAD_SELF
| Operation::CALL
| Operation::CALL_NATIVE
| Operation::ADD | Operation::ADD
| Operation::SUBTRACT | Operation::SUBTRACT
| Operation::MULTIPLY | Operation::MULTIPLY
@ -1201,7 +1206,7 @@ impl<'src> Compiler<'src> {
let local_index = if let Ok(local_index) = self.get_local_index(identifier) { let local_index = if let Ok(local_index) = self.get_local_index(identifier) {
local_index local_index
} else if let Some(native_function) = NativeFunction::from_str(identifier) { } else if let Some(native_function) = NativeFunction::from_str(identifier) {
return self.parse_call_native(native_function); return self.parse_call_native(native_function, start_position);
} else if self.function_name.as_deref() == Some(identifier) && !self.is_main { } else if self.function_name.as_deref() == Some(identifier) && !self.is_main {
let destination = self.next_function_register(); let destination = self.next_function_register();
let load_self = Instruction::load_self(destination, false); let load_self = Instruction::load_self(destination, false);
@ -1656,41 +1661,6 @@ impl<'src> Compiler<'src> {
Ok(()) Ok(())
} }
fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> {
let start = self.previous_position.0;
let mut first_argument_index = None;
self.expect(Token::LeftParenthesis)?;
while !self.allow(Token::RightParenthesis)? {
self.parse_expression()?;
self.allow(Token::Comma)?;
if first_argument_index.is_none() {
first_argument_index = Some(self.instructions.last().unwrap().0.a_field());
}
}
let end = self.previous_position.1;
let destination = match function.r#type().return_type.as_ref() {
Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(),
Type::Float => self.next_float_register(),
Type::Integer => self.next_integer_register(),
Type::String => self.next_string_register(),
Type::None => 0,
_ => todo!(),
};
let return_type = *function.r#type().return_type;
let call_native =
Instruction::call_native(destination, function, first_argument_index.unwrap_or(0));
self.emit_instruction(call_native, return_type, Span(start, end));
Ok(())
}
fn parse_expression(&mut self) -> Result<(), CompileError> { fn parse_expression(&mut self) -> Result<(), CompileError> {
self.parse(Precedence::None)?; self.parse(Precedence::None)?;
@ -2036,11 +2006,7 @@ impl<'src> Compiler<'src> {
} }
let load_function = Instruction::load_function(destination, prototype_index, false); let load_function = Instruction::load_function(destination, prototype_index, false);
let r#type = if identifier.is_some() { let r#type = Type::Function(function_type);
Type::None
} else {
Type::Function(function_type)
};
self.emit_instruction(load_function, r#type, Span(function_start, function_end)); self.emit_instruction(load_function, r#type, Span(function_start, function_end));
@ -2072,7 +2038,11 @@ impl<'src> Compiler<'src> {
}); });
} }
}; };
let function_register = if last_instruction.operation() == Operation::LOAD_FUNCTION { let last_operation = last_instruction.operation();
let function_register = if matches!(
last_operation,
Operation::LOAD_FUNCTION | Operation::LOAD_SELF
) {
last_instruction.a_field() last_instruction.a_field()
} else if last_instruction.operation() == Operation::MOVE { } else if last_instruction.operation() == Operation::MOVE {
self.instructions.pop(); self.instructions.pop();
@ -2086,7 +2056,9 @@ impl<'src> Compiler<'src> {
}); });
}; };
let mut argument_list = Vec::new(); let type_argument_list = Vec::new();
let mut value_argument_list = Vec::new();
while !self.allow(Token::RightParenthesis)? { while !self.allow(Token::RightParenthesis)? {
self.parse_expression()?; self.parse_expression()?;
@ -2102,12 +2074,13 @@ impl<'src> Compiler<'src> {
_ => todo!(), _ => todo!(),
}; };
argument_list.push(argument_index); value_argument_list.push(argument_index);
} }
let argument_list_index = self.argument_lists.len() as u16; let argument_list_index = self.argument_lists.len() as u16;
self.argument_lists.push(argument_list); self.argument_lists
.push((value_argument_list, type_argument_list));
let end = self.current_position.1; let end = self.current_position.1;
let destination = match function_return_type { let destination = match function_return_type {
@ -2120,11 +2093,13 @@ impl<'src> Compiler<'src> {
Type::String => self.next_string_register(), Type::String => self.next_string_register(),
_ => todo!(), _ => todo!(),
}; };
let is_recursive = last_operation == Operation::LOAD_SELF;
let call = Instruction::call( let call = Instruction::call(
destination, destination,
function_register, function_register,
argument_list_index, argument_list_index,
function_return_type.type_code(), function_return_type.type_code(),
is_recursive,
); );
self.emit_instruction(call, function_return_type, Span(start, end)); self.emit_instruction(call, function_return_type, Span(start, end));
@ -2132,6 +2107,69 @@ impl<'src> Compiler<'src> {
Ok(()) Ok(())
} }
fn parse_call_native(
&mut self,
function: NativeFunction,
start: Span,
) -> Result<(), CompileError> {
let mut type_argument_list = Vec::new();
if self.allow(Token::Less)? {
while !self.allow(Token::Greater)? {
let r#type = self.parse_type_from(self.current_token, self.current_position)?;
type_argument_list.push(r#type);
self.advance()?;
self.allow(Token::Comma)?;
}
}
self.expect(Token::LeftParenthesis)?;
let mut value_argument_list = Vec::new();
while !self.allow(Token::RightParenthesis)? {
self.parse_expression()?;
self.allow(Token::Comma)?;
let argument_index = match self.get_last_instruction_type() {
Type::Boolean => self.next_boolean_register() - 1,
Type::Byte => self.next_byte_register() - 1,
Type::Character => self.next_character_register() - 1,
Type::Float => self.next_float_register() - 1,
Type::Integer => self.next_integer_register() - 1,
Type::String => self.next_string_register() - 1,
_ => todo!(),
};
value_argument_list.push(argument_index);
}
let argument_list_index = self.argument_lists.len() as u16;
self.argument_lists
.push((value_argument_list, type_argument_list));
let end = self.current_position.1;
let return_type = function.r#type().return_type.as_ref().clone();
let destination = match return_type {
Type::None => 0,
Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(),
Type::Float => self.next_float_register(),
Type::Integer => self.next_integer_register(),
Type::String => self.next_string_register(),
_ => todo!(),
};
let call_native = Instruction::call_native(destination, function, argument_list_index);
self.emit_instruction(call_native, return_type, Span(start.0, end));
Ok(())
}
fn parse_semicolon(&mut self) -> Result<(), CompileError> { fn parse_semicolon(&mut self) -> Result<(), CompileError> {
let (_, last_instruction_type, _) = self.instructions.last_mut().unwrap(); let (_, last_instruction_type, _) = self.instructions.last_mut().unwrap();

View File

@ -9,6 +9,7 @@ pub struct Call {
pub function_register: u16, pub function_register: u16,
pub argument_list_index: u16, pub argument_list_index: u16,
pub return_type: TypeCode, pub return_type: TypeCode,
pub is_recursive: bool,
} }
impl From<Instruction> for Call { impl From<Instruction> for Call {
@ -17,12 +18,14 @@ impl From<Instruction> for Call {
let function_register = instruction.b_field(); let function_register = instruction.b_field();
let argument_list_index = instruction.c_field(); let argument_list_index = instruction.c_field();
let return_type = instruction.b_type(); let return_type = instruction.b_type();
let is_recursive = instruction.b_is_constant();
Call { Call {
destination, destination,
function_register, function_register,
argument_list_index, argument_list_index,
return_type, return_type,
is_recursive,
} }
} }
} }
@ -31,6 +34,7 @@ impl From<Call> for Instruction {
fn from(call: Call) -> Self { fn from(call: Call) -> Self {
let a_field = call.destination; let a_field = call.destination;
let b_field = call.function_register; let b_field = call.function_register;
let b_is_constant = call.is_recursive;
let b_type = call.return_type; let b_type = call.return_type;
let c_field = call.argument_list_index; let c_field = call.argument_list_index;
@ -38,6 +42,7 @@ impl From<Call> for Instruction {
operation: Operation::CALL, operation: Operation::CALL,
a_field, a_field,
b_field, b_field,
b_is_constant,
b_type, b_type,
c_field, c_field,
..Default::default() ..Default::default()
@ -53,15 +58,15 @@ impl Display for Call {
function_register, function_register,
argument_list_index, argument_list_index,
return_type, return_type,
.. is_recursive: _,
} = self; } = self;
match *return_type { match *return_type {
TypeCode::NONE => {} TypeCode::NONE => {}
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} = ")?, TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} = ")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination} = ")?, TypeCode::BYTE => write!(f, "R_BYTE_{destination} = ")?,
TypeCode::CHARACTER => write!(f, "R_CHR_{destination} = ")?, TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} = ")?,
TypeCode::FLOAT => write!(f, "R_FLT_{destination} = ")?, TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} = ")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination} = ")?, TypeCode::INTEGER => write!(f, "R_INT_{destination} = ")?,
TypeCode::STRING => write!(f, "R_STR_{destination} = ")?, TypeCode::STRING => write!(f, "R_STR_{destination} = ")?,
TypeCode::LIST => write!(f, "R_LIST_{destination} = ")?, TypeCode::LIST => write!(f, "R_LIST_{destination} = ")?,
@ -69,6 +74,6 @@ impl Display for Call {
_ => unreachable!(), _ => unreachable!(),
} }
write!(f, "R_FN_{function_register}({argument_list_index})") write!(f, "R_FN_{function_register}(ARGS_{argument_list_index})")
} }
} }

View File

@ -7,7 +7,7 @@ use super::InstructionFields;
pub struct CallNative { pub struct CallNative {
pub destination: u16, pub destination: u16,
pub function: NativeFunction, pub function: NativeFunction,
pub first_argument_index: u16, pub argument_list_index: u16,
} }
impl From<Instruction> for CallNative { impl From<Instruction> for CallNative {
@ -19,7 +19,7 @@ impl From<Instruction> for CallNative {
CallNative { CallNative {
destination, destination,
function, function,
first_argument_index, argument_list_index: first_argument_index,
} }
} }
} }
@ -29,7 +29,7 @@ impl From<CallNative> for Instruction {
let operation = Operation::CALL_NATIVE; let operation = Operation::CALL_NATIVE;
let a_field = call_native.destination; let a_field = call_native.destination;
let b_field = call_native.function as u16; let b_field = call_native.function as u16;
let c_field = call_native.first_argument_index; let c_field = call_native.argument_list_index;
InstructionFields { InstructionFields {
operation, operation,
@ -47,57 +47,23 @@ impl Display for CallNative {
let CallNative { let CallNative {
destination, destination,
function, function,
first_argument_index, argument_list_index,
} = self; } = self;
let argument_count = function.r#type().value_parameters.len() as u16; let return_type = function.r#type().return_type;
if function.returns_value() { match *return_type {
write!(f, "R{destination} = ")?; Type::None => {}
Type::Boolean => write!(f, "R_BOOL_{destination} = ")?,
Type::Byte => write!(f, "R_BYTE_{destination} = ")?,
Type::Character => write!(f, "R_CHR_{destination} = ")?,
Type::Float => write!(f, "R_FLT_{destination} = ")?,
Type::Integer => write!(f, "R_INT_{destination} = ")?,
Type::String => write!(f, "R_STR_{destination} = ")?,
Type::List(_) => write!(f, "R_LIST_{destination} = ")?,
Type::Function(_) => write!(f, "R_FN_{destination} = ")?,
_ => unreachable!(),
} }
write!(f, "{function}")?; write!(f, "{function}(ARGS_{argument_list_index})")
match argument_count {
0 => {
write!(f, "()")
}
_ => {
let arguments_end = first_argument_index + argument_count - 1;
let arguments_index_range = *first_argument_index..=arguments_end;
let function_type = function.r#type();
let argument_types = function_type.value_parameters.iter();
write!(f, "(")?;
for (index, r#type) in arguments_index_range.zip(argument_types) {
match r#type {
Type::Boolean => {
write!(f, "R_BOOL_{index}")
}
Type::Byte => {
write!(f, "R_BYTE_{index}")
}
Type::Float => {
write!(f, "R_FLOAT_{index}")
}
Type::Integer => {
write!(f, "R_INT_{index}")
}
Type::String => {
write!(f, "R_STR_{index}")
}
unsupported => {
todo!("Support for {unsupported:?} arguments")
}
}?;
if index != arguments_end {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
} }
} }

View File

@ -51,17 +51,13 @@ impl Display for LoadConstant {
} = self; } = self;
match *constant_type { match *constant_type {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?, TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} = C_CHAR_{constant_index}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?, TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} = C_FLOAT_{constant_index}")?,
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination}")?, TypeCode::INTEGER => write!(f, "R_INT_{destination} = C_INT_{constant_index}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?, TypeCode::STRING => write!(f, "R_STR_{destination} = C_STR_{constant_index}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
unsupported => panic!("Unsupported type code: {}", unsupported.0), unsupported => panic!("Unsupported type code: {}", unsupported.0),
} }
write!(f, " = C{constant_index}")?;
if *jump_next { if *jump_next {
write!(f, " JUMP +1")?; write!(f, " JUMP +1")?;
} }

View File

@ -183,15 +183,15 @@ impl From<&Instruction> for InstructionFields {
impl Default for InstructionFields { impl Default for InstructionFields {
fn default() -> Self { fn default() -> Self {
InstructionFields { InstructionFields {
operation: Operation::MOVE, operation: Operation::NO_OP,
a_field: 0, a_field: 0,
b_field: 0, b_field: 0,
c_field: 0, c_field: 0,
d_field: false, d_field: false,
b_is_constant: false, b_is_constant: false,
c_is_constant: false, c_is_constant: false,
b_type: TypeCode::BOOLEAN, b_type: TypeCode::NONE,
c_type: TypeCode::BOOLEAN, c_type: TypeCode::NONE,
} }
} }
} }
@ -278,9 +278,9 @@ impl Instruction {
pub fn as_operand(&self) -> Operand { pub fn as_operand(&self) -> Operand {
match self.operation() { match self.operation() {
Operation::MOVE => { Operation::MOVE => {
let Move { operand: to, .. } = Move::from(self); let Move { operand, .. } = Move::from(self);
Operand::Register(to.index(), to.as_type()) operand
} }
Operation::LOAD_ENCODED => { Operation::LOAD_ENCODED => {
let LoadEncoded { let LoadEncoded {
@ -362,6 +362,15 @@ impl Instruction {
Operand::Register(destination, left.as_type()) Operand::Register(destination, left.as_type())
} }
Operation::CALL => {
let Call {
destination,
return_type,
..
} = Call::from(*self);
Operand::Register(destination, return_type)
}
unsupported => todo!("Support {unsupported}"), unsupported => todo!("Support {unsupported}"),
} }
} }
@ -546,24 +555,26 @@ impl Instruction {
function_register: u16, function_register: u16,
argument_list_register: u16, argument_list_register: u16,
return_type: TypeCode, return_type: TypeCode,
is_recursive: bool,
) -> Instruction { ) -> Instruction {
Instruction::from(Call { Instruction::from(Call {
destination, destination,
function_register, function_register,
argument_list_index: argument_list_register, argument_list_index: argument_list_register,
return_type, return_type,
is_recursive,
}) })
} }
pub fn call_native( pub fn call_native(
destination: u16, destination: u16,
function: NativeFunction, function: NativeFunction,
first_argument_index: u16, argument_list_index: u16,
) -> Instruction { ) -> Instruction {
Instruction::from(CallNative { Instruction::from(CallNative {
destination, destination,
function, function,
first_argument_index, argument_list_index,
}) })
} }
@ -724,15 +735,11 @@ impl Display for Operand {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Operand::Constant(index, r#type) => match *r#type { Operand::Constant(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "C_{}", index), TypeCode::CHARACTER => write!(f, "C_CHAR_{}", index),
TypeCode::BYTE => write!(f, "C_{}", index), TypeCode::FLOAT => write!(f, "C_FLOAT_{}", index),
TypeCode::CHARACTER => write!(f, "C_{}", index), TypeCode::INTEGER => write!(f, "C_INT_{}", index),
TypeCode::INTEGER => write!(f, "C_{}", index), TypeCode::STRING => write!(f, "C_STR_{}", index),
TypeCode::FLOAT => write!(f, "C_{}", index), unsupported => panic!("Unsupported type code: {}", unsupported.0),
TypeCode::STRING => write!(f, "C_{}", index),
TypeCode::LIST => write!(f, "C_{}", index),
TypeCode::FUNCTION => write!(f, "C_{}", index),
_ => unreachable!(),
}, },
Operand::Register(index, r#type) => match *r#type { Operand::Register(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index), TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index),
@ -743,7 +750,7 @@ impl Display for Operand {
TypeCode::STRING => write!(f, "R_STR_{}", index), TypeCode::STRING => write!(f, "R_STR_{}", index),
TypeCode::LIST => write!(f, "R_LIST_{}", index), TypeCode::LIST => write!(f, "R_LIST_{}", index),
TypeCode::FUNCTION => write!(f, "R_FN_{}", index), TypeCode::FUNCTION => write!(f, "R_FN_{}", index),
_ => unreachable!(), unsupported => panic!("Unsupported type code: {}", unsupported.0),
}, },
} }
} }

View File

@ -0,0 +1,36 @@
use std::io::{stdout, Write};
use crate::{instruction::CallNative, vm::Thread, Instruction, Type};
pub fn write_line(instruction: Instruction, thread: &mut Thread) {
let CallNative {
destination: _,
function,
argument_list_index,
} = CallNative::from(instruction);
let current_frame = thread.current_frame();
let current_registers = thread.current_registers();
let arguments = current_frame.get_argument_list(argument_list_index);
let mut stdout = stdout();
for (argument_index, argument_type) in arguments
.0
.iter()
.zip(function.r#type().value_parameters.iter())
{
match argument_type {
Type::String => {
let string = current_registers
.strings
.get(*argument_index as usize)
.as_value();
stdout.write_all(string.as_bytes()).unwrap();
}
_ => unreachable!(),
}
}
stdout.write_all(b"\n").unwrap();
}

View File

@ -2,15 +2,14 @@
//! //!
//! Native functions are used to implement features that are not possible to implement in Dust //! Native functions are used to implement features that are not possible to implement in Dust
//! itself or that are more efficient to implement in Rust. //! itself or that are more efficient to implement in Rust.
mod io;
mod string;
use std::{ use std::fmt::{self, Display, Formatter};
fmt::{self, Display, Formatter},
ops::Range,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{vm::Thread, FunctionType, Type}; use crate::{vm::Thread, FunctionType, Instruction, Type};
macro_rules! define_native_function { macro_rules! define_native_function {
($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => { ($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => {
@ -25,15 +24,10 @@ macro_rules! define_native_function {
} }
impl NativeFunction { impl NativeFunction {
pub fn call( pub fn call(&self, instruction: Instruction, thread: &mut Thread) {
&self,
thread: &mut Thread,
destination: usize,
argument_range: Range<usize>,
) {
match self { match self {
$( $(
NativeFunction::$name => $function(thread, destination, argument_range), NativeFunction::$name => $function(instruction, thread),
)* )*
} }
} }
@ -127,18 +121,18 @@ define_native_function! {
// assert::panic // assert::panic
// ), // ),
// // Type conversion // Type conversion
// (Parse, 4_u8, "parse", true), // (Parse, 4_u8, "parse", true),
// (ToByte, 5_u8, "to_byte", true), // (ToByte, 5_u8, "to_byte", true),
// (ToFloat, 6_u8, "to_float", true), // (ToFloat, 6_u8, "to_float", true),
// (ToInteger, 7_u8, "to_integer", true), // (ToInteger, 7_u8, "to_integer", true),
// ( (
// ToString, ToString,
// 8, 8,
// "to_string", "to_string",
// FunctionType::new([], [Type::Any], Type::String), FunctionType::new([], [Type::Any], Type::String),
// string::to_string string::to_string
// ), ),
// // List and string // // List and string
// (All, 9_u8, "all", true), // (All, 9_u8, "all", true),
@ -209,13 +203,13 @@ define_native_function! {
// io::write // io::write
// ), // ),
// (WriteFile, 56_u8, "write_file", false), // (WriteFile, 56_u8, "write_file", false),
// ( (
// WriteLine, WriteLine,
// 57, 57,
// "write_line", "write_line",
// FunctionType::new([], [Type::String], Type::None), FunctionType::new([], [Type::String], Type::None),
// io::write_line io::write_line
// ), ),
// // Random // // Random
// ( // (
@ -236,4 +230,4 @@ define_native_function! {
) )
} }
fn spawn(_: &mut Thread, _: usize, _: Range<usize>) {} fn spawn(_: Instruction, _: &mut Thread) {}

View File

@ -0,0 +1,31 @@
use crate::{instruction::CallNative, vm::Thread, DustString, Instruction, Type};
pub fn to_string(instruction: Instruction, thread: &mut Thread) {
let CallNative {
destination,
function: _,
argument_list_index,
} = CallNative::from(instruction);
let current_frame = thread.current_frame();
let current_registers = thread.current_registers();
let arguments = current_frame.get_argument_list(argument_list_index);
let string = match arguments.1[0] {
Type::Integer => {
let integer = current_registers
.integers
.get(arguments.0[0] as usize)
.as_value();
DustString::from(integer.to_string())
}
_ => unreachable!(),
};
*thread
.current_registers_mut()
.strings
.get_mut(destination as usize)
.as_value_mut() = DustString::from(string);
}

View File

@ -1,5 +1,4 @@
//! Virtual machine and errors //! Virtual machine and errors
// mod action;
mod thread; mod thread;
use std::{ use std::{
@ -13,7 +12,7 @@ pub use thread::Thread;
use crossbeam_channel::bounded; use crossbeam_channel::bounded;
use tracing::{span, Level}; use tracing::{span, Level};
use crate::{compile, AbstractList, Chunk, DustError, DustString, Function, Value}; use crate::{compile, AbstractList, Chunk, DustError, DustString, Function, Type, Value};
pub fn run(source: &str) -> Result<Option<Value>, DustError> { pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let chunk = compile(source)?; let chunk = compile(source)?;
@ -106,6 +105,14 @@ impl CallFrame {
unsafe { self.chunk.string_constants.get_unchecked(constant_index) } unsafe { self.chunk.string_constants.get_unchecked(constant_index) }
} }
} }
pub fn get_argument_list(&self, index: u16) -> &(Vec<u16>, Vec<Type>) {
if cfg!(debug_assertions) {
self.chunk.argument_lists.get(index as usize).unwrap()
} else {
unsafe { self.chunk.argument_lists.get_unchecked(index as usize) }
}
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -5,7 +5,7 @@ use tracing::{info, trace};
use crate::{ use crate::{
instruction::TypeCode, instruction::TypeCode,
vm::{CallFrame, Pointer}, vm::{CallFrame, Pointer},
AbstractList, Chunk, DustString, Operation, Span, Type, Value, AbstractList, Chunk, DustString, NativeFunction, Operation, Span, Type, Value,
}; };
use super::RegisterTable; use super::RegisterTable;
@ -1274,16 +1274,26 @@ impl Thread {
let destination = instruction.a_field(); let destination = instruction.a_field();
let function_register = instruction.b_field(); let function_register = instruction.b_field();
let argument_list_register = instruction.c_field(); let argument_list_register = instruction.c_field();
let is_recursive = instruction.b_is_constant();
let function = registers let function = if is_recursive {
.functions current_frame.chunk.as_function()
.get(function_register as usize) } else {
.as_value(); registers
let function_prototype = current_frame .functions
.chunk .get(function_register as usize)
.prototypes .as_value()
.get(function.prototype_index as usize) .clone()
.unwrap(); };
let function_prototype = if is_recursive {
&current_frame.chunk
} else {
current_frame
.chunk
.prototypes
.get(function.prototype_index as usize)
.unwrap()
};
let argument_list = current_frame let argument_list = current_frame
.chunk .chunk
.argument_lists .argument_lists
@ -1300,7 +1310,7 @@ impl Thread {
.r#type .r#type
.value_parameters .value_parameters
.iter() .iter()
.zip(argument_list.iter()) .zip(argument_list.0.iter())
{ {
let register_index = *register_index as usize; let register_index = *register_index as usize;
@ -1335,21 +1345,12 @@ impl Thread {
self.call_stack.push(call_frame); self.call_stack.push(call_frame);
self.register_stack.push(new_registers); self.register_stack.push(new_registers);
trace!( trace!("Call Stack: {:?}", self.call_stack);
"Call Stack: [{}]", }
self.call_stack Operation::CALL_NATIVE => {
.iter() let function = NativeFunction::from(instruction.b_field());
.map(|call_frame| format!(
"{}:{} ", function.call(instruction, &mut self);
call_frame
.chunk
.name
.clone()
.unwrap_or_else(|| DustString::from("anonymous")),
call_frame.ip
))
.collect::<String>()
);
} }
Operation::JUMP => { Operation::JUMP => {
let offset = instruction.b_field() as usize; let offset = instruction.b_field() as usize;

View File

@ -5,4 +5,4 @@ fn fib (n: int) -> int {
fib(n - 1) + fib(n - 2) fib(n - 1) + fib(n - 2)
} }
write_line(fib(25)) write_line(to_string<int>(fib(25)))