509 lines
13 KiB
C
509 lines
13 KiB
C
#include "tlang.h"
|
|
#include <stdlib.h>
|
|
tobject_t* tobject_same(runtime_t* rt,tobject_t* l,tobject_t* r,bool* freeleftifzero)
|
|
{
|
|
|
|
tobject_t* out=NULL;
|
|
tobject_type_t ltype=l->type;
|
|
tobject_type_t rtype =r->type;
|
|
if(ltype == tdict)
|
|
{
|
|
if(dict_haskey(l->data.dict,"eq"))
|
|
{
|
|
kvp_t* kvp=dict_getkvp(l->data.dict,"eq");
|
|
if(kvp->value->type == texternalmethod || kvp->value->type == tinternalmethod)
|
|
{
|
|
list_tobject_t ls;
|
|
list_create(rt,&ls,0);
|
|
list_add(&ls,r);
|
|
out=tobject_call(rt->globals,kvp->value,&ls);
|
|
|
|
out->count++; //ensure i dont get deleted
|
|
tobject_freeifzero(l);
|
|
out->count--; //set me back bitch
|
|
|
|
*freeleftifzero = false;
|
|
} else {
|
|
if(r->type == tdict)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean = l == r;
|
|
|
|
}
|
|
}
|
|
}else {
|
|
if(r->type == tdict)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean = l == r;
|
|
|
|
}
|
|
}
|
|
}
|
|
if(ltype == tnumber && rtype == tnumber)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean = l->data.number == r->data.number;
|
|
|
|
}
|
|
if(ltype == tbool && rtype == tbool)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean = l->data.boolean == r->data.boolean;
|
|
|
|
}
|
|
if(ltype == tstring && rtype == tstring)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean =string_sames(l->data.string,r->data.string);
|
|
}
|
|
if(ltype == tchar && rtype == tchar)
|
|
{
|
|
out = tobject_create(rt);
|
|
out->type = tbool;
|
|
out->data.boolean = l->data.chr == r->data.chr;
|
|
}
|
|
if(out == NULL)
|
|
{
|
|
out = tobject_bool(rt,false);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
bool tobject_sameb(runtime_t* rt,tobject_t* l,tobject_t* r)
|
|
{
|
|
bool freeleftifzero=true;
|
|
bool ret0=false;
|
|
tobject_t* ret=tobject_same(rt,l,r,&freeleftifzero);
|
|
ret0=tobject_tobool(ret);
|
|
ret->count++;
|
|
if(freeleftifzero)
|
|
{
|
|
tobject_freeifzero(l);
|
|
}
|
|
tobject_freeifzero(r);
|
|
ret->count--;
|
|
tobject_freeifzero(ret);
|
|
return ret0;
|
|
}
|
|
tobject_t* tobject_create(runtime_t* rt)
|
|
{
|
|
tobject_t* obj =(tobject_t*)malloc(sizeof(tobject_t));
|
|
memset(obj,0,sizeof(tobject_t));
|
|
obj->count = 0;
|
|
obj->type = tnull;
|
|
obj->free = NULL;
|
|
return obj;
|
|
}
|
|
void list_create(runtime_t* rt,list_tobject_t* ls,int count)
|
|
{
|
|
ls->rt = rt;
|
|
ls->length = count;
|
|
ls->capacity = count + 128;
|
|
ls->items = (tobject_t**)malloc(sizeof(tobject_t*) * ls->capacity);
|
|
int i;
|
|
for(i=0;i<ls->length;i++)
|
|
{
|
|
ls->items[i] = tobject_create(rt);
|
|
ls->items[i]->count = 1;
|
|
}
|
|
}
|
|
void list_set(list_tobject_t* a,int index,tobject_t* item)
|
|
{
|
|
|
|
if(index >= a->length)
|
|
{
|
|
index=a->length-1;
|
|
}
|
|
if(index==-1)
|
|
{
|
|
list_add(a,item);
|
|
}else{
|
|
tobject_addref(item); // just in case someone sets a variable to itself
|
|
tobject_rmref(a->items[index]);
|
|
a->items[index] = item;
|
|
|
|
}
|
|
}
|
|
int list_indexof(list_tobject_t* a,tobject_t* item)
|
|
{
|
|
int index = -1;
|
|
int i;
|
|
item->count++;
|
|
for(i=0;i<a->length;i++)
|
|
{
|
|
bool res= tobject_sameb(a->rt,a->items[0],item);
|
|
if(res)
|
|
{
|
|
index=i;
|
|
break;
|
|
}
|
|
}
|
|
item->count--;
|
|
return index;
|
|
}
|
|
bool list_contains(list_tobject_t* a,tobject_t* item)
|
|
{
|
|
return list_indexof(a,item) > -1;
|
|
}
|
|
void list_remove(list_tobject_t* a,tobject_t* item)
|
|
{
|
|
int i= list_indexof(a,item);
|
|
if(i>-1) list_rm(a,i);
|
|
}
|
|
void list_add(list_tobject_t* a,tobject_t* item)
|
|
{
|
|
tobject_addref(item);
|
|
if(a->length + 1 > a->capacity)
|
|
{
|
|
a->capacity = a->length + 128;
|
|
a->items=(tobject_t**)realloc(a->items,a->capacity * sizeof(tobject_t*));
|
|
|
|
}
|
|
a->items[a->length++] = item;
|
|
}
|
|
tobject_t* list_at(list_tobject_t* a,int offset)
|
|
{
|
|
if(offset<a->length) return a->items[offset];
|
|
return NULL;
|
|
}
|
|
void list_rm(list_tobject_t* a,int offset)
|
|
{
|
|
if(offset<a->length)
|
|
{
|
|
tobject_rmref(a->items[offset]);
|
|
int i;
|
|
a->length--;
|
|
for(i=offset;i<a->length;i++)
|
|
{
|
|
a->items[i] = a->items[i+1];
|
|
}
|
|
}
|
|
}
|
|
void list_clear(list_tobject_t* a)
|
|
{
|
|
int i;
|
|
for(i=0;i<a->length;i++)
|
|
{
|
|
tobject_rmref(a->items[i]);
|
|
}
|
|
a->length = 0;
|
|
}
|
|
void list_free(list_tobject_t* a)
|
|
{
|
|
list_clear(a);
|
|
free(a->items);
|
|
|
|
}
|
|
tobject_t* tobject_create_array(runtime_t* rt,int count)
|
|
{
|
|
tobject_t* obj= tobject_create(rt);
|
|
obj->type = tlist;
|
|
list_create(rt,&obj->data.list,count);
|
|
return obj;
|
|
}
|
|
tobject_t* tobject_basic(runtime_t* rt,tobject_type_t type)
|
|
{
|
|
tobject_t* o=tobject_create(rt);
|
|
o->type = type;
|
|
return o;
|
|
}
|
|
tobject_t* tobject_fromexternalmethod(runtime_t* rt,void* data,external_method_t method,texternalmethod_free_t free)
|
|
{
|
|
tobject_t* obj= tobject_create(rt);
|
|
obj->type = texternalmethod;
|
|
obj->data.external_method.data = data;
|
|
obj->data.external_method.method = method;
|
|
obj->free = free;
|
|
obj->count=0;
|
|
|
|
return obj;
|
|
}
|
|
|
|
int requiredArguments(list_string_t* str)
|
|
{
|
|
int i;
|
|
for(i =0;i<str->count;i++)
|
|
{
|
|
if(str->strings[i]->length > 0 && str->strings[i]->text[0] == '$')
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return str->count;
|
|
}
|
|
int optionalArgs(list_string_t* str,int argLen)
|
|
{
|
|
int i;
|
|
for(i =0;i<str->count;i++)
|
|
{
|
|
string_t* str0=str->strings[i];
|
|
if(str0->length > 2 && str0->text[0] == '$' && str0->text[1] == '$')
|
|
{
|
|
if(argLen < i)
|
|
return argLen;
|
|
return i;
|
|
}
|
|
}
|
|
if(argLen < str->count)
|
|
return argLen;
|
|
return str->count;
|
|
|
|
}
|
|
|
|
tobject_t* tobject_call(scope_t* scope,tobject_t* func,list_tobject_t* args)
|
|
{
|
|
if(func->type == texternalmethod)
|
|
{
|
|
|
|
return func->data.external_method.method(scope->rt,func->data.external_method.data,args);
|
|
}
|
|
if(func->type == tinternalmethod)
|
|
{
|
|
//execute_internal_method
|
|
tobject_t* res;
|
|
scope_t* scope2=scope_begin(func->data.internal_method.scope);
|
|
|
|
list_string_t* strs=&func->data.internal_method.closure->data.closure_node.argNames;
|
|
int argCountClosure = strs->count;//Body.Arguments.Count;
|
|
int argCountCaller = args->length;
|
|
if(argCountCaller < requiredArguments(strs))
|
|
{
|
|
return tobject_basic(scope->rt,tnull);
|
|
}
|
|
int i = 0;
|
|
for(;i<optionalArgs(strs,argCountCaller);i++)
|
|
{
|
|
tobject_t* _obj=args->items[i];
|
|
char* t = string_dupp(strs->strings[i]);
|
|
scope2->setvariable(scope2,string_trimstart(t,'$'),_obj);
|
|
free(t);
|
|
}
|
|
|
|
if(i==argCountClosure-1)
|
|
{
|
|
//do tarray
|
|
tobject_t* array= tobject_create_array(scope->rt,0);
|
|
char* t = string_dupp(strs->strings[i]);
|
|
scope2->setvariable(scope2,string_trimstart(t,'$'),array);
|
|
free(t);
|
|
for(;i<args->length;i++)
|
|
{
|
|
tobject_t* _obj=args->items[i];
|
|
|
|
list_add(&array->data.list,_obj);
|
|
}
|
|
|
|
}
|
|
retarg_t _arg;
|
|
_arg.isBreaking=false;
|
|
_arg.isReturning=false;
|
|
res=func->data.internal_method.closure->data.closure_node.node->execute(func->data.internal_method.closure->data.closure_node.node,scope2,&_arg);
|
|
scope_end(scope2);
|
|
return res;
|
|
}
|
|
return tobject_basic(scope->rt,tundef);
|
|
}
|
|
void tobject_addref(tobject_t* obj)
|
|
{
|
|
obj->count++;
|
|
}
|
|
void tobject_freeifzero(tobject_t* obj)
|
|
{
|
|
if(obj->count<=0)
|
|
{
|
|
if(obj->type == tdict)
|
|
{
|
|
dict_free(obj->data.dict);
|
|
}
|
|
if(obj->type == tlist)
|
|
{
|
|
list_free(&obj->data.list);
|
|
}
|
|
if(obj->type == tstring)
|
|
{
|
|
string_free(obj->data.string);
|
|
}
|
|
if(obj->type == tinternalmethod)
|
|
{
|
|
node_t* n = obj->data.internal_method.closure;
|
|
node_free(n->data.closure_node.node);
|
|
int i;
|
|
for(i=0;i<n->data.closure_node.argNames.count;i++)
|
|
{
|
|
string_free(n->data.closure_node.argNames.strings[i]);
|
|
}
|
|
free(n->data.closure_node.argNames.strings);
|
|
node_free(n);
|
|
tscope_rmref(obj->data.internal_method.scope);
|
|
|
|
}
|
|
if(obj->free != NULL)
|
|
{
|
|
obj->free(obj);
|
|
}
|
|
free(obj);
|
|
|
|
}
|
|
}
|
|
void tobject_rmref(tobject_t* obj)
|
|
{
|
|
obj->count--;
|
|
tobject_freeifzero(obj);
|
|
|
|
}
|
|
tobject_t* tobject_number(runtime_t* rt,double num)
|
|
{
|
|
tobject_t* o = tobject_create(rt);
|
|
o->data.number = num;
|
|
o->type = tnumber;
|
|
return o;
|
|
}
|
|
tobject_t* tobject_charp(runtime_t* rt,const char* text)
|
|
{
|
|
string_t* s = string_create();
|
|
string_appendp(s,text);
|
|
return tobject_string(rt,s);
|
|
}
|
|
tobject_t* tobject_string(runtime_t* rt,string_t* str)
|
|
{
|
|
tobject_t* o = tobject_create(rt);
|
|
o->data.string = str;
|
|
o->type = tstring;
|
|
return o;
|
|
}
|
|
string_t* tobject_tostring(scope_t* sc,tobject_t* s)
|
|
{
|
|
if(s->type == tstring)
|
|
{
|
|
|
|
string_t* s2= string_dups(s->data.string);
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
if(s->type == tnumber)
|
|
{
|
|
string_t* s2 = string_create();
|
|
string_appendn(s2,s->data.number);
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
if(s->type == tchar)
|
|
{
|
|
string_t* s2 = string_create();
|
|
string_appendc(s2,s->data.chr);
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
if(s->type == tbool)
|
|
{
|
|
string_t* s2 = string_create();
|
|
string_appendp(s2,s->data.boolean ? "true" : "false");
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
if(s->type == tnull)
|
|
{
|
|
string_t* s2 = string_create();
|
|
string_appendp(s2, "null");
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
if(s->type == tdict)
|
|
{
|
|
string_t* s2 = string_create();
|
|
if(dict_haskey(s->data.dict,"toString"))
|
|
{
|
|
tobject_t* o2 = dict_getkvp(s->data.dict,"toString")->value;
|
|
if(o2->type == texternalmethod || o2->type == tinternalmethod)
|
|
{
|
|
list_tobject_t o;
|
|
list_create(sc->rt,&o,0);
|
|
tobject_t* res=tobject_call(sc,o2,&o);
|
|
list_free(&o);
|
|
|
|
|
|
string_t* str=tobject_tostring(sc,res);
|
|
|
|
tobject_freeifzero(o2);
|
|
tobject_freeifzero(s);
|
|
return str;
|
|
|
|
}
|
|
}
|
|
|
|
tobject_freeifzero(s);
|
|
return s2;
|
|
}
|
|
|
|
string_t* s3 = string_create();
|
|
string_appendp(s3, "undefined");
|
|
return s3;
|
|
}
|
|
|
|
tobject_t* tobject_bool(runtime_t* rt,bool b)
|
|
{
|
|
tobject_t* o = tobject_create(rt);
|
|
o->data.boolean = b;
|
|
o->type = tbool;
|
|
return o;
|
|
}
|
|
tobject_t* tobject_stringp(runtime_t* rt,const char* ptr)
|
|
{
|
|
string_t* str=string_create();
|
|
string_appendp(str,ptr);
|
|
return tobject_string(rt,str);
|
|
}
|
|
tobject_t* tobject_char(runtime_t* rt,char c)
|
|
{
|
|
tobject_t* o = tobject_create(rt);
|
|
o->data.chr = c;
|
|
o->type = tchar;
|
|
return o;
|
|
}
|
|
bool tobject_tobool(tobject_t* o)
|
|
{
|
|
if(o->type == tbool)
|
|
{
|
|
return o->data.boolean;
|
|
}
|
|
if(o->type == tnumber)
|
|
{
|
|
return o->data.number != 0;
|
|
}
|
|
if(o->type == tchar)
|
|
{
|
|
return o->data.chr != 0;
|
|
}
|
|
if(o->type == tdict)
|
|
{
|
|
return true;
|
|
}
|
|
if(o->type == tlist)
|
|
{
|
|
return o->data.list.length > 0;
|
|
}
|
|
if(o->type == tstring)
|
|
{
|
|
return o->data.list.length > 0;
|
|
}
|
|
if(o->type == texternalmethod)
|
|
{
|
|
return true;
|
|
}
|
|
if(o->type == tinternalmethod)
|
|
{
|
|
return true;
|
|
}
|
|
if(o->type == tnull)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
} |