Add the to_string, write and write_line natives
This commit is contained in:
parent
af4e43fc9f
commit
c264aaeb13
@ -584,6 +584,7 @@ impl Instruction {
|
|||||||
let native_function_name = match native_function {
|
let native_function_name = match native_function {
|
||||||
NativeFunction::Panic => "PANIC",
|
NativeFunction::Panic => "PANIC",
|
||||||
NativeFunction::ToString => "TO_STRING",
|
NativeFunction::ToString => "TO_STRING",
|
||||||
|
NativeFunction::Write => "WRITE",
|
||||||
NativeFunction::WriteLine => "WRITE_LINE",
|
NativeFunction::WriteLine => "WRITE_LINE",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -567,8 +567,11 @@ impl<'src> Lexer<'src> {
|
|||||||
"return" => Token::Return,
|
"return" => Token::Return,
|
||||||
"str" => Token::Str,
|
"str" => Token::Str,
|
||||||
"struct" => Token::Struct,
|
"struct" => Token::Struct,
|
||||||
|
"to_string" => Token::ToString,
|
||||||
"true" => Token::Boolean("true"),
|
"true" => Token::Boolean("true"),
|
||||||
"while" => Token::While,
|
"while" => Token::While,
|
||||||
|
"write" => Token::Write,
|
||||||
|
"write_line" => Token::WriteLine,
|
||||||
_ => Token::Identifier(string),
|
_ => Token::Identifier(string),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1255,7 +1258,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
lex(input),
|
lex(input),
|
||||||
Ok(vec![
|
Ok(vec![
|
||||||
(Token::Identifier("write_line"), Span(0, 10)),
|
(Token::WriteLine, Span(0, 10)),
|
||||||
(Token::LeftParenthesis, Span(10, 11)),
|
(Token::LeftParenthesis, Span(10, 11)),
|
||||||
(Token::String("Hello, world!"), Span(11, 26)),
|
(Token::String("Hello, world!"), Span(11, 26)),
|
||||||
(Token::RightParenthesis, Span(26, 27)),
|
(Token::RightParenthesis, Span(26, 27)),
|
||||||
|
@ -2,12 +2,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
const PANIC: u8 = 0b0000_0000;
|
const PANIC: u8 = 0b0000_0000;
|
||||||
const TO_STRING: u8 = 0b0000_0001;
|
const TO_STRING: u8 = 0b0000_0001;
|
||||||
const WRITE_LINE: u8 = 0b0000_0010;
|
const WRITE: u8 = 0b0000_0010;
|
||||||
|
const WRITE_LINE: u8 = 0b0000_0011;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum NativeFunction {
|
pub enum NativeFunction {
|
||||||
Panic = PANIC as isize,
|
Panic = PANIC as isize,
|
||||||
ToString = TO_STRING as isize,
|
ToString = TO_STRING as isize,
|
||||||
|
Write = WRITE as isize,
|
||||||
WriteLine = WRITE_LINE as isize,
|
WriteLine = WRITE_LINE as isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,10 +18,11 @@ impl From<u8> for NativeFunction {
|
|||||||
match byte {
|
match byte {
|
||||||
PANIC => NativeFunction::Panic,
|
PANIC => NativeFunction::Panic,
|
||||||
TO_STRING => NativeFunction::ToString,
|
TO_STRING => NativeFunction::ToString,
|
||||||
|
WRITE => NativeFunction::Write,
|
||||||
WRITE_LINE => NativeFunction::WriteLine,
|
WRITE_LINE => NativeFunction::WriteLine,
|
||||||
_ => {
|
_ => {
|
||||||
if cfg!(test) {
|
if cfg!(test) {
|
||||||
panic!("Invalid operation byte: {}", byte)
|
panic!("Invalid native function byte: {}", byte)
|
||||||
} else {
|
} else {
|
||||||
NativeFunction::Panic
|
NativeFunction::Panic
|
||||||
}
|
}
|
||||||
@ -33,6 +36,7 @@ impl From<NativeFunction> for u8 {
|
|||||||
match native_function {
|
match native_function {
|
||||||
NativeFunction::Panic => PANIC,
|
NativeFunction::Panic => PANIC,
|
||||||
NativeFunction::ToString => TO_STRING,
|
NativeFunction::ToString => TO_STRING,
|
||||||
|
NativeFunction::Write => WRITE,
|
||||||
NativeFunction::WriteLine => WRITE_LINE,
|
NativeFunction::WriteLine => WRITE_LINE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1058,7 +1058,18 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_panic(&mut self, _: Allowed) -> Result<(), ParseError> {
|
fn parse_native_call(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
|
let native_function = match self.current_token {
|
||||||
|
Token::Panic => NativeFunction::Panic,
|
||||||
|
Token::ToString => NativeFunction::ToString,
|
||||||
|
Token::Write => NativeFunction::Write,
|
||||||
|
Token::WriteLine => NativeFunction::WriteLine,
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let is_expression = self.current_token.is_expression();
|
||||||
|
|
||||||
let start = self.current_position.0;
|
let start = self.current_position.0;
|
||||||
let start_register = self.next_register();
|
let start_register = self.next_register();
|
||||||
|
|
||||||
@ -1086,9 +1097,10 @@ impl<'src> Parser<'src> {
|
|||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
let to_register = self.next_register();
|
let to_register = self.next_register();
|
||||||
let argument_count = to_register - start_register;
|
let argument_count = to_register - start_register;
|
||||||
|
self.current_is_expression = is_expression;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::call_native(to_register, NativeFunction::Panic, argument_count),
|
Instruction::call_native(to_register, native_function, argument_count),
|
||||||
Span(start, end),
|
Span(start, end),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1727,7 +1739,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
|
|||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
Token::Panic => ParseRule {
|
Token::Panic => ParseRule {
|
||||||
prefix: Some(Parser::parse_panic),
|
prefix: Some(Parser::parse_native_call),
|
||||||
infix: None,
|
infix: None,
|
||||||
precedence: Precedence::Call,
|
precedence: Precedence::Call,
|
||||||
},
|
},
|
||||||
@ -1807,11 +1819,26 @@ impl From<&Token<'_>> for ParseRule<'_> {
|
|||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
Token::Struct => todo!(),
|
Token::Struct => todo!(),
|
||||||
|
Token::ToString => ParseRule {
|
||||||
|
prefix: Some(Parser::parse_native_call),
|
||||||
|
infix: None,
|
||||||
|
precedence: Precedence::Call,
|
||||||
|
},
|
||||||
Token::While => ParseRule {
|
Token::While => ParseRule {
|
||||||
prefix: Some(Parser::parse_while),
|
prefix: Some(Parser::parse_while),
|
||||||
infix: None,
|
infix: None,
|
||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
|
Token::Write => ParseRule {
|
||||||
|
prefix: Some(Parser::parse_native_call),
|
||||||
|
infix: None,
|
||||||
|
precedence: Precedence::Call,
|
||||||
|
},
|
||||||
|
Token::WriteLine => ParseRule {
|
||||||
|
prefix: Some(Parser::parse_native_call),
|
||||||
|
infix: None,
|
||||||
|
precedence: Precedence::Call,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,28 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Source code token.
|
macro_rules! define_tokens {
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Default, Serialize, Deserialize)]
|
($($variant:ident $(($data_type:ty))?),+ $(,)?) => {
|
||||||
pub enum Token<'src> {
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Default, Serialize, Deserialize)]
|
||||||
// End of file
|
pub enum Token<'src> {
|
||||||
#[default]
|
#[default]
|
||||||
Eof,
|
Eof,
|
||||||
|
$(
|
||||||
|
$variant $(($data_type))?,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum TokenKind {
|
||||||
|
Eof,
|
||||||
|
$(
|
||||||
|
$variant,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
define_tokens! {
|
||||||
// Hard-coded values
|
// Hard-coded values
|
||||||
Boolean(&'src str),
|
Boolean(&'src str),
|
||||||
Byte(&'src str),
|
Byte(&'src str),
|
||||||
@ -36,7 +51,11 @@ pub enum Token<'src> {
|
|||||||
Return,
|
Return,
|
||||||
Str,
|
Str,
|
||||||
Struct,
|
Struct,
|
||||||
|
ToString,
|
||||||
While,
|
While,
|
||||||
|
Write,
|
||||||
|
|
||||||
|
WriteLine,
|
||||||
|
|
||||||
// Symbols
|
// Symbols
|
||||||
ArrowThin,
|
ArrowThin,
|
||||||
@ -100,7 +119,10 @@ impl<'src> Token<'src> {
|
|||||||
Token::Mut => 3,
|
Token::Mut => 3,
|
||||||
Token::Str => 3,
|
Token::Str => 3,
|
||||||
Token::Struct => 6,
|
Token::Struct => 6,
|
||||||
|
Token::ToString => 8,
|
||||||
Token::While => 5,
|
Token::While => 5,
|
||||||
|
Token::Write => 5,
|
||||||
|
Token::WriteLine => 10,
|
||||||
Token::BangEqual => 2,
|
Token::BangEqual => 2,
|
||||||
Token::Bang => 1,
|
Token::Bang => 1,
|
||||||
Token::Colon => 1,
|
Token::Colon => 1,
|
||||||
@ -162,6 +184,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::Mut => "mut",
|
Token::Mut => "mut",
|
||||||
Token::Str => "str",
|
Token::Str => "str",
|
||||||
Token::Struct => "struct",
|
Token::Struct => "struct",
|
||||||
|
Token::ToString => "to_string",
|
||||||
Token::While => "while",
|
Token::While => "while",
|
||||||
Token::BangEqual => "!=",
|
Token::BangEqual => "!=",
|
||||||
Token::Bang => "!",
|
Token::Bang => "!",
|
||||||
@ -196,6 +219,8 @@ impl<'src> Token<'src> {
|
|||||||
Token::SlashEqual => "/=",
|
Token::SlashEqual => "/=",
|
||||||
Token::Star => "*",
|
Token::Star => "*",
|
||||||
Token::StarEqual => "*=",
|
Token::StarEqual => "*=",
|
||||||
|
Token::Write => "write",
|
||||||
|
Token::WriteLine => "write_line",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +282,10 @@ impl<'src> Token<'src> {
|
|||||||
Token::String(text) => TokenOwned::String(text.to_string()),
|
Token::String(text) => TokenOwned::String(text.to_string()),
|
||||||
Token::Str => TokenOwned::Str,
|
Token::Str => TokenOwned::Str,
|
||||||
Token::Struct => TokenOwned::Struct,
|
Token::Struct => TokenOwned::Struct,
|
||||||
|
Token::ToString => TokenOwned::ToString,
|
||||||
Token::While => TokenOwned::While,
|
Token::While => TokenOwned::While,
|
||||||
|
Token::Write => TokenOwned::Write,
|
||||||
|
Token::WriteLine => TokenOwned::WriteLine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,8 +346,11 @@ impl<'src> Token<'src> {
|
|||||||
Token::SlashEqual => TokenKind::SlashEqual,
|
Token::SlashEqual => TokenKind::SlashEqual,
|
||||||
Token::Str => TokenKind::Str,
|
Token::Str => TokenKind::Str,
|
||||||
Token::String(_) => TokenKind::String,
|
Token::String(_) => TokenKind::String,
|
||||||
|
Token::ToString => TokenKind::ToString,
|
||||||
Token::Struct => TokenKind::Struct,
|
Token::Struct => TokenKind::Struct,
|
||||||
Token::While => TokenKind::While,
|
Token::While => TokenKind::While,
|
||||||
|
Token::Write => TokenKind::Write,
|
||||||
|
Token::WriteLine => TokenKind::WriteLine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,13 +387,13 @@ impl<'src> Token<'src> {
|
|||||||
| Token::MinusEqual
|
| Token::MinusEqual
|
||||||
| Token::Percent
|
| Token::Percent
|
||||||
| Token::PercentEqual
|
| Token::PercentEqual
|
||||||
| Token::Panic
|
|
||||||
| Token::Plus
|
| Token::Plus
|
||||||
| Token::PlusEqual
|
| Token::PlusEqual
|
||||||
| Token::Slash
|
| Token::Slash
|
||||||
| Token::SlashEqual
|
| Token::SlashEqual
|
||||||
| Token::Star
|
| Token::Star
|
||||||
| Token::StarEqual
|
| Token::StarEqual
|
||||||
|
| Token::ToString
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,8 +456,11 @@ impl<'src> Display for Token<'src> {
|
|||||||
Token::StarEqual => write!(f, "*="),
|
Token::StarEqual => write!(f, "*="),
|
||||||
Token::Str => write!(f, "str"),
|
Token::Str => write!(f, "str"),
|
||||||
Token::String(value) => write!(f, "{value}"),
|
Token::String(value) => write!(f, "{value}"),
|
||||||
|
Token::ToString => write!(f, "to_string"),
|
||||||
Token::Struct => write!(f, "struct"),
|
Token::Struct => write!(f, "struct"),
|
||||||
Token::While => write!(f, "while"),
|
Token::While => write!(f, "while"),
|
||||||
|
Token::Write => write!(f, "write"),
|
||||||
|
Token::WriteLine => write!(f, "write_line"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,7 +498,10 @@ pub enum TokenOwned {
|
|||||||
Panic,
|
Panic,
|
||||||
Return,
|
Return,
|
||||||
Str,
|
Str,
|
||||||
|
ToString,
|
||||||
While,
|
While,
|
||||||
|
Write,
|
||||||
|
WriteLine,
|
||||||
|
|
||||||
// Symbols
|
// Symbols
|
||||||
ArrowThin,
|
ArrowThin,
|
||||||
@ -561,80 +598,14 @@ impl Display for TokenOwned {
|
|||||||
TokenOwned::Str => Token::Str.fmt(f),
|
TokenOwned::Str => Token::Str.fmt(f),
|
||||||
TokenOwned::String(string) => Token::String(string).fmt(f),
|
TokenOwned::String(string) => Token::String(string).fmt(f),
|
||||||
TokenOwned::Struct => Token::Struct.fmt(f),
|
TokenOwned::Struct => Token::Struct.fmt(f),
|
||||||
|
TokenOwned::ToString => Token::ToString.fmt(f),
|
||||||
TokenOwned::While => Token::While.fmt(f),
|
TokenOwned::While => Token::While.fmt(f),
|
||||||
|
TokenOwned::Write => Token::Write.fmt(f),
|
||||||
|
TokenOwned::WriteLine => Token::WriteLine.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Token representation that holds no data.
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum TokenKind {
|
|
||||||
Eof,
|
|
||||||
|
|
||||||
Identifier,
|
|
||||||
|
|
||||||
// Hard-coded values
|
|
||||||
Boolean,
|
|
||||||
Byte,
|
|
||||||
Character,
|
|
||||||
Float,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
|
|
||||||
// Keywords
|
|
||||||
Async,
|
|
||||||
Bool,
|
|
||||||
Break,
|
|
||||||
Else,
|
|
||||||
FloatKeyword,
|
|
||||||
Fn,
|
|
||||||
If,
|
|
||||||
Int,
|
|
||||||
Let,
|
|
||||||
Loop,
|
|
||||||
Map,
|
|
||||||
Panic,
|
|
||||||
Return,
|
|
||||||
Str,
|
|
||||||
While,
|
|
||||||
|
|
||||||
// Symbols
|
|
||||||
ArrowThin,
|
|
||||||
BangEqual,
|
|
||||||
Bang,
|
|
||||||
Colon,
|
|
||||||
Comma,
|
|
||||||
Dot,
|
|
||||||
DoubleAmpersand,
|
|
||||||
DoubleDot,
|
|
||||||
DoubleEqual,
|
|
||||||
DoublePipe,
|
|
||||||
Equal,
|
|
||||||
Greater,
|
|
||||||
GreaterEqual,
|
|
||||||
LeftCurlyBrace,
|
|
||||||
LeftParenthesis,
|
|
||||||
LeftSquareBrace,
|
|
||||||
Less,
|
|
||||||
LessEqual,
|
|
||||||
Minus,
|
|
||||||
MinusEqual,
|
|
||||||
Mut,
|
|
||||||
Percent,
|
|
||||||
PercentEqual,
|
|
||||||
Plus,
|
|
||||||
PlusEqual,
|
|
||||||
RightCurlyBrace,
|
|
||||||
RightParenthesis,
|
|
||||||
RightSquareBrace,
|
|
||||||
Semicolon,
|
|
||||||
Star,
|
|
||||||
StarEqual,
|
|
||||||
Struct,
|
|
||||||
Slash,
|
|
||||||
SlashEqual,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TokenKind {
|
impl Display for TokenKind {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -694,7 +665,10 @@ impl Display for TokenKind {
|
|||||||
TokenKind::SlashEqual => Token::SlashEqual.fmt(f),
|
TokenKind::SlashEqual => Token::SlashEqual.fmt(f),
|
||||||
TokenKind::String => write!(f, "string value"),
|
TokenKind::String => write!(f, "string value"),
|
||||||
TokenKind::Struct => Token::Struct.fmt(f),
|
TokenKind::Struct => Token::Struct.fmt(f),
|
||||||
|
TokenKind::ToString => Token::ToString.fmt(f),
|
||||||
TokenKind::While => Token::While.fmt(f),
|
TokenKind::While => Token::While.fmt(f),
|
||||||
|
TokenKind::Write => Token::Write.fmt(f),
|
||||||
|
TokenKind::WriteLine => Token::WriteLine.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use std::{cmp::Ordering, mem::replace};
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
io::{self, stdout, Write},
|
||||||
|
mem::replace,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parse, value::Primitive, AnnotatedError, Chunk, ChunkError, DustError, FunctionType,
|
parse, value::Primitive, AnnotatedError, Chunk, ChunkError, DustError, FunctionType,
|
||||||
@ -423,7 +427,56 @@ impl Vm {
|
|||||||
|
|
||||||
Some(Value::Primitive(Primitive::String(string)))
|
Some(Value::Primitive(Primitive::String(string)))
|
||||||
}
|
}
|
||||||
NativeFunction::WriteLine => todo!(),
|
NativeFunction::Write => {
|
||||||
|
let mut stdout = stdout();
|
||||||
|
|
||||||
|
for argument_index in 0..argument_count {
|
||||||
|
if argument_index != 0 {
|
||||||
|
stdout.write(b" ").map_err(|io_error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument = self.get(argument_index, position)?;
|
||||||
|
|
||||||
|
write!(stdout, "{}", argument).map_err(|io_error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
NativeFunction::WriteLine => {
|
||||||
|
let mut stdout = stdout();
|
||||||
|
|
||||||
|
for argument_index in 0..argument_count {
|
||||||
|
if argument_index != 0 {
|
||||||
|
stdout.write(b" ").map_err(|io_error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument_string =
|
||||||
|
self.get(argument_index, position)?.to_string();
|
||||||
|
|
||||||
|
stdout.write_all(argument_string.as_bytes()).map_err(
|
||||||
|
|io_error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout.write(b"\n").map_err(|io_error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = return_value {
|
if let Some(value) = return_value {
|
||||||
@ -695,6 +748,10 @@ pub enum VmError {
|
|||||||
|
|
||||||
// Wrappers for foreign errors
|
// Wrappers for foreign errors
|
||||||
Chunk(ChunkError),
|
Chunk(ChunkError),
|
||||||
|
Io {
|
||||||
|
error: io::ErrorKind,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
Value {
|
Value {
|
||||||
error: ValueError,
|
error: ValueError,
|
||||||
position: Span,
|
position: Span,
|
||||||
@ -725,6 +782,7 @@ impl AnnotatedError for VmError {
|
|||||||
Self::StackUnderflow { .. } => "Stack underflow",
|
Self::StackUnderflow { .. } => "Stack underflow",
|
||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
Self::UndefinedVariable { .. } => "Undefined variable",
|
||||||
Self::Chunk(error) => error.description(),
|
Self::Chunk(error) => error.description(),
|
||||||
|
Self::Io { .. } => "I/O error",
|
||||||
Self::Value { .. } => "Value error",
|
Self::Value { .. } => "Value error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -741,6 +799,7 @@ impl AnnotatedError for VmError {
|
|||||||
Some(format!("{identifier} is not in scope"))
|
Some(format!("{identifier} is not in scope"))
|
||||||
}
|
}
|
||||||
Self::Chunk(error) => error.details(),
|
Self::Chunk(error) => error.details(),
|
||||||
|
Self::Io { error, .. } => Some(error.to_string()),
|
||||||
Self::Value { error, .. } => Some(error.to_string()),
|
Self::Value { error, .. } => Some(error.to_string()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -759,6 +818,7 @@ impl AnnotatedError for VmError {
|
|||||||
Self::StackOverflow { position } => *position,
|
Self::StackOverflow { position } => *position,
|
||||||
Self::UndefinedVariable { position, .. } => *position,
|
Self::UndefinedVariable { position, .. } => *position,
|
||||||
Self::Chunk(error) => error.position(),
|
Self::Chunk(error) => error.position(),
|
||||||
|
Self::Io { position, .. } => *position,
|
||||||
Self::Value { position, .. } => *position,
|
Self::Value { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ fn panic() {
|
|||||||
Instruction::call_native(2, NativeFunction::Panic, 2),
|
Instruction::call_native(2, NativeFunction::Panic, 2),
|
||||||
Span(0, 27)
|
Span(0, 27)
|
||||||
),
|
),
|
||||||
(Instruction::r#return(true), Span(27, 27))
|
|
||||||
],
|
],
|
||||||
vec![Value::string("Goodbye world!"), Value::integer(42)],
|
vec![Value::string("Goodbye world!"), Value::integer(42)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -33,3 +32,27 @@ fn panic() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_string() {
|
||||||
|
let source = "to_string(42)";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0, false), Span(10, 12)),
|
||||||
|
(
|
||||||
|
Instruction::call_native(1, NativeFunction::ToString, 1),
|
||||||
|
Span(0, 13)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(13, 13))
|
||||||
|
],
|
||||||
|
vec![Value::integer(42)],
|
||||||
|
vec![]
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(Value::string("42"))))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user