/*************************************************************************/
/*                                                                       */
/*                  Language Technologies Institute                      */
/*                     Carnegie Mellon University                        */
/*                        Copyright (c) 2001                             */
/*                        All Rights Reserved.                           */
/*                                                                       */
/*  Permission is hereby granted, free of charge, to use and distribute  */
/*  this software and its documentation without restriction, including   */
/*  without limitation the rights to use, copy, modify, merge, publish,  */
/*  distribute, sublicense, and/or sell copies of this work, and to      */
/*  permit persons to whom this work is furnished to do so, subject to   */
/*  the following conditions:                                            */
/*   1. The code must retain the above copyright notice, this list of    */
/*      conditions and the following disclaimer.                         */
/*   2. Any modifications must be clearly marked as such.                */
/*   3. Original authors' names are not deleted.                         */
/*   4. The authors' names are not used to endorse or promote products   */
/*      derived from this software without specific prior written        */
/*      permission.                                                      */
/*                                                                       */
/*  CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK         */
/*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
/*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
/*  SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE      */
/*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
/*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
/*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
/*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
/*  THIS SOFTWARE.                                                       */
/*                                                                       */
/*************************************************************************/
/*             Author:  Alan W Black (awb@cs.cmu.edu)                    */
/*               Date:  January 2001                                     */
/*************************************************************************/
/*                                                                       */
/*  Const Vals, and macros to define them                                */
/*                                                                       */
/*  Before you give up in disgust bear with me on this.  Every single    */
/*  line in this file has been *very* carefully decided on after much    */
/*  thought, experimentation and reading more specs of the C language    */
/*  than most people even thought existed.  However inspite of that, the */
/*  result is still unsatisfying from an elegance point of view but the  */
/*  given all the constraints this is probably the best compromise.      */
/*                                                                       */
/*  This file offers macros for defining const cst_vals.  I know many    */
/*  are already laughing at me for wanting runtime types on objects and  */
/*  will use this code as exemplars of why this should be done in C++, I */
/*  say good luck to them with their 4M footprint while I go for my      */
/*  50K footprint.  But I *will* do cst_vals in 8 bytes and I *will*     */
/*  have them defined const so they are in the text segment              */
/*                                                                       */
/*  The problem here is that there is not yet a standard way to do       */
/*  initialization of unions.  There is one in the C99 standard and GCC  */
/*  already supports it, but other compilers do not so I can't use that  */
/*                                                                       */
/*  So I need a way to make an object that will have the right 8 bytes   */
/*  for ints, floats, strings and cons cells that will work on any C     */
/*  compiler and will be of type const cst_val.  That unfortunately      */
/*  isn't trivial.                                                       */
/*                                                                       */
/*  For the time being ignoring byte order, and address size, which      */
/*  will be ignored in the particular discuss (though dealt with below)  */
/*  I'd like to do something like                                        */
/*                                                                       */
/*  const cst_val fredi = { CST_VAL_TYPE_INT,-1, 42 };                   */
/*  const cst_val fredf = { CST_VAL_TYPE_FLOAT,-1, 4.2 };                */
/*  const cst_val freds = { CST_VAL_TYPE_STRING,-1, "42" };              */
/*                                                                       */
/*  Even if you accept warnings this isn't going to work, if you add     */
/*  extra {} you can get rid of some warnings but the fval/ival/ *vval   */
/*  part isn't going to work, the compiler *may* try to take the value   */
/*  and assign it using the type of the first field defined in the       */
/*  union.  This could be made to work for ints and void* as pointers    */
/*  can be used as ints (even of 64 bit architectures) but the float     */
/*  isn't going to work.  Casting will cause the float to be changed to  */
/*  an int by CPP which isn't what you want, what you want is that the   */
/*  four byte region gets filled with the four bytes that represent the  */
/*  float itself.  Now you could get the four byte represention of the   */
/*  float and pretend that is an int (0xbfff9a4 for 4.2 on intel), that  */
/*  would work but that doesn't seem satifying and I'd need to have a    */
/*  preprocessor that could convert that.  You could make atoms always   */
/*  have a pointer to another piece of memory, but that would take up    */
/*  another 4 bytes not just for these constants but all other cst_vals  */
/*  create                                                               */
/*                                                                       */
/*  So you could do                                                      */
/*                                                                       */
/*  const cst_val_int fredi = { CST_VAL_TYPE_INT,-1, 42 };               */
/*  const cst_val_float fredf = { CST_VAL_TYPE_FLOAT,-1, 4.2 };          */
/*  const cst_val_string freds = { CST_VAL_TYPE_STRING,-1, "42" };       */
/*                                                                       */
/*  Though that's a slippery slope I don't want to have these explicit   */
/*  new types, the first short defines the type perfectly adequately     */
/*  and the whole point of runtime types is that there is one object     */
/*  type.                                                                */
/*                                                                       */
/*  Well just initialize them at runtime, but, that isn't thread safe,   */
/*  slows down startup, requires a instance implicitly in the code and   */
/*  on the heap. As these are const, they should go in ROM.              */
/*                                                                       */
/*  At this moment, I think the second version is the least problematic  */
/*  though it makes defining val_consts more unpleasant than they should */
/*  be and forces changes elsewhere in the code even when the compiler   */
/*  does support initialization of unions                                */
/*                                                                       */
/*                                                                       */
/*************************************************************************/
#ifndef _CST_VAL_CONSTS_H__
#define _CST_VAL_CONSTS_H__

#include "cst_val_defs.h"

#include <stdint.h>

/* There is built-in int to string conversions here for numbers   */
/* up to 20, note if you make this bigger you have to hand change */
/* other things too                                               */
#define CST_CONST_INT_MAX 19

#ifndef NO_UNION_INITIALIZATION

/* This is the simple way when initialization of unions is supported */

#define DEF_CONST_VAL_INT(N,V) const cst_val N = {{.a={.type=CST_VAL_TYPE_INT,.ref_count=-1,.v={.ival=V}}}}
#define DEF_CONST_VAL_STRING(N,S) const cst_val N = {{.a={.type=CST_VAL_TYPE_STRING,.ref_count=-1,.v={.vval= (void *)S}}}}
#define DEF_CONST_VAL_FLOAT(N,F) const cst_val N = {{.a={.type=CST_VAL_TYPE_FLOAT,.ref_count=-1,.v={.fval=F}}}}
#define DEF_CONST_VAL_CONS(N,A,D) const cst_val N = {{.cc={.car=(cst_val *)A,.cdr=(cst_val *)D }}}

extern const cst_val val_int_0; 
extern const cst_val val_int_1; 
extern const cst_val val_int_2;
extern const cst_val val_int_3;
extern const cst_val val_int_4;
extern const cst_val val_int_5;
extern const cst_val val_int_6;
extern const cst_val val_int_7;
extern const cst_val val_int_8;
extern const cst_val val_int_9;
extern const cst_val val_int_10; 
extern const cst_val val_int_11; 
extern const cst_val val_int_12;
extern const cst_val val_int_13;
extern const cst_val val_int_14;
extern const cst_val val_int_15;
extern const cst_val val_int_16;
extern const cst_val val_int_17;
extern const cst_val val_int_18;
extern const cst_val val_int_19;
extern const cst_val val_int_20;
extern const cst_val val_int_21;
extern const cst_val val_int_22;
extern const cst_val val_int_23;
extern const cst_val val_int_24;

extern const cst_val val_string_0; 
extern const cst_val val_string_1; 
extern const cst_val val_string_2;
extern const cst_val val_string_3;
extern const cst_val val_string_4;
extern const cst_val val_string_5;
extern const cst_val val_string_6;
extern const cst_val val_string_7;
extern const cst_val val_string_8;
extern const cst_val val_string_9;
extern const cst_val val_string_10; 
extern const cst_val val_string_11; 
extern const cst_val val_string_12;
extern const cst_val val_string_13;
extern const cst_val val_string_14;
extern const cst_val val_string_15;
extern const cst_val val_string_16;
extern const cst_val val_string_17;
extern const cst_val val_string_18;
extern const cst_val val_string_19;
extern const cst_val val_string_20;
extern const cst_val val_string_21;
extern const cst_val val_string_22;
extern const cst_val val_string_23;
extern const cst_val val_string_24;

#else
/* Only GCC seems to currently support the C99 standard for giving      */
/* explicit names for fields for initializing unions, because we want   */
/* things to be const, and to be small structures this is really useful */
/* thus for compilers not supporting no_union_initization we use other  */
/* structure that we know (hope ?) are the same size and use agressive  */
/* casting. The goal here is wholly justified but the method here isn't */
/* pretty                                                               */

/* These structures are defined *solely* to get round initialization    */
/* problems if you need to use these in any code you are using, you are */
/* unquestionably doing the wrong thing                                 */
typedef struct cst_val_atom_struct_float {
#ifdef WORDS_BIGENDIAN
#if UINTPTR_MAX > 0xfffffffful
    int ref_count;
    int type;  /* order is here important */
#else
    short ref_count;
    short type;  /* order is here important */
#endif
#else
#if UINTPTR_MAX > 0xfffffffful
    int type;  /* order is here important */
    int ref_count;
#else
    short type;  /* order is here important */
    short ref_count;
#endif
#endif
#if UINTPTR_MAX > 0xfffffffful
    double fval;
#else
    float fval;
#endif
} cst_val_float;

typedef struct cst_val_atom_struct_int {
#ifdef WORDS_BIGENDIAN
#if UINTPTR_MAX > 0xfffffffful
    int ref_count;
    int type;  /* order is here important (and unintuitive) */
#else
    short ref_count;
    short type;  /* order is here important (and unintuitive) */
#endif
#else
#if UINTPTR_MAX > 0xfffffffful
    int type;  /* order is here important */
    int ref_count;
#else
    short type;  /* order is here important */
    short ref_count;
#endif
#endif
#if UINTPTR_MAX > 0xfffffffful
    long long ival;
#else
    int ival;
#endif
} cst_val_int;

typedef struct cst_val_atom_struct_void {
#ifdef WORDS_BIGENDIAN
#if UINTPTR_MAX > 0xfffffffful
    int ref_count;
    int type;  /* order is here important */
#else
    short ref_count;
    short type;  /* order is here important */
#endif
#else
#if UINTPTR_MAX > 0xfffffffful
    int type;  /* order is here important */
    int ref_count;
#else
    short type;  /* order is here important */
    short ref_count;
#endif
#endif
    void *vval;
} cst_val_void;

#ifdef WORDS_BIGENDIAN
#define DEF_CONST_VAL_INT(N,V) const cst_val_int N={-1, CST_VAL_TYPE_INT, V}
#define DEF_CONST_VAL_STRING(N,S) const cst_val_void N={-1,CST_VAL_TYPE_STRING,(void *)S}
#define DEF_CONST_VAL_FLOAT(N,F) const cst_val_float N={-1,CST_VAL_TYPE_FLOAT,(float)F}
#else
#define DEF_CONST_VAL_INT(N,V) const cst_val_int N={CST_VAL_TYPE_INT,-1,V}
#define DEF_CONST_VAL_STRING(N,S) const cst_val_void N={CST_VAL_TYPE_STRING,-1,(void *)S}
#define DEF_CONST_VAL_FLOAT(N,F) const cst_val_float N={CST_VAL_TYPE_FLOAT,-1,(float)F}
#endif
#define DEF_CONST_VAL_CONS(N,A,D) const cst_val_cons N={A,D}

/* in the non-union intialization version we these consts have to be */
/* more typed than need, we'll cast the back later                   */
extern const cst_val_int val_int_0; 
extern const cst_val_int val_int_1; 
extern const cst_val_int val_int_2;
extern const cst_val_int val_int_3;
extern const cst_val_int val_int_4;
extern const cst_val_int val_int_5;
extern const cst_val_int val_int_6;
extern const cst_val_int val_int_7;
extern const cst_val_int val_int_8;
extern const cst_val_int val_int_9;
extern const cst_val_int val_int_10; 
extern const cst_val_int val_int_11; 
extern const cst_val_int val_int_12;
extern const cst_val_int val_int_13;
extern const cst_val_int val_int_14;
extern const cst_val_int val_int_15;
extern const cst_val_int val_int_16;
extern const cst_val_int val_int_17;
extern const cst_val_int val_int_18;
extern const cst_val_int val_int_19;
extern const cst_val_int val_int_20;
extern const cst_val_int val_int_21;
extern const cst_val_int val_int_22;
extern const cst_val_int val_int_23;
extern const cst_val_int val_int_24;

extern const cst_val_void val_string_0; 
extern const cst_val_void val_string_1; 
extern const cst_val_void val_string_2;
extern const cst_val_void val_string_3;
extern const cst_val_void val_string_4;
extern const cst_val_void val_string_5;
extern const cst_val_void val_string_6;
extern const cst_val_void val_string_7;
extern const cst_val_void val_string_8;
extern const cst_val_void val_string_9;
extern const cst_val_void val_string_10; 
extern const cst_val_void val_string_11; 
extern const cst_val_void val_string_12;
extern const cst_val_void val_string_13;
extern const cst_val_void val_string_14;
extern const cst_val_void val_string_15;
extern const cst_val_void val_string_16;
extern const cst_val_void val_string_17;
extern const cst_val_void val_string_18;
extern const cst_val_void val_string_19;
extern const cst_val_void val_string_20;
extern const cst_val_void val_string_21;
extern const cst_val_void val_string_22;
extern const cst_val_void val_string_23;
extern const cst_val_void val_string_24;

#endif

#define DEF_STATIC_CONST_VAL_INT(N,V) static DEF_CONST_VAL_INT(N,V)
#define DEF_STATIC_CONST_VAL_STRING(N,S) static DEF_CONST_VAL_STRING(N,S)
#define DEF_STATIC_CONST_VAL_FLOAT(N,F) static DEF_CONST_VAL_FLOAT(N,F)
#define DEF_STATIC_CONST_VAL_CONS(N,A,D) static DEF_CONST_VAL_CONS(N,A,D)

/* Some actual val consts */
/* The have casts as in the non-union intialize case the casts are necessary */
/* but in the union initial case these casts are harmless                    */

#define VAL_INT_0 (cst_val *)&val_int_0
#define VAL_INT_1 (cst_val *)&val_int_1
#define VAL_INT_2 (cst_val *)&val_int_2
#define VAL_INT_3 (cst_val *)&val_int_3
#define VAL_INT_4 (cst_val *)&val_int_4
#define VAL_INT_5 (cst_val *)&val_int_5
#define VAL_INT_6 (cst_val *)&val_int_6
#define VAL_INT_7 (cst_val *)&val_int_7
#define VAL_INT_8 (cst_val *)&val_int_8
#define VAL_INT_9 (cst_val *)&val_int_9
#define VAL_INT_10 (cst_val *)&val_int_10
#define VAL_INT_11 (cst_val *)&val_int_11
#define VAL_INT_12 (cst_val *)&val_int_12
#define VAL_INT_13 (cst_val *)&val_int_13
#define VAL_INT_14 (cst_val *)&val_int_14
#define VAL_INT_15 (cst_val *)&val_int_15
#define VAL_INT_16 (cst_val *)&val_int_16
#define VAL_INT_17 (cst_val *)&val_int_17
#define VAL_INT_18 (cst_val *)&val_int_18
#define VAL_INT_19 (cst_val *)&val_int_19
#define VAL_INT_20 (cst_val *)&val_int_20
#define VAL_INT_21 (cst_val *)&val_int_21
#define VAL_INT_22 (cst_val *)&val_int_22
#define VAL_INT_23 (cst_val *)&val_int_23
#define VAL_INT_24 (cst_val *)&val_int_24

const cst_val *val_int_n(int n);

#define VAL_STRING_0 (cst_val *)&val_string_0
#define VAL_STRING_1 (cst_val *)&val_string_1
#define VAL_STRING_2 (cst_val *)&val_string_2
#define VAL_STRING_3 (cst_val *)&val_string_3
#define VAL_STRING_4 (cst_val *)&val_string_4
#define VAL_STRING_5 (cst_val *)&val_string_5
#define VAL_STRING_6 (cst_val *)&val_string_6
#define VAL_STRING_7 (cst_val *)&val_string_7
#define VAL_STRING_8 (cst_val *)&val_string_8
#define VAL_STRING_9 (cst_val *)&val_string_9
#define VAL_STRING_10 (cst_val *)&val_string_10
#define VAL_STRING_11 (cst_val *)&val_string_11
#define VAL_STRING_12 (cst_val *)&val_string_12
#define VAL_STRING_13 (cst_val *)&val_string_13
#define VAL_STRING_14 (cst_val *)&val_string_14
#define VAL_STRING_15 (cst_val *)&val_string_15
#define VAL_STRING_16 (cst_val *)&val_string_16
#define VAL_STRING_17 (cst_val *)&val_string_17
#define VAL_STRING_18 (cst_val *)&val_string_18
#define VAL_STRING_19 (cst_val *)&val_string_19
#define VAL_STRING_20 (cst_val *)&val_string_20
#define VAL_STRING_21 (cst_val *)&val_string_21
#define VAL_STRING_22 (cst_val *)&val_string_22
#define VAL_STRING_23 (cst_val *)&val_string_23
#define VAL_STRING_24 (cst_val *)&val_string_24

const cst_val *val_string_n(int n);


#endif
