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
*/
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,

67
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. <identifier>,<identifier>,...
*/
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 <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 {
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);

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)
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;
}

Loading…
Cancel
Save