Browse Source

defuck tabs in files

pull/8/head
nisstyre56 11 years ago
parent
commit
db2933031d
  1. 270
      parse.js
  2. 144
      representation.js

270
parse.js

@ -11,33 +11,33 @@ var error = require("./errors.js");
var print = console.log; var print = console.log;
function fst(ts) { function fst(ts) {
return ts[ts.length-1]; return ts[ts.length-1];
} }
function snd(ts) { function snd(ts) {
return ts[ts.length-2]; return ts[ts.length-2];
} }
/*Checks if the next token is not followed by any of ``checks'' */ /*Checks if the next token is not followed by any of ``checks'' */
function notFollowedBy(tokens, checks, linenum, charnum) { function notFollowedBy(tokens, checks, linenum, charnum) {
if (!fst(tokens)) { if (!fst(tokens)) {
throw error.JSyntaxError(0,0,"unexpected end of source"); throw error.JSyntaxError(0,0,"unexpected end of source");
} }
var nextT = fst(tokens)[0]; var nextT = fst(tokens)[0];
if (checks.some(function (x) { if (checks.some(function (x) {
return x === nextT; return x === nextT;
})) }))
return false; return false;
else else
return true; return true;
} }
/* returns a function that takes a parameter and /* returns a function that takes a parameter and
checks if it is in the array ``props''*/ checks if it is in the array ``props''*/
function makeChecker(props) { function makeChecker(props) {
return function(x) { return function(x) {
return x && props.some(function (y) {return y(x);}); return x && props.some(function (y) {return y(x);});
}; };
} }
function tokTypeCheck(name) { function tokTypeCheck(name) {
@ -61,43 +61,43 @@ function parseMany(parse, exprType, valid, tokens, charnum, linenum) {
"Unexpected end of source"); "Unexpected end of source");
} }
var current = fst(tokens)[0]; var current = fst(tokens)[0];
var results = []; var results = [];
var parsed; var parsed;
if (valid(fst(tokens))) { if (valid(fst(tokens))) {
parsed = parse(tokens); parsed = parse(tokens);
} }
else { else {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Unexpected token: ``"+fst(tokens)[0]+"''"); "Unexpected token: ``"+fst(tokens)[0]+"''");
} }
results.push(parsed); results.push(parsed);
//make sure there are at least 2 tokens to parse //make sure there are at least 2 tokens to parse
if (tokens.length > 1 && fst(tokens) && valid(fst(tokens))) { if (tokens.length > 1 && fst(tokens) && valid(fst(tokens))) {
while (valid(snd(tokens))) { while (valid(snd(tokens))) {
if (!(valid(fst(tokens)))) if (!(valid(fst(tokens))))
break; break;
results.push(parse(tokens)); results.push(parse(tokens));
if (!exprType(fst(results).exprType)) if (!exprType(fst(results).exprType))
break; break;
if (fst(tokens)) if (fst(tokens))
current = fst(tokens)[0]; current = fst(tokens)[0];
else else
throw error.JSyntaxError(charnum, linenum, "Unexpected end of source"); throw error.JSyntaxError(charnum, linenum, "Unexpected end of source");
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)) if (!fst(tokens))
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"unexpected end of source"); "unexpected end of source");
if (valid(fst(tokens))) if (valid(fst(tokens)))
results.push(parse(tokens)); results.push(parse(tokens));
return results; return results;
} }
@ -149,7 +149,7 @@ function parseList(tokens) {
function parseDefFunction(tokens) { function parseDefFunction(tokens) {
var fname = parse(tokens); var fname = parse(tokens);
var parameters; var parameters;
if (fname.exprType != "Name") { if (fname.exprType != "Name") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
@ -285,7 +285,7 @@ function parseLetBinding(tokens, linenum, charnum) {
charnum, charnum,
"A definition cannot be the value of a binding"); "A definition cannot be the value of a binding");
} }
return new typ.Def(name, bound); return new typ.Def(name, bound);
} }
function parseLetItem(tokens) { function parseLetItem(tokens) {
@ -321,12 +321,12 @@ function parseDef(tokens, linenum, charnum) {
fst(tokens)[2]); fst(tokens)[2]);
} }
if (notFollowedBy(tokens, ["identifier"], linenum, charnum)) { if (notFollowedBy(tokens, ["identifier"], linenum, charnum)) {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"def must be followed by identifier, not "+fst(tokens)[0]); "def must be followed by identifier, not "+fst(tokens)[0]);
} }
else { else {
var identifier = parse(tokens); var identifier = parse(tokens);
if (!fst(tokens)) if (!fst(tokens))
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
@ -349,8 +349,8 @@ function parseDef(tokens, linenum, charnum) {
charnum, charnum,
"A definition cannot be the value of a binding"); "A definition cannot be the value of a binding");
} }
return new typ.Def(identifier, bound); return new typ.Def(identifier, bound);
} }
} }
function parseDefOp(tokens, linenum, charnum) { function parseDefOp(tokens, linenum, charnum) {
@ -402,35 +402,35 @@ function parseDefOp(tokens, linenum, charnum) {
function parseIf(tokens) { function parseIf(tokens) {
var linenum = fst(tokens)[3]; var linenum = fst(tokens)[3];
var charnum = fst(tokens)[2]; var charnum = fst(tokens)[2];
if (!notFollowedBy(tokens, if (!notFollowedBy(tokens,
["def","comma","lambda"], ["def","comma","lambda"],
linenum, linenum,
charnum)) { charnum)) {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"``if'' cannot be followed by "+fst(tokens)[0]) ; "``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 error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2], fst(tokens)[2],
"if ``exp'' must be folowed by ``then'' exp, not "+snd(tokens)[0]); "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);
if (fst(tokens) && fst(tokens)[0] === "elsexp") { if (fst(tokens) && fst(tokens)[0] === "elsexp") {
tokens.pop(); tokens.pop();
if (_.size(tokens) < 1) { if (_.size(tokens) < 1) {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Unexpected end of source"); "Unexpected end of source");
} }
else { else {
var elseC = parse(tokens); var elseC = parse(tokens);
return new typ.If(ifC, thenC, elseC); return new typ.If(ifC, thenC, elseC);
} }
} }
else { else {
@ -452,20 +452,20 @@ function validFormPar(tok) {
function parseLambda(tokens) { function parseLambda(tokens) {
var linenum = fst(tokens)[2]; var linenum = fst(tokens)[2];
var charnum = fst(tokens)[3]; var charnum = fst(tokens)[3];
var parameters = parseMany(parse, var parameters = parseMany(parse,
validName, validName,
validFormPar, validFormPar,
tokens, tokens,
charnum, charnum,
linenum); linenum);
if (fst(tokens)[1] !== "->") { if (fst(tokens)[1] !== "->") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2], fst(tokens)[2],
"arrow must follow parameters in lambda, not "+fst(tokens)[0]); "arrow must follow parameters in lambda, not "+fst(tokens)[0]);
} }
tokens.pop(); tokens.pop();
var body = parse(tokens); var body = parse(tokens);
return new typ.FuncT(parameters, body); return new typ.FuncT(parameters, body);
} }
var invalidArguments = ["def", "comma", "right_paren", "right_square", "right_brace", "left_brace", "right_brace"].map(tokTypeCheck); var invalidArguments = ["def", "comma", "right_paren", "right_square", "right_brace", "left_brace", "right_brace"].map(tokTypeCheck);
@ -477,31 +477,31 @@ function computeApp(tokens, charnum, linenum) {
var lhs = parse(tokens); var lhs = parse(tokens);
var next; var next;
var result; var result;
if (fst(tokens)) { if (fst(tokens)) {
next = fst(tokens); next = fst(tokens);
} }
else { else {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Unexpected end of source"); "Unexpected end of source");
} }
if (typ.OPInfo[next[1]]) { if (typ.OPInfo[next[1]]) {
/* it's an infix expression */ /* it's an infix expression */
result = parseInfix(tokens, 1, lhs, linenum, charnum); result = parseInfix(tokens, 1, lhs, linenum, charnum);
if (!fst(tokens) || fst(tokens)[0] !== "right_paren") { if (!fst(tokens) || fst(tokens)[0] !== "right_paren") {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Mismatched parentheses or missing parenthesis on right-hand side"); "Mismatched parentheses or missing parenthesis on right-hand side");
} }
else { else {
tokens.pop(); tokens.pop();
return result; return result;
} }
} }
else { else {
/* it's a prefix application */ /* it's a prefix application */
var parameters; var parameters;
if (fst(tokens)[0] !== "right_paren") { if (fst(tokens)[0] !== "right_paren") {
parameters = parseMany(parse, parameters = parseMany(parse,
validArgTypes, validArgTypes,
validArgument, validArgument,
@ -512,16 +512,16 @@ function computeApp(tokens, charnum, linenum) {
else { else {
parameters = []; parameters = [];
} }
if ((!fst(tokens)) || fst(tokens)[0] !== "right_paren") { if ((!fst(tokens)) || fst(tokens)[0] !== "right_paren") {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Mismatched parentheses or missing parenthesis on right-hand side"); "Mismatched parentheses or missing parenthesis on right-hand side");
} }
else { else {
tokens.pop(); tokens.pop();
return typ.makeApp(lhs, parameters); return typ.makeApp(lhs, parameters);
} }
} }
} }
/*Parses infix expressions by precedence climbing /*Parses infix expressions by precedence climbing
@ -529,81 +529,81 @@ function computeApp(tokens, charnum, linenum) {
http://eli.thegreenplace.net/2012/08/02/parsing-expressions-by-precedence-climbing/ http://eli.thegreenplace.net/2012/08/02/parsing-expressions-by-precedence-climbing/
*/ */
function parseInfix(tokens, minPrec, lhs, linenum, charnum) { function parseInfix(tokens, minPrec, lhs, linenum, charnum) {
if (!lhs) { if (!lhs) {
lhs = parse(tokens); lhs = parse(tokens);
} }
while (true) { while (true) {
var cur = fst(tokens); var cur = fst(tokens);
if (!cur) { if (!cur) {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
"Unexpected end of source"); "Unexpected end of source");
} }
var opinfo = typ.OPInfo[cur[1]]; var opinfo = typ.OPInfo[cur[1]];
if (!opinfo || opinfo[0] < minPrec) if (!opinfo || opinfo[0] < minPrec)
break; break;
var op = new typ.Name(cur[1]); var op = new typ.Name(cur[1]);
var prec = opinfo[0]; var prec = opinfo[0];
var assoc = opinfo[1]; var assoc = opinfo[1];
var nextMinPrec = assoc === "Left" ? prec + 1 : prec; var nextMinPrec = assoc === "Left" ? prec + 1 : prec;
tokens.pop(); tokens.pop();
/*remove the operator token*/ /*remove the operator token*/
var rhs = parseInfix(tokens, nextMinPrec); var rhs = parseInfix(tokens, nextMinPrec);
lhs = typ.makeApp(op, [lhs, rhs]); lhs = typ.makeApp(op, [lhs, rhs]);
} }
return lhs; return lhs;
} }
function parse(tokens) { function parse(tokens) {
var charnum = fst(tokens)[2]; var charnum = fst(tokens)[2];
var linenum = fst(tokens)[3]; var linenum = fst(tokens)[3];
var toktype; var toktype;
if (fst(tokens)) { if (fst(tokens)) {
toktype = fst(tokens)[0]; toktype = fst(tokens)[0];
} }
else { else {
process.exit(code=1); process.exit(code=1);
} }
var token = fst(tokens)[1]; var token = fst(tokens)[1];
tokens.pop(); tokens.pop();
if (toktype === "stringlit") { if (toktype === "stringlit") {
return new typ.StrT(token); return new typ.StrT(token);
} }
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 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") {
return new typ.FloatT(token); return new typ.FloatT(token);
} }
else if (toktype === "identifier") { else if (toktype === "identifier") {
return new typ.Name(token); return new typ.Name(token);
} }
else if (toktype === "constructor") { else if (toktype === "constructor") {
return new typ.TypeOp(token); return new typ.TypeOp(token);
} }
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" ||
toktype === "let") { toktype === "let") {
return parseDef(tokens, fst(tokens)[3], fst(tokens)[2]); return parseDef(tokens, fst(tokens)[3], fst(tokens)[2]);
} }
else if (toktype === "defop") { else if (toktype === "defop") {
return parseDefOp(tokens, fst(tokens)[3], fst(tokens)[2]); return parseDefOp(tokens, fst(tokens)[3], fst(tokens)[2]);
} }
else if (toktype === "ifexp") { else if (toktype === "ifexp") {
return 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 = parseLambda(tokens); var parsed = parseLambda(tokens);
tokens.pop(); tokens.pop();

144
representation.js

@ -2,26 +2,26 @@ var errors = require("./errors.js");
var _ = require("underscore"); var _ = require("underscore");
var Expression = { var Expression = {
display : display :
function() { function() {
return this.exprType + " " + this.val; return this.exprType + " " + this.val;
}, },
type : type :
function () { function () {
return this.exprType; return this.exprType;
} }
}; };
var TypeExpression = { var TypeExpression = {
unify : unify :
function (t) { function (t) {
if (this.expr === t.expr) { if (this.expr === t.expr) {
return t.expr; return t.expr;
} }
else { else {
console.log("Could not unify " + this.expr + " with " + t.expr); console.log("Could not unify " + this.expr + " with " + t.expr);
} }
}, },
isTypeExpr : true isTypeExpr : true
}; };
@ -62,46 +62,46 @@ function UnaryOp(op, v) {
UnaryOp.prototype = Expression; UnaryOp.prototype = Expression;
function IntT(v) { function IntT(v) {
this.exprType = "Integer"; this.exprType = "Integer";
this.val = parseInt(v, 10); this.val = parseInt(v, 10);
return this; return this;
} }
IntT.prototype = Expression; IntT.prototype = Expression;
function FloatT(v) { function FloatT(v) {
this.exprType = "Float"; this.exprType = "Float";
this.val = parseFloat(v, 10); this.val = parseFloat(v, 10);
return this; return this;
} }
FloatT.prototype = Expression; FloatT.prototype = Expression;
function StrT(v) { function StrT(v) {
this.exprType = "String"; this.exprType = "String";
this.val = v; this.val = v;
return this; return this;
} }
StrT.prototype = Expression; StrT.prototype = Expression;
function BoolT(b) { function BoolT(b) {
if (b === "true") { if (b === "true") {
this.val = true; this.val = true;
} }
else { else {
this.val = false; this.val = false;
} }
this.exprType = "Bool"; this.exprType = "Bool";
return this; return this;
} }
BoolT.prototype = Expression; BoolT.prototype = Expression;
function ListT(xs) { function ListT(xs) {
this.xs = xs; this.xs = xs;
this.val = xs; this.val = xs;
this.exprType = "List"; this.exprType = "List";
return this; return this;
} }
function Nil() { function Nil() {
@ -113,47 +113,47 @@ Nil.prototype = Expression;
ListT.prototype = Expression; ListT.prototype = Expression;
function FuncT(p, body) { function FuncT(p, body) {
this.p = p; this.p = p;
this.body = body; this.body = body;
this.val = [p, body]; this.val = [p, body];
this.exprType = "Function"; this.exprType = "Function";
return this; return this;
} }
FuncT.prototype = Expression; FuncT.prototype = Expression;
//Wrapper for function objects //Wrapper for function objects
function OpT(operator) { function OpT(operator) {
this.op = operator; this.op = operator;
this.val = this.op; this.val = this.op;
this.exprType = "Function"; this.exprType = "Function";
return this; return this;
} }
OpT.prototype = Expression; OpT.prototype = Expression;
// Applications separate from other types // Applications separate from other types
function App(func, p) { function App(func, p) {
this.func = func; this.func = func;
this.exprType = "Application"; this.exprType = "Application";
if (p) if (p)
this.p = p; this.p = p;
return this; return this;
} }
// Names are not types // Names are not types
function Name(identifier) { function Name(identifier) {
this.ident = identifier; this.ident = identifier;
this.val = this.ident; this.val = this.ident;
this.exprType = "Name"; this.exprType = "Name";
return this; return this;
} }
function Def(ident, exp) { function Def(ident, exp) {
this.ident = ident; this.ident = ident;
this.val = exp; this.val = exp;
this.exprType = "Definition"; this.exprType = "Definition";
return this; return this;
} }
function DefFunc(ident, params, body) { function DefFunc(ident, params, body) {
@ -166,11 +166,11 @@ function DefFunc(ident, params, body) {
} }
function If(condition, thenexp, elseexp) { function If(condition, thenexp, elseexp) {
this.condition = condition; this.condition = condition;
this.thenexp = thenexp; this.thenexp = thenexp;
this.elseexp = elseexp; this.elseexp = elseexp;
this.exprType = "If"; this.exprType = "If";
return this; return this;
} }
function TypeVar(name) { function TypeVar(name) {
@ -221,14 +221,14 @@ TypeApp.prototype = TypeExpression;
//Applies the function ``name'' to the list of parameters //Applies the function ``name'' to the list of parameters
function makeApp(name, parameters) { function makeApp(name, parameters) {
if (parameters) { if (parameters) {
return parameters.slice(1).reduce(function(f, ident) { return parameters.slice(1).reduce(function(f, ident) {
return new App(f, ident); return new App(f, ident);
}, new App(name, parameters[0])); }, new App(name, parameters[0]));
} }
else { else {
return new App(name); return new App(name);
} }
} }
function makeGensym() { function makeGensym() {

Loading…
Cancel
Save