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(())
            }
        }
    }
}