ref: 1da09c81867fc8416f99b8d7a24d73b2e3acf6e6
dir: /prim.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "dat.h"
#include "fns.h"
/* NOTE: In LPA, system functions are treated as primitives as well */
/* monadic functions */
static Array *primfn_same(Array *);
static Array *primfn_shape(Array *);
/* dyadic functions */
static Array *primfn_left(Array *, Array *);
static Array *primfn_right(Array *, Array *);
static Array *primfn_match(Array *, Array *);
struct {
char *spelling;
int nameclass;
Array *(*nilad)(void);
Array *(*monad)(Array *);
Array *(*dyad)(Array *, Array *);
} primspecs[] = {
"⊢", NameclassFunc, nil, primfn_same, primfn_right,
"⊣", NameclassFunc, nil, primfn_same, primfn_left,
"+", NameclassFunc, nil, nil, nil,
"-", NameclassFunc, nil, nil, nil,
"⍴", NameclassFunc, nil, primfn_shape, nil,
"≡", NameclassFunc, nil, nil, primfn_match,
};
char *
primsymb(int id)
{
return primspecs[id].spelling;
}
int
primclass(int id)
{
return primspecs[id].nameclass;
}
int
primvalence(int id)
{
int valence = 0;
if(primspecs[id].monad)
valence |= Monadic;
if(primspecs[id].dyad)
valence |= Dyadic;
return valence;
}
int
primid(char *s)
{
for(int i = 0; i < nelem(primspecs); i++){
char *x = primspecs[i].spelling;
if(strncmp(s, x, strlen(x)) == 0)
return i;
}
return -1;
}
Array *
primnilad(int id)
{
if(primspecs[id].nilad)
return primspecs[id].nilad();
else
error(EInternal, "primitive %s has no niladic definition", primsymb(id));
}
Array *
primmonad(int id, Array *y)
{
if(primspecs[id].monad)
return primspecs[id].monad(y);
else
error(EInternal, "primitive %s has no monadic definition", primsymb(id));
}
Array *
primdyad(int id, Array *x, Array *y)
{
if(primspecs[id].dyad)
return primspecs[id].dyad(x, y);
else
error(EInternal, "primitive %s has no dyadic definition", primsymb(id));
}
/* monadic functions */
static Array *
primfn_same(Array *a)
{
return a;
}
static Array *
primfn_shape(Array *a)
{
Array *r;
int rank;
rank = getrank(a);
r = allocarray(TypeNumber, 1, rank);
for(int dim = 0; dim < rank; dim++)
setint(r, dim, getshape(a, dim));
return r;
}
/* dyadic functions */
static Array *
primfn_left(Array *x, Array *)
{
return x;
}
static Array *
primfn_right(Array *, Array *y)
{
return y;
}
static int
matches(Array *x, Array *y)
{
int res = 0;
usize size = 1;
int type = gettype(x);
if(gettype(x) != gettype(y))
goto no;
if(getrank(x) != getrank(y))
goto no;
for(int dim = 0; dim < getrank(x); dim++){
if(getshape(x, dim) != getshape(y, dim))
goto no;
size *= getshape(x, dim);
}
for(usize i = 0; i < size; i++){
switch(type){
case TypeNumber:
if(getint(x, i) != getint(y, i))
goto no;
break;
case TypeChar:
if(getchar(x, i) != getchar(y, i))
goto no;
break;
case TypeArray:
if(!matches(getarray(x, i), getarray(y, i))) /* TODO: RECURSION */
goto no;
/* TODO: that means we can save space by making them
* point to the same thing :)
*/
break;
default:
error(EInternal, "unknown element type");
}
}
res = 1;
no:
return res;
}
static Array *
primfn_match(Array *x, Array *y)
{
Array *z = allocarray(TypeNumber, 0, 1);
setint(z, 0, matches(x, y));
return z;
}