Browse Source

almost done adding let forms to the language, made sure to throw exceptions in most places

pull/1/head
Wesley Kerfoot 12 years ago
parent
commit
fc6c61994d
  1. 72
      parse.js
  2. 18
      representation.js
  3. 27
      tokenize.js
  4. 11
      tools.js
  5. 0
      typecheck.js

72
parse.js

@ -43,12 +43,9 @@ function parseMany(exprType, valid, tokens) {
if (valid(fst(tokens)[0])) { if (valid(fst(tokens)[0])) {
parsed = parse(tokens); parsed = parse(tokens);
//console.log(parsed.exprType);
} }
else { else {
console.log("Error: unexpected token "+fst(tokens)); throw "Error: unexpected token "+fst(tokens)[0]+" in parseMany";
console.log("in parseMany," + ", " + tokens);
return;
} }
results.push(parsed); results.push(parsed);
@ -61,13 +58,14 @@ function parseMany(exprType, valid, tokens) {
results.push(parse(tokens)); results.push(parse(tokens));
if (!exprType(fst(results).exprType)) if (!exprType(fst(results).exprType))
break; break;
//console.log(results);
current = fst(tokens)[0] current = fst(tokens)[0]
if (tokens.length <= 1) if (tokens.length <= 1)
break; break;
} }
} }
//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))
throw "Error: 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;
@ -80,8 +78,7 @@ function parseMany(exprType, valid, tokens) {
function parseBetween(exprType, between, tokens) { function parseBetween(exprType, between, tokens) {
var first = parse(tokens); var first = parse(tokens);
if (!exprType(first)) { if (!exprType(first)) {
console.log("Error, unexpected token:"+fst(tokens)[0]); throw "Error, unexpected token:"+fst(tokens)[0];
return;
} }
var items = [first]; var items = [first];
var parsed; var parsed;
@ -108,8 +105,7 @@ function parseList(tokens) {
var xs = parseBetween(function (x) { return true; }, "comma", tokens); var xs = parseBetween(function (x) { return true; }, "comma", tokens);
} }
if (fst(tokens)[0] !== "right_square") { if (fst(tokens)[0] !== "right_square") {
console.log("Error, list must be terminated by ]"); throw "Error, list must be terminated by ]";
return undefined;
} }
tokens.pop(); tokens.pop();
return new typ.ListT(xs); return new typ.ListT(xs);
@ -119,8 +115,7 @@ function parseList(tokens) {
function parseDefFunction(tokens) { function parseDefFunction(tokens) {
var fname = parse(tokens); var fname = parse(tokens);
if (!fname.exprType === "identifier") { if (!fname.exprType === "identifier") {
console.log("Error, expected an identifier in function definition"); throw "Error, expected an identifier in function definition";
return undefined;
} }
if (fst(tokens)[0] === "right_paren") { if (fst(tokens)[0] === "right_paren") {
var parameters = []; var parameters = [];
@ -129,8 +124,7 @@ function parseDefFunction(tokens) {
var parameters = parseMany(validName, validFormPar, tokens); var parameters = parseMany(validName, validFormPar, tokens);
} }
if ((fst(tokens)[0]) !== "right_paren") { if ((fst(tokens)[0]) !== "right_paren") {
console.log("Error, formal parameters must be followed by )"); throw "Error, formal parameters must be followed by )";
return undefined;
} }
tokens.pop(); tokens.pop();
var body = parse(tokens); var body = parse(tokens);
@ -146,14 +140,12 @@ function parseDef(tokens) {
return parseDefFunction(tokens); return parseDefFunction(tokens);
} }
if (notFollowedBy(tokens, ["identifier"])) { if (notFollowedBy(tokens, ["identifier"])) {
console.log("Error: def must be followed by identifier, not "+fst(tokens)[0]); throw "Error: def must be followed by identifier, not "+fst(tokens)[0];
return undefined;
} }
else { else {
var identifier = parse(tokens); var identifier = parse(tokens);
if (!notFollowedBy(tokens, ["def", "comma", "arrow", "right_brace", "right_square"])) { if (!notFollowedBy(tokens, ["def", "comma", "arrow", "right_brace", "right_square"])) {
console.log("Error: def " + identifier.val + " must not be followed by " + fst(tokens)[0]); throw "Error: def " + identifier.val + " must not be followed by " + fst(tokens)[0];
return;
} }
return new typ.Def(identifier, parse(tokens)); return new typ.Def(identifier, parse(tokens));
} }
@ -162,13 +154,12 @@ function parseDef(tokens) {
function parseIf(tokens) { function parseIf(tokens) {
if (!notFollowedBy(tokens, ["def","comma","lambda"])) { if (!notFollowedBy(tokens, ["def","comma","lambda"])) {
console.log("Error: ``if'' cannot be followed by "+fst(tokens)[0]) throw "Error: ``if'' cannot be followed by "+fst(tokens)[0];
return;
} }
else { else {
var ifC = parse(tokens); var ifC = parse(tokens);
if (!fst(tokens) || fst(tokens)[0] !== "thenexp") if (!fst(tokens) || fst(tokens)[0] !== "thenexp")
console.log("Error: if <exp> must be folowed by <then> exp, not "+snd(tokens)[0]); throw "Error: 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);
@ -194,8 +185,7 @@ function parseLambda(tokens) {
var parameters = parseMany(validName,validFormPar, tokens); var parameters = parseMany(validName,validFormPar, tokens);
if (fst(tokens)[0] !== "arrow") { if (fst(tokens)[0] !== "arrow") {
console.log("Error: arrow must follow parameters in lambda, not "+fst(tokens)[0]) throw "Error: arrow must follow parameters in lambda, not "+fst(tokens)[0];
return;
} }
tokens.pop() tokens.pop()
var body = parse(tokens); var body = parse(tokens);
@ -207,31 +197,19 @@ var validArgument = tool.compose(tool.not, makeChecker(invalidArguments));
var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"])); var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"]));
var validOperator = makeChecker(["identifier"]); var validOperator = makeChecker(["identifier"]);
function checkParse(p) {
if (p === undefined) {
console.log("Quitting, could not finish parsing!");
process.exit(code=1);
}
else
return p;
}
//Parses function application (either infix or prefix) //Parses function application (either infix or prefix)
function computeApp(tokens) { function computeApp(tokens) {
var lhs = parse(tokens); var lhs = parse(tokens);
//console.log(lhs);
if (fst(tokens)) if (fst(tokens))
var next = fst(tokens); var next = fst(tokens);
else { else {
console.log("Unexpected end of source"); throw "Error: Unexpected end of source";
process.exit(code=1);
} }
if (typ.OPInfo[next[1]]) { if (typ.OPInfo[next[1]]) {
//it's an infix expression //it's an infix expression
var result = parseInfix(tokens, 1, lhs); var result = parseInfix(tokens, 1, lhs);
if (fst(tokens)[0] !== "right_paren") { if (fst(tokens)[0] !== "right_paren") {
console.log("Error: mismatched parentheses"); throw "Error: mismatched parentheses";
process.exit(code=1);
} }
else { else {
//return the result //return the result
@ -243,10 +221,8 @@ function computeApp(tokens) {
//it's a prefix application //it's a prefix application
var parameters = parseMany(validArgTypes, validArgument, tokens); var parameters = parseMany(validArgTypes, validArgument, tokens);
//console.log(parameters);
if (fst(tokens)[0] !== "right_paren") { if (fst(tokens)[0] !== "right_paren") {
console.log("Error: mismatched parentheses"); throw "Error: mismatched parentheses";
process.exit(code=1);
} }
else { else {
//return the result //return the result
@ -267,8 +243,7 @@ function parseInfix(tokens, minPrec, lhs) {
while (true) { while (true) {
var cur = fst(tokens); var cur = fst(tokens);
if (!cur) { if (!cur) {
console.log("Unexpected end of source") throw "Error: Unexpected end of source";
process.exit(code=1);
} }
var opinfo = typ.OPInfo[cur[1]]; var opinfo = typ.OPInfo[cur[1]];
@ -291,7 +266,6 @@ function parse(tokens) {
if (fst(tokens)) if (fst(tokens))
var toktype = fst(tokens)[0]; var toktype = fst(tokens)[0];
else { else {
//console.log("Unexpected end of source")
process.exit(code=1); process.exit(code=1);
} }
var token = fst(tokens)[1]; var token = fst(tokens)[1];
@ -301,7 +275,7 @@ function parse(tokens) {
else if (toktype === "left_square") else if (toktype === "left_square")
return parseList(tokens); return parseList(tokens);
else if (toktype === "lambda") else if (toktype === "lambda")
return checkParse(parseLambda(tokens)); return parseLambda(tokens);
else if (toktype === "integer") else if (toktype === "integer")
return new typ.IntT(token); return new typ.IntT(token);
else if (toktype === "float") else if (toktype === "float")
@ -311,22 +285,24 @@ function parse(tokens) {
else if (toktype === "truelit" || toktype === "falselit") else if (toktype === "truelit" || toktype === "falselit")
return new typ.BoolT(token); return new typ.BoolT(token);
else if (toktype === "def") else if (toktype === "def")
return checkParse(parseDef(tokens)); return parseDef(tokens);
else if (toktype === "ifexp") else if (toktype === "ifexp")
return checkParse(parseIf(tokens)); return parseIf(tokens);
else if (toktype === "left_paren") { else if (toktype === "left_paren") {
if (fst(tokens)[0] === "lambda") { if (fst(tokens)[0] === "lambda") {
tokens.pop(); tokens.pop();
var parsed = checkParse(parseLambda(tokens)); var parsed = parseLambda(tokens);
tokens.pop(); tokens.pop();
return parsed; return parsed;
} }
else else
return computeApp(tokens); return computeApp(tokens);
} }
/*else if (toktype === "let") {
return parseLet(tokens);
}*/
else { else {
console.log("Unexpected token: " + toktype); throw "Error: Unexpected token: " + toktype;
process.exit(code=1);
} }
} }

18
representation.js

@ -1,3 +1,5 @@
var tool = require("./tools.js");
var Expression = { var Expression = {
display : display :
function() { function() {
@ -18,6 +20,17 @@ var Expression = {
} }
}; };
function LetExp(pairs) {
if (!pairs.every(function(x) {
return x.exprType === "Name";
})) {
throw "let can only be used to bind things to names";
}
this.exprType = "Let";
this.val = tool.dict(pairs);
return this;
}
function UnaryOp(op, v) { function UnaryOp(op, v) {
this.exprType = "Unary"; this.exprType = "Unary";
this.val = v; this.val = v;
@ -170,6 +183,8 @@ OPInfo = {"+" : [3, "Left"],
">=" : [2, "Left"], ">=" : [2, "Left"],
"<" : [2, "Left"], "<" : [2, "Left"],
"<=" : [2, "Left"], "<=" : [2, "Left"],
"&&" : [2, "Left"],
"||" : [2, "Left"],
":" : [2, "Left"], ":" : [2, "Left"],
"$" : [1, "Left"], "$" : [1, "Left"],
">>" : [1, "Left"], ">>" : [1, "Left"],
@ -194,4 +209,5 @@ module.exports =
If : If, If : If,
DefFunc : DefFunc, DefFunc : DefFunc,
UnaryOp : UnaryOp, UnaryOp : UnaryOp,
Nil : Nil } Nil : Nil,
LetExp : LetExp}

27
tokenize.js

@ -96,8 +96,7 @@ function tokenizeStr(tokstream) {
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
n++; n++;
if (tokstream.length < 1) { if (tokstream.length < 1) {
console.log("Error: missing quotation mark"); throw "Error: missing quotation mark";
process.exit(code=1);
} }
} }
n++; n++;
@ -232,9 +231,15 @@ function tokenize(tokstream) {
} }
case 105: // 'i' case 105: // 'i'
var result = peek(tokstream, "ifexp", "if"); var ifexp = peek(tokstream, "ifexp", "if");
if (result) { if (ifexp) {
tokens.push(result); tokens.push(ifexp);
tokstream = tokstream.substr(2);
break;
}
var inkeyword = peek(tokstream, "in", "in");
if (inkeyword) {
tokens.push(inkeyword);
tokstream = tokstream.substr(2); tokstream = tokstream.substr(2);
break; break;
} }
@ -261,12 +266,18 @@ function tokenize(tokstream) {
break; break;
} }
case 108: // l case 108: // l
var result = peek(tokstream, "lambda", "lambda"); var lambda = peek(tokstream, "lambda", "lambda");
if (result) { if (lambda) {
tokens.push(result); tokens.push(lambda);
tokstream = tokstream.substr(6); tokstream = tokstream.substr(6);
break; break;
} }
var letexp = peek(tokstream, "let", "let");
if (letexp) {
tokens.push(letexp);
tokstream = tokstream.substr(3);
break;
}
default: default:
if (isDigit(tokstream[0])) { if (isDigit(tokstream[0])) {

11
tools.js

@ -114,6 +114,14 @@ function find(f, haystack) {
return false; return false;
} }
function dict(pairs) {
var o = new Object();
pairs.map(function(p) {
o[p[0]] = p[1];
});
return o;
}
/* /*
* Problem: * Problem:
@ -154,4 +162,5 @@ module.exports = {compose : compose,
maxBy : maxBy, maxBy : maxBy,
len : len, len : len,
groupOps : groupOps, groupOps : groupOps,
opMatch : operatorMatch} opMatch : operatorMatch,
dict: dict}

0
typecheck.js

Loading…
Cancel
Save