forked from LeenkxTeam/LNXSDK
575 lines
15 KiB
C
575 lines
15 KiB
C
/*
|
|
* Copyright (C)2005-2016 Haxe Foundation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include <hl.h>
|
|
#include <math.h>
|
|
|
|
#define TK2(a,b) ((a) | ((b)<<5))
|
|
|
|
static void invalid_cast( hl_type *from, hl_type *to ) {
|
|
hl_error("Can't cast %s to %s",hl_type_str(from),hl_type_str(to));
|
|
}
|
|
|
|
HL_PRIM vdynamic *hl_make_dyn( void *data, hl_type *t ) {
|
|
vdynamic *v;
|
|
switch( t->kind ) {
|
|
case HUI8:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.i = *(unsigned char*)data;
|
|
return v;
|
|
case HUI16:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.i = *(unsigned short*)data;
|
|
return v;
|
|
case HI32:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.i = *(int*)data;
|
|
return v;
|
|
case HI64:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.i64 = *(int64*)data;
|
|
return v;
|
|
case HF32:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.f = *(float*)data;
|
|
return v;
|
|
case HF64:
|
|
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
|
|
v->t = t;
|
|
v->v.d = *(double*)data;
|
|
return v;
|
|
case HBOOL:
|
|
return hl_alloc_dynbool(*(bool*)data);
|
|
case HBYTES:
|
|
case HTYPE:
|
|
case HREF:
|
|
case HABSTRACT:
|
|
{
|
|
void *p = *(void**)data;
|
|
if( p == NULL ) return NULL;
|
|
v = hl_alloc_dynamic(t);
|
|
v->v.ptr = p;
|
|
return v;
|
|
}
|
|
default:
|
|
return *(vdynamic**)data;
|
|
}
|
|
}
|
|
|
|
|
|
HL_PRIM int hl_dyn_casti( void *data, hl_type *t, hl_type *to ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
|
|
if( t->kind == HDYN ) {
|
|
vdynamic *v = *((vdynamic**)data);
|
|
if( v == NULL ) return 0;
|
|
t = v->t;
|
|
if( !hl_is_dynamic(t) ) data = &v->v;
|
|
}
|
|
switch( t->kind ) {
|
|
case HUI8:
|
|
return *(unsigned char*)data;
|
|
case HUI16:
|
|
return *(unsigned short*)data;
|
|
case HI32:
|
|
return *(int*)data;
|
|
case HI64:
|
|
return (int)*(int64*)data;
|
|
case HF32:
|
|
return (int)*(float*)data;
|
|
case HF64:
|
|
return (int)*(double*)data;
|
|
case HBOOL:
|
|
return *(bool*)data;
|
|
case HNULL:
|
|
{
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL ) return 0;
|
|
return hl_dyn_casti(&v->v,t->tparam,to);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
invalid_cast(t,to);
|
|
return 0;
|
|
}
|
|
|
|
HL_PRIM int64 hl_dyn_casti64( void *data, hl_type *t ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_i64));
|
|
if( t->kind == HDYN ) {
|
|
vdynamic *v = *((vdynamic**)data);
|
|
if( v == NULL ) return 0;
|
|
t = v->t;
|
|
if( !hl_is_dynamic(t) ) data = &v->v;
|
|
}
|
|
switch( t->kind ) {
|
|
case HUI8:
|
|
return *(unsigned char*)data;
|
|
case HUI16:
|
|
return *(unsigned short*)data;
|
|
case HI32:
|
|
return *(int*)data;
|
|
case HI64:
|
|
return *(int64*)data;
|
|
case HF32:
|
|
return (int64)*(float*)data;
|
|
case HF64:
|
|
return (int64)*(double*)data;
|
|
case HBOOL:
|
|
return *(bool*)data;
|
|
case HNULL:
|
|
{
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL ) return 0;
|
|
return hl_dyn_casti64(&v->v,t->tparam);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
invalid_cast(t,&hlt_i64);
|
|
return 0;
|
|
}
|
|
|
|
HL_PRIM void *hl_dyn_castp( void *data, hl_type *t, hl_type *to ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
|
|
if( to->kind == HDYN && hl_is_dynamic(t) )
|
|
return *(vdynamic**)data;
|
|
if( t->kind == HDYN || t->kind == HNULL ) {
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL )
|
|
return NULL;
|
|
if( to->kind == HNULL && v->t == to->tparam && hl_is_gc_ptr(v) )
|
|
return v; // v might be a vdynamic on the stack
|
|
t = v->t;
|
|
if( !hl_is_dynamic(t) ) data = &v->v;
|
|
} else if( hl_is_dynamic(t) ) {
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL ) return NULL;
|
|
t = v->t;
|
|
}
|
|
if( t == to || hl_safe_cast(t,to) )
|
|
return *(void**)data;
|
|
switch( TK2(t->kind,to->kind) ) {
|
|
case TK2(HOBJ,HOBJ):
|
|
case TK2(HSTRUCT,HSTRUCT):
|
|
{
|
|
hl_type_obj *t1 = t->obj;
|
|
hl_type_obj *t2 = to->obj;
|
|
while( true ) {
|
|
if( t1 == t2 )
|
|
return *(void**)data;
|
|
if( t1->super == NULL )
|
|
break;
|
|
t1 = t1->super->obj;
|
|
}
|
|
if( t->obj->rt->castFun ) {
|
|
vdynamic *v = t->obj->rt->castFun(*(vdynamic**)data,to);
|
|
if( v ) return v;
|
|
}
|
|
break;
|
|
}
|
|
case TK2(HFUN,HFUN):
|
|
{
|
|
vclosure *c = *(vclosure**)data;
|
|
if( c == NULL ) return NULL;
|
|
c = hl_make_fun_wrapper(c,to);
|
|
if( c ) return c;
|
|
}
|
|
break;
|
|
case TK2(HOBJ,HVIRTUAL):
|
|
case TK2(HDYNOBJ,HVIRTUAL):
|
|
case TK2(HVIRTUAL,HVIRTUAL):
|
|
return hl_to_virtual(to,*(vdynamic**)data);
|
|
case TK2(HVIRTUAL,HOBJ):
|
|
{
|
|
vvirtual *v = *(vvirtual**)data;
|
|
if( v->value == NULL ) break;
|
|
return hl_dyn_castp( &v->value, v->value->t, to);
|
|
}
|
|
case TK2(HOBJ,HDYN):
|
|
case TK2(HDYNOBJ,HDYN):
|
|
case TK2(HFUN,HDYN):
|
|
case TK2(HNULL,HDYN):
|
|
case TK2(HARRAY,HDYN):
|
|
// NO(HSTRUCT,HDYN)
|
|
return *(void**)data;
|
|
}
|
|
if( to->kind == HDYN )
|
|
return hl_make_dyn(data,t);
|
|
if( to->kind == HNULL ) {
|
|
if( to->tparam->kind == t->kind )
|
|
return hl_make_dyn(data,t);
|
|
switch( to->tparam->kind ) {
|
|
case HUI8:
|
|
case HUI16:
|
|
case HI32:
|
|
case HBOOL:
|
|
{
|
|
int v = hl_dyn_casti(data,t,to->tparam);
|
|
return hl_make_dyn(&v,to->tparam);
|
|
}
|
|
case HI64:
|
|
{
|
|
int64 v = hl_dyn_casti64(data,t);
|
|
return hl_make_dyn(&v,to->tparam);
|
|
}
|
|
case HF32:
|
|
{
|
|
float f = hl_dyn_castf(data,t);
|
|
return hl_make_dyn(&f,to->tparam);
|
|
}
|
|
case HF64:
|
|
{
|
|
double d = hl_dyn_castd(data,t);
|
|
return hl_make_dyn(&d,to->tparam);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if( to->kind == HREF ) {
|
|
switch( to->tparam->kind ) {
|
|
case HUI8:
|
|
case HUI16:
|
|
case HI32:
|
|
case HBOOL:
|
|
{
|
|
int *v = (int*)hl_gc_alloc_noptr(sizeof(int));
|
|
*v = hl_dyn_casti(data,t,to->tparam);
|
|
return v;
|
|
}
|
|
case HI64:
|
|
{
|
|
int64 *d = (int64*)hl_gc_alloc_noptr(sizeof(int64));
|
|
*d = hl_dyn_casti64(data,t);
|
|
return d;
|
|
}
|
|
case HF32:
|
|
{
|
|
float *f = (float*)hl_gc_alloc_noptr(sizeof(float));
|
|
*f = hl_dyn_castf(data,t);
|
|
return f;
|
|
}
|
|
case HF64:
|
|
{
|
|
double *d = (double*)hl_gc_alloc_noptr(sizeof(double));
|
|
*d = hl_dyn_castd(data,t);
|
|
return d;
|
|
}
|
|
default:
|
|
{
|
|
void **p = (void**)hl_gc_alloc_raw(sizeof(void*));
|
|
*p = hl_dyn_castp(data,t,to->tparam);
|
|
return p;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
invalid_cast(t,to);
|
|
return 0;
|
|
}
|
|
|
|
HL_PRIM double hl_dyn_castd( void *data, hl_type *t ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f64));
|
|
if( t->kind == HDYN ) {
|
|
vdynamic *v = *((vdynamic**)data);
|
|
if( v == NULL ) return 0;
|
|
t = v->t;
|
|
if( !hl_is_dynamic(t) ) data = &v->v;
|
|
}
|
|
switch( t->kind ) {
|
|
case HF32:
|
|
return *(float*)data;
|
|
case HF64:
|
|
return *(double*)data;
|
|
case HUI8:
|
|
return *(unsigned char*)data;
|
|
case HUI16:
|
|
return *(unsigned short*)data;
|
|
case HI32:
|
|
return *(int*)data;
|
|
case HI64:
|
|
return (double)*(int64*)data;
|
|
case HBOOL:
|
|
return *(bool*)data;
|
|
case HNULL:
|
|
{
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL ) return 0;
|
|
return hl_dyn_castd(&v->v,t->tparam);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
invalid_cast(t,&hlt_f64);
|
|
return 0.;
|
|
}
|
|
|
|
HL_PRIM float hl_dyn_castf( void *data, hl_type *t ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f32));
|
|
if( t->kind == HDYN ) {
|
|
vdynamic *v = *((vdynamic**)data);
|
|
if( v == NULL ) return 0;
|
|
t = v->t;
|
|
if( !hl_is_dynamic(t) ) data = &v->v;
|
|
}
|
|
switch( t->kind ) {
|
|
case HF32:
|
|
return *(float*)data;
|
|
case HF64:
|
|
return (float)*(double*)data;
|
|
case HUI8:
|
|
return *(unsigned char*)data;
|
|
case HUI16:
|
|
return *(unsigned short*)data;
|
|
case HI32:
|
|
return (float)*(int*)data;
|
|
case HI64:
|
|
return (float)*(int64*)data;
|
|
case HBOOL:
|
|
return *(bool*)data;
|
|
case HNULL:
|
|
{
|
|
vdynamic *v = *(vdynamic**)data;
|
|
if( v == NULL ) return 0;
|
|
return hl_dyn_castf(&v->v,t->tparam);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
invalid_cast(t,&hlt_f32);
|
|
return 0;
|
|
}
|
|
|
|
static int fcompare( float a, float b ) {
|
|
float d = a - b;
|
|
if( d != d )
|
|
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
|
|
return d == 0.f ? 0 : (d > 0.f ? 1 : -1);
|
|
}
|
|
|
|
static int dcompare( double a, double b ) {
|
|
double d = a - b;
|
|
if( d != d )
|
|
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
|
|
return d == 0. ? 0 : (d > 0. ? 1 : -1);
|
|
}
|
|
|
|
HL_PRIM int hl_ptr_compare( vdynamic *a, vdynamic *b ) {
|
|
if( a == b )
|
|
return 0;
|
|
return a > b ? 1 : -1;
|
|
}
|
|
|
|
HL_PRIM int hl_dyn_compare( vdynamic *a, vdynamic *b ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
|
|
if( a == b )
|
|
return 0;
|
|
if( a == NULL )
|
|
return -1;
|
|
if( b == NULL )
|
|
return 1;
|
|
switch( TK2(a->t->kind,b->t->kind) ) {
|
|
case TK2(HUI8,HUI8):
|
|
return (int)a->v.ui8 - (int)b->v.ui8;
|
|
case TK2(HUI16,HUI16):
|
|
return (int)a->v.ui16 - (int)b->v.ui16;
|
|
case TK2(HI32,HI32):
|
|
{
|
|
int d = a->v.i - b->v.i;
|
|
return d == hl_invalid_comparison ? -1 : d;
|
|
}
|
|
case TK2(HI64,HI64):
|
|
{
|
|
int64 d = a->v.i64 - b->v.i64;
|
|
return d == 0 ? 0 : (d > 0 ? 1 : -1);
|
|
}
|
|
case TK2(HF32,HF32):
|
|
return fcompare(a->v.f,b->v.f);
|
|
case TK2(HF64,HF64):
|
|
return dcompare(a->v.d,b->v.d);
|
|
case TK2(HBOOL,HBOOL):
|
|
return (int)a->v.b - (int)b->v.b;
|
|
case TK2(HF64, HI32):
|
|
return dcompare(a->v.d,(double)b->v.i);
|
|
case TK2(HI32, HF64):
|
|
return dcompare((double)a->v.i,b->v.d);
|
|
case TK2(HF64, HF32):
|
|
return dcompare(a->v.d,(double)b->v.f);
|
|
case TK2(HF32, HF64):
|
|
return dcompare((double)a->v.f,b->v.d);
|
|
case TK2(HOBJ,HOBJ):
|
|
case TK2(HSTRUCT,HSTRUCT):
|
|
if( a->t->obj->rt->compareFun )
|
|
return a->t->obj->rt->compareFun(a,b);
|
|
return a > b ? 1 : -1;
|
|
case TK2(HENUM,HENUM):
|
|
return a > b ? 1 : -1;
|
|
case TK2(HTYPE,HTYPE):
|
|
case TK2(HBYTES,HBYTES):
|
|
return a->v.ptr != b->v.ptr;
|
|
case TK2(HOBJ,HVIRTUAL):
|
|
case TK2(HDYNOBJ,HVIRTUAL):
|
|
return hl_dyn_compare(a,((vvirtual*)b)->value);
|
|
case TK2(HVIRTUAL,HOBJ):
|
|
case TK2(HVIRTUAL,HDYNOBJ):
|
|
return hl_dyn_compare(((vvirtual*)a)->value,b);
|
|
case TK2(HFUN,HFUN):
|
|
if( ((vclosure*)a)->hasValue == 2 )
|
|
return hl_dyn_compare((vdynamic*)((vclosure_wrapper*)a)->wrappedFun,b);
|
|
if( ((vclosure*)b)->hasValue == 2 )
|
|
return hl_dyn_compare(a,(vdynamic*)((vclosure_wrapper*)b)->wrappedFun);
|
|
if( ((vclosure*)a)->fun != ((vclosure*)b)->fun )
|
|
return hl_invalid_comparison;
|
|
return hl_dyn_compare(((vclosure*)a)->value,((vclosure*)b)->value);
|
|
case TK2(HVIRTUAL,HVIRTUAL):
|
|
if( ((vvirtual*)a)->value && ((vvirtual*)b)->value )
|
|
return hl_dyn_compare(((vvirtual*)a)->value,((vvirtual*)b)->value);
|
|
return hl_invalid_comparison;
|
|
}
|
|
return hl_invalid_comparison;
|
|
}
|
|
|
|
HL_PRIM void hl_write_dyn( void *data, hl_type *t, vdynamic *v, bool is_tmp ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
|
|
switch( t->kind ) {
|
|
case HUI8:
|
|
*(unsigned char*)data = (unsigned char)hl_dyn_casti(&v,&hlt_dyn,t);
|
|
break;
|
|
case HBOOL:
|
|
*(bool*)data = hl_dyn_casti(&v,&hlt_dyn,t) != 0;
|
|
break;
|
|
case HUI16:
|
|
*(unsigned short*)data = (unsigned short)hl_dyn_casti(&v,&hlt_dyn,t);
|
|
break;
|
|
case HI32:
|
|
*(int*)data = hl_dyn_casti(&v,&hlt_dyn,t);
|
|
break;
|
|
case HI64:
|
|
*(int64*)data = hl_dyn_casti64(&v,&hlt_dyn);
|
|
break;
|
|
case HF32:
|
|
*(float*)data = hl_dyn_castf(&v,&hlt_dyn);
|
|
break;
|
|
case HF64:
|
|
*(double*)data = hl_dyn_castd(&v,&hlt_dyn);
|
|
break;
|
|
default:
|
|
{
|
|
void *ret = (v && hl_same_type(t,v->t)) ? v : hl_dyn_castp(&v,&hlt_dyn,t);
|
|
if( is_tmp && ret == v ) {
|
|
ret = hl_alloc_dynamic(v->t);
|
|
((vdynamic*)ret)->v = v->v;
|
|
}
|
|
*(void**)data = ret;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HL_PRIM vdynamic* hl_value_cast( vdynamic *v, hl_type *t ) {
|
|
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
|
|
if( t->kind == HDYN || v == NULL || hl_safe_cast(v->t,t) )
|
|
return v;
|
|
invalid_cast(v->t,t);
|
|
return NULL;
|
|
}
|
|
|
|
HL_PRIM bool hl_type_safe_cast( hl_type *a, hl_type *b ) {
|
|
return hl_safe_cast(a,b);
|
|
}
|
|
|
|
#define NULL_VAL HLAST
|
|
#define OP(op,t1,t2) (TK2(t1,t2) | (op << 10))
|
|
#define OP_ADD 0
|
|
#define OP_SUB 1
|
|
#define OP_MUL 2
|
|
#define OP_MOD 3
|
|
#define OP_DIV 4
|
|
#define OP_SHL 5
|
|
#define OP_SHR 6
|
|
#define OP_USHR 7
|
|
#define OP_AND 8
|
|
#define OP_OR 9
|
|
#define OP_XOR 10
|
|
|
|
static vdynamic *hl_dynf64( double v ) {
|
|
vdynamic *d = hl_alloc_dynamic(&hlt_f64);
|
|
d->v.d = v;
|
|
return d;
|
|
}
|
|
|
|
static vdynamic *hl_dyni32( int v ) {
|
|
vdynamic *d = hl_alloc_dynamic(&hlt_i32);
|
|
d->v.i = v;
|
|
return d;
|
|
}
|
|
|
|
static bool is_number( hl_type *t ) {
|
|
return t->kind >= HUI8 && t->kind <= HBOOL;
|
|
}
|
|
|
|
#define FOP(op) { double va = hl_dyn_castd(&a,&hlt_dyn); double vb = hl_dyn_castd(&b,&hlt_dyn); return hl_dynf64(va op vb); }
|
|
#define IOP(op) { int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32); int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32); return hl_dyni32(va op vb); }
|
|
|
|
HL_PRIM vdynamic *hl_dyn_op( int op, vdynamic *a, vdynamic *b ) {
|
|
static uchar *op_names[] = { USTR("+"), USTR("-"), USTR("*"), USTR("%"), USTR("/"), USTR("<<"), USTR(">>"), USTR(">>>"), USTR("&"), USTR("|"), USTR("^") };
|
|
if( op < 0 || op >= OpLast ) hl_error("Invalid op %d",op);
|
|
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
|
|
if( !a && !b ) return op == OP_DIV || op == OP_MOD ? hl_dynf64(hl_nan()) : NULL;
|
|
if( (!a || is_number(a->t)) && (!b || is_number(b->t)) ) {
|
|
switch( op ) {
|
|
case OP_ADD: FOP(+);
|
|
case OP_SUB: FOP(-);
|
|
case OP_MUL: FOP(*);
|
|
case OP_MOD: {
|
|
double va = hl_dyn_castd(&a,&hlt_dyn);
|
|
double vb = hl_dyn_castd(&b,&hlt_dyn);
|
|
return hl_dynf64(fmod(va,vb));
|
|
}
|
|
case OP_DIV: FOP(/);
|
|
case OP_SHL: IOP(<<);
|
|
case OP_SHR: IOP(>>);
|
|
case OP_USHR: {
|
|
int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32);
|
|
int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32);
|
|
return hl_dyni32( ((unsigned)va) >> ((unsigned)vb) );
|
|
}
|
|
case OP_AND: IOP(&);
|
|
case OP_OR: IOP(|);
|
|
case OP_XOR: IOP(^);
|
|
}
|
|
}
|
|
hl_error("Can't perform dyn op %s %s %s",hl_type_str(a->t),op_names[op],hl_type_str(b->t));
|
|
return NULL;
|
|
}
|
|
|
|
DEFINE_PRIM(_I32, dyn_compare, _DYN _DYN);
|
|
DEFINE_PRIM(_DYN, value_cast, _DYN _TYPE);
|
|
DEFINE_PRIM(_BOOL, type_safe_cast, _TYPE _TYPE);
|
|
DEFINE_PRIM(_DYN, dyn_op, _I32 _DYN _DYN);
|
|
DEFINE_PRIM(_I32, ptr_compare, _DYN _DYN);
|
|
|