Browse Source

readability fixes, a few bug fixes, can calculate free variables of let blocks, environments not being passed yet or closures created

pull/1/head
nisstyre56 11 years ago
parent
commit
b890053d20
  1. 2
      cexps.js
  2. 94
      closure_conversion.js
  3. 2
      desugar.js
  4. 13
      environments.js
  5. 10
      errors.js
  6. 18
      evaluate.js
  7. 49
      parse.js
  8. 33
      representation.js
  9. 68
      tokenize.js
  10. 40
      tools.js
  11. 19
      typecheck.js

2
cexps.js

@ -40,7 +40,7 @@ function offset(i, v, w, next_cexp) {
offset.prototype = cexp; offset.prototype = cexp;
function app(k, vs) { function app(k, vs) {
this.k =k; this.k = k;
this.vs = vs; this.vs = vs;
return this; return this;
} }

94
closure_conversion.js

@ -8,8 +8,8 @@
* in the current environment. * in the current environment.
* A free variable is simply those that are not in the list of formal parameters. * A free variable is simply those that are not in the list of formal parameters.
* We start with the global environment and traverse the AST. Every time a new function is entered * We start with the global environment and traverse the AST. Every time a new function is entered
* the current environment gets extended with the formal parameters of the function. * the current environment gets $.extended with the formal parameters of the function.
* When a let is encountered the current environment also gets extended. * When a let is encountered the current environment also gets $.extended.
* The algorithm continues for any further function definitions in that branch * The algorithm continues for any further function definitions in that branch
* otherwise it just stops for that particular branch and continues with the rest of the AST * otherwise it just stops for that particular branch and continues with the rest of the AST
* *
@ -24,33 +24,11 @@ var env = require("./environments.js");
var errors = require("./errors.js"); var errors = require("./errors.js");
var parser = require("./parse.js"); var parser = require("./parse.js");
var pprint = require("./pprint.js"); var pprint = require("./pprint.js");
var tool = require("./tools.js"); var $ = require("./tools.js");
/*function convert(stx, cur_types, cur_exprs) { var notEmpty = $.compose($.not, $.eq([]));
switch (stx.exprType) {
case "If":
case "Definition":
case "Name":
case "Application":
case "Function":
case "Let":
default:
return stx;
}
}*/
function fvs(stx) {
/*if (stx.exprType !== "Function" &&
stx.exprType !== "Let") {
throw errors.JInternalError(
["Tried to calculate the free variables of",
"something that was not a function or let.\n",
"That something was a: " + stx.exprType +"\n"].reduce(
function (a,b) {
return a+" "+b
}, ""));
}*/
function fvs_helper(stx) {
switch (stx.exprType) { switch (stx.exprType) {
case "Integer": case "Integer":
return []; return [];
@ -62,38 +40,62 @@ function fvs(stx) {
return []; return [];
case "Nil": case "Nil":
return []; return [];
case "List":
return [];
case "Bool": case "Bool":
return []; return [];
case "FunctionDefinition":
return [];
case "Let": case "Let":
return stx.pairs.map(fvs); return [];
case "Unary": case "Unary":
return fvs(stx.val); return $.flatten([stx.op.ident, fvs_helper(stx.val)]);
case "Definition": case "Definition":
return [fvs(stx.val)]; return $.flatten(fvs_helper(stx.val));
case "Application": case "Application":
var vs = fvs(stx.p); var vs = $.flatten(fvs_helper(stx.p));
var f_fvs = fvs(stx.func); var f_fvs = $.flatten(fvs_helper(stx.func));
return [].concat.apply([], [vs, f_fvs]); return $.flatten([vs, f_fvs]);
case "If": case "If":
if (stx.elseexp) { if (stx.elseexp) {
var cond_fvs = fvs(stx.condition); var cond_fvs = fvs_helper(stx.condition);
var then_fvs = fvs(stx.thenexp); var then_fvs = fvs_helper(stx.thenexp);
var else_fvs = fvs(stx.elseexp); var else_fvs = fvs_helper(stx.elseexp);
return [cond_fvs, then_fvs, else_fvs]; return $.flatten([cond_fvs, then_fvs, else_fvs]);
} }
else { else {
return [fvs(stx.condition)] + [fvs(stx.thenexp)]; return $.flatten([fvs_helper(stx.condition), fvs_helper(stx.thenexp)]);
} }
case "Name": case "Name":
return stx.ident; return stx.ident;
} }
} }
var ast = parser.parse("(^ wat (a+(ar*b*c^twerp+\"sdfdsfsdfsdfsdf\")*rt))")[0]; function fvs(stx) {
console.log(pprint.pprint(ast)); if (stx.exprType !== "Function" &&
console.log(tool.unique(fvs(ast))); stx.exprType !== "Let") {
//console.log(ast); throw errors.JInternalError(
["Tried to calculate the free variables of",
"something that was not a function or let.\n",
"That something was a: " + stx.exprType +"\n"].reduce(
function (a,b) {
return a+" "+b;
}, ""));
}
var variables;
switch (stx.exprType) {
case "Let":
var bound_vars = stx.pairs.map(
function (stx) {
return stx.ident.ident;
});
var let_fvs = stx.pairs.map(fvs_helper);
var body_fvs = fvs_helper(stx.body);
variables = $.flatten(let_fvs);
$.extend(variables, $.flatten(body_fvs));
}
return $.difference($.unique($.flatten(variables)), bound_vars);
}
//var ast = parser.parse("let { c = trtr a = let {tttt = (rtertret^yyyy) } let { dfsdf = let { asdsd = 3434 } gdfgdfg } (45+(asdddy*uyuy)) q = ((lambda x y -> (x+y)) 4 ui) } (^ wat (a+(ar*b*c^twerp+\"sdfdsfsdfsdfsdf\")*rt))")[0];
//var ast = parser.parse("let { a = let { b = let {dsdfgf = sddd } fdgfg } gggggg } t")[0];
//console.log(pprint.pprint(ast));
var ast = parser.parse("let { a = 12 b = (a + t) } (a + b * d)")[0];
console.log(fvs(ast));

2
desugar.js

@ -32,7 +32,7 @@ function desugarLet(stx) {
} }
function desugar(stx) { function desugar(stx) {
switch (stx.exprType) { switch (stx.exprType) {
case "If": case "If":
if (stx.elseexp) if (stx.elseexp)
return new typ.If(desugar(stx.condition), desugar(stx.thenexp), desugar(stx.elseexp)); return new typ.If(desugar(stx.condition), desugar(stx.thenexp), desugar(stx.elseexp));

13
environments.js

@ -11,10 +11,15 @@ var rep = require("./representation.js");
function extend(env, values) { function extend(env, values) {
for (var i = 0; i < values.length; i++) { var new_env = {};
env[values[i][0].val] = values[i][1]; var env_keys = Object.keys(env);
for (var i = 0; i < env_keys.length; i++) {
new_env[env_keys[i]] = env[env_keys[i]];
} }
return env; for (i = 0; i < values.length; i++) {
new_env[values[i][0].val] = values[i][1];
}
return new_env;
} }
// creates a new environment initialized with the pairs in values // creates a new environment initialized with the pairs in values
@ -22,7 +27,7 @@ function makeEnv(name, values) {
var env = {}; var env = {};
env.name = name; env.name = name;
for (var i = 0; i < values.length; i++) { for (var i = 0; i < values.length; i++) {
var name = values[i][0].val; name = values[i][0].val;
var val = values[i][1]; var val = values[i][1];
env[name] = val; env[name] = val;
} }

10
errors.js

@ -26,6 +26,14 @@ function JTypeError(linenum, charnum, token, message) {
return this; return this;
} }
function JInternalError(message) {
this.errormessage = message;
console.log(message);
return this;
}
module.exports = module.exports =
{JSyntaxError : JSyntaxError, {JSyntaxError : JSyntaxError,
JTypeError : JTypeError}; JTypeError : JTypeError,
JInternalError : JInternalError
};

18
evaluate.js

@ -0,0 +1,18 @@
var parse = require("./parse.js").parse;
function isAtom(x) {
return stx.exprType != "List";
}
function evaluate(exp, env) {
if (isAtom(exp)) {
switch (exp.exprType) {
case "Function":
return evaluate(invoke(exp, env), env);
case "Name":
return lookup(expr.val);
default:
return expr.val;
}
}
}

49
parse.js

@ -21,7 +21,7 @@ function snd(ts) {
/*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) {
@ -71,7 +71,7 @@ function parseMany(parse, exprType, valid, tokens, charnum, linenum) {
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)
@ -115,15 +115,16 @@ function parseBetween(exprType, between, tokens, charnum, linenum) {
} }
function parseList(tokens) { function parseList(tokens) {
var xs;
if (fst(tokens)[0] === "right_square") { if (fst(tokens)[0] === "right_square") {
var xs = []; xs = [];
} }
else if (fst(tokens)[0] === "comma") { else if (fst(tokens)[0] === "comma") {
tokens.pop(); tokens.pop();
var xs = []; xs = [];
} }
else { else {
var xs = parseBetween(function (x) { return true; }, "comma", tokens, fst(tokens)[3], fst(tokens)[2]); xs = parseBetween(function (x) { return true; }, "comma", tokens, fst(tokens)[3], fst(tokens)[2]);
} }
if (!fst(tokens) || fst(tokens)[0] !== "right_square") { if (!fst(tokens) || fst(tokens)[0] !== "right_square") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
@ -137,16 +138,17 @@ function parseList(tokens) {
function parseDefFunction(tokens) { function parseDefFunction(tokens) {
var fname = parse(tokens); var fname = parse(tokens);
var parameters;
if (fname.exprType != "Name") { if (fname.exprType != "Name") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2], fst(tokens)[2],
"Expected an identifier in function definition"); "Expected an identifier in function definition");
} }
if (fst(tokens)[0] === "right_paren") { if (fst(tokens)[0] === "right_paren") {
var parameters = []; parameters = [];
} }
else { else {
var parameters = parseMany(parse, parameters = parseMany(parse,
validName, validName,
validFormPar, validFormPar,
tokens, tokens,
@ -209,6 +211,7 @@ function parseLetForm(tokens, linenum, charnum) {
function parseLetFunction(tokens, linenum, charnum) { function parseLetFunction(tokens, linenum, charnum) {
var fname = parse(tokens); var fname = parse(tokens);
var parameters;
if (fname.exprType != "Name") { if (fname.exprType != "Name") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
@ -216,10 +219,10 @@ function parseLetFunction(tokens, linenum, charnum) {
"Expected an identifier in function definition"); "Expected an identifier in function definition");
} }
if (fst(tokens)[0] === "right_paren") { if (fst(tokens)[0] === "right_paren") {
var parameters = []; parameters = [];
} }
else { else {
var parameters = parseMany(parse, parameters = parseMany(parse,
validName, validName,
validFormPar, validFormPar,
tokens, tokens,
@ -235,7 +238,7 @@ function parseLetFunction(tokens, linenum, charnum) {
if (fst(tokens)[0] !== "arrow") { if (fst(tokens)[0] !== "arrow") {
throw error.JSyntaxError(fst(tokens)[3], throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2], fst(tokens)[2],
"Function parameters in let/def form must be followed by ->") "Function parameters in let/def form must be followed by ->");
} }
tokens.pop(); tokens.pop();
var body = parse(tokens); var body = parse(tokens);
@ -435,7 +438,7 @@ function parseLambda(tokens) {
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);
} }
@ -448,8 +451,10 @@ var validOperator = makeChecker(["identifier"]);
/* Parses function application (either infix or prefix) */ /* Parses function application (either infix or prefix) */
function computeApp(tokens, charnum, linenum) { function computeApp(tokens, charnum, linenum) {
var lhs = parse(tokens); var lhs = parse(tokens);
var next;
var result;
if (fst(tokens)) if (fst(tokens))
var next = fst(tokens); next = fst(tokens);
else { else {
throw error.JSyntaxError(linenum, throw error.JSyntaxError(linenum,
charnum, charnum,
@ -457,7 +462,7 @@ function computeApp(tokens, charnum, linenum) {
} }
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, 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,
@ -495,7 +500,7 @@ function computeApp(tokens, charnum, linenum) {
*/ */
function parseInfix(tokens, minPrec, lhs, linenum, charnum) { function parseInfix(tokens, minPrec, lhs, linenum, charnum) {
if (!lhs) { if (!lhs) {
var lhs = parse(tokens); lhs = parse(tokens);
} }
while (true) { while (true) {
var cur = fst(tokens); var cur = fst(tokens);
@ -524,8 +529,9 @@ function parseInfix(tokens, minPrec, lhs, linenum, charnum) {
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;
if (fst(tokens)) { if (fst(tokens)) {
var toktype = fst(tokens)[0]; toktype = fst(tokens)[0];
} }
else { else {
process.exit(code=1); process.exit(code=1);
@ -570,9 +576,9 @@ function parse(tokens) {
} }
} }
var istr = fs.readFileSync('/dev/stdin').toString(); //var istr = fs.readFileSync('/dev/stdin').toString();
function parseFull(tokenized) { function parseFull(tokenized) {
var ast = new Array(); var ast = [];
try { try {
while (tokenized.length > 0) { while (tokenized.length > 0) {
var parsed = desugarer.desugar(parse(tokenized)); var parsed = desugarer.desugar(parse(tokenized));
@ -584,7 +590,14 @@ function parseFull(tokenized) {
process.exit(1); process.exit(1);
} }
} }
console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint).join("\n"));
module.exports = { parse : function(str) {
return parseFull(tokenizer.tokenize(str));
}
};
//console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint).join("\n"));
//console.log(tokenizer.tokenize(istr)); //console.log(tokenizer.tokenize(istr));
//console.log(parseFull(tokenizer.tokenize(istr))); //console.log(parseFull(tokenizer.tokenize(istr)));

33
representation.js

@ -168,13 +168,6 @@ function TypeOp(name, params, body) {
return this; return this;
} }
function TypeBinding(name, type) {
this.name = name;
this.type = type;
return this;
}
//convenience function to construct binary operators //convenience function to construct binary operators
//assumes that the identifier refers to the name of a primitive //assumes that the identifier refers to the name of a primitive
//operation //operation
@ -195,11 +188,22 @@ function makeApp(name, parameters) {
} }
function makeGensym() {
var n = 0;
return function() {
var x = "G"+n;
n = n + 1;
return x;
};
}
var gensym = makeGensym();
OPInfo = {"+" : [3, "Left"], OPInfo = {"+" : [3, "Left"],
"-" : [3, "Left"], "-" : [3, "Left"],
"*" : [4, "Left"], "*" : [4, "Left"],
"/" : [4, "Left"], "/" : [4, "Left"],
"^" : [5, "Right"], "^" : [5, "Right"],
"++" : [3, "Left"], "++" : [3, "Left"],
"==" : [2, "Left"], "==" : [2, "Left"],
">" : [2, "Left"], ">" : [2, "Left"],
@ -234,5 +238,8 @@ module.exports =
DefFunc : DefFunc, DefFunc : DefFunc,
UnaryOp : UnaryOp, UnaryOp : UnaryOp,
Nil : Nil, Nil : Nil,
LetExp : LetExp LetExp : LetExp,
} gensym : gensym,
TypeVar : TypeVar,
TypeOp : TypeOp
};

68
tokenize.js

@ -136,70 +136,83 @@ function tokenize(tokstream, matchop) {
var tokens = []; var tokens = [];
var charnum = 1; var charnum = 1;
var linenum = 1; var linenum = 1;
var i, result, lambda, num;
while (tokstream) { while (tokstream) {
switch (tokstream[0].charCodeAt()) { switch (tokstream[0].charCodeAt()) {
/* falls through */
case 9: // '\t' case 9: // '\t'
charnum++; charnum++;
tokens.push(["whitespace", '\t', charnum, linenum]); tokens.push(["whitespace", '\t', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 32: // ' ' case 32: // ' '
charnum++; charnum++;
tokens.push(["whitespace", ' ', charnum, linenum]); tokens.push(["whitespace", ' ', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 10: // '\n' case 10: // '\n'
linenum++; linenum++;
charnum = 1; charnum = 1;
tokens.push(["whitespace", '\n', charnum, linenum]); tokens.push(["whitespace", '\n', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 44: // ',' case 44: // ','
charnum++; charnum++;
tokens.push(["comma", ",", charnum, linenum]); tokens.push(["comma", ",", charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 40: // '(' case 40: // '('
charnum++; charnum++;
tokens.push(["left_paren", '(', charnum, linenum]); tokens.push(["left_paren", '(', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 41: // ')' case 41: // ')'
charnum++; charnum++;
tokens.push(["right_paren", ')', charnum, linenum]); tokens.push(["right_paren", ')', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 123: // '{' case 123: // '{'
charnum++; charnum++;
tokens.push(["left_brace", '{', charnum, linenum]); tokens.push(["left_brace", '{', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 125: // '}' case 125: // '}'
charnum++; charnum++;
tokens.push(["right_brace", '}', charnum, linenum]); tokens.push(["right_brace", '}', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 91: // '[' case 91: // '['
charnum++; charnum++;
tokens.push(["left_square", '[', charnum, linenum]); tokens.push(["left_square", '[', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 93: // ']' case 93: // ']'
charnum++; charnum++;
tokens.push(["right_square", ']', charnum, linenum]); tokens.push(["right_square", ']', charnum, linenum]);
tokstream = tokstream.substr(1); tokstream = tokstream.substr(1);
break; break;
/* falls through */
case 34: // '"' case 34: // '"'
var result = tokenizeStr(tokstream, charnum, linenum); result = tokenizeStr(tokstream, charnum, linenum);
var str = result[1]; var str = result[1];
var i = result[0]; i = result[0];
tokens.push(str); tokens.push(str);
tokstream = tokstream.substr(i); tokstream = tokstream.substr(i);
break; break;
/* falls through */
case 45: // '-' case 45: // '-'
var lambda = peek(tokstream, "arrow", "->"); lambda = peek(tokstream, "arrow", "->");
if (lambda) { if (lambda) {
tokens.push(lambda); tokens.push(lambda);
tokstream = tokstream.substr(2); tokstream = tokstream.substr(2);
@ -212,24 +225,27 @@ function tokenize(tokstream, matchop) {
break; break;
} }
/* falls through */
case 46: // '.' case 46: // '.'
if (isDigit(tokstream[1])) { if (isDigit(tokstream[1])) {
var result = tokenizeNum(tokstream, charnum, linenum); result = tokenizeNum(tokstream, charnum, linenum);
var num = result[1]; num = result[1];
var i = result[0]; i = result[0];
if (num[1] !== NaN) if (!isNaN(num[1])) {
tokens.push(num); tokens.push(num);
}
tokstream = tokstream.substr(i); tokstream = tokstream.substr(i);
break; break;
} }
/* falls through */
case 116: // 't' case 116: // 't'
var result = tokenizeT(tokstream); result = tokenizeT(tokstream);
if (result) { if (result) {
tokens.push(result); tokens.push(result);
tokstream = tokstream.substr(4); // 4 = length of either token tokstream = tokstream.substr(4); // 4 = length of either token
break; break;
} }
/* falls through */
case 105: // 'i' case 105: // 'i'
var ifexp = peek(tokstream, "ifexp", "if"); var ifexp = peek(tokstream, "ifexp", "if");
if (ifexp) { if (ifexp) {
@ -244,6 +260,7 @@ function tokenize(tokstream, matchop) {
break; break;
} }
/* falls through */
case 100: // 'd' case 100: // 'd'
var defop = peek(tokstream, "defop", "defop"); var defop = peek(tokstream, "defop", "defop");
if (defop) { if (defop) {
@ -257,22 +274,25 @@ function tokenize(tokstream, matchop) {
tokstream = tokstream.substr(3); tokstream = tokstream.substr(3);
break; break;
} }
/* falls through */
case 101: // e case 101: // e
var result = peek(tokstream, "elsexp", "else"); result = peek(tokstream, "elsexp", "else");
if (result) { if (result) {
tokens.push(result); tokens.push(result);
tokstream = tokstream.substr(4); tokstream = tokstream.substr(4);
break; break;
} }
/* falls through */
case 102: // f case 102: // f
var result = peek(tokstream, "falselit", "false"); result = peek(tokstream, "falselit", "false");
if (result) { if (result) {
tokens.push(result); tokens.push(result);
tokstream = tokstream.substr(5); tokstream = tokstream.substr(5);
break; break;
} }
/* falls through */
case 108: // l case 108: // l
var lambda = peek(tokstream, "lambda", "lambda"); lambda = peek(tokstream, "lambda", "lambda");
if (lambda) { if (lambda) {
tokens.push(lambda); tokens.push(lambda);
tokstream = tokstream.substr(6); tokstream = tokstream.substr(6);
@ -285,13 +305,15 @@ function tokenize(tokstream, matchop) {
break; break;
} }
/* falls through */
default: default:
if (isDigit(tokstream[0])) { if (isDigit(tokstream[0])) {
var result = tokenizeNum(tokstream, charnum, linenum); result = tokenizeNum(tokstream, charnum, linenum);
var num = result[1]; num = result[1];
var i = result[0]; i = result[0];
if (num[1] !== NaN) if (!isNaN(num[1])) {
tokens.push(num); tokens.push(num);
}
tokstream = tokstream.substr(i); tokstream = tokstream.substr(i);
break; break;
} }
@ -303,12 +325,12 @@ function tokenize(tokstream, matchop) {
tokens.push(["identifier", op, charnum, linenum]); tokens.push(["identifier", op, charnum, linenum]);
} }
else { else {
var result = tokenizeIdent(tokstream, matchop, charnum, linenum); result = tokenizeIdent(tokstream, matchop, charnum, linenum);
result.map(function(x) { for(var index = 0; index < result.length; index++) {
charnum++; charnum++;
tokens.push(x[1]); tokens.push(result[index][1]);
tokstream = tokstream.substr(x[0]); tokstream = tokstream.substr(result[index][0]);
}); }
} }
} }
} }
@ -328,9 +350,9 @@ function tokenizeHelp(input, matchop) {
function tokenizeFull(input) { function tokenizeFull(input) {
var matchop = tools.opMatch(operators); var matchop = tools.opMatch(operators);
var initialPass = tokenizeHelp(input, matchop).reverse();; var initialPass = tokenizeHelp(input, matchop).reverse();
for (var i = 0; i < initialPass.length; i++) { for (var i = 0; i < initialPass.length; i++) {
if (initialPass.slice(i, i+7).map(function(x) { return x[0]; }) === if (initialPass.slice(i, i+7).map(tools.fst) ===
["defop", "integer", "identifier", "Left", "Right", ["defop", "integer", "identifier", "Left", "Right",
"left_paren", "identifier", "identifier", "identifier", "left_paren", "identifier", "identifier", "identifier",
"right_paren"]) "right_paren"])

40
tools.js

@ -85,6 +85,10 @@ function eq(a) {
}; };
} }
function fst(xs) {
return xs[0];
}
function equal(a) { function equal(a) {
return function(b) { return function(b) {
return a === b; return a === b;
@ -103,11 +107,11 @@ function groupBy(eq, xs) {
} }
function groupOps(ops) { function groupOps(ops) {
return groupBy(eq, ops.sort()); return groupBy(function (x) { return function(y) { return x === y; };}, ops.sort());
} }
function unique(ops) { function unique(ops) {
return groupOps(ops).map(function(x) { return x[0]; }); return groupOps(ops).map(fst);
} }
function find(f, haystack) { function find(f, haystack) {
@ -126,13 +130,34 @@ function dict(pairs) {
return o; return o;
} }
function flatten(xs) {
if (!(xs instanceof Array))
return xs;
if (xs.every(function (x) { return !(x instanceof Array); }))
return xs;
return [].concat.apply([], xs);
}
function extend(xs, ys) {
xs.push.apply(xs, ys);
return xs;
}
function difference(xs, ys) {
var difflist = groupOps(extend(xs, ys));
return difflist.filter(function (group) {
if (group.length > 1) {
return false;
}
return true;
}).map(fst);
}
/* /*
* Problem: * Problem:
* >> > >>^ <- longest one must be matched * >> > >>^ <- longest one must be matched
* regex? * regex?
*/ */
RegExp.escape= function(s) { RegExp.escape= function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}; };
@ -151,6 +176,8 @@ function operatorMatch(ops) {
return false; return false;
}; };
} }
/* /*
var print = console.log; var print = console.log;
@ -168,4 +195,9 @@ module.exports = {compose : compose,
groupOps : groupOps, groupOps : groupOps,
opMatch : operatorMatch, opMatch : operatorMatch,
dict: dict, dict: dict,
unique : unique}; unique : unique,
fst : fst,
eq: eq,
extend : extend,
flatten : flatten,
difference : difference}

19
typecheck.js

@ -0,0 +1,19 @@
/*
* Typecheck an AST with a given environment
* the environment maps variables to types
* a variable can either be bound or free
* when we say a variable is free that means that it is either
* unbound (which causes an exception to be raised immediately)
* or it is bound in the outer scope
*
* So the AST must first be converted to a form where each function body is tied
* to an environment mapping identifiers to types
*/
var rep = require("./representation.js");
var env = require("./environments.js");
var TypeOp = rep.TypeOp;
var TypeVar = rep.TypeVar;
Loading…
Cancel
Save