//! @file a68g-optimiser.h
//! @author J. Marcel van der Veer

//! @section Copyright
//!
//! This file is part of Algol68G - an Algol 68 compiler-interpreter.
//! Copyright 2001-2025 J. Marcel van der Veer [algol68g@xs4all.nl].

//! @section License
//!
//! This program is free software; you can redistribute it and/or modify it 
//! under the terms of the GNU General Public License as published by the 
//! Free Software Foundation; either version 3 of the License, or 
//! (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful, but 
//! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
//! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
//! more details. You should have received a copy of the GNU General Public 
//! License along with this program. If not, see [http://www.gnu.org/licenses/].

//! @section Synopsis
//!
//! Definitions for the plugin compiler.

#if !defined (__A68G_OPTIMISER_H__)
#define __A68G_OPTIMISER_H__

BOOL_T constant_unit (NODE_T *);
BOOL_T folder_mode (MOID_T *);
void build_script (void);
void load_script (void);
void plugin_driver_clean (int);
void plugin_driver_code (void);
void plugin_driver_compile (void);
void plugin_driver_emit (FILE_T);
void plugin_driver_genie (void);
void push_unit (NODE_T *);
void rewrite_script_source (void);

// Library for code generator

INT_T a68g_add_int (INT_T, INT_T);
INT_T a68g_sub_int (INT_T, INT_T);
INT_T a68g_mul_int (INT_T, INT_T);
INT_T a68g_over_int (INT_T, INT_T);
INT_T a68g_mod_int (INT_T, INT_T);
REAL_T a68g_div_int (INT_T, INT_T);

void a68g_ln_complex (A68G_REAL *, A68G_REAL *);
void a68g_sqrt_complex (A68G_REAL *, A68G_REAL *);
void a68g_sin_complex (A68G_REAL *, A68G_REAL *);
void a68g_cos_complex (A68G_REAL *, A68G_REAL *);
void a68g_tan_complex (A68G_REAL *, A68G_REAL *);
void a68g_asin_complex (A68G_REAL *, A68G_REAL *);
void a68g_acos_complex (A68G_REAL *, A68G_REAL *);
void a68g_atan_complex (A68G_REAL *, A68G_REAL *);
void a68g_sinh_complex (A68G_REAL *, A68G_REAL *);
void a68g_cosh_complex (A68G_REAL *, A68G_REAL *);
void a68g_tanh_complex (A68G_REAL *, A68G_REAL *);
void a68g_asinh_real_complex (A68G_REAL *, A68G_REAL *);
void a68g_acosh_real_complex (A68G_REAL *, A68G_REAL *);
void a68g_atanh_real_complex (A68G_REAL *, A68G_REAL *);

// Operators that are inlined in compiled code

#define a68g_eq_complex(x, y) (RE (x) == RE (y) && IM (x) == IM (y))
#define a68g_ne_complex(x, y) (! a68g_eq_complex (x, y))
#define a68g_plusab_int(i, j) (VALUE ((A68G_INT *) ADDRESS (i)) += (j), (i))
#define a68g_min_realusab_int(i, j) (VALUE ((A68G_INT *) ADDRESS (i)) -= (j), (i))
#define a68g_timesab_int(i, j) (VALUE ((A68G_INT *) ADDRESS (i)) *= (j), (i))
#define a68g_overab_int(i, j) (VALUE ((A68G_INT *) ADDRESS (i)) /= (j), (i))
#define a68g_entier(x) ((int) floor (x))
#define a68g_plusab_real(i, j) (VALUE ((A68G_REAL *) ADDRESS (i)) += (j), (i))
#define a68g_min_realusab_real(i, j) (VALUE ((A68G_REAL *) ADDRESS (i)) -= (j), (i))
#define a68g_timesab_real(i, j) (VALUE ((A68G_REAL *) ADDRESS (i)) *= (j), (i))
#define a68g_divab_real(i, j) (VALUE ((A68G_REAL *) ADDRESS (i)) /= (j), (i))
#define a68g_re_complex(z) (RE (z))
#define a68g_im_complex(z) (IM (z))
#define a68g_abs_real_complex(z) a68g_hypot_real (RE (z), IM (z))
#define a68g_arg_complex(z) atan2 (IM (z), RE (z))

#define a68g_i_complex(z, re, im) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = re;\
  IM (z) = im;}

#define a68g_min_realus_complex(z, x) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = -RE (x);\
  IM (z) = -IM (x);}

#define a68g_conj_complex(z, x) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = RE (x);\
  IM (z) = -IM (x);}

#define a68g_add_complex(z, x, y) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = RE (x) + RE (y);\
  IM (z) = IM (x) + IM (y);}

#define a68g_sub_complex(z, x, y) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = RE (x) - RE (y);\
  IM (z) = IM (x) - IM (y);}

#define a68g_mul_complex(z, x, y) {\
  STATUS_RE (z) = INIT_MASK;\
  STATUS_IM (z) = INIT_MASK;\
  RE (z) = RE (x) * RE (y) - IM (x) * IM (y);\
  IM (z) = IM (x) * RE (y) + RE (x) * IM (y);}

#endif
