summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2022-01-26 09:40:50 +0000
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2022-01-26 09:40:50 +0000
commitbcaf7f25f42b21067a26895e097ada73765ba7d5 (patch)
treeccfb887cf08619c17b3afa3b517bfc3dcdfa18ad
parent57a86f761605b6261d1045558c9cb7c83d723b60 (diff)
Implement a new "mixed" type which can be either of the three scalar types: int, float, rune. This allows scalar arrays with mixed scalar types
-rw-r--r--apl9.h14
-rw-r--r--array.c92
-rw-r--r--eval.c4
-rw-r--r--print.c38
-rw-r--r--quadnames.c35
5 files changed, 145 insertions, 38 deletions
diff --git a/apl9.h b/apl9.h
index b15b7e6..9004636 100644
--- a/apl9.h
+++ b/apl9.h
@@ -22,6 +22,7 @@ typedef enum
AtypeInt,
AtypeFloat,
AtypeRune,
+ AtypeMixed,
AtypeArray,
} arrayDataType;
@@ -57,6 +58,7 @@ typedef enum
} errorCodes;
/* Data types */
+typedef struct Mixed Mixed;
typedef struct Array Array;
typedef struct Statement Statement;
typedef struct Operator Operator;
@@ -69,6 +71,16 @@ typedef struct QuadnameDef QuadnameDef;
typedef struct ErrorHandler ErrorHandler;
typedef struct DfnFrame DfnFrame;
+struct Mixed
+{
+ int type;
+ union {
+ vlong i;
+ double f;
+ Rune r;
+ };
+};
+
struct Array
{
arrayDataType type;
@@ -82,6 +94,7 @@ struct Array
vlong *intdata;
double *floatdata;
Rune *runedata;
+ Mixed *mixeddata;
Array **arraydata;
};
};
@@ -222,6 +235,7 @@ Array *arrayitem(Array *, int);
Array *simplifyarray(Array *);
int comparearray(Array *, Array *, int);
Array *fillelement(Array *);
+uvlong arrayspaceused(Array *);
/* eval.c */
Datum *eval(Statement *, int);
diff --git a/array.c b/array.c
index b6bc87b..1ae2125 100644
--- a/array.c
+++ b/array.c
@@ -10,6 +10,7 @@ int datasizes[] = {
[AtypeInt] = sizeof(vlong),
[AtypeFloat] = sizeof(double),
[AtypeRune] = sizeof(Rune),
+ [AtypeMixed] = sizeof(Mixed),
[AtypeArray] = sizeof(Array *)
};
@@ -63,6 +64,7 @@ duparrayshape(Array *a, int type)
{
Array *b = allocarray(type, a->rank, a->size);
memcpy(b->shape, a->shape, sizeof(int) * a->rank);
+ b->stranded = a->stranded;
return b;
}
@@ -174,13 +176,21 @@ arrayitem(Array *a, int index)
case AtypeRune:
res = mkscalarrune(a->runedata[index]);
break;
+ case AtypeMixed:
+ switch(a->mixeddata[index].type){
+ case AtypeInt: res = mkscalarint(a->mixeddata[index].i); break;
+ case AtypeFloat: res = mkscalarfloat(a->mixeddata[index].f); break;
+ case AtypeRune: res = mkscalarrune(a->mixeddata[index].r); break;
+ default:
+ throwerror(L"Unhandled case in arrayitem", ENotImplemented);
+ }
+ break;
case AtypeArray:
res = a->arraydata[index];
incref(res);
break;
default:
- print("Unhandled case in arrayitem()\n");
- exits(nil);
+ throwerror(L"Unhandled case in arrayitem", ENotImplemented);
}
return res;
}
@@ -189,30 +199,40 @@ Array *
simplifyarray(Array *a)
{
/* simplify an array if possible. */
- if(a->type != AtypeArray || a->size == 0)
+ if((a->type != AtypeArray && a->type != AtypeMixed) || a->size == 0)
return fnSame(a);
- int type = a->arraydata[0]->type;
+ int nested = a->type == AtypeArray;
+ int type = nested ? a->arraydata[0]->type : a->mixeddata[0].type;
int canfloat = type == AtypeFloat || type == AtypeInt;
int sametype = 1;
+ int canmix = 1;
int i;
for(i = 0; i < a->size; i++){
- int t = a->arraydata[i]->type;
+ int t = nested ? a->arraydata[i]->type : a->mixeddata[i].type;
canfloat = canfloat && (t == AtypeFloat || t == AtypeInt);
sametype = sametype && (t == type);
- if(a->arraydata[i]->rank != 0)
+ canmix = canmix && (t != AtypeArray);
+ if(nested && a->arraydata[i]->rank != 0)
return fnSame(a); /* cannot be simplified */
}
if(sametype){
- Array *b = allocarray(type, a->rank, a->size);
- b->stranded = a->stranded;
- for(i = 0; i < a->rank; i++)
- b->shape[i] = a->shape[i];
+ Array *b = duparrayshape(a, type);
for(i = 0; i < a->size; i++){
- memcpy(b->rawdata + i * datasizes[type], a->arraydata[i]->rawdata, datasizes[type]);
- if(b->type == AtypeArray)
- incref(b->arraydata[i]);
+ if(nested){
+ memcpy(b->rawdata + i * datasizes[type], a->arraydata[i]->rawdata, datasizes[type]);
+ if(b->type == AtypeArray)
+ incref(b->arraydata[i]);
+ }else{
+ switch(b->type){
+ case AtypeInt: b->intdata[i] = a->mixeddata[i].i; break;
+ case AtypeFloat: b->floatdata[i] = a->mixeddata[i].f; break;
+ case AtypeRune: b->runedata[i] = a->mixeddata[i].r; break;
+ default:
+ throwerror(L"Missing case in simplifyarray", ENotImplemented);
+ }
+ }
}
if(b->type == AtypeArray){
Array *tmp = b;
@@ -221,15 +241,32 @@ simplifyarray(Array *a)
}
return b;
}else if(canfloat){
- Array *b = allocarray(AtypeFloat, a->rank, a->size);
- b->stranded = a->stranded;
- for(i = 0; i < a->rank; i++)
- b->shape[i] = a->shape[i];
+ Array *b = duparrayshape(a, AtypeFloat);
for(i = 0; i < a->size; i++){
- if(a->arraydata[i]->type == AtypeFloat)
- b->floatdata[i] = a->arraydata[i]->floatdata[0];
- else
- b->floatdata[i] = a->arraydata[i]->intdata[0];
+ if(nested){
+ if(a->arraydata[i]->type == AtypeFloat)
+ b->floatdata[i] = a->arraydata[i]->floatdata[0];
+ else
+ b->floatdata[i] = a->arraydata[i]->intdata[0];
+ }else{
+ if(a->mixeddata[i].type == AtypeFloat)
+ b->floatdata[i] = a->mixeddata[i].f;
+ else
+ b->floatdata[i] = a->mixeddata[i].i;
+ }
+ }
+ return b;
+ }else if(canmix && nested){
+ Array *b = duparrayshape(a, AtypeMixed);
+ for(i = 0; i < a->size; i++){
+ b->mixeddata[i].type = a->arraydata[i]->type;
+ switch(b->mixeddata[i].type){
+ case AtypeInt: b->mixeddata[i].i = a->arraydata[i]->intdata[0]; break;
+ case AtypeFloat: b->mixeddata[i].f = a->arraydata[i]->floatdata[0]; break;
+ case AtypeRune: b->mixeddata[i].r = a->arraydata[i]->runedata[0]; break;
+ default:
+ throwerror(L"Missing case in simplifyarray", ENotImplemented);
+ }
}
return b;
}else
@@ -304,4 +341,17 @@ fillelement(Array *a)
exits(nil);
return 0;
}
+}
+
+uvlong
+arrayspaceused(Array *a)
+{
+ uvlong size = 0;
+ size += sizeof(*a);
+ size += sizeof(int) * a->rank;
+ size += datasizes[a->type] * a->size;
+
+ for(int i = 0; i < a->size && a->type == AtypeArray; i++)
+ size += arrayspaceused(a->arraydata[i]);
+ return size;
} \ No newline at end of file
diff --git a/eval.c b/eval.c
index aff3f73..e33c3b5 100644
--- a/eval.c
+++ b/eval.c
@@ -164,9 +164,11 @@ strand(Datum left, Datum right)
result.shy = 0;
Array *leftarr = left.array->stranded ? fnSame(left.array) : fnEnclose(left.array);
Array *rightarr = right.array->stranded ? fnSame(right.array) : fnEnclose(right.array);
+ Array *tmp = fnCatenateFirst(leftarr, rightarr);
result.tag = ArrayTag;
- result.array = fnCatenateFirst(leftarr, rightarr);
+ result.array = simplifyarray(tmp);
result.array->stranded = 1;
+ freearray(tmp);
freearray(leftarr);
freearray(rightarr);
return result;
diff --git a/print.c b/print.c
index e46866c..3c119dd 100644
--- a/print.c
+++ b/print.c
@@ -63,24 +63,30 @@ pparray(Array *a)
Rune *arrstr = pparray(a->arraydata[i]);
elemstrs[i] = runesmprint("%S", arrstr);
free(arrstr);
- }else if(a->type == AtypeInt)
- elemstrs[i] = runesmprint("%lld", a->intdata[i]);
- else if(a->type == AtypeRune)
- elemstrs[i] = runesmprint("%C", a->runedata[i]);
- else if(a->type == AtypeFloat){
- char *fmt = smprint("%%.%df", printprecision);
- elemstrs[i] = runesmprint(fmt, a->floatdata[i]);
- free(fmt);
- Rune *p = &elemstrs[i][runestrlen(elemstrs[i])-1];
- int done = 0;
- while((*p == '0' || *p == '.') && !done){
- if(*p == '.')
- done = 1;
- *p-- = 0; /* remove trailing 0's */
+ }else{
+ Array *e = arrayitem(a, i); /* a scalar */
+ if(e->type == AtypeInt)
+ elemstrs[i] = runesmprint("%lld", e->intdata[0]);
+ else if(e->type == AtypeRune)
+ elemstrs[i] = runesmprint("%C", e->runedata[0]);
+ else if(e->type == AtypeFloat){
+ char *fmt = smprint("%%.%df", printprecision);
+ elemstrs[i] = runesmprint(fmt, e->floatdata[0]);
+ free(fmt);
+ Rune *p = &elemstrs[i][runestrlen(elemstrs[i])-1];
+ int done = 0;
+ while((*p == '0' || *p == '.') && !done){
+ if(*p == '.')
+ done = 1;
+ *p-- = 0; /* remove trailing 0's */
+ }
}
+
+ if(elemstrs[i][0] == '-' && (e->type == AtypeInt || e->type == AtypeFloat))
+ elemstrs[i][0] = L'¯';
+ freearray(e);
}
- if(elemstrs[i][0] == '-' && (a->type == AtypeInt || a->type == AtypeFloat))
- elemstrs[i][0] = L'¯';
+
}
int lastdim = a->rank ? a->shape[a->rank-1] : 1;
diff --git a/quadnames.c b/quadnames.c
index 8ce54e1..2646840 100644
--- a/quadnames.c
+++ b/quadnames.c
@@ -16,6 +16,7 @@ void setdiv(Datum);
Array *runfile(Array *);
Array *quadthrow1(Array *);
Array *quadthrow2(Array *, Array *);
+Array *quadinfo(Array *);
QuadnameDef quadnames[] = {
{L"⎕", NameTag, getquad, setquad, nil, nil},
@@ -24,6 +25,7 @@ QuadnameDef quadnames[] = {
{L"⎕DIV", NameTag, getdiv, setdiv, nil, nil},
{L"⎕RUN", FunctionTag, nil, nil, runfile, nil},
{L"⎕THROW", FunctionTag, nil, nil, quadthrow1, quadthrow2},
+ {L"⎕INFO", FunctionTag, nil, nil, quadinfo, nil},
{nil, 0, nil, nil, nil, nil} /* MUST BE LAST */
};
@@ -190,4 +192,37 @@ quadthrow2(Array *msg, Array *code)
throwerror(nil, ERank);
throwerror(pparray(msg), code->intdata[0]);
return nil;
+}
+
+/* ⎕INFO */
+Array *
+quadinfo(Array *a)
+{
+ if(a->type != AtypeRune)
+ throwerror(nil, EType);
+ Rune *code = pparray(a);
+ Datum *res = evalline(code, nil, 0);
+ Rune *info;
+ switch(res->tag){
+ case ArrayTag:{
+ char *typestring = "?";
+ switch(res->array->type){
+ case AtypeInt: typestring = "int"; break;
+ case AtypeFloat: typestring = "float"; break;
+ case AtypeRune: typestring = "rune"; break;
+ case AtypeMixed: typestring = "mixed"; break;
+ case AtypeArray: typestring = "array"; break;
+ }
+ uvlong size = arrayspaceused(res->array);
+ info = runesmprint("Type = %s, size in bytes = %ulld", typestring, size);
+ break;
+ }
+ default:
+ info = runesmprint("Can't show info for datum tag %d", res->tag);
+ }
+ Array *infoarr = mkrunearray(info);
+ free(code);
+ free(res);
+ free(info);
+ return infoarr;
} \ No newline at end of file