From 3b4b0fd33cfc9b9a78e83e1a8ba3fb104b99991a Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Tue, 24 Dec 2013 18:51:18 -0500 Subject: [PATCH] added more error handling, fixed a typo in the tokenizer --- errors.js | 17 +------------- parse.js | 67 +++++++++++++++++++++++++++++++++++++---------------- tokenize.js | 4 ++-- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/errors.js b/errors.js index e02eef9..05a1dab 100644 --- a/errors.js +++ b/errors.js @@ -5,20 +5,6 @@ * not thought about how that will work much */ -var JLException = { - stxerror : - function () { - console.log("There was an error\n", - "Line #",this.linenum,"\n", - "Character #", this.charnum,"\n", - this.errormessage); - }, - type_error : - function () { - return; - } -} - function JSyntaxError(linenum, charnum, message) { this.linenum = linenum; this.charnum = charnum; @@ -26,7 +12,7 @@ function JSyntaxError(linenum, charnum, message) { this.stxerror = function() { console.log("Syntax Error\n", "Line #", this.linenum,"\n", - "Character #", this.charnum, "\n", + "Near character #", this.charnum, "\n", this.errormessage); }; return this; @@ -39,7 +25,6 @@ function JTypeError(linenum, charnum, token, message) { this.token = token; return this; } -TypeError.prototype = JLException; module.exports = {JSyntaxError : JSyntaxError, diff --git a/parse.js b/parse.js index 38d1deb..5d2469a 100755 --- a/parse.js +++ b/parse.js @@ -37,7 +37,7 @@ function makeChecker(props) { /*Tries to parse until the prediction ``valid'' fails or the wrong type is parsed Collects the results into an array and returns it*/ -function parseMany(exprType, valid, tokens) { +function parseMany(exprType, valid, tokens, charnum, linenum) { var current = fst(tokens)[0]; var results = []; var parsed; @@ -46,7 +46,9 @@ function parseMany(exprType, valid, tokens) { parsed = parse(tokens); } else { - throw error.JSyntaxError(fst(tokens)[2], fst(tokens)[3], "unexpected token "+fst(tokens)[0]+" in parseMany"); + throw error.JSyntaxError(linenum, + charnum, + "unexpected token "+fst(tokens)[0]+" in parseMany"); } results.push(parsed); @@ -66,7 +68,9 @@ function parseMany(exprType, valid, tokens) { } //do the same validity check as before and in the loop if (!fst(tokens)) - throw "unexpected end of source"; + throw error.JSyntaxError(linenum, + charnum, + "unexpected end of source"); if (valid(fst(tokens)[0])) results.push(parse(tokens)); return results; @@ -76,7 +80,7 @@ function parseMany(exprType, valid, tokens) { /* Tries to parse exprType separated by the token between * e.g. ,,... */ -function parseBetween(exprType, between, tokens) { +function parseBetween(exprType, between, tokens, charnum, linenum) { var first = parse(tokens); if (!exprType(first)) { throw "unexpected token:"+fst(tokens)[0]; @@ -87,6 +91,10 @@ function parseBetween(exprType, between, tokens) { while (fst(tokens)[0] === between) { tokens.pop(); parsed = parse(tokens); + if (!fst(tokens)) + throw error.JSyntaxError(linenum, + charnum, + "Missing terminator: "+between); items.push(parsed); } return items; @@ -103,10 +111,12 @@ function parseList(tokens) { var xs = []; } else { - var xs = parseBetween(function (x) { return true; }, "comma", tokens); + var xs = parseBetween(function (x) { return true; }, "comma", tokens, fst(tokens)[3], fst(tokens)[2]); } if (fst(tokens)[0] !== "right_square") { - throw error.JSyntaxError(fst(tokens)[3], fst(tokens)[2], "list must be terminated by ]"); + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "list must be terminated by ]"); } tokens.pop(); return new typ.ListT(xs); @@ -116,16 +126,20 @@ function parseList(tokens) { function parseDefFunction(tokens) { var fname = parse(tokens); if (fname.exprType != "Name") { - throw error.JSyntaxError(fst(tokens)[3], fst(tokens)[2], "Expected an identifier in function definition"); + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "Expected an identifier in function definition"); } if (fst(tokens)[0] === "right_paren") { var parameters = []; } else { - var parameters = parseMany(validName, validFormPar, tokens); + var parameters = parseMany(validName, validFormPar, tokens, fst(tokens)[2], fst(tokens)[3]); } if ((fst(tokens)[0]) !== "right_paren") { - throw error.JSyntaxError(fst(tokens)[3], fst(tokens)[2],"Formal parameters must be followed by )"); + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "Formal parameters must be followed by )"); } tokens.pop(); var body = parse(tokens); @@ -155,12 +169,16 @@ function parseDef(tokens) { function parseIf(tokens) { if (!notFollowedBy(tokens, ["def","comma","lambda"])) { - throw "``if'' cannot be followed by "+fst(tokens)[0]; + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "``if'' cannot be followed by "+fst(tokens)[0]) ; } else { var ifC = parse(tokens); if (!fst(tokens) || fst(tokens)[0] !== "thenexp") - throw "if must be folowed by exp, not "+snd(tokens)[0]; + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "if ``exp'' must be folowed by ``then'' exp, not "+snd(tokens)[0]); else { tokens.pop(); var thenC = parse(tokens); @@ -183,10 +201,12 @@ var validFormPar = makeChecker(["identifier"]); var validName = makeChecker(["Name"]); function parseLambda(tokens) { - var parameters = parseMany(validName,validFormPar, tokens); + var parameters = parseMany(validName,validFormPar, tokens, fst(tokens)[2], fst(tokens)[3]); if (fst(tokens)[0] !== "arrow") { - throw "arrow must follow parameters in lambda, not "+fst(tokens)[0]; + throw error.JSyntaxError(fst(tokens)[3], + fst(tokens)[2], + "arrow must follow parameters in lambda, not "+fst(tokens)[0]); } tokens.pop() var body = parse(tokens); @@ -202,12 +222,14 @@ var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"])); var validOperator = makeChecker(["identifier"]); //Parses function application (either infix or prefix) -function computeApp(tokens) { +function computeApp(tokens, charnum, linenum) { var lhs = parse(tokens); if (fst(tokens)) var next = fst(tokens); else { - throw "Unexpected end of source"; + throw error.JSyntaxError(linenum, + charnum, + "Unexpected end of source"); } if (typ.OPInfo[next[1]]) { //it's an infix expression @@ -224,9 +246,11 @@ function computeApp(tokens) { else { //it's a prefix application - var parameters = parseMany(validArgTypes, validArgument, tokens); - if (fst(tokens)[0] !== "right_paren") { - throw "mismatched parentheses"; + var parameters = parseMany(validArgTypes, validArgument, tokens, fst(tokens)[2], fst(tokens)[3]); + if (!fst(tokens) || fst(tokens)[0] !== "right_paren") { + throw error.JSyntaxError(linenum, + charnum, + "Mismatched parentheses or missing parenthesis on right-hand side"); } else { //return the result @@ -267,8 +291,11 @@ function parseInfix(tokens, minPrec, lhs) { } function parse(tokens) { - if (fst(tokens)) + var charnum = fst(tokens)[2]; + var linenum = fst(tokens)[3]; + if (fst(tokens)) { var toktype = fst(tokens)[0]; + } else { process.exit(code=1); } @@ -300,7 +327,7 @@ function parse(tokens) { return parsed; } else - return computeApp(tokens); + return computeApp(tokens, charnum, linenum); } // else if (toktype === "let") { // return parseLet(tokens); diff --git a/tokenize.js b/tokenize.js index 8c42e77..b80e58a 100755 --- a/tokenize.js +++ b/tokenize.js @@ -112,7 +112,7 @@ function tokenizeStr(tokstream, charnum, linenum) { } -function tokenizeT(tokstreami, charnum, linenum) { +function tokenizeT(tokstream, charnum, linenum) { if (tokstream.length < 4) return false; var next4 = tokstream.substr(0,4); @@ -249,7 +249,7 @@ function tokenize(tokstream) { case 100: // 'd' var result = peek(tokstream, "def", "def"); if (result) { - tokens.push(result); + tokens.push(["def", "def", charnum, linenum]); tokstream = tokstream.substr(3); break; }