Add lots of new native functions
This commit is contained in:
parent
d7be203bfc
commit
4d6412006a
@ -581,12 +581,7 @@ impl Instruction {
|
|||||||
let to_register = self.a();
|
let to_register = self.a();
|
||||||
let native_function = NativeFunction::from(self.b());
|
let native_function = NativeFunction::from(self.b());
|
||||||
let argument_count = self.c();
|
let argument_count = self.c();
|
||||||
let native_function_name = match native_function {
|
let native_function_name = native_function.as_str();
|
||||||
NativeFunction::Panic => "PANIC",
|
|
||||||
NativeFunction::ToString => "TO_STRING",
|
|
||||||
NativeFunction::Write => "WRITE",
|
|
||||||
NativeFunction::WriteLine => "WRITE_LINE",
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut output = format!("R{to_register} = {native_function_name}(");
|
let mut output = format!("R{to_register} = {native_function_name}(");
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ pub use operation::Operation;
|
|||||||
pub use parser::{parse, ParseError, Parser};
|
pub use parser::{parse, ParseError, Parser};
|
||||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||||
pub use token::{Token, TokenKind, TokenOwned};
|
pub use token::{Token, TokenKind, TokenOwned};
|
||||||
pub use value::{Function, Value, ValueError};
|
pub use value::{Function, Primitive, Value, ValueError};
|
||||||
pub use vm::{run, Vm, VmError};
|
pub use vm::{run, Vm, VmError};
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -1,23 +1,401 @@
|
|||||||
|
use std::{
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
io::{self, stdout, Write},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{Instruction, Primitive, Span, Value, Vm, VmError};
|
||||||
|
|
||||||
const PANIC: u8 = 0b0000_0000;
|
const PANIC: u8 = 0b0000_0000;
|
||||||
const TO_STRING: u8 = 0b0000_0001;
|
|
||||||
const WRITE: u8 = 0b0000_0010;
|
// Type conversion
|
||||||
const WRITE_LINE: u8 = 0b0000_0011;
|
const PARSE: u8 = 0b0000_0001;
|
||||||
|
const TO_BYTE: u8 = 0b0000_0010;
|
||||||
|
const TO_FLOAT: u8 = 0b0000_0011;
|
||||||
|
const TO_INTEGER: u8 = 0b0000_0100;
|
||||||
|
const TO_STRING: u8 = 0b0000_0101;
|
||||||
|
|
||||||
|
// List
|
||||||
|
const ALL: u8 = 0b0000_0110;
|
||||||
|
const ANY: u8 = 0b0000_0111;
|
||||||
|
const APPEND: u8 = 0b0000_1000;
|
||||||
|
const CONTAINS: u8 = 0b0000_1001;
|
||||||
|
const FIND: u8 = 0b0000_1010;
|
||||||
|
const FLATTEN: u8 = 0b0000_1011;
|
||||||
|
const GET: u8 = 0b0000_1100;
|
||||||
|
const INDEX_OF: u8 = 0b0000_1101;
|
||||||
|
const JOIN: u8 = 0b0000_1110;
|
||||||
|
const LENGTH: u8 = 0b0000_1111;
|
||||||
|
const MAP: u8 = 0b0001_0000;
|
||||||
|
const PREPEND: u8 = 0b0001_0001;
|
||||||
|
const REDUCE: u8 = 0b0001_0010;
|
||||||
|
const REMOVE: u8 = 0b0001_0011;
|
||||||
|
const REVERSE: u8 = 0b0001_0100;
|
||||||
|
const SET: u8 = 0b0001_0101;
|
||||||
|
const SLICE: u8 = 0b0001_0110;
|
||||||
|
const SORT: u8 = 0b0001_0111;
|
||||||
|
const SPLIT: u8 = 0b0001_1000;
|
||||||
|
const UNZIP: u8 = 0b0001_1001;
|
||||||
|
const ZIP: u8 = 0b0001_1010;
|
||||||
|
|
||||||
|
// String
|
||||||
|
const CHAR_AT: u8 = 0b0001_1011;
|
||||||
|
const CHAR_CODE_AT: u8 = 0b0001_1100;
|
||||||
|
const CHARS: u8 = 0b0001_1101;
|
||||||
|
const ENDS_WITH: u8 = 0b0001_1110;
|
||||||
|
const FORMAT: u8 = 0b0001_1111;
|
||||||
|
const INCLUDES: u8 = 0b0010_0000;
|
||||||
|
const MATCH: u8 = 0b0010_0001;
|
||||||
|
const PAD_END: u8 = 0b0010_0010;
|
||||||
|
const PAD_START: u8 = 0b0010_0011;
|
||||||
|
const REPEAT: u8 = 0b0010_0100;
|
||||||
|
const REPLACE: u8 = 0b0010_0101;
|
||||||
|
const SPLIT_AT: u8 = 0b0010_0110;
|
||||||
|
const SPLIT_LINES: u8 = 0b0010_0111;
|
||||||
|
const SPLIT_WHITESPACE: u8 = 0b0010_1000;
|
||||||
|
const STARTS_WITH: u8 = 0b0010_1001;
|
||||||
|
const TO_LOWER_CASE: u8 = 0b0010_1010;
|
||||||
|
const TO_UPPER_CASE: u8 = 0b0010_1011;
|
||||||
|
const TRIM: u8 = 0b0010_1100;
|
||||||
|
const TRIM_END: u8 = 0b0010_1101;
|
||||||
|
const TRIM_START: u8 = 0b0010_1110;
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
const READ_LINE: u8 = 0b0010_1111;
|
||||||
|
const WRITE_LINE: u8 = 0b0011_0001;
|
||||||
|
const WRITE: u8 = 0b0011_0000;
|
||||||
|
|
||||||
#[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,
|
||||||
|
|
||||||
|
// Type conversion
|
||||||
|
Parse = PARSE as isize,
|
||||||
|
ToByte = TO_BYTE as isize,
|
||||||
|
ToFloat = TO_FLOAT as isize,
|
||||||
|
ToInteger = TO_INTEGER as isize,
|
||||||
ToString = TO_STRING as isize,
|
ToString = TO_STRING as isize,
|
||||||
Write = WRITE as isize,
|
|
||||||
|
// List
|
||||||
|
All = ALL as isize,
|
||||||
|
Any = ANY as isize,
|
||||||
|
Append = APPEND as isize,
|
||||||
|
Contains = CONTAINS as isize,
|
||||||
|
Find = FIND as isize,
|
||||||
|
Flatten = FLATTEN as isize,
|
||||||
|
Get = GET as isize,
|
||||||
|
IndexOf = INDEX_OF as isize,
|
||||||
|
Join = JOIN as isize,
|
||||||
|
Length = LENGTH as isize,
|
||||||
|
Map = MAP as isize,
|
||||||
|
Prepend = PREPEND as isize,
|
||||||
|
Reduce = REDUCE as isize,
|
||||||
|
Remove = REMOVE as isize,
|
||||||
|
Reverse = REVERSE as isize,
|
||||||
|
Set = SET as isize,
|
||||||
|
Slice = SLICE as isize,
|
||||||
|
Sort = SORT as isize,
|
||||||
|
Split = SPLIT as isize,
|
||||||
|
Unzip = UNZIP as isize,
|
||||||
|
Zip = ZIP as isize,
|
||||||
|
|
||||||
|
// String
|
||||||
|
CharAt = CHAR_AT as isize,
|
||||||
|
CharCodeAt = CHAR_CODE_AT as isize,
|
||||||
|
Chars = CHARS as isize,
|
||||||
|
EndsWith = ENDS_WITH as isize,
|
||||||
|
Format = FORMAT as isize,
|
||||||
|
Includes = INCLUDES as isize,
|
||||||
|
Match = MATCH as isize,
|
||||||
|
PadEnd = PAD_END as isize,
|
||||||
|
PadStart = PAD_START as isize,
|
||||||
|
Repeat = REPEAT as isize,
|
||||||
|
Replace = REPLACE as isize,
|
||||||
|
SplitAt = SPLIT_AT as isize,
|
||||||
|
SplitLines = SPLIT_LINES as isize,
|
||||||
|
SplitWhitespace = SPLIT_WHITESPACE as isize,
|
||||||
|
StartsWith = STARTS_WITH as isize,
|
||||||
|
ToLowerCase = TO_LOWER_CASE as isize,
|
||||||
|
ToUpperCase = TO_UPPER_CASE as isize,
|
||||||
|
Trim = TRIM as isize,
|
||||||
|
TrimEnd = TRIM_END as isize,
|
||||||
|
TrimStart = TRIM_START as isize,
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
ReadLine = READ_LINE as isize,
|
||||||
WriteLine = WRITE_LINE as isize,
|
WriteLine = WRITE_LINE as isize,
|
||||||
|
Write = WRITE as isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeFunction {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
NativeFunction::Panic => "panic",
|
||||||
|
NativeFunction::Parse => "parse",
|
||||||
|
NativeFunction::ToByte => "to_byte",
|
||||||
|
NativeFunction::ToFloat => "to_float",
|
||||||
|
NativeFunction::ToInteger => "to_integer",
|
||||||
|
NativeFunction::ToString => "to_string",
|
||||||
|
NativeFunction::All => "all",
|
||||||
|
NativeFunction::Any => "any",
|
||||||
|
NativeFunction::Append => "append",
|
||||||
|
NativeFunction::Contains => "contains",
|
||||||
|
NativeFunction::Find => "find",
|
||||||
|
NativeFunction::Flatten => "flatten",
|
||||||
|
NativeFunction::Get => "get",
|
||||||
|
NativeFunction::IndexOf => "index_of",
|
||||||
|
NativeFunction::Join => "join",
|
||||||
|
NativeFunction::Length => "length",
|
||||||
|
NativeFunction::Map => "map",
|
||||||
|
NativeFunction::Prepend => "prepend",
|
||||||
|
NativeFunction::Reduce => "reduce",
|
||||||
|
NativeFunction::Remove => "remove",
|
||||||
|
NativeFunction::Reverse => "reverse",
|
||||||
|
NativeFunction::Set => "set",
|
||||||
|
NativeFunction::Slice => "slice",
|
||||||
|
NativeFunction::Sort => "sort",
|
||||||
|
NativeFunction::Split => "split",
|
||||||
|
NativeFunction::Unzip => "unzip",
|
||||||
|
NativeFunction::Zip => "zip",
|
||||||
|
NativeFunction::CharAt => "char_at",
|
||||||
|
NativeFunction::CharCodeAt => "char_code_at",
|
||||||
|
NativeFunction::Chars => "chars",
|
||||||
|
NativeFunction::EndsWith => "ends_with",
|
||||||
|
NativeFunction::Format => "format",
|
||||||
|
NativeFunction::Includes => "includes",
|
||||||
|
NativeFunction::Match => "match",
|
||||||
|
NativeFunction::PadEnd => "pad_end",
|
||||||
|
NativeFunction::PadStart => "pad_start",
|
||||||
|
NativeFunction::Repeat => "repeat",
|
||||||
|
NativeFunction::Replace => "replace",
|
||||||
|
NativeFunction::SplitAt => "split_at",
|
||||||
|
NativeFunction::SplitLines => "split_lines",
|
||||||
|
NativeFunction::SplitWhitespace => "split_whitespace",
|
||||||
|
NativeFunction::StartsWith => "starts_with",
|
||||||
|
NativeFunction::ToLowerCase => "to_lower_case",
|
||||||
|
NativeFunction::ToUpperCase => "to_upper_case",
|
||||||
|
NativeFunction::Trim => "trim",
|
||||||
|
NativeFunction::TrimEnd => "trim_end",
|
||||||
|
NativeFunction::TrimStart => "trim_start",
|
||||||
|
NativeFunction::ReadLine => "read_line",
|
||||||
|
NativeFunction::WriteLine => "write_line",
|
||||||
|
NativeFunction::Write => "write",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(
|
||||||
|
&self,
|
||||||
|
instruction: Instruction,
|
||||||
|
vm: &Vm,
|
||||||
|
position: Span,
|
||||||
|
) -> Result<Option<Value>, VmError> {
|
||||||
|
let to_register = instruction.a();
|
||||||
|
let argument_count = instruction.c();
|
||||||
|
|
||||||
|
let return_value = match self {
|
||||||
|
NativeFunction::Panic => {
|
||||||
|
let message = if argument_count == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut message = String::new();
|
||||||
|
|
||||||
|
for argument_index in 0..argument_count {
|
||||||
|
if argument_index != 0 {
|
||||||
|
message.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument = vm.get(argument_index, position)?;
|
||||||
|
|
||||||
|
message.push_str(&argument.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(message)
|
||||||
|
};
|
||||||
|
|
||||||
|
return Err(VmError::Panic { message, position });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type conversion
|
||||||
|
NativeFunction::Parse => todo!(),
|
||||||
|
NativeFunction::ToByte => todo!(),
|
||||||
|
NativeFunction::ToFloat => todo!(),
|
||||||
|
NativeFunction::ToInteger => todo!(),
|
||||||
|
NativeFunction::ToString => {
|
||||||
|
let mut string = String::new();
|
||||||
|
|
||||||
|
for argument_index in 0..argument_count {
|
||||||
|
let argument = vm.get(argument_index, position)?;
|
||||||
|
|
||||||
|
string.push_str(&argument.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Value::Primitive(Primitive::String(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// List
|
||||||
|
NativeFunction::All => todo!(),
|
||||||
|
NativeFunction::Any => todo!(),
|
||||||
|
NativeFunction::Append => todo!(),
|
||||||
|
NativeFunction::Contains => todo!(),
|
||||||
|
NativeFunction::Find => todo!(),
|
||||||
|
NativeFunction::Flatten => todo!(),
|
||||||
|
NativeFunction::Get => todo!(),
|
||||||
|
NativeFunction::IndexOf => todo!(),
|
||||||
|
NativeFunction::Join => todo!(),
|
||||||
|
NativeFunction::Length => todo!(),
|
||||||
|
NativeFunction::Map => todo!(),
|
||||||
|
NativeFunction::Prepend => todo!(),
|
||||||
|
NativeFunction::Reduce => todo!(),
|
||||||
|
NativeFunction::Remove => todo!(),
|
||||||
|
NativeFunction::Reverse => todo!(),
|
||||||
|
NativeFunction::Set => todo!(),
|
||||||
|
NativeFunction::Slice => todo!(),
|
||||||
|
NativeFunction::Sort => todo!(),
|
||||||
|
NativeFunction::Split => todo!(),
|
||||||
|
NativeFunction::Unzip => todo!(),
|
||||||
|
NativeFunction::Zip => todo!(),
|
||||||
|
|
||||||
|
// String
|
||||||
|
NativeFunction::CharAt => todo!(),
|
||||||
|
NativeFunction::CharCodeAt => todo!(),
|
||||||
|
NativeFunction::Chars => todo!(),
|
||||||
|
NativeFunction::EndsWith => todo!(),
|
||||||
|
NativeFunction::Format => todo!(),
|
||||||
|
NativeFunction::Includes => todo!(),
|
||||||
|
NativeFunction::Match => todo!(),
|
||||||
|
NativeFunction::PadEnd => todo!(),
|
||||||
|
NativeFunction::PadStart => todo!(),
|
||||||
|
NativeFunction::Repeat => todo!(),
|
||||||
|
NativeFunction::Replace => todo!(),
|
||||||
|
NativeFunction::SplitAt => todo!(),
|
||||||
|
NativeFunction::SplitLines => todo!(),
|
||||||
|
NativeFunction::SplitWhitespace => todo!(),
|
||||||
|
NativeFunction::StartsWith => todo!(),
|
||||||
|
NativeFunction::ToLowerCase => todo!(),
|
||||||
|
NativeFunction::ToUpperCase => todo!(),
|
||||||
|
NativeFunction::Trim => todo!(),
|
||||||
|
NativeFunction::TrimEnd => todo!(),
|
||||||
|
NativeFunction::TrimStart => todo!(),
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
NativeFunction::ReadLine => todo!(),
|
||||||
|
NativeFunction::Write => {
|
||||||
|
let to_register = instruction.a();
|
||||||
|
let mut stdout = stdout();
|
||||||
|
let map_err = |io_error: io::Error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
};
|
||||||
|
|
||||||
|
let first_argument = to_register.saturating_sub(argument_count);
|
||||||
|
let last_argument = to_register.saturating_sub(1);
|
||||||
|
|
||||||
|
for argument_index in first_argument..=last_argument {
|
||||||
|
if argument_index != first_argument {
|
||||||
|
stdout.write(b" ").map_err(map_err)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument_string = vm.get(argument_index, position)?.to_string();
|
||||||
|
|
||||||
|
stdout
|
||||||
|
.write_all(argument_string.as_bytes())
|
||||||
|
.map_err(map_err)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
NativeFunction::WriteLine => {
|
||||||
|
let mut stdout = stdout();
|
||||||
|
let map_err = |io_error: io::Error| VmError::Io {
|
||||||
|
error: io_error.kind(),
|
||||||
|
position,
|
||||||
|
};
|
||||||
|
|
||||||
|
let first_argument = to_register.saturating_sub(argument_count);
|
||||||
|
let last_argument = to_register.saturating_sub(1);
|
||||||
|
|
||||||
|
for argument_index in first_argument..=last_argument {
|
||||||
|
if argument_index != 0 {
|
||||||
|
stdout.write(b" ").map_err(map_err)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argument_string = vm.get(argument_index, position)?.to_string();
|
||||||
|
|
||||||
|
stdout
|
||||||
|
.write_all(argument_string.as_bytes())
|
||||||
|
.map_err(map_err)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout.write(b"\n").map_err(map_err)?;
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(return_value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for NativeFunction {
|
impl From<u8> for NativeFunction {
|
||||||
fn from(byte: u8) -> Self {
|
fn from(byte: u8) -> Self {
|
||||||
match byte {
|
match byte {
|
||||||
PANIC => NativeFunction::Panic,
|
PANIC => NativeFunction::Panic,
|
||||||
|
|
||||||
|
// Type conversion
|
||||||
|
PARSE => NativeFunction::Parse,
|
||||||
|
TO_BYTE => NativeFunction::ToByte,
|
||||||
|
TO_FLOAT => NativeFunction::ToFloat,
|
||||||
|
TO_INTEGER => NativeFunction::ToInteger,
|
||||||
TO_STRING => NativeFunction::ToString,
|
TO_STRING => NativeFunction::ToString,
|
||||||
|
|
||||||
|
// List
|
||||||
|
ALL => NativeFunction::All,
|
||||||
|
ANY => NativeFunction::Any,
|
||||||
|
APPEND => NativeFunction::Append,
|
||||||
|
CONTAINS => NativeFunction::Contains,
|
||||||
|
FIND => NativeFunction::Find,
|
||||||
|
FLATTEN => NativeFunction::Flatten,
|
||||||
|
GET => NativeFunction::Get,
|
||||||
|
INDEX_OF => NativeFunction::IndexOf,
|
||||||
|
JOIN => NativeFunction::Join,
|
||||||
|
LENGTH => NativeFunction::Length,
|
||||||
|
MAP => NativeFunction::Map,
|
||||||
|
PREPEND => NativeFunction::Prepend,
|
||||||
|
REDUCE => NativeFunction::Reduce,
|
||||||
|
REMOVE => NativeFunction::Remove,
|
||||||
|
REVERSE => NativeFunction::Reverse,
|
||||||
|
SET => NativeFunction::Set,
|
||||||
|
SLICE => NativeFunction::Slice,
|
||||||
|
SORT => NativeFunction::Sort,
|
||||||
|
SPLIT => NativeFunction::Split,
|
||||||
|
UNZIP => NativeFunction::Unzip,
|
||||||
|
ZIP => NativeFunction::Zip,
|
||||||
|
|
||||||
|
// String
|
||||||
|
CHAR_AT => NativeFunction::CharAt,
|
||||||
|
CHAR_CODE_AT => NativeFunction::CharCodeAt,
|
||||||
|
CHARS => NativeFunction::Chars,
|
||||||
|
ENDS_WITH => NativeFunction::EndsWith,
|
||||||
|
FORMAT => NativeFunction::Format,
|
||||||
|
INCLUDES => NativeFunction::Includes,
|
||||||
|
MATCH => NativeFunction::Match,
|
||||||
|
PAD_END => NativeFunction::PadEnd,
|
||||||
|
PAD_START => NativeFunction::PadStart,
|
||||||
|
REPEAT => NativeFunction::Repeat,
|
||||||
|
REPLACE => NativeFunction::Replace,
|
||||||
|
SPLIT_AT => NativeFunction::SplitAt,
|
||||||
|
SPLIT_LINES => NativeFunction::SplitLines,
|
||||||
|
SPLIT_WHITESPACE => NativeFunction::SplitWhitespace,
|
||||||
|
STARTS_WITH => NativeFunction::StartsWith,
|
||||||
|
TO_LOWER_CASE => NativeFunction::ToLowerCase,
|
||||||
|
TO_UPPER_CASE => NativeFunction::ToUpperCase,
|
||||||
|
TRIM => NativeFunction::Trim,
|
||||||
|
TRIM_END => NativeFunction::TrimEnd,
|
||||||
|
TRIM_START => NativeFunction::TrimStart,
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
READ_LINE => NativeFunction::ReadLine,
|
||||||
WRITE => NativeFunction::Write,
|
WRITE => NativeFunction::Write,
|
||||||
WRITE_LINE => NativeFunction::WriteLine,
|
WRITE_LINE => NativeFunction::WriteLine,
|
||||||
_ => {
|
_ => {
|
||||||
@ -35,9 +413,61 @@ impl From<NativeFunction> for u8 {
|
|||||||
fn from(native_function: NativeFunction) -> Self {
|
fn from(native_function: NativeFunction) -> Self {
|
||||||
match native_function {
|
match native_function {
|
||||||
NativeFunction::Panic => PANIC,
|
NativeFunction::Panic => PANIC,
|
||||||
|
NativeFunction::Parse => PARSE,
|
||||||
|
NativeFunction::ToByte => TO_BYTE,
|
||||||
|
NativeFunction::ToFloat => TO_FLOAT,
|
||||||
|
NativeFunction::ToInteger => TO_INTEGER,
|
||||||
NativeFunction::ToString => TO_STRING,
|
NativeFunction::ToString => TO_STRING,
|
||||||
NativeFunction::Write => WRITE,
|
NativeFunction::All => ALL,
|
||||||
|
NativeFunction::Any => ANY,
|
||||||
|
NativeFunction::Append => APPEND,
|
||||||
|
NativeFunction::Contains => CONTAINS,
|
||||||
|
NativeFunction::Find => FIND,
|
||||||
|
NativeFunction::Flatten => FLATTEN,
|
||||||
|
NativeFunction::Get => GET,
|
||||||
|
NativeFunction::IndexOf => INDEX_OF,
|
||||||
|
NativeFunction::Join => JOIN,
|
||||||
|
NativeFunction::Length => LENGTH,
|
||||||
|
NativeFunction::Map => MAP,
|
||||||
|
NativeFunction::Prepend => PREPEND,
|
||||||
|
NativeFunction::Reduce => REDUCE,
|
||||||
|
NativeFunction::Remove => REMOVE,
|
||||||
|
NativeFunction::Reverse => REVERSE,
|
||||||
|
NativeFunction::Set => SET,
|
||||||
|
NativeFunction::Slice => SLICE,
|
||||||
|
NativeFunction::Sort => SORT,
|
||||||
|
NativeFunction::Split => SPLIT,
|
||||||
|
NativeFunction::Unzip => UNZIP,
|
||||||
|
NativeFunction::Zip => ZIP,
|
||||||
|
NativeFunction::CharAt => CHAR_AT,
|
||||||
|
NativeFunction::CharCodeAt => CHAR_CODE_AT,
|
||||||
|
NativeFunction::Chars => CHARS,
|
||||||
|
NativeFunction::EndsWith => ENDS_WITH,
|
||||||
|
NativeFunction::Format => FORMAT,
|
||||||
|
NativeFunction::Includes => INCLUDES,
|
||||||
|
NativeFunction::Match => MATCH,
|
||||||
|
NativeFunction::PadEnd => PAD_END,
|
||||||
|
NativeFunction::PadStart => PAD_START,
|
||||||
|
NativeFunction::Repeat => REPEAT,
|
||||||
|
NativeFunction::Replace => REPLACE,
|
||||||
|
NativeFunction::SplitAt => SPLIT_AT,
|
||||||
|
NativeFunction::SplitLines => SPLIT_LINES,
|
||||||
|
NativeFunction::SplitWhitespace => SPLIT_WHITESPACE,
|
||||||
|
NativeFunction::StartsWith => STARTS_WITH,
|
||||||
|
NativeFunction::ToLowerCase => TO_LOWER_CASE,
|
||||||
|
NativeFunction::ToUpperCase => TO_UPPER_CASE,
|
||||||
|
NativeFunction::Trim => TRIM,
|
||||||
|
NativeFunction::TrimEnd => TRIM_END,
|
||||||
|
NativeFunction::TrimStart => TRIM_START,
|
||||||
|
NativeFunction::ReadLine => READ_LINE,
|
||||||
NativeFunction::WriteLine => WRITE_LINE,
|
NativeFunction::WriteLine => WRITE_LINE,
|
||||||
|
NativeFunction::Write => WRITE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for NativeFunction {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
use std::{
|
use std::{cmp::Ordering, io, mem::replace};
|
||||||
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,
|
||||||
@ -391,98 +387,12 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::CallNative => {
|
Operation::CallNative => {
|
||||||
let to_register = instruction.a();
|
|
||||||
let native_function = NativeFunction::from(instruction.b());
|
let native_function = NativeFunction::from(instruction.b());
|
||||||
let argument_count = instruction.c();
|
let return_value = native_function.call(instruction, &self, position)?;
|
||||||
let return_value = match native_function {
|
|
||||||
NativeFunction::Panic => {
|
|
||||||
let message = if argument_count == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let mut message = String::new();
|
|
||||||
|
|
||||||
for argument_index in 0..argument_count {
|
|
||||||
if argument_index != 0 {
|
|
||||||
message.push(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
let argument = self.get(argument_index, position)?;
|
|
||||||
|
|
||||||
message.push_str(&argument.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(message)
|
|
||||||
};
|
|
||||||
|
|
||||||
return Err(VmError::Panic { message, position });
|
|
||||||
}
|
|
||||||
NativeFunction::ToString => {
|
|
||||||
let mut string = String::new();
|
|
||||||
|
|
||||||
for argument_index in 0..argument_count {
|
|
||||||
let argument = self.get(argument_index, position)?;
|
|
||||||
|
|
||||||
string.push_str(&argument.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Value::Primitive(Primitive::String(string)))
|
|
||||||
}
|
|
||||||
NativeFunction::Write => {
|
|
||||||
let to_register = instruction.a();
|
|
||||||
let mut stdout = stdout();
|
|
||||||
let map_err = |io_error: io::Error| VmError::Io {
|
|
||||||
error: io_error.kind(),
|
|
||||||
position,
|
|
||||||
};
|
|
||||||
|
|
||||||
let first_argument = to_register.saturating_sub(argument_count);
|
|
||||||
let last_argument = to_register.saturating_sub(1);
|
|
||||||
|
|
||||||
for argument_index in first_argument..=last_argument {
|
|
||||||
if argument_index != first_argument {
|
|
||||||
stdout.write(b" ").map_err(map_err)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let argument_string =
|
|
||||||
self.get(argument_index, position)?.to_string();
|
|
||||||
|
|
||||||
stdout
|
|
||||||
.write_all(argument_string.as_bytes())
|
|
||||||
.map_err(map_err)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
NativeFunction::WriteLine => {
|
|
||||||
let mut stdout = stdout();
|
|
||||||
let map_err = |io_error: io::Error| VmError::Io {
|
|
||||||
error: io_error.kind(),
|
|
||||||
position,
|
|
||||||
};
|
|
||||||
|
|
||||||
let first_argument = to_register.saturating_sub(argument_count);
|
|
||||||
let last_argument = to_register.saturating_sub(1);
|
|
||||||
|
|
||||||
for argument_index in first_argument..=last_argument {
|
|
||||||
if argument_index != 0 {
|
|
||||||
stdout.write(b" ").map_err(map_err)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let argument_string =
|
|
||||||
self.get(argument_index, position)?.to_string();
|
|
||||||
|
|
||||||
stdout
|
|
||||||
.write_all(argument_string.as_bytes())
|
|
||||||
.map_err(map_err)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout.write(b"\n").map_err(map_err)?;
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(value) = return_value {
|
if let Some(value) = return_value {
|
||||||
|
let to_register = instruction.a();
|
||||||
|
|
||||||
self.set(to_register, value, position)?;
|
self.set(to_register, value, position)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user