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
|
||||
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::PlusEqual => {
|
||||
if let Type::List(item_type) = identifier_type {
|
||||
println!("{item_type} {statement_type}");
|
||||
item_type
|
||||
.check(&statement_type)
|
||||
.map_err(|error| error.at_node(statement_node, source))?;
|
||||
|
@ -152,8 +152,6 @@ impl AbstractTree for FunctionCall {
|
||||
|
||||
let identifier_type = identifier.expected_type(context)?;
|
||||
|
||||
println!("{identifier_type:?}");
|
||||
|
||||
if let Type::Function {
|
||||
parameter_types: _,
|
||||
return_type,
|
||||
|
@ -86,6 +86,10 @@ impl Type {
|
||||
(Type::Option(left), Type::Option(right)) => {
|
||||
if left == right {
|
||||
Ok(())
|
||||
} else if let Type::Any = left.as_ref() {
|
||||
Ok(())
|
||||
} else if let Type::Any = right.as_ref() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TypeCheck {
|
||||
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)) => {
|
||||
if self_item_type.check(&other_item_type).is_err() {
|
||||
Err(Error::TypeCheck {
|
||||
|
@ -7,6 +7,7 @@ mod commands;
|
||||
mod data_formats;
|
||||
mod fs;
|
||||
mod network;
|
||||
mod option;
|
||||
mod output;
|
||||
mod packages;
|
||||
mod random;
|
||||
@ -16,7 +17,7 @@ mod r#type;
|
||||
///
|
||||
/// This is the public interface to access built-in functions by iterating over
|
||||
/// the references it holds.
|
||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 18] = [
|
||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 21] = [
|
||||
&assert::Assert,
|
||||
&assert::AssertEqual,
|
||||
&collections::Length,
|
||||
@ -28,6 +29,9 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 18] = [
|
||||
&fs::Write,
|
||||
&fs::Append,
|
||||
&network::Download,
|
||||
&option::EitherOr,
|
||||
&option::IsNone,
|
||||
&option::IsSome,
|
||||
&output::Output,
|
||||
&packages::InstallPackages,
|
||||
&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',
|
||||
'bash',
|
||||
'download',
|
||||
'either_or',
|
||||
'fish',
|
||||
'from_json',
|
||||
'is_none',
|
||||
'is_some',
|
||||
'length',
|
||||
'metadata',
|
||||
'output',
|
||||
|
@ -1361,6 +1361,10 @@
|
||||
"type": "STRING",
|
||||
"value": "download"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "either_or"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "fish"
|
||||
@ -1369,6 +1373,14 @@
|
||||
"type": "STRING",
|
||||
"value": "from_json"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "is_none"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "is_some"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "length"
|
||||
|
@ -721,6 +721,10 @@
|
||||
"type": "download",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "either_or",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "else",
|
||||
"named": false
|
||||
@ -773,6 +777,14 @@
|
||||
"type": "integer",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "is_none",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "is_some",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "length",
|
||||
"named": false
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user