ryna/
operations.rs

1use serde::{Deserialize, Serialize};
2
3use crate::annotations::Annotation;
4use crate::compilation::CompiledRynaExpr;
5use crate::parser::Location;
6use crate::types::{Type, INT, BOOL, STR, T_0, FLOAT};
7use crate::{object::*, ARR_OF};
8use crate::context::RynaContext;
9
10/*
11                                                  ╒══════════════════╕
12    ============================================= │  IMPLEMENTATION  │ =============================================
13                                                  ╘══════════════════╛
14*/
15
16pub type UnaryFunctionFn = fn(&Vec<Type>, &Type, Object) -> Result<Object, String>;
17pub type BinaryFunctionFn = fn(&Vec<Type>, &Type, Object, Object, &RynaContext) -> Result<Object, String>;
18pub type NaryFunctionFn = fn((&mut Vec<Object>, &mut usize, &mut Vec<(i32, usize, i32)>, &mut i32), &Vec<Type>, &Type) -> Result<(), String>;
19
20pub type OptUnaryFunctionFn = Option<UnaryFunctionFn>;
21pub type OptBinaryFunctionFn = Option<BinaryFunctionFn>;
22pub type OptNaryFunctionFn = Option<NaryFunctionFn>;
23
24#[derive(Clone, Serialize, Deserialize)]
25#[serde(bound = "")]
26pub struct Operation<T> {
27    pub location: Location,
28    pub annotations: Vec<Annotation>,
29    pub templates: usize,
30    pub args: Type,
31    pub ret: Type,
32
33    #[serde(skip)]
34    pub operation: Option<T>
35}
36
37pub type UnaryOperations = Vec<Operation<UnaryFunctionFn>>;
38pub type BinaryOperations = Vec<Operation<BinaryFunctionFn>>;
39pub type NaryOperations = Vec<Operation<NaryFunctionFn>>;
40
41const EMPTY_UN_FUNC: UnaryFunctionFn = |_, _, _| Ok(Object::empty());
42const EMPTY_BIN_FUNC: BinaryFunctionFn = |_, _, _, _, _| Ok(Object::empty());
43const EMPTY_NARY_FUNC: NaryFunctionFn = |_, _, _| Ok(());
44
45#[derive(Clone, Serialize, Deserialize)]
46pub enum Operator {
47    Unary {
48        id: usize,
49        representation: String,
50        prefix: bool,
51        precedence: usize,
52        operations: UnaryOperations
53    },
54
55    Binary {
56        id: usize,
57        right_associative: bool,
58        representation: String,
59        precedence: usize,
60        operations: BinaryOperations
61    },
62
63    Nary {
64        id: usize,
65        open_rep: String, // N-ary operators are only allowed to be enclosers, such as the call operator and the multidimensional index operator
66        close_rep: String,
67        precedence: usize,
68        operations: NaryOperations
69    }
70}
71
72impl Operator {
73    pub fn get_id(&self) -> usize {
74        match self {
75            Operator::Unary { id, .. } => *id,
76            Operator::Binary { id, .. } => *id,
77            Operator::Nary { id, .. } => *id
78        }
79    }
80
81    pub fn get_precedence(&self) -> usize {
82        match self {
83            Operator::Unary { precedence: p, .. } => *p,
84            Operator::Binary { precedence: p, .. } => *p,
85            Operator::Nary { precedence: p, .. } => *p
86        }
87    }
88
89    pub fn get_repr(&self) -> String {
90        match self {
91            Operator::Unary { representation: r, .. } => r.into(),
92            Operator::Binary { representation: r, .. } => r.into(),
93            Operator::Nary { open_rep: o, close_rep: c, .. } => format!("{o}{c}")
94        }
95    }
96
97    pub fn is_right_associative(&self) -> bool {
98        match self {
99            Operator::Binary { right_associative, .. } => *right_associative,
100            _ => unreachable!()
101        }
102    }
103}
104
105/*
106                                                  ╒════════════════╕
107    ============================================= │  STANDARD OPS  │ =============================================
108                                                  ╘════════════════╛
109*/
110
111macro_rules! define_unary_native_op {
112    ($ctx: ident, $id: expr, $inner_type: expr, $return_type: expr) => {
113        $ctx.define_native_unary_operation($id, 0, $inner_type, $return_type, EMPTY_UN_FUNC).unwrap();
114    };
115}
116
117macro_rules! define_unary_native_op_combinations {
118    ($ctx: ident, $id: expr, $inner_type: expr, $return_type: expr) => {
119        let base_ref = Type::Ref(Box::new($inner_type.clone()));
120        let base_mut = Type::MutRef(Box::new($inner_type.clone()));
121        
122        define_unary_native_op!($ctx, $id, $inner_type, $return_type);
123        define_unary_native_op!($ctx, $id, base_ref.clone(), $return_type);
124        define_unary_native_op!($ctx, $id, base_mut.clone(), $return_type);
125    };
126}
127
128pub const NEG_UNOP_ID: usize = 0;
129pub const NOT_UNOP_ID: usize = 1;
130pub const DEREF_UNOP_ID: usize = 2;
131
132pub fn standard_unary_operations(ctx: &mut RynaContext) {
133    ctx.define_unary_operator("-".into(), true, 300).unwrap();
134
135    define_unary_native_op_combinations!(ctx, 0, INT, INT);
136    define_unary_native_op_combinations!(ctx, 0, FLOAT, FLOAT);
137
138    ctx.define_unary_operator("!".into(), true, 250).unwrap();
139
140    define_unary_native_op_combinations!(ctx, 1, BOOL, BOOL);
141    define_unary_native_op_combinations!(ctx, 1, INT, INT);
142
143    ctx.define_unary_operator("*".into(), true, 155).unwrap();
144
145    ctx.define_native_unary_operation(2, 1, T_0.to_mut(), T_0, EMPTY_UN_FUNC).unwrap();
146    ctx.define_native_unary_operation(2, 1, T_0.to_ref(), T_0, EMPTY_UN_FUNC).unwrap();
147}
148
149macro_rules! define_binary_native_op {
150    ($ctx: ident, $id: expr, $l_type: expr, $r_type: expr, $return_type: expr) => {
151        $ctx.define_native_binary_operation($id, 0, $l_type, $r_type, $return_type, EMPTY_BIN_FUNC).unwrap();
152    };
153}
154
155macro_rules! define_binary_native_op_combinations_distinct {
156    ($ctx: ident, $id: expr, $base_type_1: expr, $base_type_2: expr, $return_type: expr) => {
157        let base_ref_1 = Type::Ref(Box::new($base_type_1.clone()));
158        let base_mut_1 = Type::MutRef(Box::new($base_type_1.clone()));
159        let base_ref_2 = Type::Ref(Box::new($base_type_2.clone()));
160        let base_mut_2 = Type::MutRef(Box::new($base_type_2.clone()));
161        
162        define_binary_native_op!($ctx, $id, $base_type_1, $base_type_2, $return_type);
163        define_binary_native_op!($ctx, $id, base_ref_1.clone(), $base_type_2, $return_type);
164        define_binary_native_op!($ctx, $id, $base_type_1, base_ref_2.clone(), $return_type);
165        define_binary_native_op!($ctx, $id, base_mut_1.clone(), $base_type_2, $return_type);
166        define_binary_native_op!($ctx, $id, $base_type_1, base_mut_2.clone(), $return_type);
167        define_binary_native_op!($ctx, $id, base_ref_1.clone(), base_ref_2.clone(), $return_type);
168        define_binary_native_op!($ctx, $id, base_ref_1.clone(), base_mut_2.clone(), $return_type);
169        define_binary_native_op!($ctx, $id, base_mut_1.clone(), base_mut_2.clone(), $return_type);
170        define_binary_native_op!($ctx, $id, base_mut_1.clone(), base_ref_2.clone(), $return_type);
171    };
172}
173
174macro_rules! define_binary_native_op_combinations {
175    ($ctx: ident, $id: expr, $base_type: expr, $return_type: expr) => {
176        define_binary_native_op_combinations_distinct!($ctx, $id, $base_type, $base_type, $return_type);
177    };
178}
179
180// Constant identifiers
181pub const ADD_BINOP_ID: usize = 0;
182pub const SUB_BINOP_ID: usize = 1;
183pub const MUL_BINOP_ID: usize = 2;
184pub const DIV_BINOP_ID: usize = 3;
185pub const MOD_BINOP_ID: usize = 4;
186
187pub const DOT_BINOP_ID: usize = 5;
188
189pub const LT_BINOP_ID: usize = 6;
190pub const GT_BINOP_ID: usize = 7;
191pub const LTEQ_BINOP_ID: usize = 8;
192pub const GTEQ_BINOP_ID: usize = 9;
193pub const EQ_BINOP_ID: usize = 10;
194pub const NEQ_BINOP_ID: usize = 11;
195
196pub const OR_BINOP_ID: usize = 12;
197pub const AND_BINOP_ID: usize = 13;
198pub const XOR_BINOP_ID: usize = 19;
199
200pub const SHR_BINOP_ID: usize = 15;
201pub const SHL_BINOP_ID: usize = 16;
202pub const ANDB_BINOP_ID: usize = 17;
203pub const ORB_BINOP_ID: usize = 18;
204
205pub const ASSIGN_BINOP_ID: usize = 14;
206
207pub const LT_BINOP_PREC: usize = 900;
208
209pub const DEFINE_BINOP_ID: usize = 20;
210
211pub const IDX_NARYOP_ID: usize = 1;
212
213pub fn standard_binary_operations(ctx: &mut RynaContext) {
214    
215    /*
216        ╒═════════════════════════════╕
217        │ Basic arithmetic operations │
218        ╘═════════════════════════════╛
219    */
220
221    ctx.define_binary_operator("+".into(), false, 650).unwrap();
222
223    define_binary_native_op_combinations!(ctx, 0, INT, INT);
224    define_binary_native_op_combinations!(ctx, 0, FLOAT, FLOAT);
225    define_binary_native_op_combinations_distinct!(ctx, 0, INT, FLOAT, FLOAT);
226    define_binary_native_op_combinations_distinct!(ctx, 0, FLOAT, INT, FLOAT);
227
228    define_binary_native_op_combinations!(ctx, 0, STR, STR);
229
230    ctx.define_binary_operator("-".into(), true, 700).unwrap();
231
232    define_binary_native_op_combinations!(ctx, 1, INT, INT);
233    define_binary_native_op_combinations!(ctx, 1, FLOAT, FLOAT);
234    define_binary_native_op_combinations_distinct!(ctx, 1, INT, FLOAT, FLOAT);
235    define_binary_native_op_combinations_distinct!(ctx, 1, FLOAT, INT, FLOAT);
236
237    ctx.define_binary_operator("*".into(), false, 500).unwrap();
238
239    define_binary_native_op_combinations!(ctx, 2, INT, INT);
240    define_binary_native_op_combinations!(ctx, 2, FLOAT, FLOAT);
241    define_binary_native_op_combinations_distinct!(ctx, 2, INT, FLOAT, FLOAT);
242    define_binary_native_op_combinations_distinct!(ctx, 2, FLOAT, INT, FLOAT);
243
244    ctx.define_binary_operator("/".into(), false, 550).unwrap();
245
246    define_binary_native_op_combinations!(ctx, 3, INT, INT);
247    define_binary_native_op_combinations!(ctx, 3, FLOAT, FLOAT);
248    define_binary_native_op_combinations_distinct!(ctx, 3, INT, FLOAT, FLOAT);
249    define_binary_native_op_combinations_distinct!(ctx, 3, FLOAT, INT, FLOAT);
250
251    ctx.define_binary_operator("%".into(), false, 600).unwrap();
252
253    define_binary_native_op_combinations!(ctx, 4, INT, INT);
254    define_binary_native_op_combinations!(ctx, 4, FLOAT, FLOAT);
255    define_binary_native_op_combinations_distinct!(ctx, 4, INT, FLOAT, FLOAT);
256    define_binary_native_op_combinations_distinct!(ctx, 4, FLOAT, INT, FLOAT);
257
258    /*
259        ╒══════════════════════╕
260        │ Ancillary operations │
261        ╘══════════════════════╛
262    */
263
264    ctx.define_binary_operator(".".into(), true, 100).unwrap();
265
266    /*
267        ╒═══════════════════════╕
268        │ Comparison operations │
269        ╘═══════════════════════╛
270    */
271
272    ctx.define_binary_operator("<".into(), false, 900).unwrap();
273
274    define_binary_native_op_combinations!(ctx, 6, INT, BOOL);
275    define_binary_native_op_combinations!(ctx, 6, FLOAT, BOOL);
276    define_binary_native_op_combinations_distinct!(ctx, 6, INT, FLOAT, BOOL);
277    define_binary_native_op_combinations_distinct!(ctx, 6, FLOAT, INT, BOOL);
278
279    ctx.define_binary_operator(">".into(), false, 950).unwrap();
280
281    define_binary_native_op_combinations!(ctx, 7, INT, BOOL);
282    define_binary_native_op_combinations!(ctx, 7, FLOAT, BOOL);
283    define_binary_native_op_combinations_distinct!(ctx, 7, INT, FLOAT, BOOL);
284    define_binary_native_op_combinations_distinct!(ctx, 7, FLOAT, INT, BOOL);
285
286    ctx.define_binary_operator("<=".into(), false, 1000).unwrap();
287
288    define_binary_native_op_combinations!(ctx, 8, INT, BOOL);
289    define_binary_native_op_combinations!(ctx, 8, FLOAT, BOOL);
290    define_binary_native_op_combinations_distinct!(ctx, 8, INT, FLOAT, BOOL);
291    define_binary_native_op_combinations_distinct!(ctx, 8, FLOAT, INT, BOOL);
292
293    ctx.define_binary_operator(">=".into(), false, 1050).unwrap();
294
295    define_binary_native_op_combinations!(ctx, 9, INT, BOOL);
296    define_binary_native_op_combinations!(ctx, 9, FLOAT, BOOL);
297    define_binary_native_op_combinations_distinct!(ctx, 9, INT, FLOAT, BOOL);
298    define_binary_native_op_combinations_distinct!(ctx, 9, FLOAT, INT, BOOL);
299
300    ctx.define_binary_operator("==".into(), false, 1100).unwrap();
301
302    define_binary_native_op_combinations!(ctx, 10, INT, BOOL);
303    define_binary_native_op_combinations!(ctx, 10, FLOAT, BOOL);
304    define_binary_native_op_combinations!(ctx, 10, STR, BOOL);
305    define_binary_native_op_combinations!(ctx, 10, BOOL, BOOL);
306
307    ctx.define_binary_operator("!=".into(), false, 1150).unwrap();
308
309    define_binary_native_op_combinations!(ctx, 11, INT, BOOL);
310    define_binary_native_op_combinations!(ctx, 11, FLOAT, BOOL);
311    define_binary_native_op_combinations!(ctx, 11, STR, BOOL);
312    define_binary_native_op_combinations!(ctx, 11, BOOL, BOOL);
313
314    /*
315        ╒════════════════════╕
316        │ Logical operations │
317        ╘════════════════════╛
318    */
319
320    ctx.define_binary_operator("||".into(), false, 1500).unwrap();
321
322    define_binary_native_op_combinations!(ctx, 12, BOOL, BOOL);
323
324    ctx.define_binary_operator("&&".into(), false, 1550).unwrap();
325
326    define_binary_native_op_combinations!(ctx, 13, BOOL, BOOL);
327
328    ctx.define_binary_operator(":=".into(), false, 100000).unwrap();
329
330    ctx.define_native_binary_operation(
331        14, 1, 
332        T_0.to_mut(), T_0, Type::Empty, 
333        |_, _, a, b, ctx| {
334            a.assign(b, ctx)?;
335            Ok(Object::empty())
336        }
337    ).unwrap();
338
339    ctx.define_binary_operator(">>".into(), false, 350).unwrap();
340
341    define_binary_native_op_combinations!(ctx, 15, INT, INT);
342
343    ctx.define_binary_operator("<<".into(), false, 360).unwrap();
344
345    define_binary_native_op_combinations!(ctx, 16, INT, INT);
346
347    ctx.define_binary_operator("&".into(), false, 370).unwrap();
348
349    define_binary_native_op_combinations!(ctx, 17, INT, INT);
350
351    ctx.define_binary_operator("|".into(), false, 380).unwrap();
352
353    define_binary_native_op_combinations!(ctx, 18, INT, INT);
354
355    ctx.define_binary_operator("^".into(), false, 390).unwrap();
356
357    define_binary_native_op_combinations!(ctx, 19, BOOL, BOOL);
358    define_binary_native_op_combinations!(ctx, 19, INT, INT);
359
360    ctx.define_binary_operator("=".into(), false, 200000).unwrap();
361}
362
363pub const CALL_OP: usize = 0;
364
365pub fn standard_nary_operations(ctx: &mut RynaContext) {
366    ctx.define_nary_operator("(".into(), ")".into(), 50).unwrap();
367
368    for n in 0..30 {
369        let args = (0..n).map(|i| Type::TemplateParam(i, vec!())).collect::<Vec<_>>();
370
371        let f_type = Type::Function(
372            Box::new(Type::And(args.clone())),
373            Box::new(Type::TemplateParam(n, vec!()))
374        );
375
376        let res = ctx.define_native_nary_operation(
377            0, n + 1, 
378            Type::MutRef(Box::new(f_type.clone())), 
379            args.as_slice(), 
380            Type::TemplateParam(n, vec!()), 
381            EMPTY_NARY_FUNC
382        ).unwrap();
383
384        ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCallRef, 0));
385
386        let res = ctx.define_native_nary_operation(
387            0, n + 1, 
388            Type::Ref(Box::new(f_type.clone())), 
389            args.as_slice(), 
390            Type::TemplateParam(n, vec!()), 
391            EMPTY_NARY_FUNC
392        ).unwrap();
393
394        ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCallRef, 0));
395
396        let res = ctx.define_native_nary_operation(
397            0, n + 1, 
398            f_type, 
399            args.as_slice(), 
400            Type::TemplateParam(n, vec!()), 
401            EMPTY_NARY_FUNC
402        ).unwrap();
403
404        ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCall, 0));
405    }  
406
407    ctx.define_nary_operator("[".into(), "]".into(), 75).unwrap();
408
409    // Indexing operations on arrays
410    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0), &[INT], T_0, EMPTY_NARY_FUNC).unwrap();
411    ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxMove, 0));
412    
413    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_mut(), &[INT], T_0.to_mut(), EMPTY_NARY_FUNC).unwrap();
414    ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxMut, 0));
415    
416    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_ref(), &[INT], T_0.to_ref(), EMPTY_NARY_FUNC).unwrap();
417    ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxRef, 0));
418}