Create formatter
This commit is contained in:
parent
5eb901f468
commit
c7bba88875
@ -1,12 +1,10 @@
|
|||||||
use std::{
|
use std::fmt::{self, Debug, Display};
|
||||||
f32::DIGITS,
|
|
||||||
fmt::{self, Debug, Display, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use rayon::{iter::ParallelIterator, str::ParallelString};
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
@ -281,7 +279,7 @@ impl Default for Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Chunk {
|
impl Display for Chunk {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
@ -291,7 +289,7 @@ impl Display for Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Chunk {
|
impl Debug for Chunk {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
@ -448,6 +446,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
} else {
|
} else {
|
||||||
line_characters.iter().collect::<String>()
|
line_characters.iter().collect::<String>()
|
||||||
};
|
};
|
||||||
|
let length_before_content = disassembly.chars().count();
|
||||||
|
|
||||||
for _ in 0..indent {
|
for _ in 0..indent {
|
||||||
disassembly.push_str("│ ");
|
disassembly.push_str("│ ");
|
||||||
@ -461,10 +460,18 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
disassembly.push_str(&content);
|
disassembly.push_str(&content);
|
||||||
disassembly.push_str(&" ".repeat(right_pad_length));
|
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 {
|
if add_border {
|
||||||
disassembly.push('│');
|
disassembly.push('│');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disassembly.push_str(&line_length.to_string());
|
||||||
disassembly.push('\n');
|
disassembly.push('\n');
|
||||||
|
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
@ -480,6 +487,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let push_header = |header: &str, disassembly: &mut String| {
|
let push_header = |header: &str, disassembly: &mut String| {
|
||||||
push(
|
push(
|
||||||
header,
|
header,
|
||||||
@ -527,19 +535,6 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
push_border(&top_border, &mut disassembly);
|
push_border(&top_border, &mut disassembly);
|
||||||
push_header(self.name, &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!(
|
let info_line = format!(
|
||||||
"{} instructions, {} constants, {} locals",
|
"{} instructions, {} constants, {} locals",
|
||||||
self.chunk.instructions.len(),
|
self.chunk.instructions.len(),
|
||||||
@ -658,6 +653,12 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
|
|
||||||
push_border(&bottom_border, &mut disassembly);
|
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 expected_length = self.predict_length();
|
||||||
let actual_length = disassembly.len();
|
let actual_length = disassembly.len();
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ impl<'src> DustError<'src> {
|
|||||||
.unwrap_or_else(|| "While running this code".to_string());
|
.unwrap_or_else(|| "While running this code".to_string());
|
||||||
let message = Level::Error.title(&label).snippet(
|
let message = Level::Error.title(&label).snippet(
|
||||||
Snippet::source(source)
|
Snippet::source(source)
|
||||||
.fold(true)
|
.fold(false)
|
||||||
.annotation(Level::Error.span(position.0..position.1).label(&details)),
|
.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());
|
.unwrap_or_else(|| "While parsing this code".to_string());
|
||||||
let message = Level::Error.title(&label).snippet(
|
let message = Level::Error.title(&label).snippet(
|
||||||
Snippet::source(source)
|
Snippet::source(source)
|
||||||
.fold(true)
|
.fold(false)
|
||||||
.annotation(Level::Error.span(position.0..position.1).label(&details)),
|
.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 serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Chunk, Operation, Span};
|
use crate::{Chunk, Operation};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct Instruction(u32);
|
pub struct Instruction(u32);
|
||||||
@ -208,11 +208,11 @@ impl Instruction {
|
|||||||
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);
|
let mut instruction = Instruction(Operation::Call as u32);
|
||||||
|
|
||||||
instruction.set_a(function_index);
|
instruction.set_a(to_register);
|
||||||
instruction.set_b(argument_count);
|
instruction.set_b(function_index);
|
||||||
|
|
||||||
instruction
|
instruction
|
||||||
}
|
}
|
||||||
@ -286,8 +286,8 @@ impl Instruction {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_a(&mut self, destination: u8) {
|
pub fn set_a(&mut self, to_register: u8) {
|
||||||
self.0 |= (destination as u32) << 24;
|
self.0 |= (to_register as u32) << 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_b(&mut self, argument: u8) {
|
pub fn set_b(&mut self, argument: u8) {
|
||||||
@ -404,14 +404,14 @@ impl Instruction {
|
|||||||
Some(format!("R{register_index} = C{constant_index} {jump}",))
|
Some(format!("R{register_index} = C{constant_index} {jump}",))
|
||||||
}
|
}
|
||||||
Operation::LoadList => {
|
Operation::LoadList => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let first_index = self.b();
|
let first_index = self.b();
|
||||||
let last_index = self.c();
|
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 => {
|
Operation::DefineLocal => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let local_index = self.b();
|
let local_index = self.b();
|
||||||
let identifier_display = if let Some(chunk) = chunk {
|
let identifier_display = if let Some(chunk) = chunk {
|
||||||
match chunk.get_identifier(local_index) {
|
match chunk.get_identifier(local_index) {
|
||||||
@ -424,7 +424,7 @@ impl Instruction {
|
|||||||
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
|
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"L{local_index} = R{destination} {mutable_display} {identifier_display}"
|
"L{local_index} = R{to_register} {mutable_display} {identifier_display}"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::GetLocal => {
|
Operation::GetLocal => {
|
||||||
@ -451,55 +451,55 @@ impl Instruction {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let (first_argument, second_argument) = format_arguments();
|
let (first_argument, second_argument) = format_arguments();
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"R{destination} = {first_argument} + {second_argument}",
|
"R{to_register} = {first_argument} + {second_argument}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let (first_argument, second_argument) = format_arguments();
|
let (first_argument, second_argument) = format_arguments();
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"R{destination} = {first_argument} - {second_argument}",
|
"R{to_register} = {first_argument} - {second_argument}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let (first_argument, second_argument) = format_arguments();
|
let (first_argument, second_argument) = format_arguments();
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"R{destination} = {first_argument} * {second_argument}",
|
"R{to_register} = {first_argument} * {second_argument}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let (first_argument, second_argument) = format_arguments();
|
let (first_argument, second_argument) = format_arguments();
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"R{destination} = {first_argument} / {second_argument}",
|
"R{to_register} = {first_argument} / {second_argument}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Modulo => {
|
Operation::Modulo => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let (first_argument, second_argument) = format_arguments();
|
let (first_argument, second_argument) = format_arguments();
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"R{destination} = {first_argument} % {second_argument}",
|
"R{to_register} = {first_argument} % {second_argument}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Test => {
|
Operation::Test => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let test_value = self.c_as_boolean();
|
let test_value = self.c_as_boolean();
|
||||||
|
|
||||||
jump_offset = Some(1);
|
jump_offset = Some(1);
|
||||||
|
|
||||||
Some(format!("if R{destination} != {test_value} {{ JUMP }}",))
|
Some(format!("if R{to_register} != {test_value} {{ JUMP }}",))
|
||||||
}
|
}
|
||||||
Operation::TestSet => {
|
Operation::TestSet => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let argument = format!("R{}", self.b());
|
let argument = format!("R{}", self.b());
|
||||||
let test_value = self.c_as_boolean();
|
let test_value = self.c_as_boolean();
|
||||||
let bang = if test_value { "" } else { "!" };
|
let bang = if test_value { "" } else { "!" };
|
||||||
@ -507,7 +507,7 @@ impl Instruction {
|
|||||||
jump_offset = Some(1);
|
jump_offset = Some(1);
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
"if {bang}R{destination} {{ R{destination} = R{argument} }}",
|
"if {bang}R{to_register} {{ R{to_register} = R{argument} }}",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Equal => {
|
Operation::Equal => {
|
||||||
@ -539,24 +539,24 @@ impl Instruction {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
Operation::Negate => {
|
Operation::Negate => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let argument = if self.b_is_constant() {
|
let argument = if self.b_is_constant() {
|
||||||
format!("C{}", self.b())
|
format!("C{}", self.b())
|
||||||
} else {
|
} else {
|
||||||
format!("R{}", self.b())
|
format!("R{}", self.b())
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(format!("R{destination} = -{argument}"))
|
Some(format!("R{to_register} = -{argument}"))
|
||||||
}
|
}
|
||||||
Operation::Not => {
|
Operation::Not => {
|
||||||
let destination = self.a();
|
let to_register = self.a();
|
||||||
let argument = if self.b_is_constant() {
|
let argument = if self.b_is_constant() {
|
||||||
format!("C{}", self.b())
|
format!("C{}", self.b())
|
||||||
} else {
|
} else {
|
||||||
format!("R{}", self.b())
|
format!("R{}", self.b())
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(format!("R{destination} = !{argument}"))
|
Some(format!("R{to_register} = !{argument}"))
|
||||||
}
|
}
|
||||||
Operation::Jump => {
|
Operation::Jump => {
|
||||||
let offset = self.b() as isize;
|
let offset = self.b() as isize;
|
||||||
@ -571,14 +571,12 @@ impl Instruction {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
Operation::Call => {
|
Operation::Call => {
|
||||||
let function_index = self.a();
|
let to_register = self.a();
|
||||||
let argument_count = self.b();
|
let function_index = self.b();
|
||||||
let first_argument = function_index + 1;
|
|
||||||
let last_argument = function_index + argument_count;
|
|
||||||
|
|
||||||
let mut output = format!("R{function_index}(");
|
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));
|
output.push_str(&format!("R{}", register));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,11 +793,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn call() {
|
fn call() {
|
||||||
let instruction = Instruction::call(4, 1);
|
let instruction = Instruction::call(4, 3);
|
||||||
|
|
||||||
assert_eq!(instruction.operation(), Operation::Call);
|
assert_eq!(instruction.operation(), Operation::Call);
|
||||||
assert_eq!(instruction.a(), 4);
|
assert_eq!(instruction.a(), 4);
|
||||||
assert_eq!(instruction.b(), 1);
|
assert_eq!(instruction.b(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
//! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions
|
//! - [`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
|
//! - [`Lexer`], which lexes the input a token at a time
|
||||||
|
|
||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{dust_error::AnnotatedError, Span, Token};
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
mod chunk;
|
mod chunk;
|
||||||
mod dust_error;
|
mod dust_error;
|
||||||
|
mod formatter;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
@ -14,6 +15,7 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
||||||
pub use dust_error::{AnnotatedError, DustError};
|
pub use dust_error::{AnnotatedError, DustError};
|
||||||
|
pub use formatter::Formatter;
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use instruction::Instruction;
|
pub use instruction::Instruction;
|
||||||
pub use lexer::{lex, LexError, Lexer};
|
pub use lexer::{lex, LexError, Lexer};
|
||||||
|
@ -437,14 +437,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse(
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
rule.precedence.increment(),
|
|
||||||
Allowed {
|
|
||||||
assignment: false,
|
|
||||||
explicit_return: false,
|
|
||||||
implicit_return: false,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (right_instruction, right_position) =
|
let (right_instruction, right_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -562,14 +555,7 @@ impl<'src> Parser<'src> {
|
|||||||
let rule = ParseRule::from(&operator);
|
let rule = ParseRule::from(&operator);
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse(
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
rule.precedence.increment(),
|
|
||||||
Allowed {
|
|
||||||
assignment: false,
|
|
||||||
explicit_return: false,
|
|
||||||
implicit_return: false,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (right_instruction, right_position) =
|
let (right_instruction, right_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -646,14 +632,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse(
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
rule.precedence.increment(),
|
|
||||||
Allowed {
|
|
||||||
assignment: false,
|
|
||||||
explicit_return: false,
|
|
||||||
implicit_return: false,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (right_instruction, right_position) =
|
let (right_instruction, right_position) =
|
||||||
self.chunk.pop_instruction(self.current_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> {
|
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();
|
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> {
|
fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
if !allowed.explicit_return {
|
if !allowed.explicit_return {
|
||||||
return Err(ParseError::UnexpectedReturn {
|
return Err(ParseError::UnexpectedReturn {
|
||||||
@ -1160,26 +1157,21 @@ impl<'src> Parser<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
let function_register = self.current_register;
|
let function_register = self.current_register;
|
||||||
let mut argument_count = 0;
|
|
||||||
|
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
|
|
||||||
while !self.allow(Token::RightParenthesis)? {
|
while !self.allow(Token::RightParenthesis)? {
|
||||||
if argument_count > 0 {
|
|
||||||
self.expect(Token::Comma)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
self.allow(Token::Comma)?;
|
||||||
argument_count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::call(function_register, argument_count),
|
Instruction::call(self.current_register, function_register),
|
||||||
Span(start, end),
|
Span(start, end),
|
||||||
);
|
);
|
||||||
|
self.increment_register()?;
|
||||||
|
|
||||||
self.parsed_expression = true;
|
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 {
|
pub fn to_owned(&self) -> TokenOwned {
|
||||||
match self {
|
match self {
|
||||||
Token::Async => TokenOwned::Async,
|
Token::Async => TokenOwned::Async,
|
||||||
|
@ -368,8 +368,8 @@ impl Vm {
|
|||||||
self.ip = new_ip;
|
self.ip = new_ip;
|
||||||
}
|
}
|
||||||
Operation::Call => {
|
Operation::Call => {
|
||||||
let function_index = instruction.a();
|
let to_register = instruction.a();
|
||||||
let argument_count = instruction.b();
|
let function_index = instruction.b();
|
||||||
let value = self.get(function_index, position)?.clone();
|
let value = self.get(function_index, position)?.clone();
|
||||||
let function = if let Value::Function(function) = value {
|
let function = if let Value::Function(function) = value {
|
||||||
function
|
function
|
||||||
@ -380,13 +380,12 @@ impl Vm {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
let mut function_vm = Vm::new(function.take_chunk());
|
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 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()?;
|
let return_value = function_vm.run()?;
|
||||||
|
Loading…
Reference in New Issue
Block a user