Implement option type
This commit is contained in:
parent
9dfaf1420c
commit
34db948c6e
@ -1,6 +1,22 @@
|
|||||||
create_user = (fn email <string>, name <option(string)>) <map> {
|
create_user = (fn email <str>, name <option(str)>) <map> {
|
||||||
{
|
{
|
||||||
email = email
|
email = email
|
||||||
username = (either_or username email)
|
username = (either_or name email)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(assert_equal
|
||||||
|
{
|
||||||
|
email = "bob@example.com"
|
||||||
|
username = "bob"
|
||||||
|
},
|
||||||
|
(create_user "bob@example.com" some("bob"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_equal
|
||||||
|
{
|
||||||
|
email = "sue@example.com"
|
||||||
|
username = "sue@example.com"
|
||||||
|
},
|
||||||
|
(create_user "sue@example.com" none)
|
||||||
|
)
|
||||||
|
@ -90,7 +90,6 @@ impl AbstractTree for Assignment {
|
|||||||
AssignmentOperator::Equal => {}
|
AssignmentOperator::Equal => {}
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Type::List(item_type) = identifier_type {
|
if let Type::List(item_type) = identifier_type {
|
||||||
println!("{item_type} {statement_type}");
|
|
||||||
item_type
|
item_type
|
||||||
.check(&statement_type)
|
.check(&statement_type)
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
.map_err(|error| error.at_node(statement_node, source))?;
|
||||||
|
@ -152,8 +152,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
let identifier_type = identifier.expected_type(context)?;
|
||||||
|
|
||||||
println!("{identifier_type:?}");
|
|
||||||
|
|
||||||
if let Type::Function {
|
if let Type::Function {
|
||||||
parameter_types: _,
|
parameter_types: _,
|
||||||
return_type,
|
return_type,
|
||||||
|
@ -86,6 +86,10 @@ impl Type {
|
|||||||
(Type::Option(left), Type::Option(right)) => {
|
(Type::Option(left), Type::Option(right)) => {
|
||||||
if left == right {
|
if left == right {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else if let Type::Any = left.as_ref() {
|
||||||
|
Ok(())
|
||||||
|
} else if let Type::Any = right.as_ref() {
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::TypeCheck {
|
Err(Error::TypeCheck {
|
||||||
expected: self.clone(),
|
expected: self.clone(),
|
||||||
@ -93,6 +97,7 @@ impl Type {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(Type::Option(_), Type::None) | (Type::None, Type::Option(_)) => Ok(()),
|
||||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||||
if self_item_type.check(&other_item_type).is_err() {
|
if self_item_type.check(&other_item_type).is_err() {
|
||||||
Err(Error::TypeCheck {
|
Err(Error::TypeCheck {
|
||||||
|
@ -7,6 +7,7 @@ mod commands;
|
|||||||
mod data_formats;
|
mod data_formats;
|
||||||
mod fs;
|
mod fs;
|
||||||
mod network;
|
mod network;
|
||||||
|
mod option;
|
||||||
mod output;
|
mod output;
|
||||||
mod packages;
|
mod packages;
|
||||||
mod random;
|
mod random;
|
||||||
@ -16,7 +17,7 @@ mod r#type;
|
|||||||
///
|
///
|
||||||
/// This is the public interface to access built-in functions by iterating over
|
/// This is the public interface to access built-in functions by iterating over
|
||||||
/// the references it holds.
|
/// the references it holds.
|
||||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 18] = [
|
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 21] = [
|
||||||
&assert::Assert,
|
&assert::Assert,
|
||||||
&assert::AssertEqual,
|
&assert::AssertEqual,
|
||||||
&collections::Length,
|
&collections::Length,
|
||||||
@ -28,6 +29,9 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 18] = [
|
|||||||
&fs::Write,
|
&fs::Write,
|
||||||
&fs::Append,
|
&fs::Append,
|
||||||
&network::Download,
|
&network::Download,
|
||||||
|
&option::EitherOr,
|
||||||
|
&option::IsNone,
|
||||||
|
&option::IsSome,
|
||||||
&output::Output,
|
&output::Output,
|
||||||
&packages::InstallPackages,
|
&packages::InstallPackages,
|
||||||
&random::Random,
|
&random::Random,
|
||||||
|
69
src/built_in_functions/option.rs
Normal file
69
src/built_in_functions/option.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use crate::{BuiltInFunction, Map, Result, Type, Value};
|
||||||
|
|
||||||
|
pub struct EitherOr;
|
||||||
|
|
||||||
|
impl BuiltInFunction for EitherOr {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"either_or"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
||||||
|
let option = arguments.first().unwrap_or_default().as_option()?;
|
||||||
|
let value = if let Some(value) = option {
|
||||||
|
*value.clone()
|
||||||
|
} else {
|
||||||
|
arguments.get(1).unwrap_or_default().clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> Type {
|
||||||
|
Type::Function {
|
||||||
|
parameter_types: vec![Type::Option(Box::new(Type::Any)), Type::Any],
|
||||||
|
return_type: Box::new(Type::Boolean),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IsNone;
|
||||||
|
|
||||||
|
impl BuiltInFunction for IsNone {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"is_none"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
||||||
|
let option = arguments.first().unwrap_or_default().as_option()?;
|
||||||
|
|
||||||
|
Ok(Value::Boolean(option.is_none()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> Type {
|
||||||
|
Type::Function {
|
||||||
|
parameter_types: vec![Type::Option(Box::new(Type::Any))],
|
||||||
|
return_type: Box::new(Type::Boolean),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IsSome;
|
||||||
|
|
||||||
|
impl BuiltInFunction for IsSome {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"is_some"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
||||||
|
let option = arguments.first().unwrap_or_default().as_option()?;
|
||||||
|
|
||||||
|
Ok(Value::Boolean(option.is_some()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> Type {
|
||||||
|
Type::Function {
|
||||||
|
parameter_types: vec![Type::Option(Box::new(Type::Any))],
|
||||||
|
return_type: Box::new(Type::Boolean),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -414,8 +414,11 @@ module.exports = grammar({
|
|||||||
'assert_equal',
|
'assert_equal',
|
||||||
'bash',
|
'bash',
|
||||||
'download',
|
'download',
|
||||||
|
'either_or',
|
||||||
'fish',
|
'fish',
|
||||||
'from_json',
|
'from_json',
|
||||||
|
'is_none',
|
||||||
|
'is_some',
|
||||||
'length',
|
'length',
|
||||||
'metadata',
|
'metadata',
|
||||||
'output',
|
'output',
|
||||||
|
@ -1361,6 +1361,10 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "download"
|
"value": "download"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "either_or"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "fish"
|
"value": "fish"
|
||||||
@ -1369,6 +1373,14 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "from_json"
|
"value": "from_json"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "is_none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "is_some"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "length"
|
"value": "length"
|
||||||
|
@ -721,6 +721,10 @@
|
|||||||
"type": "download",
|
"type": "download",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "either_or",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "else",
|
"type": "else",
|
||||||
"named": false
|
"named": false
|
||||||
@ -773,6 +777,14 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "is_none",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "is_some",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "length",
|
"type": "length",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user