Browse Source

Merge pull request #3 from oftn/master

merge OFTN version
pull/21/head
Wesley Kerfoot 10 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. 81
      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:

10
closure_conversion.js

@ -2,7 +2,7 @@
* A closure is a triple of:
* the bound 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
* are in the environment, or an exception is raised because the variable is not bound
* in the current environment.
@ -12,6 +12,10 @@
* 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
* 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");
@ -102,7 +106,7 @@ function closure_convert(stx) {
return new rep.Closure(bound_vars, free_variables, stx, []);
}
function closure_convert_all(stx) {
function closure_convert_all(stx, env) {
var closure;
switch (stx.exprType) {
case "Let":
@ -147,6 +151,8 @@ function test(src) {
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 = {
test : test,
closureConvert : closure_convert_all

36
parse.js

@ -553,27 +553,40 @@ function parse(tokens) {
}
var token = fst(tokens)[1];
tokens.pop();
if (toktype === "stringlit")
if (toktype === "stringlit") {
return new typ.StrT(token);
else if (toktype === "left_square")
}
else if (toktype === "left_square") {
return parseList(tokens);
else if (toktype === "lambda")
}
else if (toktype === "lambda") {
return parseLambda(tokens);
else if (toktype === "integer")
}
else if (toktype === "integer") {
return new typ.IntT(token);
else if (toktype === "float")
}
else if (toktype === "float") {
return new typ.FloatT(token);
else if (toktype === "identifier")
}
else if (toktype === "identifier") {
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);
}
else if (toktype === "def" ||
toktype === "let")
toktype === "let") {
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]);
else if (toktype === "ifexp")
}
else if (toktype === "ifexp") {
return parseIf(tokens);
}
else if (toktype === "left_paren") {
if (fst(tokens)[0] === "lambda") {
tokens.pop();
@ -610,4 +623,5 @@ module.exports = { parse : function(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) {
if (func.p.exprType === "Name")
return "(\\ " + pprint(func.p) + " -> " + pprint(func.body) + ")";
return "(lambda " + pprint(func.p) + " -> " + pprint(func.body) + ")";
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) {
if (ifexp.elseexp)
return "(if " + pprint(ifexp.condition) + " then " + pprint(ifexp.thenexp) + " else " + pprint(ifexp.elseexp) + ")";
else
return "(if " + pprint(ifexp.condition) + " then " + pprint(ifexp.thenexp) + ")";
return ("(if " + pprint(ifexp.condition) +
" then " + pprint(ifexp.thenexp) +
" else " + pprint(ifexp.elseexp) + ")");
}
function pprint(expr) {
if (expr.exprType === "Name")
if (expr.exprType === "Name") {
return expr.val;
}
else if (expr.exprType === "TypeOperator") {
return expr.val;
else if (expr.exprType === "Bool")
if (expr.val)
}
else if (expr.exprType === "Bool") {
if (expr.val) {
return "True";
else
}
else {
return "False";
else if (expr.exprType === "Integer")
}
}
else if (expr.exprType === "Integer") {
return "("+expr.val+")";
else if (expr.exprType === "Float")
}
else if (expr.exprType === "Float") {
return "("+expr.val+")";
else if (expr.exprType === "String")
}
else if (expr.exprType === "String") {
return '"'+expr.val+'"';
else if (expr.exprType === "Name")
}
else if (expr.exprType === "Name") {
return expr.val;
else if (expr.exprType === "Application")
}
else if (expr.exprType === "Application") {
return pprintApp(expr);
else if (expr.exprType === "Definition")
}
else if (expr.exprType === "Definition") {
return pprintDef(expr);
else if (expr.exprType === "If")
}
else if (expr.exprType === "If") {
return pprintIf(expr);
else if (expr.exprType === "Function")
}
else if (expr.exprType === "Function") {
return pprintFunc(expr);
else if (expr.exprType === "Nil")
}
else if (expr.exprType === "Nil") {
return "[]";
else if (expr.exprType === "Unary")
}
else if (expr.exprType === "Unary") {
return "("+expr.op.ident+" "+pprint(expr.val)+")";
else if (expr.exprType === "Let")
}
else if (expr.exprType === "Let") {
return "let {" + expr.pairs.map(
function (v) {
return pprint(v);
}).join(" ; ") + "} in " + pprint(expr.body);
}
}
module.exports = {pprint : pprint};

50
representation.js

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

81
tokenize.js

@ -6,24 +6,51 @@ var error = require("./errors.js");
var operators = Object.keys(rep.OPInfo);
var _ = require("underscore");
function isDigit(a) {
if (!a)
function isDigit(c) {
if (!c)
return false;
var code = a.charCodeAt();
return (46 < code && code < 58 || code < 58 && code > 46);
var code = c.charCodeAt();
if (isNaN(code)) {
return false;
}
return (46 < code &&
code < 58 ||
code < 58 &&
code > 46);
}
function isWhitespace(a) {
if (!a)
function isWhitespace(c) {
if (!c)
return true;
var code = a.charCodeAt();
return (code === 9 || code === 32 || code === 10 || code === 13 || code === 11);
var code = c.charCodeAt();
if (isNaN(code)) {
return false;
}
return (code === 9 ||
code === 32 ||
code === 10 ||
code === 13 ||
code === 11);
}
function isIdentifier(c) {
var code = c.charCodeAt();
return (!isNaN(code) &&
code !== 41 &&
code !== 40 &&
code !== 125 &&
code !== 123 &&
code !== 93 &&
code !== 91 &&
code !== 44);
}
function isIdentifier(a) {
var code = a.charCodeAt();
return 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) {
@ -79,7 +106,10 @@ function tokenizeNum(tokstream, charnum, linenum) {
* 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 n = 0;
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]]];
}
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) {
var stringlit = [];
var n = 1;
@ -212,9 +254,9 @@ function tokenize(tokstream, matchop) {
break;
/* falls through */
case 45: // '-'
/*case 45: // '-'
lambda = peek(tokstream, "arrow", "->");
if (lambda) {
if (false) {
tokens.push($.extend(lambda, [charnum, linenum]));
tokstream = tokstream.substr(2);
break;
@ -326,7 +368,12 @@ function tokenize(tokstream, matchop) {
tokens.push(["identifier", op, charnum, linenum]);
}
else {
result = tokenizeIdent(tokstream, matchop, charnum, linenum);
if (isUpper(tokstream[0])) {
result = tokenizeCtor(tokstream, matchop, charnum, linenum);
}
else {
result = tokenizeIdent(tokstream, matchop, charnum, linenum);
}
for(var index = 0; index < result.length; index++) {
charnum++;
tokens.push(result[index][1]);
@ -376,4 +423,6 @@ function tokenizeFull(input) {
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) {
return _.groupBy(ops.sort(), _.isEqual);
}
@ -56,7 +68,8 @@ function operatorMatch(ops) {
function (op) {
return op.length > 0;
});
var rstring = ops.sort(min).reduce(
ops.sort(min);
var rstring = ops.reduce(
function(acc, x) {
if (!x || x.length < 1) {
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