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

18
representation.js

@ -1,3 +1,5 @@
var tool = require("./tools.js");
var Expression = {
display :
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) {
this.exprType = "Unary";
this.val = v;
@ -170,6 +183,8 @@ OPInfo = {"+" : [3, "Left"],
">=" : [2, "Left"],
"<" : [2, "Left"],
"<=" : [2, "Left"],
"&&" : [2, "Left"],
"||" : [2, "Left"],
":" : [2, "Left"],
"$" : [1, "Left"],
">>" : [1, "Left"],
@ -194,4 +209,5 @@ module.exports =
If : If,
DefFunc : DefFunc,
UnaryOp : UnaryOp,
Nil : Nil }
Nil : Nil,
LetExp : LetExp}

27
tokenize.js

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

11
tools.js

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

0
typecheck.js

Loading…
Cancel
Save