summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apl9.h37
-rw-r--r--error.c29
-rw-r--r--eval.c49
-rw-r--r--functions.c192
-rw-r--r--lexer.c5
-rw-r--r--main.c22
-rw-r--r--mkfile1
-rw-r--r--operators.c7
-rw-r--r--quadnames.c2
9 files changed, 194 insertions, 150 deletions
diff --git a/apl9.h b/apl9.h
index bf74bf4..d51bde1 100644
--- a/apl9.h
+++ b/apl9.h
@@ -39,6 +39,20 @@ typedef enum
FunctypeQuad,
} functionType;
+typedef enum
+{
+ ESyntax = 1,
+ EParse,
+ EValue,
+ EDomain,
+ ERank,
+ EType,
+ ELength,
+ EIndex,
+ EShape,
+ ENotImplemented,
+} errorCodes;
+
/* Data types */
typedef struct Array Array;
typedef struct Statement Statement;
@@ -48,6 +62,8 @@ typedef struct Datum Datum;
typedef struct Symbol Symbol;
typedef struct Symtab Symtab;
typedef struct QuadnameDef QuadnameDef;
+typedef struct ErrorHandler ErrorHandler;
+
struct Array
{
arrayDataType type;
@@ -143,6 +159,12 @@ struct QuadnameDef
opdyad dyadop;
};
+struct ErrorHandler
+{
+ Rune *msg;
+ jmp_buf jmp;
+};
+
/* Function prototypes for the different source files */
/* main.c */
Datum *evalline(Rune *, int);
@@ -196,6 +218,16 @@ Array *rundfn(Rune *, Array *, Array *);
/* quadnames.c */
Datum quadnamedatum(QuadnameDef);
+/* error.c */
+void throwerror(Rune *, int);
+#define SETUPERROR(e) {\
+ jmp_buf old;\
+ memcpy(old, globalerror.jmp, sizeof(jmp_buf));\
+ e = setjmp(globalerror.jmp);\
+ if(e != 0)\
+ memcpy(globalerror.jmp, old, sizeof(jmp_buf));\
+}
+
/* Monadic functions from function.c */
Array *fnSame(Array *);
Array *fnTally(Array *);
@@ -238,7 +270,6 @@ Array *opOver(Datum *, Datum *, Array *, Array *);
/* Global variables */
extern int traceeval; /* eval.c */
extern int debugmem; /* memory.c */
-extern Rune *errormsg; /* eval.c */
extern int datasizes[]; /* array.c */
extern Rune primfuncnames[]; /* functions.c */
extern Rune primmonopnames[]; /* operators.c */
@@ -252,4 +283,6 @@ extern Symtab *globalsymtab; /* symbol.c */
extern Symtab *currentsymtab; /* symbol.c */
extern int alloccounts; /* memory.c */
extern QuadnameDef quadnames[]; /* quadnames.c */
-extern int printprecision; /* print.c */ \ No newline at end of file
+extern int printprecision; /* print.c */
+extern ErrorHandler globalerror; /* error.c */
+extern Rune *errorstrs[]; /* error.c */ \ No newline at end of file
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..2d69457
--- /dev/null
+++ b/error.c
@@ -0,0 +1,29 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "apl9.h"
+
+ErrorHandler globalerror;
+
+Rune *errorstrs[] = {
+ [ESyntax] = L"SYNTAX ERROR",
+ [EParse] = L"PARSE ERROR",
+ [EValue] = L"VALUE ERROR",
+ [EDomain] = L"DOMAIN ERROR",
+ [ERank] = L"RANK ERROR",
+ [EType] = L"TYPE ERROR",
+ [ELength] = L"LENGTH ERROR",
+ [EIndex] = L"INDEX ERROR",
+ [EShape] = L"SHAPE ERROR",
+ [ENotImplemented] = L"NOT IMPLEMENTED",
+};
+
+void
+throwerror(Rune *msg, int err)
+{
+ free(globalerror.msg);
+ globalerror.msg = msg ? runestrdup(msg) : nil;
+ longjmp(globalerror.jmp, err);
+}
+
diff --git a/eval.c b/eval.c
index e794a38..bfe211e 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,6 @@
#define traceprint if(traceeval)print
-Rune *errormsg;
int traceeval;
typedef Datum (*evalfn)(Datum, Datum);
@@ -54,16 +53,9 @@ evalfn evalfns[11][11] = {
Datum *
eval(Statement *stmt, int toplevel)
{
- errormsg = nil;
-
/* start by looking up first variable if needed */
- if(stmt->ntoks > 0 && stmt->toks[stmt->ntoks-1].tag == NameTag){
- Datum *value = lookup(stmt->toks[stmt->ntoks-1]);
- if(value == nil)
- return nil;
- else
- stmt->toks[stmt->ntoks-1] = *value;
- }
+ if(stmt->ntoks > 0 && stmt->toks[stmt->ntoks-1].tag == NameTag)
+ stmt->toks[stmt->ntoks-1] = *lookup(stmt->toks[stmt->ntoks-1]);;
while(stmt->ntoks > 1){
int maxlevel = 0;
@@ -82,13 +74,8 @@ retry:
}
if(level == 0 && stmt->toks[offset-1].tag == NameTag){
- Datum *value = lookup(stmt->toks[offset-1]);
- if(value == nil)
- return nil;
- else{
- stmt->toks[offset-1] = *value;
- goto retry;
- }
+ stmt->toks[offset-1] = *lookup(stmt->toks[offset-1]);
+ goto retry;
}else if(level < maxlevel){
Datum left = stmt->toks[offset];
Datum right = stmt->toks[offset+1];
@@ -98,10 +85,9 @@ retry:
}else if(level > maxlevel)
maxlevel = level;
}
- if(maxlevel == 0){
- errormsg = L"No reduce rule. Syntax error.";
- return nil;
- }else{
+ if(maxlevel == 0)
+ throwerror(L"No reduce rule", EParse);
+ else{
Datum new = fn(stmt->toks[offset],stmt->toks[offset+1]);
traceprint("handler fn done\n");
if(stmt->toks[offset].tag == ArrayTag)
@@ -135,12 +121,13 @@ retry:
guardOK = 0;
else if(stmt->toks[0].array->intdata[0] != 0 && stmt->toks[0].array->intdata[0] != 1)
guardOK = 0;
- if(!guardOK){
- print("Guard expected single valued boolean\n");
- exits(nil);
+ if(!guardOK)
+ throwerror(L"Guard expected single valued boolean", EDomain);
+ else{
+ stop = 0;
+ if(stmt->toks[0].array->intdata[0] == 1)
+ return eval(stmt->guard, toplevel);
}
- if(stmt->toks[0].array->intdata[0] == 1)
- return eval(stmt->guard, toplevel);
}
if(stmt->next && !stop)
return eval(stmt->next, toplevel);
@@ -156,8 +143,8 @@ lookup(Datum var)
traceprint("VAR LOOKUP %S\n", var.symbol->name);
if(var.symbol->undefined){
- errormsg = runesmprint("Variable undefined: %S\n", var.symbol->name);
- return nil;
+ Rune *msg = runesmprint("Undefined name: %S", var.symbol->name);
+ throwerror(msg, EValue);
}
Datum *val;
@@ -240,10 +227,8 @@ assign(Datum left, Datum right)
{
if(left.symbol->setfn != nil){
int ok = left.symbol->setfn(right);
- if(!ok){
- print("Assignment failed\n");
- exits(nil);
- }
+ if(!ok)
+ throwerror(nil, ESyntax);
}else{
if(left.symbol->undefined == 0 && left.symbol->value.tag == ArrayTag)
freearray(left.symbol->value.array);
diff --git a/functions.c b/functions.c
index 55a72ad..3e5c902 100644
--- a/functions.c
+++ b/functions.c
@@ -143,21 +143,52 @@ runfunc(Function f, Array *left, Array *right)
currentsymtab = tmpsymtab;
return (*dfnres).array; /* TODO what if the evaluation failed */
}else if(f.type == FunctypePrim){
- if(left)
- return dyadfunctiondefs[f.code](left, right);
- else
- return monadfunctiondefs[f.code](right);
+ if(left){
+ fndyad d = dyadfunctiondefs[f.code];
+ if(d == nil){
+ Rune *err = runesmprint("dyadic %C", primfuncnames[f.code]);
+ throwerror(err, ENotImplemented);
+ }
+ return d(left, right);
+ }else{
+ fnmonad m = monadfunctiondefs[f.code];
+ if(m == nil){
+ Rune *err = runesmprint("monadic %C", primfuncnames[f.code]);
+ throwerror(err, ENotImplemented);
+ }
+ return m(right);
+ }
}else if(f.type == FunctypeOp){
/* TODO assumes prim op, not dop */
- if(f.operator.dyadic)
- return dyadoperatordefs[f.operator.code](f.operator.left, f.operator.right, left, right);
- else
- return monadoperatordefs[f.operator.code](f.operator.left, left, right);
+ if(f.operator.dyadic){
+ opdyad d = dyadoperatordefs[f.operator.code];
+ if(d == nil){
+ Rune *err = runesmprint("dyadic %C", primdyadopnames[f.operator.code]);
+ throwerror(err, ENotImplemented);
+ }
+ return d(f.operator.left, f.operator.right, left, right);
+ }else{
+ opmonad m = monadoperatordefs[f.operator.code];
+ if(m == nil){
+ Rune *err = runesmprint("monadic %C", primmonopnames[f.operator.code]);
+ throwerror(err, ENotImplemented);
+ }
+ return m(f.operator.left, left, right);
+ }
}else if(f.type == FunctypeQuad){
- if(left)
+ if(left){
+ if(f.quad->dyadfn == nil){
+ Rune *err = runesmprint("dyadic %S", f.quad->name);
+ throwerror(err, ENotImplemented);
+ }
return f.quad->dyadfn(left, right);
- else
+ }else{
+ if(f.quad->monadfn == nil){
+ Rune *err = runesmprint("monadic %S", f.quad->name);
+ throwerror(err, ENotImplemented);
+ }
return f.quad->monadfn(right);
+ }
}else
return nil;
}
@@ -306,10 +337,8 @@ fnEnclose(Array *right)
Array *
fnGradeUp(Array *right)
{
- if(right->rank == 0){
- print("Rank 0 not allowed in ⍋\n");
- exits("rank");
- }
+ if(right->rank == 0)
+ throwerror(nil, ERank);
int i,j;
int len = right->shape[0];
@@ -488,16 +517,12 @@ fnPlus(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 0);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++){
@@ -519,16 +544,12 @@ fnMinus(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 0);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++){
@@ -550,16 +571,12 @@ fnTimes(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 0);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++){
@@ -581,16 +598,12 @@ fnDivide(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 1);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++)
@@ -608,16 +621,12 @@ fnPower(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 0);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++){
@@ -639,16 +648,12 @@ fnLogarithm(Array *left, Array *right)
Array *leftarr;
Array *rightarr;
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
int typeok = commontype(leftarr, rightarr, &left, &right, 1);
- if(!typeok){
- print("Types don't match lol\n");
- exits(nil);
- }
+ if(!typeok)
+ throwerror(nil, EType);
Array *res = duparray(left);
for(int i = 0; i < left->size; i++)
@@ -686,10 +691,12 @@ fnMatch(Array *left, Array *right)
Array *
fnTake(Array *left, Array *right)
{
- if(left->type != AtypeInt || left->rank > 1 || left->size > right->rank){
- print("Invalid left arg to ↑\n");
- exits(nil);
- }
+ if(left->type != AtypeInt)
+ throwerror(nil, EType);
+ if(left->rank > 1)
+ throwerror(nil, ERank);
+ if(left->size > right->rank)
+ throwerror(nil, ELength);
int i;
if(left->size == right->rank)
@@ -749,18 +756,12 @@ fnIndex(Array *left, Array *right)
int io = currentsymtab->io;
int i;
- if(left->rank > 1){
- print("Index vector rank too large\n");
- exits(nil);
- }
- if(left->type != AtypeArray && left->type != AtypeInt){
- print("Index vector wrong type\n");
- exits(nil);
- }
- if(left->size > right->rank){
- print("Index vector too long\n");
- exits(nil);
- }
+ if(left->rank > 1)
+ throwerror(nil, ERank);
+ if(left->type != AtypeArray && left->type != AtypeInt)
+ throwerror(nil, EType);
+ if(left->size > right->rank)
+ throwerror(nil, ELength);
/* extend left index vector to full format */
Array *oldleft = left;
@@ -772,22 +773,16 @@ fnIndex(Array *left, Array *right)
left->arraydata[i] = fnIndexGenerator(n);
freearray(n);
}else if(oldleft->type == AtypeInt){
- if(oldleft->intdata[i] < io || oldleft->intdata[i] >= io + right->shape[i]){
- print("Index error\n");
- exits(nil);
- }
+ if(oldleft->intdata[i] < io || oldleft->intdata[i] >= io + right->shape[i])
+ throwerror(nil, EIndex);
left->arraydata[i] = mkscalarint(oldleft->intdata[i]);
}else if(oldleft->type == AtypeArray){
Array *sub = oldleft->arraydata[i];
- if(sub->type != AtypeInt){
- print("Type error\n");
- exits(nil);
- }
+ if(sub->type != AtypeInt)
+ throwerror(nil, EType);
for(int j = 0; j < sub->size; j++){
- if(sub->intdata[j] < io || sub->intdata[j] >= io + right->shape[i]){
- print("Index error\n");
- exits(nil);
- }
+ if(sub->intdata[j] < io || sub->intdata[j] >= io + right->shape[i])
+ throwerror(nil, EIndex);
}
left->arraydata[i] = oldleft->arraydata[i];
incref(left->arraydata[i]);
@@ -846,8 +841,8 @@ fnIndex(Array *left, Array *right)
Array *
fnCatenateFirst(Array *left, Array *right)
{
- Array *leftarr;
- Array *rightarr;
+ Array *leftarr = nil;
+ Array *rightarr = nil;
if(left->rank == 0 && right->rank != 0){
/* extend left to right->rank with first axis=1 */
@@ -890,17 +885,12 @@ fnCatenateFirst(Array *left, Array *right)
}else if(right->rank == left->rank){
leftarr = fnSame(left);
rightarr = fnSame(right);
- }else{
- print("Ranks don't match\n");
- exits(nil);
- return nil;
- }
+ }else
+ throwerror(nil, ERank);
for(int i = 1; i < leftarr->rank; i++)
- if(leftarr->shape[i] != rightarr->shape[i]){
- print("Shapes don't match, lol\n");
- exits(nil);
- }
+ if(leftarr->shape[i] != rightarr->shape[i])
+ throwerror(nil, EShape);
}
int type, rank, leftsize, rightsize;
diff --git a/lexer.c b/lexer.c
index f734912..626d181 100644
--- a/lexer.c
+++ b/lexer.c
@@ -182,11 +182,12 @@ get_digits:
else
stmt->toks[stmt->ntoks].array = mkrunearray(buf);
}else{
+ Rune *err;
syntax_error:
- print("Can't lex: %S\n", &line[offset]);
+ err = runesmprint("Can't lex: %S", &line[offset]);
free(stmt->toks);
free(stmt);
- return 0;
+ throwerror(err, ESyntax);
}
stmt->ntoks++;
}
diff --git a/main.c b/main.c
index 96a6d07..13750ef 100644
--- a/main.c
+++ b/main.c
@@ -27,23 +27,31 @@ main(int argc, char *argv[])
break;
}ARGEND
+ int errorcode;
+restart:
+ SETUPERROR(errorcode);
+ if(errorcode){
+ if(globalerror.msg)
+ print("%S: %S\n", errorstrs[errorcode], globalerror.msg);
+ else
+ print("%S\n", errorstrs[errorcode]);
+ goto restart;
+ }
+
while(!off){
checkmem("main loop");
Rune *input = prompt(L"\t");
Datum *result = evalline(input, 1);
- if(result == nil){
- if(errormsg == nil)
- off = 1;
- else
- print("ERROR: %S\n", errormsg);
- }else{
+ if(result == nil)
+ continue;
+ else{
if(result[0].shy == 0)
print("%S\n", ppdatum(*result));
if(result->tag == ArrayTag)
freearray(result->array);
free(result);
}
- print("Unfreed arrays: %d\n", alloccounts);
+ /* print("Unfreed arrays: %d\n", alloccounts); */
}
exits(nil);
}
diff --git a/mkfile b/mkfile
index ac9967f..ba72c81 100644
--- a/mkfile
+++ b/mkfile
@@ -12,6 +12,7 @@ OFILES=\
memory.$O\
operators.$O\
quadnames.$O\
+ error.$O\
HFILES=\
apl9.h\
diff --git a/operators.c b/operators.c
index 226f27b..65948de 100644
--- a/operators.c
+++ b/operators.c
@@ -36,12 +36,9 @@ opEach(Datum *lefto, Array *left, Array *right)
Array *leftarr;
Array *rightarr;
if(left){
-
int rankok = scalarextend(left, right, &leftarr, &rightarr);
- if(!rankok){
- print("Ranks don't match lol\n");
- exits(nil);
- }
+ if(!rankok)
+ throwerror(nil, ERank);
}else{
leftarr = nil;
rightarr = fnSame(right);
diff --git a/quadnames.c b/quadnames.c
index e7ebbdd..a582abb 100644
--- a/quadnames.c
+++ b/quadnames.c
@@ -43,7 +43,7 @@ quadnamedatum(QuadnameDef q)
case DyadicOpTag:
default:
print("Can't use quad names with type=%d\n", q.tag);
- exits("quadname");
+ exits(nil);
}
return d;
}