Browse Source

added more error handling, fixed a typo in the tokenizer

pull/1/head
Wesley Kerfoot 11 years ago
parent
commit
3b4b0fd33c
  1. 17
      errors.js
  2. 67
      parse.js
  3. 4
      tokenize.js

17
errors.js

@ -5,20 +5,6 @@
* not thought about how that will work much * 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) { function JSyntaxError(linenum, charnum, message) {
this.linenum = linenum; this.linenum = linenum;
this.charnum = charnum; this.charnum = charnum;
@ -26,7 +12,7 @@ function JSyntaxError(linenum, charnum, message) {
this.stxerror = function() { this.stxerror = function() {
console.log("Syntax Error\n", console.log("Syntax Error\n",
"Line #", this.linenum,"\n", "Line #", this.linenum,"\n",
"Character #", this.charnum, "\n", "Near character #", this.charnum, "\n",
this.errormessage); this.errormessage);
}; };
return this; return this;
@ -39,7 +25,6 @@ function JTypeError(linenum, charnum, token, message) {
this.token = token; this.token = token;
return this; return this;
} }
TypeError.prototype = JLException;
module.exports = module.exports =
{JSyntaxError : JSyntaxError, {JSyntaxError : JSyntaxError,

67
parse.js

@ -37,7 +37,7 @@ function makeChecker(props) {
/*Tries to parse until the prediction ``valid'' fails or the wrong type is parsed /*Tries to parse until the prediction ``valid'' fails or the wrong type is parsed
Collects the results into an array and returns it*/ 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 current = fst(tokens)[0];
var results = []; var results = [];
var parsed; var parsed;
@ -46,7 +46,9 @@ function parseMany(exprType, valid, tokens) {
parsed = parse(tokens); parsed = parse(tokens);
} }
else { 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); results.push(parsed);
@ -66,7 +68,9 @@ function parseMany(exprType, valid, tokens) {
} }
//do the same validity check as before and in the loop //do the same validity check as before and in the loop
if (!fst(tokens)) if (!fst(tokens))
throw "unexpected end of source"; throw error.JSyntaxError(linenum,
charnum,
"unexpected end of source");
if (valid(fst(tokens)[0])) if (valid(fst(tokens)[0]))
results.push(parse(tokens)); results.push(parse(tokens));
return results; return results;
@ -76,7 +80,7 @@ function parseMany(exprType, valid, tokens) {
/* Tries to parse exprType separated by the token between /* Tries to parse exprType separated by the token between
* e.g. <identifier>,<identifier>,... * e.g. <identifier>,<identifier>,...
*/ */
function parseBetween(exprType, between, tokens) { function parseBetween(exprType, between, tokens, charnum, linenum) {
var first = parse(tokens); var first = parse(tokens);
if (!exprType(first)) { if (!exprType(first)) {
throw "unexpected token:"+fst(tokens)[0]; throw "unexpected token:"+fst(tokens)[0];
@ -87,6 +91,10 @@ function parseBetween(exprType, between, tokens) {
while (fst(tokens)[0] === between) { while (fst(tokens)[0] === between) {
tokens.pop(); tokens.pop();
parsed = parse(tokens); parsed = parse(tokens);
if (!fst(tokens))
throw error.JSyntaxError(linenum,
charnum,
"Missing terminator: "+between);
items.push(parsed); items.push(parsed);
} }
return items; return items;
@ -103,10 +111,12 @@ function parseList(tokens) {
var xs = []; var xs = [];
} }
else { 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") { 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(); tokens.pop();
return new typ.ListT(xs); return new typ.ListT(xs);
@ -116,16 +126,20 @@ function parseList(tokens) {
function parseDefFunction(tokens) { function parseDefFunction(tokens) {
var fname = parse(tokens); var fname = parse(tokens);
if (fname.exprType != "Name") { 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") { if (fst(tokens)[0] === "right_paren") {
var parameters = []; var parameters = [];
} }
else { 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") { 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(); tokens.pop();
var body = parse(tokens); var body = parse(tokens);
@ -155,12 +169,16 @@ function parseDef(tokens) {
function parseIf(tokens) { function parseIf(tokens) {
if (!notFollowedBy(tokens, ["def","comma","lambda"])) { 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 { else {
var ifC = parse(tokens); var ifC = parse(tokens);
if (!fst(tokens) || fst(tokens)[0] !== "thenexp") if (!fst(tokens) || fst(tokens)[0] !== "thenexp")
throw "if <exp> must be folowed by <then> 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 { else {
tokens.pop(); tokens.pop();
var thenC = parse(tokens); var thenC = parse(tokens);
@ -183,10 +201,12 @@ var validFormPar = makeChecker(["identifier"]);
var validName = makeChecker(["Name"]); var validName = makeChecker(["Name"]);
function parseLambda(tokens) { 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") { 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() tokens.pop()
var body = parse(tokens); var body = parse(tokens);
@ -202,12 +222,14 @@ var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"]));
var validOperator = makeChecker(["identifier"]); var validOperator = makeChecker(["identifier"]);
//Parses function application (either infix or prefix) //Parses function application (either infix or prefix)
function computeApp(tokens) { function computeApp(tokens, charnum, linenum) {
var lhs = parse(tokens); var lhs = parse(tokens);
if (fst(tokens)) if (fst(tokens))
var next = fst(tokens); var next = fst(tokens);
else { else {
throw "Unexpected end of source"; throw error.JSyntaxError(linenum,
charnum,
"Unexpected end of source");
} }
if (typ.OPInfo[next[1]]) { if (typ.OPInfo[next[1]]) {
//it's an infix expression //it's an infix expression
@ -224,9 +246,11 @@ function computeApp(tokens) {
else { else {
//it's a prefix application //it's a prefix application
var parameters = parseMany(validArgTypes, validArgument, tokens); var parameters = parseMany(validArgTypes, validArgument, tokens, fst(tokens)[2], fst(tokens)[3]);
if (fst(tokens)[0] !== "right_paren") { if (!fst(tokens) || fst(tokens)[0] !== "right_paren") {
throw "mismatched parentheses"; throw error.JSyntaxError(linenum,
charnum,
"Mismatched parentheses or missing parenthesis on right-hand side");
} }
else { else {
//return the result //return the result
@ -267,8 +291,11 @@ function parseInfix(tokens, minPrec, lhs) {
} }
function parse(tokens) { function parse(tokens) {
if (fst(tokens)) var charnum = fst(tokens)[2];
var linenum = fst(tokens)[3];
if (fst(tokens)) {
var toktype = fst(tokens)[0]; var toktype = fst(tokens)[0];
}
else { else {
process.exit(code=1); process.exit(code=1);
} }
@ -300,7 +327,7 @@ function parse(tokens) {
return parsed; return parsed;
} }
else else
return computeApp(tokens); return computeApp(tokens, charnum, linenum);
} }
// else if (toktype === "let") { // else if (toktype === "let") {
// return parseLet(tokens); // return parseLet(tokens);

4
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) if (tokstream.length < 4)
return false; return false;
var next4 = tokstream.substr(0,4); var next4 = tokstream.substr(0,4);
@ -249,7 +249,7 @@ function tokenize(tokstream) {
case 100: // 'd' case 100: // 'd'
var result = peek(tokstream, "def", "def"); var result = peek(tokstream, "def", "def");
if (result) { if (result) {
tokens.push(result); tokens.push(["def", "def", charnum, linenum]);
tokstream = tokstream.substr(3); tokstream = tokstream.substr(3);
break; break;
} }

Loading…
Cancel
Save