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 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 INDENTATION: &str = "";
@ -280,7 +280,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│');
self.write_center_border_bold("Instructions")?;
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])?;
for (index, instruction) in self.chunk.instructions.iter().enumerate() {
@ -312,7 +312,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│');
self.write_center_border_bold("Locals")?;
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])?;
for (
@ -367,7 +367,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│');
self.write_center_border_bold("Constants")?;
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])?;
for (index, value) in self.chunk.character_constants.iter().enumerate() {
@ -381,7 +381,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
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)?;
}
@ -397,7 +399,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
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)?;
}
@ -413,7 +417,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
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)?;
}
@ -429,7 +435,9 @@ impl<'a, W: Write> Disassembler<'a, W> {
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)?;
}
@ -449,16 +457,23 @@ impl<'a, W: Write> Disassembler<'a, W> {
column_name_line.push('│');
self.write_center_border_bold("Argument Lists")?;
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])?;
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!(
"│{index:^5}│{:^21}│",
argument_list
"│{index:^5}│{:^21}│{:^21}│",
value_argument_list
.iter()
.map(|index| index.to_string())
.collect::<Vec<String>>()
.join(", "),
type_argument_list
.iter()
.map(|r#type| r#type.to_string())
.collect::<Vec<String>>()
.join(", ")
);

View File

@ -24,7 +24,7 @@ use std::sync::Arc;
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.
///
@ -42,7 +42,7 @@ pub struct Chunk {
pub string_constants: Vec<DustString>,
pub locals: Vec<Local>,
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 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
/// 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.
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 registers that are used for the function's arguments.
@ -357,7 +357,7 @@ impl<'src> Compiler<'src> {
.find_map(|(instruction, r#type, _)| {
if (instruction.operation() == Operation::LOAD_CONSTANT
&& instruction.b_type() == TypeCode::INTEGER)
|| r#type == &Type::Integer
|| instruction.yields_value() && r#type == &Type::Integer
{
Some(instruction.a_field() + 1)
} else {
@ -402,7 +402,10 @@ impl<'src> Compiler<'src> {
.iter()
.rev()
.find_map(|(instruction, _, _)| {
if instruction.operation() == Operation::LOAD_FUNCTION {
if matches!(
instruction.operation(),
Operation::LOAD_FUNCTION | Operation::LOAD_SELF
) {
Some(instruction.a_field() + 1)
} else {
None
@ -862,6 +865,8 @@ impl<'src> Compiler<'src> {
Operation::LOAD_ENCODED
| Operation::LOAD_LIST
| Operation::LOAD_SELF
| Operation::CALL
| Operation::CALL_NATIVE
| Operation::ADD
| Operation::SUBTRACT
| Operation::MULTIPLY
@ -1201,7 +1206,7 @@ impl<'src> Compiler<'src> {
let local_index = if let Ok(local_index) = self.get_local_index(identifier) {
local_index
} 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 {
let destination = self.next_function_register();
let load_self = Instruction::load_self(destination, false);
@ -1656,41 +1661,6 @@ impl<'src> Compiler<'src> {
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> {
self.parse(Precedence::None)?;
@ -2036,11 +2006,7 @@ impl<'src> Compiler<'src> {
}
let load_function = Instruction::load_function(destination, prototype_index, false);
let r#type = if identifier.is_some() {
Type::None
} else {
Type::Function(function_type)
};
let r#type = Type::Function(function_type);
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()
} else if last_instruction.operation() == Operation::MOVE {
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)? {
self.parse_expression()?;
@ -2102,12 +2074,13 @@ impl<'src> Compiler<'src> {
_ => todo!(),
};
argument_list.push(argument_index);
value_argument_list.push(argument_index);
}
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 destination = match function_return_type {
@ -2120,11 +2093,13 @@ impl<'src> Compiler<'src> {
Type::String => self.next_string_register(),
_ => todo!(),
};
let is_recursive = last_operation == Operation::LOAD_SELF;
let call = Instruction::call(
destination,
function_register,
argument_list_index,
function_return_type.type_code(),
is_recursive,
);
self.emit_instruction(call, function_return_type, Span(start, end));
@ -2132,6 +2107,69 @@ impl<'src> Compiler<'src> {
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> {
let (_, last_instruction_type, _) = self.instructions.last_mut().unwrap();

View File

@ -9,6 +9,7 @@ pub struct Call {
pub function_register: u16,
pub argument_list_index: u16,
pub return_type: TypeCode,
pub is_recursive: bool,
}
impl From<Instruction> for Call {
@ -17,12 +18,14 @@ impl From<Instruction> for Call {
let function_register = instruction.b_field();
let argument_list_index = instruction.c_field();
let return_type = instruction.b_type();
let is_recursive = instruction.b_is_constant();
Call {
destination,
function_register,
argument_list_index,
return_type,
is_recursive,
}
}
}
@ -31,6 +34,7 @@ impl From<Call> for Instruction {
fn from(call: Call) -> Self {
let a_field = call.destination;
let b_field = call.function_register;
let b_is_constant = call.is_recursive;
let b_type = call.return_type;
let c_field = call.argument_list_index;
@ -38,6 +42,7 @@ impl From<Call> for Instruction {
operation: Operation::CALL,
a_field,
b_field,
b_is_constant,
b_type,
c_field,
..Default::default()
@ -53,15 +58,15 @@ impl Display for Call {
function_register,
argument_list_index,
return_type,
..
is_recursive: _,
} = self;
match *return_type {
TypeCode::NONE => {}
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} = ")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination} = ")?,
TypeCode::CHARACTER => write!(f, "R_CHR_{destination} = ")?,
TypeCode::FLOAT => write!(f, "R_FLT_{destination} = ")?,
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} = ")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} = ")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination} = ")?,
TypeCode::STRING => write!(f, "R_STR_{destination} = ")?,
TypeCode::LIST => write!(f, "R_LIST_{destination} = ")?,
@ -69,6 +74,6 @@ impl Display for Call {
_ => 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 destination: u16,
pub function: NativeFunction,
pub first_argument_index: u16,
pub argument_list_index: u16,
}
impl From<Instruction> for CallNative {
@ -19,7 +19,7 @@ impl From<Instruction> for CallNative {
CallNative {
destination,
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 a_field = call_native.destination;
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 {
operation,
@ -47,57 +47,23 @@ impl Display for CallNative {
let CallNative {
destination,
function,
first_argument_index,
argument_list_index,
} = self;
let argument_count = function.r#type().value_parameters.len() as u16;
let return_type = function.r#type().return_type;
if function.returns_value() {
write!(f, "R{destination} = ")?;
match *return_type {
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}")?;
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, ")")
}
}
write!(f, "{function}(ARGS_{argument_list_index})")
}
}

View File

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

View File

@ -183,15 +183,15 @@ impl From<&Instruction> for InstructionFields {
impl Default for InstructionFields {
fn default() -> Self {
InstructionFields {
operation: Operation::MOVE,
operation: Operation::NO_OP,
a_field: 0,
b_field: 0,
c_field: 0,
d_field: false,
b_is_constant: false,
c_is_constant: false,
b_type: TypeCode::BOOLEAN,
c_type: TypeCode::BOOLEAN,
b_type: TypeCode::NONE,
c_type: TypeCode::NONE,
}
}
}
@ -278,9 +278,9 @@ impl Instruction {
pub fn as_operand(&self) -> Operand {
match self.operation() {
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 => {
let LoadEncoded {
@ -362,6 +362,15 @@ impl Instruction {
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}"),
}
}
@ -546,24 +555,26 @@ impl Instruction {
function_register: u16,
argument_list_register: u16,
return_type: TypeCode,
is_recursive: bool,
) -> Instruction {
Instruction::from(Call {
destination,
function_register,
argument_list_index: argument_list_register,
return_type,
is_recursive,
})
}
pub fn call_native(
destination: u16,
function: NativeFunction,
first_argument_index: u16,
argument_list_index: u16,
) -> Instruction {
Instruction::from(CallNative {
destination,
function,
first_argument_index,
argument_list_index,
})
}
@ -724,15 +735,11 @@ impl Display for Operand {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Operand::Constant(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "C_{}", index),
TypeCode::BYTE => write!(f, "C_{}", index),
TypeCode::CHARACTER => write!(f, "C_{}", index),
TypeCode::INTEGER => write!(f, "C_{}", index),
TypeCode::FLOAT => write!(f, "C_{}", index),
TypeCode::STRING => write!(f, "C_{}", index),
TypeCode::LIST => write!(f, "C_{}", index),
TypeCode::FUNCTION => write!(f, "C_{}", index),
_ => unreachable!(),
TypeCode::CHARACTER => write!(f, "C_CHAR_{}", index),
TypeCode::FLOAT => write!(f, "C_FLOAT_{}", index),
TypeCode::INTEGER => write!(f, "C_INT_{}", index),
TypeCode::STRING => write!(f, "C_STR_{}", index),
unsupported => panic!("Unsupported type code: {}", unsupported.0),
},
Operand::Register(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index),
@ -743,7 +750,7 @@ impl Display for Operand {
TypeCode::STRING => write!(f, "R_STR_{}", index),
TypeCode::LIST => write!(f, "R_LIST_{}", 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
//! itself or that are more efficient to implement in Rust.
mod io;
mod string;
use std::{
fmt::{self, Display, Formatter},
ops::Range,
};
use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
use crate::{vm::Thread, FunctionType, Type};
use crate::{vm::Thread, FunctionType, Instruction, Type};
macro_rules! define_native_function {
($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => {
@ -25,15 +24,10 @@ macro_rules! define_native_function {
}
impl NativeFunction {
pub fn call(
&self,
thread: &mut Thread,
destination: usize,
argument_range: Range<usize>,
) {
pub fn call(&self, instruction: Instruction, thread: &mut Thread) {
match self {
$(
NativeFunction::$name => $function(thread, destination, argument_range),
NativeFunction::$name => $function(instruction, thread),
)*
}
}
@ -127,18 +121,18 @@ define_native_function! {
// assert::panic
// ),
// // Type conversion
// Type conversion
// (Parse, 4_u8, "parse", true),
// (ToByte, 5_u8, "to_byte", true),
// (ToFloat, 6_u8, "to_float", true),
// (ToInteger, 7_u8, "to_integer", true),
// (
// ToString,
// 8,
// "to_string",
// FunctionType::new([], [Type::Any], Type::String),
// string::to_string
// ),
(
ToString,
8,
"to_string",
FunctionType::new([], [Type::Any], Type::String),
string::to_string
),
// // List and string
// (All, 9_u8, "all", true),
@ -209,13 +203,13 @@ define_native_function! {
// io::write
// ),
// (WriteFile, 56_u8, "write_file", false),
// (
// WriteLine,
// 57,
// "write_line",
// FunctionType::new([], [Type::String], Type::None),
// io::write_line
// ),
(
WriteLine,
57,
"write_line",
FunctionType::new([], [Type::String], Type::None),
io::write_line
),
// // 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
// mod action;
mod thread;
use std::{
@ -13,7 +12,7 @@ pub use thread::Thread;
use crossbeam_channel::bounded;
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> {
let chunk = compile(source)?;
@ -106,6 +105,14 @@ impl CallFrame {
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)]

View File

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

View File

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