nuttx-apps/interpreters/bas/value.c

1472 lines
33 KiB
C
Raw Normal View History

/* #includes */ /*{{{C}}}*//*{{{*/
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#ifdef HAVE_GETTEXT
#include <libintl.h>
#define _(String) gettext(String)
#else
#define _(String) String
#endif
#include <limits.h>
#include <math.h>
/* Buggy on some systems */
#if 0
#ifdef HAVE_TGMATH_H
#include <tgmath.h>
#endif
#else
extern long int lrint(double x);
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "value.h"
#ifdef USE_DMALLOC
#include "dmalloc.h"
#endif
/*}}}*/
/* variables */ /*{{{*/
static const char *typestr[]=
{
(const char*)0,
(const char*)0,
"integer",
(const char*)0,
"real",
"string",
"void"
};
/* for xgettext */
#if 0
_("integer")
_("real")
_("string")
_("void")
#endif
/*}}}*/
const enum ValueType Value_commonType[V_VOID+1][V_VOID+1]=
{
{ 0, 0, 0, 0, 0, 0, 0 },
{ 0, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR },
{ 0, V_ERROR, V_INTEGER, V_ERROR, V_REAL, V_ERROR, V_ERROR },
{ 0, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR },
{ 0, V_ERROR, V_REAL, V_ERROR, V_REAL, V_ERROR, V_ERROR },
{ 0, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_STRING, V_ERROR },
{ 0, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR, V_ERROR }
};
#ifndef HAVE_LRINT
long int lrint(double d)
{
return d;
}
#endif
static void format_double(struct String *buf, double value, int width, int precision, int exponent) /*{{{*/
{
if (exponent)
{
size_t len;
char *e;
int en;
len=buf->length;
String_appendPrintf(buf,"%.*E",width-1-(precision>=0),value);
if (buf->character[len+1]=='.') String_delete(buf,len+1,1);
if (precision>=0) String_insertChar(buf,len+width-precision-1,'.');
for (e=buf->character+buf->length-1; e>=buf->character && *e!='E'; --e);
++e;
en=strtol(e,(char**)0,10);
en=en+2-(width-precision);
len=e-buf->character;
String_delete(buf,len,buf->length-len);
String_appendPrintf(buf,"%+0*d",exponent-1,en);
}
else if (precision>0) String_appendPrintf(buf,"%.*f",precision,value);
else if (precision==0) String_appendPrintf(buf,"%.f.",value);
else if (width) String_appendPrintf(buf,"%.f",value);
else
{
double x=value;
if (x<0.0001 || x>=10000000.0) /* print scientific notation */
{
String_appendPrintf(buf,"%.7g",value);
}
else /* print decimal numbers or integers, if possible */
{
int o,n,p=6;
while (x>=10.0 && p>0) { x/=10.0; --p; }
o=buf->length;
String_appendPrintf(buf,"%.*f",p,value);
n=buf->length;
if (memchr(buf->character+o,'.',n-o))
{
while (buf->character[buf->length-1]=='0') --buf->length;
if (buf->character[buf->length-1]=='.') --buf->length;
}
}
}
}
/*}}}*/
double Value_trunc(double d) /*{{{*/
{
return (d<0.0?ceil(d):floor(d));
}
/*}}}*/
double Value_round(double d) /*{{{*/
{
return (d<0.0?ceil(d-0.5):floor(d+0.5));
}
/*}}}*/
long int Value_toi(double d, int *overflow) /*{{{*/
{
d=Value_round(d);
*overflow=(d<LONG_MIN || d>LONG_MAX);
return lrint(d);
}
/*}}}*/
long int Value_vali(const char *s, char **end, int *overflow) /*{{{*/
{
long int n;
errno=0;
if (*s=='&' && tolower(*(s+1))=='h') n=strtoul(s+2,end,16);
else if (*s=='&' && tolower(*(s+1))=='o') n=strtoul(s+2,end,8);
else n=strtol(s,end,10);
*overflow=(errno==ERANGE);
return n;
}
/*}}}*/
double Value_vald(const char *s, char **end, int *overflow) /*{{{*/
{
double d;
errno=0;
d=strtod(s,end);
*overflow=(errno==ERANGE);
return d;
}
/*}}}*/
struct Value *Value_new_NIL(struct Value *this) /*{{{*/
{
assert(this!=(struct Value*)0);
this->type=V_NIL;
return this;
}
/*}}}*/
struct Value *Value_new_ERROR(struct Value *this, int code, const char *error, ...) /*{{{*/
{
va_list ap;
char buf[128];
assert(this!=(struct Value*)0);
va_start(ap,error);
vsprintf(buf,error,ap);
va_end(ap);
this->type=V_ERROR;
this->u.error.code=code;
this->u.error.msg=strcpy(malloc(strlen(buf)+1),buf);
return this;
}
/*}}}*/
struct Value *Value_new_INTEGER(struct Value *this, int n) /*{{{*/
{
assert(this!=(struct Value*)0);
this->type=V_INTEGER;
this->u.integer=n;
return this;
}
/*}}}*/
struct Value *Value_new_REAL(struct Value *this, double n) /*{{{*/
{
assert(this!=(struct Value*)0);
this->type=V_REAL;
this->u.real=n;
return this;
}
/*}}}*/
struct Value *Value_new_STRING(struct Value *this) /*{{{*/
{
assert(this!=(struct Value*)0);
this->type=V_STRING;
String_new(&this->u.string);
return this;
}
/*}}}*/
struct Value *Value_new_VOID(struct Value *this) /*{{{*/
{
assert(this!=(struct Value*)0);
this->type=V_VOID;
return this;
}
/*}}}*/
struct Value *Value_new_null(struct Value *this, enum ValueType type) /*{{{*/
{
assert(this!=(struct Value*)0);
switch (type)
{
case V_INTEGER:
{
this->type=V_INTEGER;
this->u.integer=0;
break;
}
case V_REAL:
{
this->type=V_REAL;
this->u.real=0.0;
break;
}
case V_STRING:
{
this->type=V_STRING;
String_new(&this->u.string);
break;
}
case V_VOID:
{
this->type=V_VOID;
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
int Value_isNull(const struct Value *this) /*{{{*/
{
switch (this->type)
{
case V_INTEGER: return (this->u.integer==0);
case V_REAL: return (this->u.real==0.0);
case V_STRING: return (this->u.string.length==0);
default: assert(0);
}
return -1;
}
/*}}}*/
void Value_destroy(struct Value *this) /*{{{*/
{
assert(this!=(struct Value*)0);
switch (this->type)
{
case V_ERROR: free(this->u.error.msg); break;
case V_INTEGER: break;
case V_NIL: break;
case V_REAL: break;
case V_STRING: String_destroy(&this->u.string); break;
case V_VOID: break;
default: assert(0);
}
this->type=0;
}
/*}}}*/
struct Value *Value_clone(struct Value *this, const struct Value *original) /*{{{*/
{
assert(this!=(struct Value*)0);
assert(original!=(struct Value*)0);
switch (original->type)
{
case V_ERROR:
{
strcpy(this->u.error.msg=malloc(strlen(original->u.error.msg)+1),original->u.error.msg);
this->u.error.code=original->u.error.code;
break;
}
case V_INTEGER: this->u.integer=original->u.integer; break;
case V_NIL: break;
case V_REAL: this->u.real=original->u.real; break;
case V_STRING: String_clone(&this->u.string,&original->u.string); break;
default: assert(0);
}
this->type=original->type;
return this;
}
/*}}}*/
struct Value *Value_uplus(struct Value *this, int calc) /*{{{*/
{
switch (this->type)
{
case V_INTEGER:
case V_REAL:
{
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDUOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_uneg(struct Value *this, int calc) /*{{{*/
{
switch (this->type)
{
case V_INTEGER:
{
if (calc) this->u.integer=-this->u.integer;
break;
}
case V_REAL:
{
if (calc) this->u.real=-this->u.real;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDUOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_unot(struct Value *this, int calc) /*{{{*/
{
switch (this->type)
{
case V_INTEGER:
{
if (calc) this->u.integer=~this->u.integer;
break;
}
case V_REAL:
{
Value_retype(this,V_INTEGER);
if (calc) this->u.integer=~this->u.integer;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDUOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_add(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer+=x->u.integer;
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) this->u.real+=x->u.real;
break;
}
case V_STRING:
{
if (calc) String_appendString(&this->u.string,&x->u.string);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_sub(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer-=x->u.integer;
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) this->u.real-=x->u.real;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_mult(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer*=x->u.integer;
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) this->u.real*=x->u.real;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_div(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc)
{
if (x->u.real==0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Division by zero");
}
else this->u.real/=x->u.real;
}
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc)
{
if (x->u.real==0.0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Division by zero");
}
else this->u.real/=x->u.real;
}
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_idiv(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc)
{
if (x->u.integer==0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Division by zero");
}
else this->u.integer/=x->u.integer;
}
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc)
{
if (x->u.real==0.0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Division by zero");
}
else this->u.real=Value_trunc(this->u.real/x->u.real);
}
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_mod(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc)
{
if (x->u.integer==0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Modulo by zero");
}
else this->u.integer%=x->u.integer;
}
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc)
{
if (x->u.real==0.0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"Modulo by zero");
}
else this->u.real=fmod(this->u.real,x->u.real);
}
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_pow(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc)
{
if (this->u.integer==0 && x->u.integer==0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"0^0");
}
else if (x->u.integer>0) this->u.integer=pow(this->u.integer,x->u.integer);
else
{
long int thisi=this->u.integer;
Value_destroy(this);
Value_new_REAL(this,pow(thisi,x->u.integer));
}
}
break;
}
case V_REAL:
{
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc)
{
if (this->u.real==0.0 && x->u.real==0.0)
{
Value_destroy(this);
Value_new_ERROR(this,UNDEFINED,"0^0");
}
else this->u.real=pow(this->u.real,x->u.real);
}
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_and(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
case V_REAL:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer&=x->u.integer;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_or(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
case V_REAL:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer|=x->u.integer;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_xor(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
case V_REAL:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer^=x->u.integer;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_eqv(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
case V_REAL:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=~(this->u.integer^x->u.integer);
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_imp(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
case V_REAL:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(~this->u.integer)|x->u.integer;
break;
}
case V_STRING:
{
Value_destroy(this);
Value_new_ERROR(this,INVALIDOPERAND);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_lt(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer<x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real<x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=(String_cmp(&this->u.string,&x->u.string)<0)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_le(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer<=x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real<=x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=(String_cmp(&this->u.string,&x->u.string)<=0)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_eq(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer==x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real==x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=(String_cmp(&this->u.string,&x->u.string)==0)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_ge(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer>=x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real>=x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=(String_cmp(&this->u.string,&x->u.string)>=0)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_gt(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer>x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real>x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=(String_cmp(&this->u.string,&x->u.string)>0)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
struct Value *Value_ne(struct Value *this, struct Value *x, int calc) /*{{{*/
{
switch (Value_commonType[this->type][x->type])
{
case V_INTEGER:
{
VALUE_RETYPE(this,V_INTEGER);
VALUE_RETYPE(x,V_INTEGER);
if (calc) this->u.integer=(this->u.integer!=x->u.integer)?-1:0;
break;
}
case V_REAL:
{
int v;
VALUE_RETYPE(this,V_REAL);
VALUE_RETYPE(x,V_REAL);
if (calc) v=(this->u.real!=x->u.real)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
case V_STRING:
{
int v;
if (calc) v=String_cmp(&this->u.string,&x->u.string)?-1:0;
else v=0;
Value_destroy(this);
Value_new_INTEGER(this,v);
break;
}
default: assert(0);
}
return this;
}
/*}}}*/
int Value_exitFor(struct Value *this, struct Value *limit, struct Value *step) /*{{{*/
{
switch (this->type)
{
case V_INTEGER: return
(
step->u.integer<0
? (this->u.integer<limit->u.integer)
: (this->u.integer>limit->u.integer)
);
case V_REAL: return
(
step->u.real<0.0
? (this->u.real<limit->u.real)
: (this->u.real>limit->u.real)
);
case V_STRING: return (String_cmp(&this->u.string,&limit->u.string)>0);
default: assert(0);
}
return -1;
}
/*}}}*/
void Value_errorPrefix(struct Value *this, const char *prefix) /*{{{*/
{
size_t prefixlen,msglen;
assert(this->type==V_ERROR);
prefixlen=strlen(prefix);
msglen=strlen(this->u.error.msg);
this->u.error.msg=realloc(this->u.error.msg,prefixlen+msglen+1);
memmove(this->u.error.msg+prefixlen,this->u.error.msg,msglen);
memcpy(this->u.error.msg,prefix,prefixlen);
}
/*}}}*/
void Value_errorSuffix(struct Value *this, const char *suffix) /*{{{*/
{
size_t suffixlen,msglen;
assert(this->type==V_ERROR);
suffixlen=strlen(suffix);
msglen=strlen(this->u.error.msg);
this->u.error.msg=realloc(this->u.error.msg,suffixlen+msglen+1);
memcpy(this->u.error.msg+msglen,suffix,suffixlen+1);
}
/*}}}*/
struct Value *Value_new_typeError(struct Value *this, enum ValueType t1, enum ValueType t2) /*{{{*/
{
assert(typestr[t1]);
assert(typestr[t2]);
return Value_new_ERROR(this,TYPEMISMATCH1,_(typestr[t1]),_(typestr[t2]));
}
/*}}}*/
static void retypeError(struct Value *this, enum ValueType to) /*{{{*/
{
enum ValueType thisType=this->type;
assert(typestr[thisType]);
assert(typestr[to]);
Value_destroy(this);
Value_new_ERROR(this,TYPEMISMATCH1,_(typestr[thisType]),_(typestr[to]));
}
/*}}}*/
struct Value *Value_retype(struct Value *this, enum ValueType type) /*{{{*/
{
switch (this->type)
{
case V_INTEGER:
{
switch (type)
{
case V_INTEGER: break;
case V_REAL: this->u.real=this->u.integer; this->type=type; break;
case V_VOID: Value_destroy(this); Value_new_VOID(this); break;
default: retypeError(this,type); break;
}
break;
}
case V_REAL:
{
int overflow;
switch (type)
{
case V_INTEGER:
{
this->u.integer=Value_toi(this->u.real,&overflow);
this->type=V_INTEGER;
if (overflow)
{
Value_destroy(this);
Value_new_ERROR(this,OUTOFRANGE,typestr[V_INTEGER]);
}
break;
}
case V_REAL: break;
case V_VOID: Value_destroy(this); Value_new_VOID(this); break;
default: retypeError(this,type); break;
}
break;
}
case V_STRING:
{
switch (type)
{
case V_STRING: break;
case V_VOID: Value_destroy(this); Value_new_VOID(this); break;
default: retypeError(this,type); break;
}
break;
}
case V_VOID:
{
switch (type)
{
case V_VOID: break;
default: retypeError(this,type);
}
break;
}
case V_ERROR: break;
default: assert(0);
}
return this;
}
/*}}}*/
struct String *Value_toString(struct Value *this, struct String *s, char pad, int headingsign, size_t width, int commas, int dollar, int dollarleft, int precision, int exponent, int trailingsign) /*{{{*/
{
size_t oldlength=s->length;
switch (this->type)
{
case V_ERROR: String_appendChars(s,this->u.error.msg); break;
case V_REAL:
case V_INTEGER:
{
int sign;
struct String buf;
size_t totalwidth=width;
String_new(&buf);
if (this->type==V_INTEGER)
{
if (this->u.integer<0)
{
sign=-1;
this->u.integer=-this->u.integer;
}
else if (this->u.integer==0) sign=0;
else sign=1;
}
else
{
if (this->u.real<0.0)
{
sign=-1;
this->u.real=-this->u.real;
}
else if (this->u.real==0.0) sign=0;
else sign=1;
}
switch (headingsign)
{
case -1:
{
++totalwidth;
String_appendChar(&buf,sign==-1?'-':' ');
break;
}
case 0:
{
if (sign==-1) String_appendChar(&buf,'-');
break;
}
case 1:
{
++totalwidth;
String_appendChar(&buf,sign==-1?'-':'+');
break;
}
case 2: break;
default: assert(0);
}
totalwidth+=exponent;
if (this->type==V_INTEGER)
{
if (precision>0 || exponent) format_double(&buf,(double)this->u.integer,width,precision,exponent);
else if (precision==0) String_appendPrintf(&buf,"%lu.",this->u.integer);
else String_appendPrintf(&buf,"%lu",this->u.integer);
}
else format_double(&buf,this->u.real,width,precision,exponent);
if (commas)
{
size_t digits;
int first;
first=(headingsign?1:0);
for (digits=first; digits<buf.length && buf.character[digits]>='0' && buf.character[digits]<='9'; ++digits);
while (digits>first+3)
{
digits-=3;
String_insertChar(&buf,digits,',');
}
}
if (dollar)
{
String_insertChar(&buf,0,'$');
}
if (trailingsign==-1)
{
++totalwidth;
String_appendChar(&buf,sign==-1?'-':' ');
}
else if (trailingsign==1)
{
++totalwidth;
String_appendChar(&buf,sign==-1?'-':'+');
}
String_size(s,oldlength+(totalwidth>buf.length?totalwidth:buf.length));
if (totalwidth>buf.length) memset(s->character+oldlength,pad,totalwidth-buf.length+dollarleft);
memcpy(s->character+oldlength+(totalwidth>buf.length?(totalwidth-buf.length):0)+dollarleft,buf.character+dollarleft,buf.length-dollarleft);
if (dollarleft) s->character[oldlength]='$';
String_destroy(&buf);
break;
}
case V_STRING:
{
if (width>0)
{
size_t blanks=(this->u.string.length<width?(width-this->u.string.length):0);
String_size(s,oldlength+width);
memcpy(s->character+oldlength,this->u.string.character,blanks?this->u.string.length:width);
if (blanks) memset(s->character+oldlength+this->u.string.length,' ',blanks);
}
else String_appendString(s,&this->u.string);
break;
}
default: assert(0); return 0;
}
return s;
}
/*}}}*/
struct Value *Value_toStringUsing(struct Value *this, struct String *s, struct String *using, size_t *usingpos) /*{{{*/
{
char pad=' ';
int headingsign;
int width=0;
int commas=0;
int dollar=0;
int dollarleft=0;
int precision=-1;
int exponent=0;
int trailingsign=0;
headingsign=(using->length ? 0 : -1);
if (*usingpos==using->length) *usingpos=0;
while (*usingpos<using->length)
{
switch (using->character[*usingpos])
{
case '_': /* output next char */ /*{{{*/
{
++(*usingpos);
if (*usingpos<using->length) String_appendChar(s,using->character[(*usingpos)++]);
else
{
Value_destroy(this);
return Value_new_ERROR(this,MISSINGCHARACTER);
}
break;
}
/*}}}*/
case '!': /* output first character of string */ /*{{{*/
{
width=1;
++(*usingpos);
goto work;
}
/*}}}*/
case '\\': /* output n characters of string */ /*{{{*/
{
width=1;
++(*usingpos);
while (*usingpos<using->length && using->character[*usingpos]==' ')
{
++(*usingpos);
++width;
}
if (*usingpos<using->length && using->character[*usingpos]=='\\')
{
++(*usingpos);
++width;
goto work;
}
else
{
Value_destroy(this);
return Value_new_ERROR(this,IOERROR,_("unpaired \\ in format"));
}
break;
}
/*}}}*/
case '&': /* output string */ /*{{{*/
{
width=0;
++(*usingpos);
goto work;
}
/*}}}*/
case '*':
case '$':
case '0':
case '+':
case '#':
case '.':
{
if (using->character[*usingpos]=='+')
{
headingsign=1;
++(*usingpos);
}
while (*usingpos<using->length && strchr("$#*0,",using->character[*usingpos]))
{
switch (using->character[*usingpos])
{
case '$': if (width==0) dollarleft=1; if (++dollar>1) ++width; break;
case '*': pad='*'; ++width; break;
case '0': pad='0'; ++width; break;
case ',': commas=1; ++width; break;
default: ++width;
}
++(*usingpos);
}
if (*usingpos<using->length && using->character[*usingpos]=='.' )
{
++(*usingpos);
++width;
precision=0;
while (*usingpos<using->length && strchr("*#",using->character[*usingpos]))
{
++(*usingpos);
++precision;
++width;
}
if (width==1 && precision==0)
{
Value_destroy(this);
return Value_new_ERROR(this,BADFORMAT);
}
}
if (*usingpos<using->length && using->character[*usingpos]=='-' )
{
++(*usingpos);
if (headingsign==0) headingsign=2;
trailingsign=-1;
}
else if (*usingpos<using->length && using->character[*usingpos]=='+')
{
++(*usingpos);
if (headingsign==0) headingsign=2;
trailingsign=1;
}
while (*usingpos<using->length && using->character[*usingpos]=='^')
{
++(*usingpos);
++exponent;
}
goto work;
}
default:
{
String_appendChar(s,using->character[(*usingpos)++]);
}
}
}
work:
Value_toString(this,s,pad,headingsign,width,commas,dollar,dollarleft,precision,exponent,trailingsign);
if ((this->type==V_INTEGER || this->type==V_REAL) && width==0 && precision==-1) String_appendChar(s,' ');
while (*usingpos<using->length)
{
switch (using->character[*usingpos])
{
case '_': /* output next char */ /*{{{*/
{
++(*usingpos);
if (*usingpos<using->length) String_appendChar(s,using->character[(*usingpos)++]);
else
{
Value_destroy(this);
return Value_new_ERROR(this,MISSINGCHARACTER);
}
break;
}
/*}}}*/
case '!':
case '\\':
case '&':
case '*':
case '0':
case '+':
case '#':
case '.': return this;
default:
{
String_appendChar(s,using->character[(*usingpos)++]);
}
}
}
return this;
}
/*}}}*/
struct String *Value_toWrite(struct Value *this, struct String *s) /*{{{*/
{
switch (this->type)
{
case V_INTEGER: String_appendPrintf(s,"%ld",this->u.integer); break;
case V_REAL:
{
double x;
int p=DBL_DIG;
int n,o;
x=(this->u.real<0.0 ? -this->u.real : this->u.real);
while (x>1.0 && p>0) { x/=10.0; --p; }
o=s->length;
String_appendPrintf(s,"%.*f",p,this->u.real);
n=s->length;
if (memchr(s->character+o,'.',n-o))
{
while (s->character[s->length-1]=='0') --s->length;
if (s->character[s->length-1]=='.') --s->length;
}
break;
}
case V_STRING: /*{{{*/
{
size_t l=this->u.string.length;
char *data=this->u.string.character;
String_appendChar(s,'"');
while (l--)
{
if (*data=='"') String_appendChar(s,'"');
String_appendChar(s,*data);
++data;
}
String_appendChar(s,'"');
break;
}
/*}}}*/
default: assert(0);
}
return s;
}
/*}}}*/
struct Value *Value_nullValue(enum ValueType type) /*{{{*/
{
static struct Value integer={ V_INTEGER };
static struct Value real={ V_REAL };
static struct Value string={ V_STRING };
static char n[]="";
static int init=0;
if (!init)
{
integer.u.integer=0;
real.u.real=0.0;
string.u.string.length=0;
string.u.string.character=n;
}
switch (type)
{
case V_INTEGER: return &integer;
case V_REAL: return &real;
case V_STRING: return &string;
default: assert(0);
}
return (struct Value*)0;
}
/*}}}*/