Overhaul implicit returns and add lots of new native functions
This commit is contained in:
parent
ae6d3d7a82
commit
1947d66be5
@ -8,129 +8,88 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{AnnotatedError, Instruction, Primitive, Span, Value, Vm, VmError};
|
use crate::{AnnotatedError, Instruction, Primitive, Span, Value, Vm, VmError};
|
||||||
|
|
||||||
const PANIC: u8 = 0b0000_0000;
|
// Assertio
|
||||||
|
const ASSERT: u8 = 0b0000_0000;
|
||||||
|
const ASSERT_EQ: u8 = 0b0000_0001;
|
||||||
|
const ASSERT_NE: u8 = 0b0000_0010;
|
||||||
|
const PANIC: u8 = 0b0000_0011;
|
||||||
|
|
||||||
// Type conversion
|
// Type conversion
|
||||||
const PARSE: u8 = 0b0000_0001;
|
const PARSE: u8 = 0b0000_0100;
|
||||||
const TO_BYTE: u8 = 0b0000_0010;
|
const TO_BYTE: u8 = 0b0000_0101;
|
||||||
const TO_FLOAT: u8 = 0b0000_0011;
|
const TO_FLOAT: u8 = 0b0000_0110;
|
||||||
const TO_INTEGER: u8 = 0b0000_0100;
|
const TO_INTEGER: u8 = 0b0000_0111;
|
||||||
const TO_STRING: u8 = 0b0000_0101;
|
const TO_STRING: u8 = 0b0000_1000;
|
||||||
|
|
||||||
// List
|
// List and string
|
||||||
const ALL: u8 = 0b0000_0110;
|
const ALL: u8 = 0b0000_1001;
|
||||||
const ANY: u8 = 0b0000_0111;
|
const ANY: u8 = 0b0000_1010;
|
||||||
const APPEND: u8 = 0b0000_1000;
|
const APPEND: u8 = 0b0000_1011;
|
||||||
const CONTAINS: u8 = 0b0000_1001;
|
const CONTAINS: u8 = 0b0000_1100;
|
||||||
const FIND: u8 = 0b0000_1010;
|
const DEDUP: u8 = 0b0000_1101;
|
||||||
const FLATTEN: u8 = 0b0000_1011;
|
const ENDS_WITH: u8 = 0b0000_1110;
|
||||||
const GET: u8 = 0b0000_1100;
|
const FIND: u8 = 0b0000_1111;
|
||||||
const INDEX_OF: u8 = 0b0000_1101;
|
const GET: u8 = 0b0001_0000;
|
||||||
const JOIN: u8 = 0b0000_1110;
|
const INDEX_OF: u8 = 0b0001_0001;
|
||||||
const LENGTH: u8 = 0b0000_1111;
|
const LENGTH: u8 = 0b0001_0010;
|
||||||
const MAP: u8 = 0b0001_0000;
|
const PREPEND: u8 = 0b0001_0011;
|
||||||
const PREPEND: u8 = 0b0001_0001;
|
const REPLACE: u8 = 0b0001_0100;
|
||||||
const REDUCE: u8 = 0b0001_0010;
|
|
||||||
const REMOVE: u8 = 0b0001_0011;
|
|
||||||
const REVERSE: u8 = 0b0001_0100;
|
|
||||||
const SET: u8 = 0b0001_0101;
|
const SET: u8 = 0b0001_0101;
|
||||||
const SLICE: u8 = 0b0001_0110;
|
const STARTS_WITH: u8 = 0b0001_0110;
|
||||||
const SORT: u8 = 0b0001_0111;
|
const SLICE: u8 = 0b0001_0111;
|
||||||
const SPLIT: u8 = 0b0001_1000;
|
const SORT: u8 = 0b0001_1000;
|
||||||
const UNZIP: u8 = 0b0001_1001;
|
const SPLIT: 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)]
|
|
||||||
pub enum NativeFunction {
|
|
||||||
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,
|
|
||||||
|
|
||||||
// List
|
// List
|
||||||
All = ALL as isize,
|
const FLATTEN: u8 = 0b0001_1010;
|
||||||
Any = ANY as isize,
|
const JOIN: u8 = 0b0001_1011;
|
||||||
Append = APPEND as isize,
|
const MAP: u8 = 0b0001_1100;
|
||||||
Contains = CONTAINS as isize,
|
const REDUCE: u8 = 0b0001_1101;
|
||||||
Find = FIND as isize,
|
const REMOVE: u8 = 0b0001_1110;
|
||||||
Flatten = FLATTEN as isize,
|
const REVERSE: u8 = 0b0001_1111;
|
||||||
Get = GET as isize,
|
const UNZIP: u8 = 0b0010_0000;
|
||||||
IndexOf = INDEX_OF as isize,
|
const ZIP: u8 = 0b0010_0001;
|
||||||
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
|
// String
|
||||||
CharAt = CHAR_AT as isize,
|
const BYTES: u8 = 0b0010_0010;
|
||||||
CharCodeAt = CHAR_CODE_AT as isize,
|
const CHAR_AT: u8 = 0b0010_0011;
|
||||||
Chars = CHARS as isize,
|
const CHAR_CODE_AT: u8 = 0b0010_0100;
|
||||||
EndsWith = ENDS_WITH as isize,
|
const CHARS: u8 = 0b0010_0101;
|
||||||
Format = FORMAT as isize,
|
const FORMAT: u8 = 0b0010_0110;
|
||||||
Includes = INCLUDES as isize,
|
const REPEAT: u8 = 0b0010_0111;
|
||||||
Match = MATCH as isize,
|
const SPLIT_AT: u8 = 0b0010_1000;
|
||||||
PadEnd = PAD_END as isize,
|
const SPLIT_LINES: u8 = 0b0010_1001;
|
||||||
PadStart = PAD_START as isize,
|
const SPLIT_WHITESPACE: u8 = 0b0010_1010;
|
||||||
Repeat = REPEAT as isize,
|
const TO_LOWER_CASE: u8 = 0b0010_1011;
|
||||||
Replace = REPLACE as isize,
|
const TO_UPPER_CASE: u8 = 0b0010_1100;
|
||||||
SplitAt = SPLIT_AT as isize,
|
const TRIM: u8 = 0b0010_1101;
|
||||||
SplitLines = SPLIT_LINES as isize,
|
const TRIM_END: u8 = 0b0010_1110;
|
||||||
SplitWhitespace = SPLIT_WHITESPACE as isize,
|
const TRIM_START: u8 = 0b0010_1111;
|
||||||
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
|
// I/O
|
||||||
ReadLine = READ_LINE as isize,
|
const READ_LINE: u8 = 0b0011_0000;
|
||||||
WriteLine = WRITE_LINE as isize,
|
const WRITE_LINE: u8 = 0b0011_0001;
|
||||||
Write = WRITE as isize,
|
const WRITE: u8 = 0b0011_0010;
|
||||||
}
|
|
||||||
|
// Random
|
||||||
|
const RANDOM: u8 = 0b0011_0011;
|
||||||
|
const RANDOM_BYTE: u8 = 0b0011_0100;
|
||||||
|
const RANDOM_BYTES: u8 = 0b0011_0101;
|
||||||
|
const RANDOM_CHAR: u8 = 0b0011_0110;
|
||||||
|
const RANDOM_FLOAT: u8 = 0b0011_0111;
|
||||||
|
const RANDOM_INTEGER: u8 = 0b0011_1000;
|
||||||
|
const RANDOM_RANGE: u8 = 0b0011_1001;
|
||||||
|
const RANDOM_STRING: u8 = 0b0011_1010;
|
||||||
|
|
||||||
macro_rules! impl_from_str_for_native_function {
|
macro_rules! impl_from_str_for_native_function {
|
||||||
($(($name:ident, $str:expr, $returns_value:expr)),*) => {
|
($(($name:ident, $str:expr, $returns_value:expr)),*) => {
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub enum NativeFunction {
|
||||||
|
$(
|
||||||
|
$name,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
impl NativeFunction {
|
impl NativeFunction {
|
||||||
pub fn as_str(&self) -> &'static str {
|
pub fn as_str(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
@ -161,9 +120,12 @@ macro_rules! impl_from_str_for_native_function {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the macro to implement From<&str> for NativeFunction
|
|
||||||
impl_from_str_for_native_function! {
|
impl_from_str_for_native_function! {
|
||||||
(Panic, "panic", false),
|
// Assertion
|
||||||
|
(Assert, "assert", false),
|
||||||
|
(AssertEq, "assert_eq", false),
|
||||||
|
(AssertNe, "assert_ne", false),
|
||||||
|
(Panic, "panic", true),
|
||||||
|
|
||||||
// Type conversion
|
// Type conversion
|
||||||
(Parse, "parse", true),
|
(Parse, "parse", true),
|
||||||
@ -172,45 +134,45 @@ impl_from_str_for_native_function! {
|
|||||||
(ToInteger, "to_integer", true),
|
(ToInteger, "to_integer", true),
|
||||||
(ToString, "to_string", true),
|
(ToString, "to_string", true),
|
||||||
|
|
||||||
// List
|
// List and string
|
||||||
(All, "all", true),
|
(All, "all", true),
|
||||||
(Any, "any", true),
|
(Any, "any", true),
|
||||||
(Append, "append", true),
|
(Append, "append", false),
|
||||||
(Contains, "contains", true),
|
(Contains, "contains", true),
|
||||||
|
(Dedup, "dedup", false),
|
||||||
|
(EndsWith, "ends_with", true),
|
||||||
(Find, "find", true),
|
(Find, "find", true),
|
||||||
(Flatten, "flatten", true),
|
|
||||||
(Get, "get", true),
|
(Get, "get", true),
|
||||||
(IndexOf, "index_of", true),
|
(IndexOf, "index_of", true),
|
||||||
(Join, "join", true),
|
|
||||||
(Length, "length", true),
|
(Length, "length", true),
|
||||||
(Map, "map", true),
|
(Prepend, "prepend", false),
|
||||||
(Prepend, "prepend", true),
|
(Replace, "replace", false),
|
||||||
(Reduce, "reduce", true),
|
(Set, "set", false),
|
||||||
(Remove, "remove", true),
|
(StartsWith, "starts_with", true),
|
||||||
(Reverse, "reverse", true),
|
|
||||||
(Set, "set", true),
|
|
||||||
(Slice, "slice", true),
|
(Slice, "slice", true),
|
||||||
(Sort, "sort", true),
|
(Sort, "sort", false),
|
||||||
(Split, "split", true),
|
(Split, "split", true),
|
||||||
|
|
||||||
|
// List
|
||||||
|
(Flatten, "flatten", true),
|
||||||
|
(Join, "join", true),
|
||||||
|
(Map, "map", true),
|
||||||
|
(Reduce, "reduce", true),
|
||||||
|
(Remove, "remove", false),
|
||||||
|
(Reverse, "reverse", false),
|
||||||
(Unzip, "unzip", true),
|
(Unzip, "unzip", true),
|
||||||
(Zip, "zip", true),
|
(Zip, "zip", true),
|
||||||
|
|
||||||
// String
|
// String
|
||||||
|
(Bytes, "bytes", true),
|
||||||
(CharAt, "char_at", true),
|
(CharAt, "char_at", true),
|
||||||
(CharCodeAt, "char_code_at", true),
|
(CharCodeAt, "char_code_at", true),
|
||||||
(Chars, "chars", true),
|
(Chars, "chars", true),
|
||||||
(EndsWith, "ends_with", true),
|
|
||||||
(Format, "format", true),
|
(Format, "format", true),
|
||||||
(Includes, "includes", true),
|
|
||||||
(Match, "match", true),
|
|
||||||
(PadEnd, "pad_end", true),
|
|
||||||
(PadStart, "pad_start", true),
|
|
||||||
(Repeat, "repeat", true),
|
(Repeat, "repeat", true),
|
||||||
(Replace, "replace", true),
|
|
||||||
(SplitAt, "split_at", true),
|
(SplitAt, "split_at", true),
|
||||||
(SplitLines, "split_lines", true),
|
(SplitLines, "split_lines", true),
|
||||||
(SplitWhitespace, "split_whitespace", true),
|
(SplitWhitespace, "split_whitespace", true),
|
||||||
(StartsWith, "starts_with", true),
|
|
||||||
(ToLowerCase, "to_lower_case", true),
|
(ToLowerCase, "to_lower_case", true),
|
||||||
(ToUpperCase, "to_upper_case", true),
|
(ToUpperCase, "to_upper_case", true),
|
||||||
(Trim, "trim", true),
|
(Trim, "trim", true),
|
||||||
@ -220,7 +182,17 @@ impl_from_str_for_native_function! {
|
|||||||
// I/O
|
// I/O
|
||||||
(ReadLine, "read_line", true),
|
(ReadLine, "read_line", true),
|
||||||
(WriteLine, "write_line", false),
|
(WriteLine, "write_line", false),
|
||||||
(Write, "write", false)
|
(Write, "write", false),
|
||||||
|
|
||||||
|
// Random
|
||||||
|
(Random, "random", true),
|
||||||
|
(RandomByte, "random_byte", true),
|
||||||
|
(RandomBytes, "random_bytes", true),
|
||||||
|
(RandomChar, "random_char", true),
|
||||||
|
(RandomFloat, "random_float", true),
|
||||||
|
(RandomInteger, "random_integer", true),
|
||||||
|
(RandomRange, "random_range", true),
|
||||||
|
(RandomString, "random_string", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NativeFunction {
|
impl NativeFunction {
|
||||||
@ -276,51 +248,6 @@ impl NativeFunction {
|
|||||||
Some(Value::Primitive(Primitive::String(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
|
// I/O
|
||||||
NativeFunction::ReadLine => {
|
NativeFunction::ReadLine => {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
@ -391,6 +318,7 @@ impl NativeFunction {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(return_value)
|
Ok(return_value)
|
||||||
@ -400,64 +328,64 @@ impl NativeFunction {
|
|||||||
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,
|
ALL => NativeFunction::Assert,
|
||||||
|
ASSERT_EQ => NativeFunction::AssertEq,
|
||||||
// Type conversion
|
ASSERT_NE => NativeFunction::AssertNe,
|
||||||
PARSE => NativeFunction::Parse,
|
|
||||||
TO_BYTE => NativeFunction::ToByte,
|
|
||||||
TO_FLOAT => NativeFunction::ToFloat,
|
|
||||||
TO_INTEGER => NativeFunction::ToInteger,
|
|
||||||
TO_STRING => NativeFunction::ToString,
|
|
||||||
|
|
||||||
// List
|
|
||||||
ALL => NativeFunction::All,
|
|
||||||
ANY => NativeFunction::Any,
|
|
||||||
APPEND => NativeFunction::Append,
|
APPEND => NativeFunction::Append,
|
||||||
|
ANY => NativeFunction::Any,
|
||||||
|
BYTES => NativeFunction::Bytes,
|
||||||
|
CHAR_AT => NativeFunction::CharAt,
|
||||||
|
CHAR_CODE_AT => NativeFunction::CharCodeAt,
|
||||||
|
CHARS => NativeFunction::Chars,
|
||||||
CONTAINS => NativeFunction::Contains,
|
CONTAINS => NativeFunction::Contains,
|
||||||
|
DEDUP => NativeFunction::Dedup,
|
||||||
|
ENDS_WITH => NativeFunction::EndsWith,
|
||||||
FIND => NativeFunction::Find,
|
FIND => NativeFunction::Find,
|
||||||
FLATTEN => NativeFunction::Flatten,
|
FLATTEN => NativeFunction::Flatten,
|
||||||
|
FORMAT => NativeFunction::Format,
|
||||||
GET => NativeFunction::Get,
|
GET => NativeFunction::Get,
|
||||||
INDEX_OF => NativeFunction::IndexOf,
|
INDEX_OF => NativeFunction::IndexOf,
|
||||||
JOIN => NativeFunction::Join,
|
JOIN => NativeFunction::Join,
|
||||||
LENGTH => NativeFunction::Length,
|
LENGTH => NativeFunction::Length,
|
||||||
MAP => NativeFunction::Map,
|
MAP => NativeFunction::Map,
|
||||||
|
PANIC => NativeFunction::Panic,
|
||||||
|
PARSE => NativeFunction::Parse,
|
||||||
PREPEND => NativeFunction::Prepend,
|
PREPEND => NativeFunction::Prepend,
|
||||||
|
RANDOM => NativeFunction::Random,
|
||||||
|
RANDOM_BYTE => NativeFunction::RandomByte,
|
||||||
|
RANDOM_BYTES => NativeFunction::RandomBytes,
|
||||||
|
RANDOM_CHAR => NativeFunction::RandomChar,
|
||||||
|
RANDOM_FLOAT => NativeFunction::RandomFloat,
|
||||||
|
RANDOM_INTEGER => NativeFunction::RandomInteger,
|
||||||
|
RANDOM_RANGE => NativeFunction::RandomRange,
|
||||||
|
RANDOM_STRING => NativeFunction::RandomString,
|
||||||
|
READ_LINE => NativeFunction::ReadLine,
|
||||||
REDUCE => NativeFunction::Reduce,
|
REDUCE => NativeFunction::Reduce,
|
||||||
REMOVE => NativeFunction::Remove,
|
REMOVE => NativeFunction::Remove,
|
||||||
|
REPEAT => NativeFunction::Repeat,
|
||||||
|
REPLACE => NativeFunction::Replace,
|
||||||
REVERSE => NativeFunction::Reverse,
|
REVERSE => NativeFunction::Reverse,
|
||||||
SET => NativeFunction::Set,
|
SET => NativeFunction::Set,
|
||||||
SLICE => NativeFunction::Slice,
|
SLICE => NativeFunction::Slice,
|
||||||
SORT => NativeFunction::Sort,
|
SORT => NativeFunction::Sort,
|
||||||
SPLIT => NativeFunction::Split,
|
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_AT => NativeFunction::SplitAt,
|
||||||
SPLIT_LINES => NativeFunction::SplitLines,
|
SPLIT_LINES => NativeFunction::SplitLines,
|
||||||
SPLIT_WHITESPACE => NativeFunction::SplitWhitespace,
|
SPLIT_WHITESPACE => NativeFunction::SplitWhitespace,
|
||||||
STARTS_WITH => NativeFunction::StartsWith,
|
STARTS_WITH => NativeFunction::StartsWith,
|
||||||
|
TO_BYTE => NativeFunction::ToByte,
|
||||||
|
TO_FLOAT => NativeFunction::ToFloat,
|
||||||
|
TO_INTEGER => NativeFunction::ToInteger,
|
||||||
TO_LOWER_CASE => NativeFunction::ToLowerCase,
|
TO_LOWER_CASE => NativeFunction::ToLowerCase,
|
||||||
|
TO_STRING => NativeFunction::ToString,
|
||||||
TO_UPPER_CASE => NativeFunction::ToUpperCase,
|
TO_UPPER_CASE => NativeFunction::ToUpperCase,
|
||||||
TRIM => NativeFunction::Trim,
|
TRIM => NativeFunction::Trim,
|
||||||
TRIM_END => NativeFunction::TrimEnd,
|
TRIM_END => NativeFunction::TrimEnd,
|
||||||
TRIM_START => NativeFunction::TrimStart,
|
TRIM_START => NativeFunction::TrimStart,
|
||||||
|
UNZIP => NativeFunction::Unzip,
|
||||||
// I/O
|
|
||||||
READ_LINE => NativeFunction::ReadLine,
|
|
||||||
WRITE => NativeFunction::Write,
|
WRITE => NativeFunction::Write,
|
||||||
WRITE_LINE => NativeFunction::WriteLine,
|
WRITE_LINE => NativeFunction::WriteLine,
|
||||||
|
ZIP => NativeFunction::Zip,
|
||||||
_ => {
|
_ => {
|
||||||
if cfg!(test) {
|
if cfg!(test) {
|
||||||
panic!("Invalid native function byte: {}", byte)
|
panic!("Invalid native function byte: {}", byte)
|
||||||
@ -472,56 +400,65 @@ impl From<u8> for NativeFunction {
|
|||||||
impl From<NativeFunction> for u8 {
|
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::Parse => PARSE,
|
|
||||||
NativeFunction::ToByte => TO_BYTE,
|
|
||||||
NativeFunction::ToFloat => TO_FLOAT,
|
|
||||||
NativeFunction::ToInteger => TO_INTEGER,
|
|
||||||
NativeFunction::ToString => TO_STRING,
|
|
||||||
NativeFunction::All => ALL,
|
NativeFunction::All => ALL,
|
||||||
NativeFunction::Any => ANY,
|
NativeFunction::Any => ANY,
|
||||||
NativeFunction::Append => APPEND,
|
NativeFunction::Append => APPEND,
|
||||||
|
NativeFunction::Assert => ASSERT,
|
||||||
|
NativeFunction::AssertEq => ASSERT_EQ,
|
||||||
|
NativeFunction::AssertNe => ASSERT_NE,
|
||||||
|
NativeFunction::Bytes => BYTES,
|
||||||
|
NativeFunction::CharAt => CHAR_AT,
|
||||||
|
NativeFunction::CharCodeAt => CHAR_CODE_AT,
|
||||||
|
NativeFunction::Chars => CHARS,
|
||||||
NativeFunction::Contains => CONTAINS,
|
NativeFunction::Contains => CONTAINS,
|
||||||
|
NativeFunction::Dedup => DEDUP,
|
||||||
|
NativeFunction::EndsWith => ENDS_WITH,
|
||||||
NativeFunction::Find => FIND,
|
NativeFunction::Find => FIND,
|
||||||
NativeFunction::Flatten => FLATTEN,
|
NativeFunction::Flatten => FLATTEN,
|
||||||
|
NativeFunction::Format => FORMAT,
|
||||||
NativeFunction::Get => GET,
|
NativeFunction::Get => GET,
|
||||||
NativeFunction::IndexOf => INDEX_OF,
|
NativeFunction::IndexOf => INDEX_OF,
|
||||||
NativeFunction::Join => JOIN,
|
NativeFunction::Join => JOIN,
|
||||||
NativeFunction::Length => LENGTH,
|
NativeFunction::Length => LENGTH,
|
||||||
NativeFunction::Map => MAP,
|
NativeFunction::Map => MAP,
|
||||||
|
NativeFunction::Panic => PANIC,
|
||||||
|
NativeFunction::Parse => PARSE,
|
||||||
NativeFunction::Prepend => PREPEND,
|
NativeFunction::Prepend => PREPEND,
|
||||||
|
NativeFunction::Random => RANDOM,
|
||||||
|
NativeFunction::RandomByte => RANDOM_BYTE,
|
||||||
|
NativeFunction::RandomBytes => RANDOM_BYTES,
|
||||||
|
NativeFunction::RandomChar => RANDOM_CHAR,
|
||||||
|
NativeFunction::RandomFloat => RANDOM_FLOAT,
|
||||||
|
NativeFunction::RandomInteger => RANDOM_INTEGER,
|
||||||
|
NativeFunction::RandomRange => RANDOM_RANGE,
|
||||||
|
NativeFunction::RandomString => RANDOM_STRING,
|
||||||
|
NativeFunction::ReadLine => READ_LINE,
|
||||||
NativeFunction::Reduce => REDUCE,
|
NativeFunction::Reduce => REDUCE,
|
||||||
NativeFunction::Remove => REMOVE,
|
NativeFunction::Remove => REMOVE,
|
||||||
|
NativeFunction::Repeat => REPEAT,
|
||||||
|
NativeFunction::Replace => REPLACE,
|
||||||
NativeFunction::Reverse => REVERSE,
|
NativeFunction::Reverse => REVERSE,
|
||||||
NativeFunction::Set => SET,
|
NativeFunction::Set => SET,
|
||||||
NativeFunction::Slice => SLICE,
|
NativeFunction::Slice => SLICE,
|
||||||
NativeFunction::Sort => SORT,
|
NativeFunction::Sort => SORT,
|
||||||
NativeFunction::Split => SPLIT,
|
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::SplitAt => SPLIT_AT,
|
||||||
NativeFunction::SplitLines => SPLIT_LINES,
|
NativeFunction::SplitLines => SPLIT_LINES,
|
||||||
NativeFunction::SplitWhitespace => SPLIT_WHITESPACE,
|
NativeFunction::SplitWhitespace => SPLIT_WHITESPACE,
|
||||||
NativeFunction::StartsWith => STARTS_WITH,
|
NativeFunction::StartsWith => STARTS_WITH,
|
||||||
|
NativeFunction::ToByte => TO_BYTE,
|
||||||
|
NativeFunction::ToFloat => TO_FLOAT,
|
||||||
|
NativeFunction::ToInteger => TO_INTEGER,
|
||||||
NativeFunction::ToLowerCase => TO_LOWER_CASE,
|
NativeFunction::ToLowerCase => TO_LOWER_CASE,
|
||||||
|
NativeFunction::ToString => TO_STRING,
|
||||||
NativeFunction::ToUpperCase => TO_UPPER_CASE,
|
NativeFunction::ToUpperCase => TO_UPPER_CASE,
|
||||||
NativeFunction::Trim => TRIM,
|
NativeFunction::Trim => TRIM,
|
||||||
NativeFunction::TrimEnd => TRIM_END,
|
NativeFunction::TrimEnd => TRIM_END,
|
||||||
NativeFunction::TrimStart => TRIM_START,
|
NativeFunction::TrimStart => TRIM_START,
|
||||||
NativeFunction::ReadLine => READ_LINE,
|
NativeFunction::Unzip => UNZIP,
|
||||||
NativeFunction::WriteLine => WRITE_LINE,
|
|
||||||
NativeFunction::Write => WRITE,
|
NativeFunction::Write => WRITE,
|
||||||
|
NativeFunction::WriteLine => WRITE_LINE,
|
||||||
|
NativeFunction::Zip => ZIP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,20 +17,10 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
|||||||
let lexer = Lexer::new(source);
|
let lexer = Lexer::new(source);
|
||||||
let mut parser = Parser::new(lexer).map_err(|error| DustError::Parse { error, source })?;
|
let mut parser = Parser::new(lexer).map_err(|error| DustError::Parse { error, source })?;
|
||||||
|
|
||||||
loop {
|
|
||||||
parser
|
parser
|
||||||
.parse_statement(Allowed {
|
.parse_top_level()
|
||||||
assignment: true,
|
|
||||||
explicit_return: false,
|
|
||||||
implicit_return: true,
|
|
||||||
})
|
|
||||||
.map_err(|error| DustError::Parse { error, source })?;
|
.map_err(|error| DustError::Parse { error, source })?;
|
||||||
|
|
||||||
if parser.is_eof() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(parser.finish())
|
Ok(parser.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,9 +986,10 @@ impl<'src> Parser<'src> {
|
|||||||
.chunk
|
.chunk
|
||||||
.instructions()
|
.instructions()
|
||||||
.iter()
|
.iter()
|
||||||
|
.rev()
|
||||||
.find_map(|(instruction, _)| {
|
.find_map(|(instruction, _)| {
|
||||||
if !matches!(instruction.operation(), Operation::Jump) {
|
if !matches!(instruction.operation(), Operation::Jump | Operation::Move) {
|
||||||
Some(true)
|
Some(instruction.yields_value())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -1010,6 +1001,7 @@ impl<'src> Parser<'src> {
|
|||||||
let if_last_register = self.next_register().saturating_sub(1);
|
let if_last_register = self.next_register().saturating_sub(1);
|
||||||
|
|
||||||
self.parse_else(allowed, block_allowed)?;
|
self.parse_else(allowed, block_allowed)?;
|
||||||
|
self.optimize_statement();
|
||||||
|
|
||||||
let else_last_register = self.next_register().saturating_sub(1);
|
let else_last_register = self.next_register().saturating_sub(1);
|
||||||
let else_end = self.chunk.len();
|
let else_end = self.chunk.len();
|
||||||
@ -1022,19 +1014,7 @@ impl<'src> Parser<'src> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_is_expression = if_block_is_expression
|
self.current_is_expression = if_block_is_expression && self.current_is_expression;
|
||||||
&& self
|
|
||||||
.chunk
|
|
||||||
.instructions()
|
|
||||||
.iter()
|
|
||||||
.find_map(|(instruction, _)| {
|
|
||||||
if !matches!(instruction.operation(), Operation::Jump) {
|
|
||||||
Some(true)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if jump_distance == 1 {
|
if jump_distance == 1 {
|
||||||
if let Some(skippable) = self.get_last_jumpable_mut() {
|
if let Some(skippable) = self.get_last_jumpable_mut() {
|
||||||
@ -1081,12 +1061,6 @@ impl<'src> Parser<'src> {
|
|||||||
self.current_position,
|
self.current_position,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_is_expression = self
|
|
||||||
.chunk
|
|
||||||
.instructions()
|
|
||||||
.last()
|
|
||||||
.map_or(false, |(instruction, _)| instruction.yields_value());
|
|
||||||
} else {
|
} else {
|
||||||
return Err(ParseError::ExpectedTokenMultiple {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: &[TokenKind::If, TokenKind::LeftCurlyBrace],
|
expected: &[TokenKind::If, TokenKind::LeftCurlyBrace],
|
||||||
@ -1095,14 +1069,6 @@ impl<'src> Parser<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_is_expression = self
|
|
||||||
.chunk
|
|
||||||
.instructions()
|
|
||||||
.last()
|
|
||||||
.map_or(false, |(instruction, _)| instruction.yields_value());
|
|
||||||
|
|
||||||
self.optimize_statement();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1195,11 +1161,29 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_top_level(&mut self) -> Result<(), ParseError> {
|
||||||
|
loop {
|
||||||
|
self.parse_statement(Allowed {
|
||||||
|
assignment: true,
|
||||||
|
explicit_return: false,
|
||||||
|
implicit_return: true,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if self.is_eof() || self.allow(Token::RightCurlyBrace)? {
|
||||||
|
self.parse_implicit_return()?;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
self.parse(Precedence::None, allowed)?;
|
self.parse(Precedence::None, allowed)?;
|
||||||
|
|
||||||
if allowed.implicit_return {
|
if self.allow(Token::Semicolon)? {
|
||||||
self.parse_implicit_return()?;
|
self.current_is_expression = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1259,30 +1243,15 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_implicit_return(&mut self) -> Result<(), ParseError> {
|
fn parse_implicit_return(&mut self) -> Result<(), ParseError> {
|
||||||
if !self.current_is_expression {
|
|
||||||
if self.is_eof() {
|
|
||||||
self.emit_instruction(Instruction::r#return(false), self.current_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let end_of_statement = matches!(
|
|
||||||
self.current_token,
|
|
||||||
Token::Eof | Token::RightCurlyBrace | Token::Semicolon
|
|
||||||
);
|
|
||||||
let has_semicolon = self.allow(Token::Semicolon)?;
|
let has_semicolon = self.allow(Token::Semicolon)?;
|
||||||
let returned = self
|
|
||||||
.chunk
|
|
||||||
.instructions()
|
|
||||||
.last()
|
|
||||||
.map(|(instruction, _)| matches!(instruction.operation(), Operation::Return))
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if end_of_statement && !has_semicolon && !returned {
|
if has_semicolon {
|
||||||
self.emit_instruction(Instruction::r#return(true), self.current_position);
|
|
||||||
} else if self.is_eof() {
|
|
||||||
self.emit_instruction(Instruction::r#return(false), self.current_position);
|
self.emit_instruction(Instruction::r#return(false), self.current_position);
|
||||||
|
} else {
|
||||||
|
self.emit_instruction(
|
||||||
|
Instruction::r#return(self.current_is_expression),
|
||||||
|
self.current_position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1426,16 +1395,7 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function_parser.expect(Token::LeftCurlyBrace)?;
|
function_parser.expect(Token::LeftCurlyBrace)?;
|
||||||
|
function_parser.parse_top_level()?;
|
||||||
while function_parser.current_token != Token::RightCurlyBrace {
|
|
||||||
function_parser.parse_statement(Allowed {
|
|
||||||
assignment: true,
|
|
||||||
explicit_return: true,
|
|
||||||
implicit_return: true,
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
function_parser.advance()?;
|
|
||||||
|
|
||||||
self.previous_token = function_parser.previous_token;
|
self.previous_token = function_parser.previous_token;
|
||||||
self.previous_position = function_parser.previous_position;
|
self.previous_position = function_parser.previous_position;
|
||||||
@ -1531,13 +1491,6 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_semicolon(&mut self, _: Allowed) -> Result<(), ParseError> {
|
|
||||||
self.current_is_expression = false;
|
|
||||||
|
|
||||||
self.optimize_statement();
|
|
||||||
self.advance()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expect_expression(&mut self, _: Allowed) -> Result<(), ParseError> {
|
fn expect_expression(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
if self.current_token.is_expression() {
|
if self.current_token.is_expression() {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1874,7 +1827,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
|
|||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
Token::Semicolon => ParseRule {
|
Token::Semicolon => ParseRule {
|
||||||
prefix: Some(Parser::parse_semicolon),
|
prefix: Some(Parser::expect_expression),
|
||||||
infix: None,
|
infix: None,
|
||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
|
@ -99,9 +99,9 @@ fn if_else_assigment() {
|
|||||||
Instruction::call_native(9, NativeFunction::Panic, 0),
|
Instruction::call_native(9, NativeFunction::Panic, 0),
|
||||||
Span(121, 128)
|
Span(121, 128)
|
||||||
),
|
),
|
||||||
(Instruction::r#move(8, 4), Span(138, 139)),
|
(Instruction::r#move(9, 4), Span(138, 139)),
|
||||||
(Instruction::define_local(8, 0, false), Span(13, 14)),
|
(Instruction::define_local(9, 0, false), Span(13, 14)),
|
||||||
(Instruction::get_local(9, 0), Span(148, 149)),
|
(Instruction::get_local(10, 0), Span(148, 149)),
|
||||||
(Instruction::r#return(true), Span(149, 149)),
|
(Instruction::r#return(true), Span(149, 149)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
@ -156,7 +156,7 @@ fn if_else_complex() {
|
|||||||
(Instruction::load_constant(6, 8, false), Span(80, 81)),
|
(Instruction::load_constant(6, 8, false), Span(80, 81)),
|
||||||
(Instruction::load_constant(7, 9, false), Span(83, 84)),
|
(Instruction::load_constant(7, 9, false), Span(83, 84)),
|
||||||
(Instruction::r#move(7, 3), Span(95, 95)),
|
(Instruction::r#move(7, 3), Span(95, 95)),
|
||||||
(Instruction::r#return(true), Span(95, 95)),
|
(Instruction::r#return(false), Span(95, 95)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
@ -172,7 +172,9 @@ fn if_else_complex() {
|
|||||||
],
|
],
|
||||||
vec![]
|
vec![]
|
||||||
))
|
))
|
||||||
)
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
@ -265,7 +267,8 @@ fn if_else_false() {
|
|||||||
Instruction::call_native(0, NativeFunction::Panic, 0),
|
Instruction::call_native(0, NativeFunction::Panic, 0),
|
||||||
Span(12, 19)
|
Span(12, 19)
|
||||||
),
|
),
|
||||||
(Instruction::load_constant(0, 2, true), Span(29, 31)),
|
(Instruction::load_constant(1, 2, true), Span(29, 31)),
|
||||||
|
(Instruction::r#move(1, 0), Span(33, 33)),
|
||||||
(Instruction::r#return(true), Span(33, 33)),
|
(Instruction::r#return(true), Span(33, 33)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2), Value::integer(42)],
|
vec![Value::integer(1), Value::integer(2), Value::integer(42)],
|
||||||
@ -297,6 +300,7 @@ fn if_else_true() {
|
|||||||
Instruction::call_native(1, NativeFunction::Panic, 0),
|
Instruction::call_native(1, NativeFunction::Panic, 0),
|
||||||
Span(24, 31)
|
Span(24, 31)
|
||||||
),
|
),
|
||||||
|
(Instruction::r#move(1, 0), Span(33, 33)),
|
||||||
(Instruction::r#return(true), Span(33, 33))
|
(Instruction::r#return(true), Span(33, 33))
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(1), Value::integer(42)],
|
vec![Value::integer(1), Value::integer(1), Value::integer(42)],
|
||||||
|
@ -227,140 +227,6 @@ fn empty_list() {
|
|||||||
assert_eq!(run(source), Ok(Some(Value::list(0, 0, Type::Any))));
|
assert_eq!(run(source), Ok(Some(Value::list(0, 0, Type::Any))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function() {
|
|
||||||
let source = "fn(a: int, b: int) -> int { a + b }";
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
run(source),
|
|
||||||
Ok(Some(Value::function(
|
|
||||||
Chunk::with_data(
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
(Instruction::add(2, 0, 1), Span(30, 31)),
|
|
||||||
(Instruction::r#return(true), Span(34, 35)),
|
|
||||||
],
|
|
||||||
vec![],
|
|
||||||
vec![
|
|
||||||
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
|
||||||
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
FunctionType {
|
|
||||||
type_parameters: None,
|
|
||||||
value_parameters: Some(vec![
|
|
||||||
(Identifier::new("a"), Type::Integer),
|
|
||||||
(Identifier::new("b"), Type::Integer)
|
|
||||||
]),
|
|
||||||
return_type: Some(Box::new(Type::Integer)),
|
|
||||||
}
|
|
||||||
)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_declaration() {
|
|
||||||
let source = "fn add (a: int, b: int) -> int { a + b }";
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parse(source),
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
(Instruction::load_constant(0, 0, false), Span(0, 40)),
|
|
||||||
(Instruction::define_local(0, 0, false), Span(3, 6)),
|
|
||||||
(Instruction::r#return(false), Span(40, 40))
|
|
||||||
],
|
|
||||||
vec![Value::function(
|
|
||||||
Chunk::with_data(
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
(Instruction::add(2, 0, 1), Span(35, 36)),
|
|
||||||
(Instruction::r#return(true), Span(39, 40)),
|
|
||||||
],
|
|
||||||
vec![],
|
|
||||||
vec![
|
|
||||||
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
|
||||||
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
FunctionType {
|
|
||||||
type_parameters: None,
|
|
||||||
value_parameters: Some(vec![
|
|
||||||
(Identifier::new("a"), Type::Integer),
|
|
||||||
(Identifier::new("b"), Type::Integer)
|
|
||||||
]),
|
|
||||||
return_type: Some(Box::new(Type::Integer)),
|
|
||||||
},
|
|
||||||
)],
|
|
||||||
vec![Local::new(
|
|
||||||
Identifier::new("add"),
|
|
||||||
Some(Type::Function(FunctionType {
|
|
||||||
type_parameters: None,
|
|
||||||
value_parameters: Some(vec![
|
|
||||||
(Identifier::new("a"), Type::Integer),
|
|
||||||
(Identifier::new("b"), Type::Integer)
|
|
||||||
]),
|
|
||||||
return_type: Some(Box::new(Type::Integer)),
|
|
||||||
})),
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
),],
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(run(source), Ok(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn function_call() {
|
|
||||||
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
parse(source),
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
(Instruction::load_constant(0, 0, false), Span(0, 36)),
|
|
||||||
(Instruction::load_constant(1, 1, false), Span(36, 37)),
|
|
||||||
(Instruction::load_constant(2, 2, false), Span(39, 40)),
|
|
||||||
(Instruction::call(3, 0, 2), Span(35, 41)),
|
|
||||||
(Instruction::r#return(true), Span(41, 41)),
|
|
||||||
],
|
|
||||||
vec![
|
|
||||||
Value::function(
|
|
||||||
Chunk::with_data(
|
|
||||||
None,
|
|
||||||
vec![
|
|
||||||
(Instruction::add(2, 0, 1), Span(30, 31)),
|
|
||||||
(Instruction::r#return(true), Span(34, 35)),
|
|
||||||
],
|
|
||||||
vec![],
|
|
||||||
vec![
|
|
||||||
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
|
||||||
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
FunctionType {
|
|
||||||
type_parameters: None,
|
|
||||||
value_parameters: Some(vec![
|
|
||||||
(Identifier::new("a"), Type::Integer),
|
|
||||||
(Identifier::new("b"), Type::Integer)
|
|
||||||
]),
|
|
||||||
return_type: Some(Box::new(Type::Integer)),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Value::integer(1),
|
|
||||||
Value::integer(2)
|
|
||||||
],
|
|
||||||
vec![]
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list() {
|
fn list() {
|
||||||
let source = "[1, 2, 3]";
|
let source = "[1, 2, 3]";
|
||||||
|
135
dust-lang/tests/functions.rs
Normal file
135
dust-lang/tests/functions.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function() {
|
||||||
|
let source = "fn(a: int, b: int) -> int { a + b }";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
run(source),
|
||||||
|
Ok(Some(Value::function(
|
||||||
|
Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::add(2, 0, 1), Span(30, 31)),
|
||||||
|
(Instruction::r#return(true), Span(35, 35)),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
||||||
|
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
}
|
||||||
|
)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_declaration() {
|
||||||
|
let source = "fn add (a: int, b: int) -> int { a + b }";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0, false), Span(0, 40)),
|
||||||
|
(Instruction::define_local(0, 0, false), Span(3, 6)),
|
||||||
|
(Instruction::r#return(false), Span(40, 40))
|
||||||
|
],
|
||||||
|
vec![Value::function(
|
||||||
|
Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::add(2, 0, 1), Span(35, 36)),
|
||||||
|
(Instruction::r#return(true), Span(40, 40)),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
||||||
|
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
vec![Local::new(
|
||||||
|
Identifier::new("add"),
|
||||||
|
Some(Type::Function(FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
})),
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
),],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call() {
|
||||||
|
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0, false), Span(0, 36)),
|
||||||
|
(Instruction::load_constant(1, 1, false), Span(36, 37)),
|
||||||
|
(Instruction::load_constant(2, 2, false), Span(39, 40)),
|
||||||
|
(Instruction::call(3, 0, 2), Span(35, 41)),
|
||||||
|
(Instruction::r#return(true), Span(41, 41)),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
Value::function(
|
||||||
|
Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::add(2, 0, 1), Span(30, 31)),
|
||||||
|
(Instruction::r#return(true), Span(35, 36)),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
||||||
|
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Value::integer(1),
|
||||||
|
Value::integer(2)
|
||||||
|
],
|
||||||
|
vec![]
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
||||||
|
}
|
@ -15,7 +15,7 @@ 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(false), Span(27, 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![]
|
||||||
|
Loading…
Reference in New Issue
Block a user