use serde::{Deserialize, Serialize};
use crate::annotations::Annotation;
use crate::compilation::CompiledRynaExpr;
use crate::parser::Location;
use crate::types::{Type, INT, BOOL, STR, T_0, FLOAT};
use crate::{object::*, ARR_OF};
use crate::context::RynaContext;
pub type UnaryFunctionFn = fn(&Vec<Type>, &Type, Object) -> Result<Object, String>;
pub type BinaryFunctionFn = fn(&Vec<Type>, &Type, Object, Object, &RynaContext) -> Result<Object, String>;
pub type NaryFunctionFn = fn((&mut Vec<Object>, &mut usize, &mut Vec<(i32, usize, i32)>, &mut i32), &Vec<Type>, &Type) -> Result<(), String>;
pub type OptUnaryFunctionFn = Option<UnaryFunctionFn>;
pub type OptBinaryFunctionFn = Option<BinaryFunctionFn>;
pub type OptNaryFunctionFn = Option<NaryFunctionFn>;
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct Operation<T> {
pub location: Location,
pub annotations: Vec<Annotation>,
pub templates: usize,
pub args: Type,
pub ret: Type,
#[serde(skip)]
pub operation: Option<T>
}
pub type UnaryOperations = Vec<Operation<UnaryFunctionFn>>;
pub type BinaryOperations = Vec<Operation<BinaryFunctionFn>>;
pub type NaryOperations = Vec<Operation<NaryFunctionFn>>;
const EMPTY_UN_FUNC: UnaryFunctionFn = |_, _, _| Ok(Object::empty());
const EMPTY_BIN_FUNC: BinaryFunctionFn = |_, _, _, _, _| Ok(Object::empty());
const EMPTY_NARY_FUNC: NaryFunctionFn = |_, _, _| Ok(());
#[derive(Clone, Serialize, Deserialize)]
pub enum Operator {
Unary {
id: usize,
representation: String,
prefix: bool,
precedence: usize,
operations: UnaryOperations
},
Binary {
id: usize,
right_associative: bool,
representation: String,
precedence: usize,
operations: BinaryOperations
},
Nary {
id: usize,
open_rep: String, close_rep: String,
precedence: usize,
operations: NaryOperations
}
}
impl Operator {
pub fn get_id(&self) -> usize {
match self {
Operator::Unary { id, .. } => *id,
Operator::Binary { id, .. } => *id,
Operator::Nary { id, .. } => *id
}
}
pub fn get_precedence(&self) -> usize {
match self {
Operator::Unary { precedence: p, .. } => *p,
Operator::Binary { precedence: p, .. } => *p,
Operator::Nary { precedence: p, .. } => *p
}
}
pub fn get_repr(&self) -> String {
match self {
Operator::Unary { representation: r, .. } => r.into(),
Operator::Binary { representation: r, .. } => r.into(),
Operator::Nary { open_rep: o, close_rep: c, .. } => format!("{o}{c}")
}
}
pub fn is_right_associative(&self) -> bool {
match self {
Operator::Binary { right_associative, .. } => *right_associative,
_ => unreachable!()
}
}
}
macro_rules! define_unary_native_op {
($ctx: ident, $id: expr, $inner_type: expr, $return_type: expr) => {
$ctx.define_native_unary_operation($id, 0, $inner_type, $return_type, EMPTY_UN_FUNC).unwrap();
};
}
macro_rules! define_unary_native_op_combinations {
($ctx: ident, $id: expr, $inner_type: expr, $return_type: expr) => {
let base_ref = Type::Ref(Box::new($inner_type.clone()));
let base_mut = Type::MutRef(Box::new($inner_type.clone()));
define_unary_native_op!($ctx, $id, $inner_type, $return_type);
define_unary_native_op!($ctx, $id, base_ref.clone(), $return_type);
define_unary_native_op!($ctx, $id, base_mut.clone(), $return_type);
};
}
pub const NEG_UNOP_ID: usize = 0;
pub const NOT_UNOP_ID: usize = 1;
pub const DEREF_UNOP_ID: usize = 2;
pub fn standard_unary_operations(ctx: &mut RynaContext) {
ctx.define_unary_operator("-".into(), true, 300).unwrap();
define_unary_native_op_combinations!(ctx, 0, INT, INT);
define_unary_native_op_combinations!(ctx, 0, FLOAT, FLOAT);
ctx.define_unary_operator("!".into(), true, 250).unwrap();
define_unary_native_op_combinations!(ctx, 1, BOOL, BOOL);
define_unary_native_op_combinations!(ctx, 1, INT, INT);
ctx.define_unary_operator("*".into(), true, 155).unwrap();
ctx.define_native_unary_operation(2, 1, T_0.to_mut(), T_0, EMPTY_UN_FUNC).unwrap();
ctx.define_native_unary_operation(2, 1, T_0.to_ref(), T_0, EMPTY_UN_FUNC).unwrap();
}
macro_rules! define_binary_native_op {
($ctx: ident, $id: expr, $l_type: expr, $r_type: expr, $return_type: expr) => {
$ctx.define_native_binary_operation($id, 0, $l_type, $r_type, $return_type, EMPTY_BIN_FUNC).unwrap();
};
}
macro_rules! define_binary_native_op_combinations_distinct {
($ctx: ident, $id: expr, $base_type_1: expr, $base_type_2: expr, $return_type: expr) => {
let base_ref_1 = Type::Ref(Box::new($base_type_1.clone()));
let base_mut_1 = Type::MutRef(Box::new($base_type_1.clone()));
let base_ref_2 = Type::Ref(Box::new($base_type_2.clone()));
let base_mut_2 = Type::MutRef(Box::new($base_type_2.clone()));
define_binary_native_op!($ctx, $id, $base_type_1, $base_type_2, $return_type);
define_binary_native_op!($ctx, $id, base_ref_1.clone(), $base_type_2, $return_type);
define_binary_native_op!($ctx, $id, $base_type_1, base_ref_2.clone(), $return_type);
define_binary_native_op!($ctx, $id, base_mut_1.clone(), $base_type_2, $return_type);
define_binary_native_op!($ctx, $id, $base_type_1, base_mut_2.clone(), $return_type);
define_binary_native_op!($ctx, $id, base_ref_1.clone(), base_ref_2.clone(), $return_type);
define_binary_native_op!($ctx, $id, base_ref_1.clone(), base_mut_2.clone(), $return_type);
define_binary_native_op!($ctx, $id, base_mut_1.clone(), base_mut_2.clone(), $return_type);
define_binary_native_op!($ctx, $id, base_mut_1.clone(), base_ref_2.clone(), $return_type);
};
}
macro_rules! define_binary_native_op_combinations {
($ctx: ident, $id: expr, $base_type: expr, $return_type: expr) => {
define_binary_native_op_combinations_distinct!($ctx, $id, $base_type, $base_type, $return_type);
};
}
pub const ADD_BINOP_ID: usize = 0;
pub const SUB_BINOP_ID: usize = 1;
pub const MUL_BINOP_ID: usize = 2;
pub const DIV_BINOP_ID: usize = 3;
pub const MOD_BINOP_ID: usize = 4;
pub const DOT_BINOP_ID: usize = 5;
pub const LT_BINOP_ID: usize = 6;
pub const GT_BINOP_ID: usize = 7;
pub const LTEQ_BINOP_ID: usize = 8;
pub const GTEQ_BINOP_ID: usize = 9;
pub const EQ_BINOP_ID: usize = 10;
pub const NEQ_BINOP_ID: usize = 11;
pub const OR_BINOP_ID: usize = 12;
pub const AND_BINOP_ID: usize = 13;
pub const XOR_BINOP_ID: usize = 19;
pub const SHR_BINOP_ID: usize = 15;
pub const SHL_BINOP_ID: usize = 16;
pub const ANDB_BINOP_ID: usize = 17;
pub const ORB_BINOP_ID: usize = 18;
pub const ASSIGN_BINOP_ID: usize = 14;
pub const LT_BINOP_PREC: usize = 900;
pub const DEFINE_BINOP_ID: usize = 20;
pub const IDX_NARYOP_ID: usize = 1;
pub fn standard_binary_operations(ctx: &mut RynaContext) {
ctx.define_binary_operator("+".into(), false, 650).unwrap();
define_binary_native_op_combinations!(ctx, 0, INT, INT);
define_binary_native_op_combinations!(ctx, 0, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 0, INT, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 0, FLOAT, INT, FLOAT);
define_binary_native_op_combinations!(ctx, 0, STR, STR);
ctx.define_binary_operator("-".into(), true, 700).unwrap();
define_binary_native_op_combinations!(ctx, 1, INT, INT);
define_binary_native_op_combinations!(ctx, 1, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 1, INT, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 1, FLOAT, INT, FLOAT);
ctx.define_binary_operator("*".into(), false, 500).unwrap();
define_binary_native_op_combinations!(ctx, 2, INT, INT);
define_binary_native_op_combinations!(ctx, 2, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 2, INT, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 2, FLOAT, INT, FLOAT);
ctx.define_binary_operator("/".into(), false, 550).unwrap();
define_binary_native_op_combinations!(ctx, 3, INT, INT);
define_binary_native_op_combinations!(ctx, 3, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 3, INT, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 3, FLOAT, INT, FLOAT);
ctx.define_binary_operator("%".into(), false, 600).unwrap();
define_binary_native_op_combinations!(ctx, 4, INT, INT);
define_binary_native_op_combinations!(ctx, 4, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 4, INT, FLOAT, FLOAT);
define_binary_native_op_combinations_distinct!(ctx, 4, FLOAT, INT, FLOAT);
ctx.define_binary_operator(".".into(), true, 100).unwrap();
ctx.define_binary_operator("<".into(), false, 900).unwrap();
define_binary_native_op_combinations!(ctx, 6, INT, BOOL);
define_binary_native_op_combinations!(ctx, 6, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 6, INT, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 6, FLOAT, INT, BOOL);
ctx.define_binary_operator(">".into(), false, 950).unwrap();
define_binary_native_op_combinations!(ctx, 7, INT, BOOL);
define_binary_native_op_combinations!(ctx, 7, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 7, INT, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 7, FLOAT, INT, BOOL);
ctx.define_binary_operator("<=".into(), false, 1000).unwrap();
define_binary_native_op_combinations!(ctx, 8, INT, BOOL);
define_binary_native_op_combinations!(ctx, 8, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 8, INT, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 8, FLOAT, INT, BOOL);
ctx.define_binary_operator(">=".into(), false, 1050).unwrap();
define_binary_native_op_combinations!(ctx, 9, INT, BOOL);
define_binary_native_op_combinations!(ctx, 9, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 9, INT, FLOAT, BOOL);
define_binary_native_op_combinations_distinct!(ctx, 9, FLOAT, INT, BOOL);
ctx.define_binary_operator("==".into(), false, 1100).unwrap();
define_binary_native_op_combinations!(ctx, 10, INT, BOOL);
define_binary_native_op_combinations!(ctx, 10, FLOAT, BOOL);
define_binary_native_op_combinations!(ctx, 10, STR, BOOL);
define_binary_native_op_combinations!(ctx, 10, BOOL, BOOL);
ctx.define_binary_operator("!=".into(), false, 1150).unwrap();
define_binary_native_op_combinations!(ctx, 11, INT, BOOL);
define_binary_native_op_combinations!(ctx, 11, FLOAT, BOOL);
define_binary_native_op_combinations!(ctx, 11, STR, BOOL);
define_binary_native_op_combinations!(ctx, 11, BOOL, BOOL);
ctx.define_binary_operator("||".into(), false, 1500).unwrap();
define_binary_native_op_combinations!(ctx, 12, BOOL, BOOL);
ctx.define_binary_operator("&&".into(), false, 1550).unwrap();
define_binary_native_op_combinations!(ctx, 13, BOOL, BOOL);
ctx.define_binary_operator(":=".into(), false, 100000).unwrap();
ctx.define_native_binary_operation(
14, 1,
T_0.to_mut(), T_0, Type::Empty,
|_, _, a, b, ctx| {
a.assign(b, ctx)?;
Ok(Object::empty())
}
).unwrap();
ctx.define_binary_operator(">>".into(), false, 350).unwrap();
define_binary_native_op_combinations!(ctx, 15, INT, INT);
ctx.define_binary_operator("<<".into(), false, 360).unwrap();
define_binary_native_op_combinations!(ctx, 16, INT, INT);
ctx.define_binary_operator("&".into(), false, 370).unwrap();
define_binary_native_op_combinations!(ctx, 17, INT, INT);
ctx.define_binary_operator("|".into(), false, 380).unwrap();
define_binary_native_op_combinations!(ctx, 18, INT, INT);
ctx.define_binary_operator("^".into(), false, 390).unwrap();
define_binary_native_op_combinations!(ctx, 19, BOOL, BOOL);
define_binary_native_op_combinations!(ctx, 19, INT, INT);
ctx.define_binary_operator("=".into(), false, 200000).unwrap();
}
pub const CALL_OP: usize = 0;
pub fn standard_nary_operations(ctx: &mut RynaContext) {
ctx.define_nary_operator("(".into(), ")".into(), 50).unwrap();
for n in 0..30 {
let args = (0..n).map(|i| Type::TemplateParam(i, vec!())).collect::<Vec<_>>();
let f_type = Type::Function(
Box::new(Type::And(args.clone())),
Box::new(Type::TemplateParam(n, vec!()))
);
let res = ctx.define_native_nary_operation(
0, n + 1,
Type::MutRef(Box::new(f_type.clone())),
args.as_slice(),
Type::TemplateParam(n, vec!()),
EMPTY_NARY_FUNC
).unwrap();
ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCallRef, 0));
let res = ctx.define_native_nary_operation(
0, n + 1,
Type::Ref(Box::new(f_type.clone())),
args.as_slice(),
Type::TemplateParam(n, vec!()),
EMPTY_NARY_FUNC
).unwrap();
ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCallRef, 0));
let res = ctx.define_native_nary_operation(
0, n + 1,
f_type,
args.as_slice(),
Type::TemplateParam(n, vec!()),
EMPTY_NARY_FUNC
).unwrap();
ctx.cache.opcodes.nary.insert((0, res), (CompiledRynaExpr::LambdaCall, 0));
}
ctx.define_nary_operator("[".into(), "]".into(), 75).unwrap();
let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0), &[INT], T_0, EMPTY_NARY_FUNC).unwrap();
ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxMove, 0));
let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_mut(), &[INT], T_0.to_mut(), EMPTY_NARY_FUNC).unwrap();
ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxMut, 0));
let res = ctx.define_native_nary_operation(1, 1, ARR_OF!(T_0).to_ref(), &[INT], T_0.to_ref(), EMPTY_NARY_FUNC).unwrap();
ctx.cache.opcodes.nary.insert((1, res), (CompiledRynaExpr::IdxRef, 0));
}