1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use crate::{
modifiers::{AccessType, CurryType, InlineType},
types::ValkyrieMetaType,
ValkyrieValue,
};
use indexmap::IndexMap;
use shredder::Gc;
use std::{collections::BTreeMap, sync::Arc};
use valkyrie_ast::StatementBlock;
use valkyrie_error::{DefinitionSpan, RuntimeError, ValkyrieResult};
pub mod operators;
pub trait ValkyrieFunctionType {
fn boxed(self) -> ValkyrieValue;
fn type_info(&self) -> Gc<ValkyrieMetaType>;
}
/// A function that can be called from Valkyrie.
///
/// ```vk
/// fun f(self, a, <, b, c, >, @a mut **a): Return {
///
/// }
/// ```
///
///
/// ```stack
/// 0: ret pointer
/// 1: env pointer
/// ```
#[derive(Clone, Debug)]
pub struct ValkyrieFunction {
pub name: String,
pub span: DefinitionSpan,
pub overridable: bool,
pub return_type: Arc<ValkyrieMonomorphicFunction>,
}
/// Actual function definition, non-overloading, non-overriding
///
///
///
/// ## Curry Function
///
/// - All mixed arguments and named arguments must be filled.
/// - Named arguments can be filled in any order.
/// - Named arguments can not be override.
///
///
///
/// ```vk
/// curry add(< , a: int, b: int, >) { a + b }
///
/// add(1)(2) -> 3
/// add(1)(a: 2)(b: 3) -> Cannot override named a argument
///
/// curry function(self, **sum: Array<int>, a: int, b: int, c:int)
///
/// self.function(0)(0, a: 1)(0, a: 2)(0, a: 3)(b: 4, c: 5)
/// ```
///
/// ## Delay Function
///
/// - All mixed arguments and named arguments must be filled.
/// - Named arguments can be filled in any order.
/// - Named arguments can be override.
#[derive(Clone, Debug)]
pub struct ValkyrieMonomorphicFunction {
/// Behavior when input arguments are incomplete
pub curry: CurryType,
/// Threshold at which to inline this function
pub inline: InlineType,
/// Access level under normal circumstances
pub access: AccessType,
/// The arguments that must be passed without a name
pub positional: Vec<ValkyrieValue>,
/// The arguments that can be passed with a name
pub mixed: IndexMap<String, ValkyrieValue>,
/// The arguments that must be passed with a name
pub named: BTreeMap<String, ValkyrieValue>,
/// The return type of this function, auto if not specified
pub return_type: ValkyrieValue,
/// The effect type of this function, auto if not specified
pub effect_type: ValkyrieValue,
}
/// Actual function definition, overloading, non-overriding
#[derive(Clone, Debug)]
pub struct ValkyriePartialFunction {
pub prototype: Arc<ValkyrieFunction>,
pub generic: Vec<ValkyrieValue>,
pub positional: Vec<ValkyrieValue>,
pub named: BTreeMap<String, ValkyrieValue>,
pub continuation: Option<StatementBlock>,
}
pub struct ValkyrieContinuation {
pub scope: ValkyrieMetaType,
pub block: StatementBlock,
}
/// if the code contains loop, it will be compiled into a state machine
#[derive(Clone, Debug)]
pub struct ValkyrieFunctionInstance {
pub return_type: ValkyrieValue,
}
impl ValkyrieFunction {
pub fn instance(self: Arc<Self>) -> ValkyriePartialFunction {
ValkyriePartialFunction {
prototype: self.clone(),
generic: vec![],
positional: vec![],
named: Default::default(),
continuation: None,
}
}
}
impl ValkyrieMonomorphicFunction {
pub fn can_invoke(partial: &ValkyriePartialFunction) {
todo!()
}
}
impl ValkyriePartialFunction {
pub fn can_invoke(&self) -> bool {
todo!()
}
pub fn add_continuation(&mut self, continuation: StatementBlock) -> ValkyrieResult<()> {
match self.continuation {
Some(_) => Err(RuntimeError::new("continuation already exists"))?,
None => {
self.continuation = Some(continuation);
Ok(())
}
}
}
pub fn add_positional(&mut self, value: ValkyrieValue) -> ValkyrieResult<()> {
match self.positional.len() {
len if len < self.prototype.return_type.positional.len() => {
self.positional.push(value);
Ok(())
}
_ => Err(RuntimeError::new("too many arguments"))?,
}
}
pub fn add_named(&mut self, name: String, value: ValkyrieValue) -> ValkyrieResult<()> {
match self.named.get(&name) {
Some(_) => Err(RuntimeError::new("named argument already exists"))?,
None => {
self.named.insert(name, value);
Ok(())
}
}
}
}