diff --git a/parse.js b/parse.js index 9f6ca87..903ce75 100755 --- a/parse.js +++ b/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) { var linenum = fst(tokens)[3]; @@ -498,12 +543,14 @@ function parse(tokens) { else if (toktype === "float") return new typ.FloatT(token); else if (toktype === "identifier") - return new typ.Name(token); + return new typ.Name(token); else if (toktype === "truelit" || toktype === "falselit") return new typ.BoolT(token); else if (toktype === "def" || toktype === "let") 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") return parseIf(tokens); else if (toktype === "left_paren") { diff --git a/representation.js b/representation.js index bc19d72..09d456f 100644 --- a/representation.js +++ b/representation.js @@ -156,6 +156,24 @@ function If(condition, thenexp, elseexp) { 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 //assumes that the identifier refers to the name of a primitive @@ -178,25 +196,26 @@ function makeApp(name, parameters) { } 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"]} + "-" : [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"]} module.exports = { IntT : IntT, diff --git a/tokenize.js b/tokenize.js index 66d0a7f..5cdd1cc 100755 --- a/tokenize.js +++ b/tokenize.js @@ -5,8 +5,6 @@ var tools = require("./tools.js"); var error = require("./errors.js"); var operators = Object.keys(rep.OPInfo); -var matchop = tools.opMatch(operators); - function isDigit(a) { if (!a) return false; @@ -80,7 +78,7 @@ function tokenizeNum(tokstream, charnum, linenum) { * 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 n = 0; while ((!isWhitespace(tokstream[0])) && isIdentifier(tokstream[0]) && !matchop(tokstream)) { @@ -134,7 +132,7 @@ function peek(tokstream, toktype, word, charnum, linenum) { return false; } -function tokenize(tokstream) { +function tokenize(tokstream, matchop) { var tokens = []; var charnum = 1; var linenum = 1; @@ -239,10 +237,10 @@ function tokenize(tokstream) { tokstream = tokstream.substr(2); break; } - var inkeyword = peek(tokstream, "in", "in"); + var inkeyword = peek(tokstream, "in", "in "); if (inkeyword) { tokens.push(inkeyword); - tokstream = tokstream.substr(2); + tokstream = tokstream.substr(3); break; } @@ -251,6 +249,7 @@ function tokenize(tokstream) { if (defop) { tokens.push(["defop", "defop", charnum, linenum]); tokstream = tokstream.substr(5); + break; } var def = peek(tokstream, "def", "def"); if (def) { @@ -304,21 +303,21 @@ function tokenize(tokstream) { tokens.push(["identifier", op, charnum, linenum]); } else { - var result = tokenizeIdent(tokstream, charnum, linenum); + var result = tokenizeIdent(tokstream, matchop, charnum, linenum); result.map(function(x) { charnum++; tokens.push(x[1]); tokstream = tokstream.substr(x[0]); }); } - } + } } return tokens; } -function tokenizeFull(input) { +function tokenizeHelp(input, matchop) { try { - return tokenize(input).reverse().filter(function(x) { + return tokenize(input, matchop).reverse().filter(function(x) { return x[0] !== "whitespace"; }); } 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};