Create formatter
This commit is contained in:
parent
5eb901f468
commit
c7bba88875
@ -1,12 +1,10 @@
|
||||
use std::{
|
||||
f32::DIGITS,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
};
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
use colored::Colorize;
|
||||
use rayon::{iter::ParallelIterator, str::ParallelString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Type, Value};
|
||||
use crate::{AnnotatedError, Formatter, Identifier, Instruction, Operation, Span, Type, Value};
|
||||
|
||||
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Chunk {
|
||||
@ -281,7 +279,7 @@ impl Default for Chunk {
|
||||
}
|
||||
|
||||
impl Display for Chunk {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
@ -291,7 +289,7 @@ impl Display for Chunk {
|
||||
}
|
||||
|
||||
impl Debug for Chunk {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
@ -448,6 +446,7 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
} else {
|
||||
line_characters.iter().collect::<String>()
|
||||
};
|
||||
let length_before_content = disassembly.chars().count();
|
||||
|
||||
for _ in 0..indent {
|
||||
disassembly.push_str("│ ");
|
||||
@ -461,10 +460,18 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
disassembly.push_str(&content);
|
||||
disassembly.push_str(&" ".repeat(right_pad_length));
|
||||
|
||||
let length_after_content = disassembly.chars().count();
|
||||
let line_length = length_after_content - length_before_content;
|
||||
|
||||
if line_length < content_width - 1 {
|
||||
disassembly.push_str(&" ".repeat(content_width - line_length));
|
||||
}
|
||||
|
||||
if add_border {
|
||||
disassembly.push('│');
|
||||
}
|
||||
|
||||
disassembly.push_str(&line_length.to_string());
|
||||
disassembly.push('\n');
|
||||
|
||||
if !remainder.is_empty() {
|
||||
@ -480,6 +487,7 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let push_header = |header: &str, disassembly: &mut String| {
|
||||
push(
|
||||
header,
|
||||
@ -527,19 +535,6 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
push_border(&top_border, &mut disassembly);
|
||||
push_header(self.name, &mut disassembly);
|
||||
|
||||
if let Some(source) = self.source {
|
||||
push(
|
||||
&source.split_whitespace().collect::<Vec<&str>>().join(" "),
|
||||
&mut disassembly,
|
||||
self.width,
|
||||
self.indent,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
let info_line = format!(
|
||||
"{} instructions, {} constants, {} locals",
|
||||
self.chunk.instructions.len(),
|
||||
@ -658,6 +653,12 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
|
||||
push_border(&bottom_border, &mut disassembly);
|
||||
|
||||
if let Some(source) = self.source {
|
||||
let formatted = Formatter::new(source).origin(self.name).format();
|
||||
|
||||
disassembly.push_str(&formatted);
|
||||
}
|
||||
|
||||
let expected_length = self.predict_length();
|
||||
let actual_length = disassembly.len();
|
||||
|
||||
|
@ -32,7 +32,7 @@ impl<'src> DustError<'src> {
|
||||
.unwrap_or_else(|| "While running this code".to_string());
|
||||
let message = Level::Error.title(&label).snippet(
|
||||
Snippet::source(source)
|
||||
.fold(true)
|
||||
.fold(false)
|
||||
.annotation(Level::Error.span(position.0..position.1).label(&details)),
|
||||
);
|
||||
|
||||
@ -46,7 +46,7 @@ impl<'src> DustError<'src> {
|
||||
.unwrap_or_else(|| "While parsing this code".to_string());
|
||||
let message = Level::Error.title(&label).snippet(
|
||||
Snippet::source(source)
|
||||
.fold(true)
|
||||
.fold(false)
|
||||
.annotation(Level::Error.span(position.0..position.1).label(&details)),
|
||||
);
|
||||
|
||||
|
106
dust-lang/src/formatter.rs
Normal file
106
dust-lang/src/formatter.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use annotate_snippets::{renderer::Style, Level, Renderer, Snippet};
|
||||
use colored::{Colorize, CustomColor};
|
||||
|
||||
use crate::{lex, Token};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Formatter<'src> {
|
||||
source: &'src str,
|
||||
origin: Option<&'src str>,
|
||||
footer: Option<&'src str>,
|
||||
}
|
||||
|
||||
impl<'src> Formatter<'src> {
|
||||
pub fn new(source: &'src str) -> Self {
|
||||
Self {
|
||||
source,
|
||||
origin: None,
|
||||
footer: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn origin(&mut self, origin: &'src str) -> &mut Self {
|
||||
self.origin = Some(origin);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn footer(&mut self, footer: &'src str) -> &mut Self {
|
||||
self.source = footer;
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn format(&self) -> String {
|
||||
let tokens = match lex(self.source) {
|
||||
Ok(tokens) => tokens,
|
||||
Err(error) => return format!("{}", error),
|
||||
};
|
||||
let mut block_depth = 0;
|
||||
let mut formatted = String::new();
|
||||
let line_break = |formatted: &mut String, block_depth: i32| {
|
||||
formatted.push('\n');
|
||||
|
||||
for _ in 0..block_depth {
|
||||
formatted.push_str(" ");
|
||||
}
|
||||
};
|
||||
|
||||
for (token, _) in tokens {
|
||||
match token {
|
||||
Token::Boolean(boolean) => formatted.push_str(&boolean.red()),
|
||||
Token::Byte(byte) => formatted.push_str(&byte.green()),
|
||||
Token::Character(character) => formatted.push_str(
|
||||
&character
|
||||
.to_string()
|
||||
.custom_color(CustomColor::new(225, 150, 150)),
|
||||
),
|
||||
Token::Float(float) => formatted.push_str(&float.yellow()),
|
||||
Token::Identifier(identifier) => {
|
||||
formatted.push_str(&identifier.blue());
|
||||
formatted.push(' ');
|
||||
}
|
||||
Token::Integer(integer) => formatted.push_str(&integer.cyan()),
|
||||
Token::String(string) => formatted.push_str(&string.magenta()),
|
||||
Token::LeftCurlyBrace => {
|
||||
block_depth += 1;
|
||||
|
||||
formatted.push_str(token.as_str());
|
||||
line_break(&mut formatted, block_depth)
|
||||
}
|
||||
Token::RightCurlyBrace => {
|
||||
block_depth -= 1;
|
||||
|
||||
line_break(&mut formatted, block_depth);
|
||||
formatted.push_str(token.as_str());
|
||||
}
|
||||
Token::Semicolon => {
|
||||
formatted.push_str(token.as_str());
|
||||
line_break(&mut formatted, block_depth);
|
||||
}
|
||||
Token::Eof => continue,
|
||||
token => {
|
||||
formatted.push_str(token.as_str());
|
||||
formatted.push(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let renderer = Renderer::styled();
|
||||
let mut snippet = Snippet::source(&formatted).fold(false);
|
||||
|
||||
if let Some(origin) = self.origin {
|
||||
snippet = snippet.origin(origin);
|
||||
}
|
||||
|
||||
let mut message = Level::Info.title("Formatted source").snippet(snippet);
|
||||
|
||||
if let Some(footer) = self.footer {
|
||||
message = message.footer(Level::Note.title("Footer").snippet(Snippet::source(footer)));
|
||||
}
|
||||
|
||||
let formatted = renderer.info(Style::new()).render(message).to_string();
|
||||
|
||||
formatted
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Chunk, Operation, Span};
|
||||
use crate::{Chunk, Operation};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Instruction(u32);
|
||||
@ -208,11 +208,11 @@ impl Instruction {
|
||||
instruction
|
||||
}
|
||||
|
||||
pub fn call(function_index: u8, argument_count: u8) -> Instruction {
|
||||
pub fn call(to_register: u8, function_index: u8) -> Instruction {
|
||||
let mut instruction = Instruction(Operation::Call as u32);
|
||||
|
||||
instruction.set_a(function_index);
|
||||
instruction.set_b(argument_count);
|
||||
instruction.set_a(to_register);
|
||||
instruction.set_b(function_index);
|
||||
|
||||
instruction
|
||||
}
|
||||
@ -286,8 +286,8 @@ impl Instruction {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_a(&mut self, destination: u8) {
|
||||
self.0 |= (destination as u32) << 24;
|
||||
pub fn set_a(&mut self, to_register: u8) {
|
||||
self.0 |= (to_register as u32) << 24;
|
||||
}
|
||||
|
||||
pub fn set_b(&mut self, argument: u8) {
|
||||
@ -404,14 +404,14 @@ impl Instruction {
|
||||
Some(format!("R{register_index} = C{constant_index} {jump}",))
|
||||
}
|
||||
Operation::LoadList => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let first_index = self.b();
|
||||
let last_index = self.c();
|
||||
|
||||
Some(format!("R{destination} = [R{first_index}..=R{last_index}]",))
|
||||
Some(format!("R{to_register} = [R{first_index}..=R{last_index}]",))
|
||||
}
|
||||
Operation::DefineLocal => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let local_index = self.b();
|
||||
let identifier_display = if let Some(chunk) = chunk {
|
||||
match chunk.get_identifier(local_index) {
|
||||
@ -424,7 +424,7 @@ impl Instruction {
|
||||
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
|
||||
|
||||
Some(format!(
|
||||
"L{local_index} = R{destination} {mutable_display} {identifier_display}"
|
||||
"L{local_index} = R{to_register} {mutable_display} {identifier_display}"
|
||||
))
|
||||
}
|
||||
Operation::GetLocal => {
|
||||
@ -451,55 +451,55 @@ impl Instruction {
|
||||
))
|
||||
}
|
||||
Operation::Add => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let (first_argument, second_argument) = format_arguments();
|
||||
|
||||
Some(format!(
|
||||
"R{destination} = {first_argument} + {second_argument}",
|
||||
"R{to_register} = {first_argument} + {second_argument}",
|
||||
))
|
||||
}
|
||||
Operation::Subtract => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let (first_argument, second_argument) = format_arguments();
|
||||
|
||||
Some(format!(
|
||||
"R{destination} = {first_argument} - {second_argument}",
|
||||
"R{to_register} = {first_argument} - {second_argument}",
|
||||
))
|
||||
}
|
||||
Operation::Multiply => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let (first_argument, second_argument) = format_arguments();
|
||||
|
||||
Some(format!(
|
||||
"R{destination} = {first_argument} * {second_argument}",
|
||||
"R{to_register} = {first_argument} * {second_argument}",
|
||||
))
|
||||
}
|
||||
Operation::Divide => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let (first_argument, second_argument) = format_arguments();
|
||||
|
||||
Some(format!(
|
||||
"R{destination} = {first_argument} / {second_argument}",
|
||||
"R{to_register} = {first_argument} / {second_argument}",
|
||||
))
|
||||
}
|
||||
Operation::Modulo => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let (first_argument, second_argument) = format_arguments();
|
||||
|
||||
Some(format!(
|
||||
"R{destination} = {first_argument} % {second_argument}",
|
||||
"R{to_register} = {first_argument} % {second_argument}",
|
||||
))
|
||||
}
|
||||
Operation::Test => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let test_value = self.c_as_boolean();
|
||||
|
||||
jump_offset = Some(1);
|
||||
|
||||
Some(format!("if R{destination} != {test_value} {{ JUMP }}",))
|
||||
Some(format!("if R{to_register} != {test_value} {{ JUMP }}",))
|
||||
}
|
||||
Operation::TestSet => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let argument = format!("R{}", self.b());
|
||||
let test_value = self.c_as_boolean();
|
||||
let bang = if test_value { "" } else { "!" };
|
||||
@ -507,7 +507,7 @@ impl Instruction {
|
||||
jump_offset = Some(1);
|
||||
|
||||
Some(format!(
|
||||
"if {bang}R{destination} {{ R{destination} = R{argument} }}",
|
||||
"if {bang}R{to_register} {{ R{to_register} = R{argument} }}",
|
||||
))
|
||||
}
|
||||
Operation::Equal => {
|
||||
@ -539,24 +539,24 @@ impl Instruction {
|
||||
))
|
||||
}
|
||||
Operation::Negate => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let argument = if self.b_is_constant() {
|
||||
format!("C{}", self.b())
|
||||
} else {
|
||||
format!("R{}", self.b())
|
||||
};
|
||||
|
||||
Some(format!("R{destination} = -{argument}"))
|
||||
Some(format!("R{to_register} = -{argument}"))
|
||||
}
|
||||
Operation::Not => {
|
||||
let destination = self.a();
|
||||
let to_register = self.a();
|
||||
let argument = if self.b_is_constant() {
|
||||
format!("C{}", self.b())
|
||||
} else {
|
||||
format!("R{}", self.b())
|
||||
};
|
||||
|
||||
Some(format!("R{destination} = !{argument}"))
|
||||
Some(format!("R{to_register} = !{argument}"))
|
||||
}
|
||||
Operation::Jump => {
|
||||
let offset = self.b() as isize;
|
||||
@ -571,14 +571,12 @@ impl Instruction {
|
||||
None
|
||||
}
|
||||
Operation::Call => {
|
||||
let function_index = self.a();
|
||||
let argument_count = self.b();
|
||||
let first_argument = function_index + 1;
|
||||
let last_argument = function_index + argument_count;
|
||||
let to_register = self.a();
|
||||
let function_index = self.b();
|
||||
|
||||
let mut output = format!("R{function_index}(");
|
||||
|
||||
for register in first_argument..=last_argument {
|
||||
for register in function_index + 1..to_register {
|
||||
output.push_str(&format!("R{}", register));
|
||||
}
|
||||
|
||||
@ -795,11 +793,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn call() {
|
||||
let instruction = Instruction::call(4, 1);
|
||||
let instruction = Instruction::call(4, 3);
|
||||
|
||||
assert_eq!(instruction.operation(), Operation::Call);
|
||||
assert_eq!(instruction.a(), 4);
|
||||
assert_eq!(instruction.b(), 1);
|
||||
assert_eq!(instruction.b(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -4,6 +4,8 @@
|
||||
//! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions
|
||||
//! - [`Lexer`], which lexes the input a token at a time
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{dust_error::AnnotatedError, Span, Token};
|
||||
@ -670,6 +672,18 @@ impl AnnotatedError for LexError {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LexError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.description())?;
|
||||
|
||||
if let Some(details) = self.details() {
|
||||
write!(f, ": {}", details)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod chunk;
|
||||
mod dust_error;
|
||||
mod formatter;
|
||||
mod identifier;
|
||||
mod instruction;
|
||||
mod lexer;
|
||||
@ -14,6 +15,7 @@ use std::fmt::Display;
|
||||
|
||||
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
||||
pub use dust_error::{AnnotatedError, DustError};
|
||||
pub use formatter::Formatter;
|
||||
pub use identifier::Identifier;
|
||||
pub use instruction::Instruction;
|
||||
pub use lexer::{lex, LexError, Lexer};
|
||||
|
@ -437,14 +437,7 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
self.advance()?;
|
||||
self.parse(
|
||||
rule.precedence.increment(),
|
||||
Allowed {
|
||||
assignment: false,
|
||||
explicit_return: false,
|
||||
implicit_return: false,
|
||||
},
|
||||
)?;
|
||||
self.parse_sub_expression(&rule.precedence)?;
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
@ -562,14 +555,7 @@ impl<'src> Parser<'src> {
|
||||
let rule = ParseRule::from(&operator);
|
||||
|
||||
self.advance()?;
|
||||
self.parse(
|
||||
rule.precedence.increment(),
|
||||
Allowed {
|
||||
assignment: false,
|
||||
explicit_return: false,
|
||||
implicit_return: false,
|
||||
},
|
||||
)?;
|
||||
self.parse_sub_expression(&rule.precedence)?;
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
@ -646,14 +632,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.increment_register()?;
|
||||
self.advance()?;
|
||||
self.parse(
|
||||
rule.precedence.increment(),
|
||||
Allowed {
|
||||
assignment: false,
|
||||
explicit_return: false,
|
||||
implicit_return: false,
|
||||
},
|
||||
)?;
|
||||
self.parse_sub_expression(&rule.precedence)?;
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
@ -916,7 +895,14 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
fn parse_statement(&mut self, allowed: Allowed, context: Context) -> Result<(), ParseError> {
|
||||
self.parse(Precedence::None, allowed)?;
|
||||
self.parse(
|
||||
Precedence::None,
|
||||
Allowed {
|
||||
assignment: true,
|
||||
explicit_return: true,
|
||||
implicit_return: true,
|
||||
},
|
||||
)?;
|
||||
|
||||
let previous_instructions = self.chunk.get_last_n_instructions();
|
||||
|
||||
@ -962,6 +948,17 @@ impl<'src> Parser<'src> {
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_sub_expression(&mut self, precedence: &Precedence) -> Result<(), ParseError> {
|
||||
self.parse(
|
||||
precedence.increment(),
|
||||
Allowed {
|
||||
assignment: false,
|
||||
explicit_return: false,
|
||||
implicit_return: false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||
if !allowed.explicit_return {
|
||||
return Err(ParseError::UnexpectedReturn {
|
||||
@ -1160,26 +1157,21 @@ impl<'src> Parser<'src> {
|
||||
self.advance()?;
|
||||
|
||||
let function_register = self.current_register;
|
||||
let mut argument_count = 0;
|
||||
|
||||
self.increment_register()?;
|
||||
|
||||
while !self.allow(Token::RightParenthesis)? {
|
||||
if argument_count > 0 {
|
||||
self.expect(Token::Comma)?;
|
||||
}
|
||||
|
||||
self.parse_expression()?;
|
||||
|
||||
argument_count += 1;
|
||||
self.allow(Token::Comma)?;
|
||||
}
|
||||
|
||||
let end = self.current_position.1;
|
||||
|
||||
self.emit_instruction(
|
||||
Instruction::call(function_register, argument_count),
|
||||
Instruction::call(self.current_register, function_register),
|
||||
Span(start, end),
|
||||
);
|
||||
self.increment_register()?;
|
||||
|
||||
self.parsed_expression = true;
|
||||
|
||||
|
@ -132,6 +132,66 @@ impl<'src> Token<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Token::Eof => "",
|
||||
Token::Boolean(text) => text,
|
||||
Token::Byte(text) => text,
|
||||
Token::Character(_) => "character token",
|
||||
Token::Float(text) => text,
|
||||
Token::Identifier(text) => text,
|
||||
Token::Integer(text) => text,
|
||||
Token::String(text) => text,
|
||||
Token::Async => "async",
|
||||
Token::Bool => "bool",
|
||||
Token::Break => "break",
|
||||
Token::Else => "else",
|
||||
Token::FloatKeyword => "float",
|
||||
Token::Fn => "fn",
|
||||
Token::If => "if",
|
||||
Token::Int => "int",
|
||||
Token::Let => "let",
|
||||
Token::Loop => "loop",
|
||||
Token::Map => "map",
|
||||
Token::Mut => "mut",
|
||||
Token::Str => "str",
|
||||
Token::Struct => "struct",
|
||||
Token::While => "while",
|
||||
Token::BangEqual => "!=",
|
||||
Token::Bang => "!",
|
||||
Token::Colon => ":",
|
||||
Token::Comma => ",",
|
||||
Token::Dot => ".",
|
||||
Token::DoubleAmpersand => "&&",
|
||||
Token::DoubleDot => "..",
|
||||
Token::DoubleEqual => "==",
|
||||
Token::DoublePipe => "||",
|
||||
Token::Equal => "=",
|
||||
Token::Greater => ">",
|
||||
Token::GreaterEqual => ">=",
|
||||
Token::LeftCurlyBrace => "{",
|
||||
Token::LeftParenthesis => "(",
|
||||
Token::LeftSquareBrace => "[",
|
||||
Token::Less => "<",
|
||||
Token::LessEqual => "<=",
|
||||
Token::Minus => "-",
|
||||
Token::MinusEqual => "-=",
|
||||
Token::Percent => "%",
|
||||
Token::PercentEqual => "%=",
|
||||
Token::Plus => "+",
|
||||
Token::PlusEqual => "+=",
|
||||
Token::Return => "return",
|
||||
Token::RightCurlyBrace => "}",
|
||||
Token::RightParenthesis => ")",
|
||||
Token::RightSquareBrace => "]",
|
||||
Token::Semicolon => ";",
|
||||
Token::Slash => "/",
|
||||
Token::SlashEqual => "/=",
|
||||
Token::Star => "*",
|
||||
Token::StarEqual => "*=",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_owned(&self) -> TokenOwned {
|
||||
match self {
|
||||
Token::Async => TokenOwned::Async,
|
||||
|
@ -368,8 +368,8 @@ impl Vm {
|
||||
self.ip = new_ip;
|
||||
}
|
||||
Operation::Call => {
|
||||
let function_index = instruction.a();
|
||||
let argument_count = instruction.b();
|
||||
let to_register = instruction.a();
|
||||
let function_index = instruction.b();
|
||||
let value = self.get(function_index, position)?.clone();
|
||||
let function = if let Value::Function(function) = value {
|
||||
function
|
||||
@ -380,13 +380,12 @@ impl Vm {
|
||||
});
|
||||
};
|
||||
let mut function_vm = Vm::new(function.take_chunk());
|
||||
let first_argument_index = function_index + 1;
|
||||
let last_argument_index = first_argument_index + argument_count - 1;
|
||||
|
||||
for argument_index in first_argument_index..=last_argument_index {
|
||||
for argument_index in function_index + 1..to_register {
|
||||
let argument = self.get(argument_index, position)?.clone();
|
||||
let top_of_stack = function_vm.stack.len() as u8;
|
||||
|
||||
function_vm.stack.push(Register::Value(argument));
|
||||
function_vm.set(top_of_stack, argument, position)?;
|
||||
}
|
||||
|
||||
let return_value = function_vm.run()?;
|
||||
|
Loading…
Reference in New Issue
Block a user