Browse Source

Merge pull request #3 from oftn/master

merge OFTN version
pull/21/head
Wesley Kerfoot 11 years ago
parent
commit
53e92b4b37
  1. 2
      LICENSE.md
  2. 10
      closure_conversion.js
  3. 36
      parse.js
  4. 59
      pprint.js
  5. 50
      representation.js
  6. 79
      tokenize.js
  7. 15
      tools.js
  8. 20
      treegen.js

2
LICENSE.md

@ -1,4 +1,4 @@
Copyright © 2013 Wesley Kerfoot Copyright 2014 by ΩF:∅ Working Group members
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

10
closure_conversion.js

@ -2,7 +2,7 @@
* A closure is a triple of: * A closure is a triple of:
* the bound variables in a function or let * the bound variables in a function or let
* the free variables in a function or let * the free variables in a function or let
* a function body or let body and bound values * a function body or let body and bound values (if it is an escaping closure only)
* The closure has the property that all of the free variables of the function or let * The closure has the property that all of the free variables of the function or let
* are in the environment, or an exception is raised because the variable is not bound * are in the environment, or an exception is raised because the variable is not bound
* in the current environment. * in the current environment.
@ -12,6 +12,10 @@
* call the function with the environment associated with it. * call the function with the environment associated with it.
* For the purposes of type checking it does not matter how the function gets called, the environment * For the purposes of type checking it does not matter how the function gets called, the environment
* is only used for looking up the types of names. Formal parameters are given type variables. * is only used for looking up the types of names. Formal parameters are given type variables.
*
* The first phase of closure conversion is not really closure conversion exactly.
* All it does is find out the free variables in scope and tie those up into a data structure with their types later.
* The second phase will be done to the CPS language and closures will actually lambda-lifted out potentially.
*/ */
var rep = require("./representation.js"); var rep = require("./representation.js");
@ -102,7 +106,7 @@ function closure_convert(stx) {
return new rep.Closure(bound_vars, free_variables, stx, []); return new rep.Closure(bound_vars, free_variables, stx, []);
} }
function closure_convert_all(stx) { function closure_convert_all(stx, env) {
var closure; var closure;
switch (stx.exprType) { switch (stx.exprType) {
case "Let": case "Let":
@ -147,6 +151,8 @@ function test(src) {
console.log(JSON.stringify(closure_convert_all(ast), null, 4)); console.log(JSON.stringify(closure_convert_all(ast), null, 4));
} }
//console.log(test(pprint.pprint(parser.parse(pprint.pprint(parser.parse("if something then if a then if b then c else d else rtrrt else some_other_thing")[0]))[0])));
//console.log(pprint.pprint(parser.parse("def main (print let { a = def {f = (lambda a b -> (a+b))} f} (a 2 3))")[0]));
module.export = { module.export = {
test : test, test : test,
closureConvert : closure_convert_all closureConvert : closure_convert_all

36
parse.js

@ -553,27 +553,40 @@ function parse(tokens) {
} }
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 === "truelit" || toktype === "falselit") }
else if (toktype === "constructor") {
return new typ.TypeOp(token);
}
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();
@ -610,4 +623,5 @@ module.exports = { parse : function(str) {
return parseFull(tokenizer.tokenize(str)); return parseFull(tokenizer.tokenize(str));
} }
}; };
//var istr = fs.readFileSync('/dev/stdin').toString(); /*var istr = fs.readFileSync('/dev/stdin').toString();
console.log(parseFull(tokenizer.tokenize(istr)).map(pprint.pprint));*/

59
pprint.js

@ -4,9 +4,9 @@ function pprintName(ident) {
function pprintFunc(func) { function pprintFunc(func) {
if (func.p.exprType === "Name") if (func.p.exprType === "Name")
return "(\\ " + pprint(func.p) + " -> " + pprint(func.body) + ")"; return "(lambda " + pprint(func.p) + " -> " + pprint(func.body) + ")";
else else
return "(\\ " + func.p.map(pprint).join(" ") + " -> " + pprint(func.body) + ")"; return "(lambda " + func.p.map(pprint).join(" ") + " -> " + pprint(func.body) + ")";
} }
@ -21,45 +21,62 @@ function pprintDef(def) {
} }
function pprintIf(ifexp) { function pprintIf(ifexp) {
if (ifexp.elseexp) return ("(if " + pprint(ifexp.condition) +
return "(if " + pprint(ifexp.condition) + " then " + pprint(ifexp.thenexp) + " else " + pprint(ifexp.elseexp) + ")"; " then " + pprint(ifexp.thenexp) +
else " else " + pprint(ifexp.elseexp) + ")");
return "(if " + pprint(ifexp.condition) + " then " + pprint(ifexp.thenexp) + ")";
} }
function pprint(expr) { function pprint(expr) {
if (expr.exprType === "Name") if (expr.exprType === "Name") {
return expr.val;
}
else if (expr.exprType === "TypeOperator") {
return expr.val; return expr.val;
else if (expr.exprType === "Bool") }
if (expr.val) else if (expr.exprType === "Bool") {
if (expr.val) {
return "True"; return "True";
else }
else {
return "False"; return "False";
else if (expr.exprType === "Integer") }
}
else if (expr.exprType === "Integer") {
return "("+expr.val+")"; return "("+expr.val+")";
else if (expr.exprType === "Float") }
else if (expr.exprType === "Float") {
return "("+expr.val+")"; return "("+expr.val+")";
else if (expr.exprType === "String") }
else if (expr.exprType === "String") {
return '"'+expr.val+'"'; return '"'+expr.val+'"';
else if (expr.exprType === "Name") }
else if (expr.exprType === "Name") {
return expr.val; return expr.val;
else if (expr.exprType === "Application") }
else if (expr.exprType === "Application") {
return pprintApp(expr); return pprintApp(expr);
else if (expr.exprType === "Definition") }
else if (expr.exprType === "Definition") {
return pprintDef(expr); return pprintDef(expr);
else if (expr.exprType === "If") }
else if (expr.exprType === "If") {
return pprintIf(expr); return pprintIf(expr);
else if (expr.exprType === "Function") }
else if (expr.exprType === "Function") {
return pprintFunc(expr); return pprintFunc(expr);
else if (expr.exprType === "Nil") }
else if (expr.exprType === "Nil") {
return "[]"; return "[]";
else if (expr.exprType === "Unary") }
else if (expr.exprType === "Unary") {
return "("+expr.op.ident+" "+pprint(expr.val)+")"; return "("+expr.op.ident+" "+pprint(expr.val)+")";
else if (expr.exprType === "Let") }
else if (expr.exprType === "Let") {
return "let {" + expr.pairs.map( return "let {" + expr.pairs.map(
function (v) { function (v) {
return pprint(v); return pprint(v);
}).join(" ; ") + "} in " + pprint(expr.body); }).join(" ; ") + "} in " + pprint(expr.body);
}
} }
module.exports = {pprint : pprint}; module.exports = {pprint : pprint};

50
representation.js

@ -164,13 +164,14 @@ function If(condition, thenexp, elseexp) {
function TypeVar(name) { function TypeVar(name) {
this.name = name; this.name = name;
this.exprType = "TypeVariable";
return this; return this;
} }
function TypeOp(name, params, body) { function TypeOp(name) {
this.name = name; this.name = name;
this.params = params; this.val = name;
this.body = body; this.exprType = "TypeOperator"
return this; return this;
} }
@ -205,27 +206,28 @@ function makeGensym() {
var gensym = makeGensym(); var gensym = makeGensym();
OPInfo = {"+" : [3, "Left"], OPInfo = {"+" : [4, "Left"],
"-" : [3, "Left"], "-" : [4, "Left"],
"*" : [4, "Left"], "*" : [5, "Left"],
"/" : [4, "Left"], "/" : [5, "Left"],
"^" : [5, "Right"], "^" : [6, "Right"],
"++" : [3, "Left"], "++" : [4, "Left"],
"==" : [2, "Left"], "==" : [3, "Left"],
">" : [2, "Left"], ">" : [3, "Left"],
">=" : [2, "Left"], ">=" : [3, "Left"],
"<" : [2, "Left"], "<" : [3, "Left"],
"<=" : [2, "Left"], "<=" : [3, "Left"],
"&&" : [2, "Left"], "&&" : [3, "Left"],
"||" : [2, "Left"], "||" : [3, "Left"],
"::" : [2, "Left"], "::" : [1, "Left"],
":" : [1, "Left"], ":" : [2, "Left"],
"$" : [1, "Left"], "$" : [2, "Left"],
">>" : [1, "Left"], ">>" : [2, "Left"],
">>=" : [1, "Left"], ">>=" : [2, "Left"],
"<$>" : [1, "Left"], "<$>" : [2, "Left"],
"." : [1, "Left"], "." : [2, "Left"],
"," : [1, "Left"]}; "," : [2, "Left"],
"->" : [2, "Right"]}
module.exports = module.exports =
{ IntT : IntT, { IntT : IntT,

79
tokenize.js

@ -6,24 +6,51 @@ var error = require("./errors.js");
var operators = Object.keys(rep.OPInfo); var operators = Object.keys(rep.OPInfo);
var _ = require("underscore"); var _ = require("underscore");
function isDigit(a) { function isDigit(c) {
if (!a) if (!c)
return false; return false;
var code = a.charCodeAt(); var code = c.charCodeAt();
return (46 < code && code < 58 || code < 58 && code > 46); if (isNaN(code)) {
return false;
}
return (46 < code &&
code < 58 ||
code < 58 &&
code > 46);
} }
function isWhitespace(a) { function isWhitespace(c) {
if (!a) if (!c)
return true; return true;
var code = a.charCodeAt(); var code = c.charCodeAt();
return (code === 9 || code === 32 || code === 10 || code === 13 || code === 11); if (isNaN(code)) {
return false;
}
return (code === 9 ||
code === 32 ||
code === 10 ||
code === 13 ||
code === 11);
} }
function isIdentifier(a) { function isIdentifier(c) {
var code = a.charCodeAt(); var code = c.charCodeAt();
return code !== 41 && code !== 40 && code && 125 && code && 123 && code !== 93 && code !== 91 && code !== 44; return (!isNaN(code) &&
code !== 41 &&
code !== 40 &&
code !== 125 &&
code !== 123 &&
code !== 93 &&
code !== 91 &&
code !== 44);
}
function isUpper(c) {
var code = c.charCodeAt();
return (!isNaN(code) &&
(code >= 65) &&
(code <= 90));
} }
function tokenizeNum(tokstream, charnum, linenum) { function tokenizeNum(tokstream, charnum, linenum) {
@ -79,7 +106,10 @@ function tokenizeNum(tokstream, charnum, linenum) {
* Everything after the operator goes back on to the token stream * Everything after the operator goes back on to the token stream
*/ */
function tokenizeIdent(tokstream, matchop, charnum, linenum) { function tokenizeIdent(tokstream,
matchop,
charnum,
linenum) {
var identifier = []; var identifier = [];
var n = 0; var n = 0;
while ((!isWhitespace(tokstream[0])) && isIdentifier(tokstream[0]) && !matchop(tokstream)) { while ((!isWhitespace(tokstream[0])) && isIdentifier(tokstream[0]) && !matchop(tokstream)) {
@ -93,6 +123,18 @@ function tokenizeIdent(tokstream, matchop, charnum, linenum) {
return [[n, ["identifier", identifier, charnum, linenum]]]; return [[n, ["identifier", identifier, charnum, linenum]]];
} }
function tokenizeCtor(tokstream,
matchop,
charnum,
linenum) {
var ident = tokenizeIdent(tokstream,
matchop,
charnum,
linenum);
ident[0][1][0] = "constructor";
return ident;
}
function tokenizeStr(tokstream, charnum, linenum) { function tokenizeStr(tokstream, charnum, linenum) {
var stringlit = []; var stringlit = [];
var n = 1; var n = 1;
@ -212,9 +254,9 @@ function tokenize(tokstream, matchop) {
break; break;
/* falls through */ /* falls through */
case 45: // '-' /*case 45: // '-'
lambda = peek(tokstream, "arrow", "->"); lambda = peek(tokstream, "arrow", "->");
if (lambda) { if (false) {
tokens.push($.extend(lambda, [charnum, linenum])); tokens.push($.extend(lambda, [charnum, linenum]));
tokstream = tokstream.substr(2); tokstream = tokstream.substr(2);
break; break;
@ -325,8 +367,13 @@ function tokenize(tokstream, matchop) {
tokstream = tokstream.substr(l); tokstream = tokstream.substr(l);
tokens.push(["identifier", op, charnum, linenum]); tokens.push(["identifier", op, charnum, linenum]);
} }
else {
if (isUpper(tokstream[0])) {
result = tokenizeCtor(tokstream, matchop, charnum, linenum);
}
else { else {
result = tokenizeIdent(tokstream, matchop, charnum, linenum); result = tokenizeIdent(tokstream, matchop, charnum, linenum);
}
for(var index = 0; index < result.length; index++) { for(var index = 0; index < result.length; index++) {
charnum++; charnum++;
tokens.push(result[index][1]); tokens.push(result[index][1]);
@ -376,4 +423,6 @@ function tokenizeFull(input) {
return tokenizeHelp(input, matchop, true); return tokenizeHelp(input, matchop, true);
} }
module.exports = {tokenize : tokenizeFull};
module.exports = {tokenize : tokenizeFull,
isIdentifier : isIdentifier};

15
tools.js

@ -20,6 +20,18 @@ function min(a, b) {
} }
} }
function max(a, b) {
if (a > b) {
return 1;
}
else if (a < b) {
return -1;
}
else {
return 0;
}
}
function groupOps(ops) { function groupOps(ops) {
return _.groupBy(ops.sort(), _.isEqual); return _.groupBy(ops.sort(), _.isEqual);
} }
@ -56,7 +68,8 @@ function operatorMatch(ops) {
function (op) { function (op) {
return op.length > 0; return op.length > 0;
}); });
var rstring = ops.sort(min).reduce( ops.sort(min);
var rstring = ops.reduce(
function(acc, x) { function(acc, x) {
if (!x || x.length < 1) { if (!x || x.length < 1) {
return ""; return "";

20
treegen.js

@ -0,0 +1,20 @@
#! /usr/bin/node
var parser = require("./parse.js");
var pprint = require("./pprint.js");
var repr = require("./representation.js");
var lex = require("./tokenize.js");
var qc = require("quickcheck");
function arbIdentifier() {
var st = qc.arbString()
if (lex.isIdentifier(st)) {
return new repr.Name(st);
}
else {
return arbIdentifier();
}
}
console.log(arbIdentifier());
Loading…
Cancel
Save