Browse Source

support for user defined operators, working on type declarations and inference

pull/1/head
wes 11 years ago
parent
commit
71f9342cea
  1. 47
      parse.js
  2. 21
      representation.js
  3. 33
      tokenize.js

47
parse.js

@ -338,6 +338,51 @@ function parseDef(tokens, linenum, charnum) {
} }
} }
function parseDefOp(tokens, linenum, charnum) {
if (fst(tokens)[0] !== "integer" ||
fst(tokens)[1] < 1) {
throw error.JSyntaxError(linenum,
charnum,
"defop must be followed by integer precedence >= 1");
}
tokens.pop();
if (false) {
throw error.JSyntaxError(linenum,
charnum,
"defop must be followed by precedence and then either Left or Right");
}
tokens.pop();
if (fst(tokens)[0] !== "left_paren") {
throw error.JSyntaxError(linenum,
charnum,
"defop arguments must start with (");
}
tokens.pop();
if (!(tokens.slice(tokens.length-3,
tokens.length).every(function(x) {
return x[0] === "identifier";
}))) {
throw error.JSyntaxError(linenum,
charnum,
"defop must be surrounded by exactly 3 identifier");
}
var pattern = tokens.slice(tokens.length-3,
tokens.length);
tokens.pop(); tokens.pop(); tokens.pop();
if (fst(tokens)[0] !== "right_paren") {
throw error.JSyntaxError(linenum,
charnum,
"defop pattern must be terminated with )");
}
tokens.pop();
return new typ.DefFunc(new typ.Name(pattern[1][1]),
[new typ.Name(pattern[0][1]),
new typ.Name(pattern[2][1])],
parse(tokens));
}
function parseIf(tokens) { function parseIf(tokens) {
var linenum = fst(tokens)[3]; var linenum = fst(tokens)[3];
@ -504,6 +549,8 @@ function parse(tokens) {
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")
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") {

21
representation.js

@ -156,6 +156,24 @@ function If(condition, thenexp, elseexp) {
return this; return this;
} }
function TypeVar(name) {
this.name = name;
return this;
}
function TypeOp(name, params, body) {
this.name = name;
this.params = params;
this.body = body;
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
@ -190,7 +208,8 @@ OPInfo = {"+" : [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"],

33
tokenize.js

@ -5,8 +5,6 @@ var tools = require("./tools.js");
var error = require("./errors.js"); var error = require("./errors.js");
var operators = Object.keys(rep.OPInfo); var operators = Object.keys(rep.OPInfo);
var matchop = tools.opMatch(operators);
function isDigit(a) { function isDigit(a) {
if (!a) if (!a)
return false; return false;
@ -80,7 +78,7 @@ 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, 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)) {
@ -134,7 +132,7 @@ function peek(tokstream, toktype, word, charnum, linenum) {
return false; return false;
} }
function tokenize(tokstream) { function tokenize(tokstream, matchop) {
var tokens = []; var tokens = [];
var charnum = 1; var charnum = 1;
var linenum = 1; var linenum = 1;
@ -242,7 +240,7 @@ function tokenize(tokstream) {
var inkeyword = peek(tokstream, "in", "in "); var inkeyword = peek(tokstream, "in", "in ");
if (inkeyword) { if (inkeyword) {
tokens.push(inkeyword); tokens.push(inkeyword);
tokstream = tokstream.substr(2); tokstream = tokstream.substr(3);
break; break;
} }
@ -251,6 +249,7 @@ function tokenize(tokstream) {
if (defop) { if (defop) {
tokens.push(["defop", "defop", charnum, linenum]); tokens.push(["defop", "defop", charnum, linenum]);
tokstream = tokstream.substr(5); tokstream = tokstream.substr(5);
break;
} }
var def = peek(tokstream, "def", "def"); var def = peek(tokstream, "def", "def");
if (def) { if (def) {
@ -304,7 +303,7 @@ function tokenize(tokstream) {
tokens.push(["identifier", op, charnum, linenum]); tokens.push(["identifier", op, charnum, linenum]);
} }
else { else {
var result = tokenizeIdent(tokstream, charnum, linenum); var result = tokenizeIdent(tokstream, matchop, charnum, linenum);
result.map(function(x) { result.map(function(x) {
charnum++; charnum++;
tokens.push(x[1]); tokens.push(x[1]);
@ -316,9 +315,9 @@ function tokenize(tokstream) {
return tokens; return tokens;
} }
function tokenizeFull(input) { function tokenizeHelp(input, matchop) {
try { try {
return tokenize(input).reverse().filter(function(x) { return tokenize(input, matchop).reverse().filter(function(x) {
return x[0] !== "whitespace"; return x[0] !== "whitespace";
}); });
} catch (e) { } catch (e) {
@ -327,4 +326,22 @@ function tokenizeFull(input) {
} }
} }
function tokenizeFull(input) {
var matchop = tools.opMatch(operators);
var initialPass = tokenizeHelp(input, matchop).reverse();;
for (var i = 0; i < initialPass.length; i++) {
if (initialPass.slice(i, i+7).map(function(x) { return x[0]; }) ===
["defop", "integer", "identifier", "Left", "Right",
"left_paren", "identifier", "identifier", "identifier",
"right_paren"])
rep.OPInfo[initialPass[i+5][1]] = [parseInt(initialPass[i+1][1], 10),
initialPass[i+2][1]];
}
operators = Object.keys(rep.OPInfo);
matchop = tools.opMatch(operators);
return tokenizeHelp(input, matchop);
}
module.exports = {tokenize : tokenizeFull}; module.exports = {tokenize : tokenizeFull};

Loading…
Cancel
Save