Continue function calls; Implement some built-in functions
This commit is contained in:
parent
94179b6482
commit
72de66f5c1
@ -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(", ")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")?;
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
dust-lang/src/native_function/io.rs
Normal file
36
dust-lang/src/native_function/io.rs
Normal 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();
|
||||||
|
}
|
@ -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) {}
|
||||||
|
31
dust-lang/src/native_function/string.rs
Normal file
31
dust-lang/src/native_function/string.rs
Normal 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);
|
||||||
|
}
|
@ -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)]
|
||||||
|
@ -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 {
|
||||||
|
¤t_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;
|
||||||
|
@ -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)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user