nessa/
operations.rs

1use serde::{Deserialize, Serialize};
2
3use crate::annotations::Annotation;
4use crate::compilation::CompiledNessaExpr;
5use crate::parser::Location;
6use crate::types::{Type, INT, BOOL, STR, T_0, FLOAT};
7use crate::{object::*, ARR_OF};
8use crate::context::NessaContext;
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, &NessaContext) -> 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 NessaContext) {
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 fn standard_binary_operations(ctx: &mut NessaContext) {
212    
213    /*
214        ╒═════════════════════════════╕
215        │ Basic arithmetic operations │
216        ╘═════════════════════════════╛
217    */
218
219    ctx.define_binary_operator("+".into(), false, 650).unwrap();
220
221    define_binary_native_op_combinations!(ctx, 0, INT, INT);
222    define_binary_native_op_combinations!(ctx, 0, FLOAT, FLOAT);
223    define_binary_native_op_combinations_distinct!(ctx, 0, INT, FLOAT, FLOAT);
224    define_binary_native_op_combinations_distinct!(ctx, 0, FLOAT, INT, FLOAT);
225
226    define_binary_native_op_combinations!(ctx, 0, STR, STR);
227
228    ctx.define_binary_operator("-".into(), true, 700).unwrap();
229
230    define_binary_native_op_combinations!(ctx, 1, INT, INT);
231    define_binary_native_op_combinations!(ctx, 1, FLOAT, FLOAT);
232    define_binary_native_op_combinations_distinct!(ctx, 1, INT, FLOAT, FLOAT);
233    define_binary_native_op_combinations_distinct!(ctx, 1, FLOAT, INT, FLOAT);
234
235    ctx.define_binary_operator("*".into(), false, 500).unwrap();
236
237    define_binary_native_op_combinations!(ctx, 2, INT, INT);
238    define_binary_native_op_combinations!(ctx, 2, FLOAT, FLOAT);
239    define_binary_native_op_combinations_distinct!(ctx, 2, INT, FLOAT, FLOAT);
240    define_binary_native_op_combinations_distinct!(ctx, 2, FLOAT, INT, FLOAT);
241
242    ctx.define_binary_operator("/".into(), false, 550).unwrap();
243
244    define_binary_native_op_combinations!(ctx, 3, INT, INT);
245    define_binary_native_op_combinations!(ctx, 3, FLOAT, FLOAT);
246    define_binary_native_op_combinations_distinct!(ctx, 3, INT, FLOAT, FLOAT);
247    define_binary_native_op_combinations_distinct!(ctx, 3, FLOAT, INT, FLOAT);
248
249    ctx.define_binary_operator("%".into(), false, 600).unwrap();
250
251    define_binary_native_op_combinations!(ctx, 4, INT, INT);
252    define_binary_native_op_combinations!(ctx, 4, FLOAT, FLOAT);
253    define_binary_native_op_combinations_distinct!(ctx, 4, INT, FLOAT, FLOAT);
254    define_binary_native_op_combinations_distinct!(ctx, 4, FLOAT, INT, FLOAT);
255
256    /*
257        ╒══════════════════════╕
258        │ Ancillary operations │
259        ╘══════════════════════╛
260    */
261
262    ctx.define_binary_operator(".".into(), true, 100).unwrap();
263
264    /*
265        ╒═══════════════════════╕
266        │ Comparison operations │
267        ╘═══════════════════════╛
268    */
269
270    ctx.define_binary_operator("<".into(), false, 900).unwrap();
271
272    define_binary_native_op_combinations!(ctx, 6, INT, BOOL);
273    define_binary_native_op_combinations!(ctx, 6, FLOAT, BOOL);
274    define_binary_native_op_combinations_distinct!(ctx, 6, INT, FLOAT, BOOL);
275    define_binary_native_op_combinations_distinct!(ctx, 6, FLOAT, INT, BOOL);
276
277    ctx.define_binary_operator(">".into(), false, 950).unwrap();
278
279    define_binary_native_op_combinations!(ctx, 7, INT, BOOL);
280    define_binary_native_op_combinations!(ctx, 7, FLOAT, BOOL);
281    define_binary_native_op_combinations_distinct!(ctx, 7, INT, FLOAT, BOOL);
282    define_binary_native_op_combinations_distinct!(ctx, 7, FLOAT, INT, BOOL);
283
284    ctx.define_binary_operator("<=".into(), false, 1000).unwrap();
285
286    define_binary_native_op_combinations!(ctx, 8, INT, BOOL);
287    define_binary_native_op_combinations!(ctx, 8, FLOAT, BOOL);
288    define_binary_native_op_combinations_distinct!(ctx, 8, INT, FLOAT, BOOL);
289    define_binary_native_op_combinations_distinct!(ctx, 8, FLOAT, INT, BOOL);
290
291    ctx.define_binary_operator(">=".into(), false, 1050).unwrap();
292
293    define_binary_native_op_combinations!(ctx, 9, INT, BOOL);
294    define_binary_native_op_combinations!(ctx, 9, FLOAT, BOOL);
295    define_binary_native_op_combinations_distinct!(ctx, 9, INT, FLOAT, BOOL);
296    define_binary_native_op_combinations_distinct!(ctx, 9, FLOAT, INT, BOOL);
297
298    ctx.define_binary_operator("==".into(), false, 1100).unwrap();
299
300    define_binary_native_op_combinations!(ctx, 10, INT, BOOL);
301    define_binary_native_op_combinations!(ctx, 10, FLOAT, BOOL);
302    define_binary_native_op_combinations!(ctx, 10, STR, BOOL);
303    define_binary_native_op_combinations!(ctx, 10, BOOL, BOOL);
304
305    ctx.define_binary_operator("!=".into(), false, 1150).unwrap();
306
307    define_binary_native_op_combinations!(ctx, 11, INT, BOOL);
308    define_binary_native_op_combinations!(ctx, 11, FLOAT, BOOL);
309    define_binary_native_op_combinations!(ctx, 11, STR, BOOL);
310    define_binary_native_op_combinations!(ctx, 11, BOOL, BOOL);
311
312    /*
313        ╒════════════════════╕
314        │ Logical operations │
315        ╘════════════════════╛
316    */
317
318    ctx.define_binary_operator("||".into(), false, 1500).unwrap();
319
320    define_binary_native_op_combinations!(ctx, 12, BOOL, BOOL);
321
322    ctx.define_binary_operator("&&".into(), false, 1550).unwrap();
323
324    define_binary_native_op_combinations!(ctx, 13, BOOL, BOOL);
325
326    ctx.define_binary_operator(":=".into(), false, 100000).unwrap();
327
328    ctx.define_native_binary_operation(
329        14, 1, 
330        T_0.to_mut(), T_0, Type::Empty, 
331        |_, _, a, b, ctx| {
332            a.assign(b, ctx)?;
333            Ok(Object::empty())
334        }
335    ).unwrap();
336
337    ctx.define_binary_operator(">>".into(), false, 350).unwrap();
338
339    define_binary_native_op_combinations!(ctx, 15, INT, INT);
340
341    ctx.define_binary_operator("<<".into(), false, 360).unwrap();
342
343    define_binary_native_op_combinations!(ctx, 16, INT, INT);
344
345    ctx.define_binary_operator("&".into(), false, 370).unwrap();
346
347    define_binary_native_op_combinations!(ctx, 17, INT, INT);
348
349    ctx.define_binary_operator("|".into(), false, 380).unwrap();
350
351    define_binary_native_op_combinations!(ctx, 18, INT, INT);
352
353    ctx.define_binary_operator("^".into(), false, 390).unwrap();
354
355    define_binary_native_op_combinations!(ctx, 19, BOOL, BOOL);
356    define_binary_native_op_combinations!(ctx, 19, INT, INT);
357
358    ctx.define_binary_operator("=".into(), false, 200000).unwrap();
359}
360
361pub const CALL_OP: usize = 0;
362
363pub fn standard_nary_operations(ctx: &mut NessaContext) {
364    ctx.define_nary_operator("(".into(), ")".into(), 50).unwrap();
365
366    for n in 0..30 {
367        let args = (0..n).map(|i| Type::TemplateParam(i, vec!())).collect::<Vec<_>>();
368
369        let f_type = Type::Function(
370            Box::new(Type::And(args.clone())),
371            Box::new(Type::TemplateParam(n, vec!()))
372        );
373
374        let res = ctx.define_native_nary_operation(
375            0, n + 1, 
376            Type::MutRef(Box::new(f_type.clone())), 
377            args.as_slice(), 
378            Type::TemplateParam(n, vec!()), 
379            EMPTY_NARY_FUNC
380        ).unwrap();
381
382        ctx.cache.opcodes.nary.insert((0, res), (CompiledNessaExpr::LambdaCallRef, 0));
383
384        let res = ctx.define_native_nary_operation(
385            0, n + 1, 
386            Type::Ref(Box::new(f_type.clone())), 
387            args.as_slice(), 
388            Type::TemplateParam(n, vec!()), 
389            EMPTY_NARY_FUNC
390        ).unwrap();
391
392        ctx.cache.opcodes.nary.insert((0, res), (CompiledNessaExpr::LambdaCallRef, 0));
393
394        let res = ctx.define_native_nary_operation(
395            0, n + 1, 
396            f_type, 
397            args.as_slice(), 
398            Type::TemplateParam(n, vec!()), 
399            EMPTY_NARY_FUNC
400        ).unwrap();
401
402        ctx.cache.opcodes.nary.insert((0, res), (CompiledNessaExpr::LambdaCall, 0));
403    }  
404
405    ctx.define_nary_operator("[".into(), "]".into(), 75).unwrap();
406
407    // Indexing operations on arrays
408    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0), &[INT], T_0, EMPTY_NARY_FUNC).unwrap();
409    ctx.cache.opcodes.nary.insert((1, res), (CompiledNessaExpr::IdxMove, 0));
410    
411    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_mut(), &[INT], T_0.to_mut(), EMPTY_NARY_FUNC).unwrap();
412    ctx.cache.opcodes.nary.insert((1, res), (CompiledNessaExpr::IdxMut, 0));
413    
414    let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_ref(), &[INT], T_0.to_ref(), EMPTY_NARY_FUNC).unwrap();
415    ctx.cache.opcodes.nary.insert((1, res), (CompiledNessaExpr::IdxRef, 0));
416}