Implement option type

This commit is contained in:
Jeff 2023-12-26 20:05:19 -05:00
parent 9dfaf1420c
commit 34db948c6e
10 changed files with 4730 additions and 3707 deletions

View File

@ -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)
)

View File

@ -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))?;

View File

@ -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,

View File

@ -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 {

View File

@ -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,

View 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),
}
}
}

View File

@ -414,8 +414,11 @@ module.exports = grammar({
'assert_equal',
'bash',
'download',
'either_or',
'fish',
'from_json',
'is_none',
'is_some',
'length',
'metadata',
'output',

View File

@ -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"

View File

@ -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