diff --git a/parse.js b/parse.js index 24a30dc..8f7acc7 100755 --- a/parse.js +++ b/parse.js @@ -1,4 +1,4 @@ -#! /usr/bin/nodejs +#! /usr/bin/node var typ = require("./representation.js"); var tool = require("./tools.js"); @@ -16,9 +16,7 @@ function snd(ts) { //Checks if the next token is not followed by any of ``checks'' function notFollowedBy(tokens, checks) { var nextT = fst(tokens)[0]; - if (!snd(tokens)) - console.log("Error: "+ fst(tokens)[0] +" must be followed by something"); - else if (checks.some(function (x) {return x === nextT;})) + if (checks.some(function (x) {return x === nextT;})) return false; else return true; @@ -69,7 +67,63 @@ function parseMany(exprType, valid, tokens) { return results; } +/* Tries to parse exprType separated by the token between + * e.g. ,,... + */ +function parseBetween(exprType, between, tokens) { + var first = parse(tokens); + if (!exprType(first)) { + console.log("Error, unexpected token:"+fst(tokens)[0]); + return; + } + var items = [first]; + var parsed; + if (tokens.length > 1 && fst(tokens)[0] === between) { + while (fst(tokens)[0] === between) { + tokens.pop(); + parsed = parse(tokens); + items.push(parsed); + } + return items; + } + return items; +} + +function parseList(tokens) { + var xs = parseBetween(function (x) { return true; }, "comma", tokens); + if (fst(tokens)[0] !== "right_square") { + console.log("Error, list must be terminated by ]"); + return undefined; + } + tokens.pop(); + return new typ.ListT(xs); +} + + +function parseDefFunction(tokens) { + var fname = parse(tokens); + if (!fname.exprType === "identifier") { + console.log("Error, expected an identifier in function definition"); + return undefined; + } + var parameters = parseMany(validName, validFormPar, tokens); + if ((fst(tokens)[0]) !== "right_paren") { + console.log("Error, formal parameters must be followed by )"); + return undefined; + } + tokens.pop(); + var body = parse(tokens); + return new typ.DefFunc(fname, parameters, body); +} + + + function parseDef(tokens) { + if (fst(tokens)[0] === "left_paren") { + // It's a function definition + tokens.pop(); + return parseDefFunction(tokens); + } if (notFollowedBy(tokens, ["identifier"])) { console.log("Error: def must be followed by identifier, not "+fst(tokens)[0]); return undefined; @@ -132,47 +186,6 @@ var validArgument = tool.compose(tool.not, makeChecker(invalidArguments)); var validArgTypes = tool.compose(tool.not, makeChecker(["Definition"])); var validOperator = makeChecker(["identifier"]); -function parse(tokens) { - if (fst(tokens)) - var toktype = fst(tokens)[0]; - else { - //console.log("Unexpected end of source") - process.exit(code=1); - } - var token = fst(tokens)[1]; - tokens.pop(); - if (toktype === "stringlit") - return new typ.StrT(token); - else if (toktype === "lambda") - return checkParse(parseLambda(tokens)); - else if (toktype === "integer") - return new typ.IntT(token); - else if (toktype === "float") - return new typ.FloatT(token); - else if (toktype === "identifier") - return new typ.Name(token); - else if (toktype === "truelit" || toktype === "falselit") - return new typ.BoolT(token); - else if (toktype === "def") - return checkParse(parseDef(tokens)); - else if (toktype === "ifexp") - return checkParse(parseIf(tokens)); - else if (toktype === "left_paren") { - if (fst(tokens)[0] === "lambda") { - tokens.pop(); - var parsed = checkParse(parseLambda(tokens)); - tokens.pop(); - return parsed; - } - else - return computeApp(tokens); - } - else { - console.log("Unexpected token: " + toktype); - process.exit(code=1); - } -} - function checkParse(p) { if (p === undefined) { console.log("Quitting, could not finish parsing!"); @@ -252,6 +265,49 @@ function parseInfix(tokens, minPrec, lhs) { return lhs; } +function parse(tokens) { + if (fst(tokens)) + var toktype = fst(tokens)[0]; + else { + //console.log("Unexpected end of source") + process.exit(code=1); + } + var token = fst(tokens)[1]; + tokens.pop(); + if (toktype === "stringlit") + return new typ.StrT(token); + else if (toktype === "left_square") + return parseList(tokens); + else if (toktype === "lambda") + return checkParse(parseLambda(tokens)); + else if (toktype === "integer") + return new typ.IntT(token); + else if (toktype === "float") + return new typ.FloatT(token); + else if (toktype === "identifier") + return new typ.Name(token); + else if (toktype === "truelit" || toktype === "falselit") + return new typ.BoolT(token); + else if (toktype === "def") + return checkParse(parseDef(tokens)); + else if (toktype === "ifexp") + return checkParse(parseIf(tokens)); + else if (toktype === "left_paren") { + if (fst(tokens)[0] === "lambda") { + tokens.pop(); + var parsed = checkParse(parseLambda(tokens)); + tokens.pop(); + return parsed; + } + else + return computeApp(tokens); + } + else { + console.log("Unexpected token: " + toktype); + process.exit(code=1); + } +} + function pprintName(ident) { return pprint(ident.val); } @@ -310,9 +366,8 @@ function pprint(expr) { var input = fs.readFileSync('/dev/stdin').toString(); var tokenized = tokenizer.tokenize(input).reverse().filter(function(x) { return x[0] !== "whitespace";}); //console.log(tokenized); - while (tokenized !== []) { - console.log(pprint(parse(tokenized))); + console.log(parse(tokenized)); if (!tokenized) break; } diff --git a/representation.js b/representation.js index 9734881..14e76d6 100644 --- a/representation.js +++ b/representation.js @@ -55,9 +55,8 @@ function BoolT(b) { BoolT.prototype = Expression; -function ListT(x, xs) { - this.x = x; - this.rest = xs; +function ListT(xs) { + this.xs = xs; this.val = xs; this.exprType = "List"; return this; @@ -109,6 +108,15 @@ function Def(ident, exp) { return this; } +function DefFunc(ident, params, body) { + this.ident = ident; + this.val = this.ident; + this.params = params; + this.body = body; + this.exprType = "FunctionDefinition"; + return this; +} + function If(condition, thenexp, elseexp) { this.condition = condition; this.thenexp = thenexp; @@ -163,4 +171,5 @@ module.exports = OpT : OpT, OPInfo : OPInfo, makeApp : makeApp, - If : If} + If : If, + DefFunc : DefFunc} diff --git a/test.jl b/test.jl index bbcb92f..1130c8f 100644 --- a/test.jl +++ b/test.jl @@ -16,4 +16,16 @@ def fact else (n * (fact (n - 1)))) -def main (print (fact 15)) +def fib + (lambda n -> + if (n == 0) + then 0 + else + if (n == 1) + then 1 + else + (+ + (fib (n - 1)) + (fib (n - 2)))) + +def main (print (fib 15)) diff --git a/tokenize.js b/tokenize.js index 4c07d88..5c87471 100755 --- a/tokenize.js +++ b/tokenize.js @@ -273,5 +273,4 @@ module.exports = {tokenize : tokenize}; //var tokstream = fs.readFileSync("/dev/stdin").toString(); //console.log(isIdentifier(')')); //console.log(tokenize(tokstream)); -//tokenize(tokstream);