Skip to content
Browse files

merging master

  • Loading branch information...
1 parent 1dea9ee commit 42d3c1f0a87a5aca8891404c3f2f49db22d7c14b Mattis Jeppsson committed May 19, 2010
View
53 Prelude.hs
@@ -1,53 +0,0 @@
-module Prelude where
- data Bool = True | False
-
- infixl 6 +
- infixl 6 -
- infixl 7 *
- infixr 0 $
- infixr 9 .
- infixr 2 ||
- infixr 3 &&
-
- ($) f x = f x
- (.) f g = \x -> f $ g x
-
- (&&) x y = case x of
- False -> False
- True -> y
-
- (||) x y = case x of
- True -> True
- False -> y
-
- not x = case x of
- True -> False
- False -> True
-
- otherwise = True
-
- id x = x
-
- map f xs = case xs of
- [] -> []
- (x:xs) -> f x : map f xs
-
- foldr1 f xs = case xs of
- [x] -> x
- (x:xs) -> f x (foldr1 f xs)
-
- filter f xs = case xs of
- [] -> []
- (x:xs) -> case (f x) of
- True -> x : filter f xs
- False -> filter f xs
-
- iterate f x = f x : iterate f x
-
- head xs = case xs of
- (x:_) -> x
-
- tail xs = case xs of
- (_:xs) -> xs
-
- fix f = let x = f x in x
View
1 README
@@ -0,0 +1 @@
+Yeeeah, you read me!
View
408 haskell.ast.js
@@ -1,31 +1,32 @@
-(function(ast, interpreter) {
- function expectType(o,t) {
- if (!(o instanceof t)) {
- throw new Error("Expected " + typeof t + " " + typeof o + " given.");
- };
- };
+(function(ast, interpreter, utilities) {
+ expectType = utilities.expectType;
- function expectTypeOf(o, t) {
- if ((typeof o) != t) {
- throw new Error("Expected " + t + ", " + typeof o + " given.");
- };
- };
+ expectTypeOf = utilities.expectTypeOf;
- function expectTypeArray(os, t) {
- for (i in os) {
- if (!(os[i] instanceof t)) {
- throw new Error("Expected " + typeof t + ", " + typeof os[i] + " given at index " + i);
- };
- };
- };
+ expectTypeArray = utilities.expectTypeArray;
/*
- data Module = Module [Declaration]
+ data Module = Module VisibleNames [Import] [Declaration]
*/
ast.Module = function(declarations) {
expectTypeArray(declarations, ast.Declaration);
this.declarations = declarations;
};
+
+ /*
+ data VisibleNames = Hiding [NameDef]
+ | Showing [NameDef]
+ */
+
+ /*
+ data NameDef = Name Identifier | ConstructorName Identifer [NameDef] | NoName
+ // NoName = ...
+ */
+
+ /*
+ Import = Import Identifier VisibleNames
+ | ImportQualified Identifer VisibleNames Identifier
+ */
/*
data Expression = Constant Value
@@ -34,21 +35,39 @@
| Let Pattern Expression Expression
| Case Expression [(Pattern, Expression)]
| VariableLookup Identifier
+ | Do [DoNotation]
+ | List [Expression]
+ | ArithmeticSequence Expression (Maybe Expression) (Maybe Expression)
+ | ListComprehension Expression [ListNotation]
| Primitive Function
*/
-
+ // Eval returns a whnf
ast.Expression = function(){};
-
-
+ ast.Expression.prototype = new Object();
+ // Either desugar or the other needs overriding in child objects
+ ast.Expression.prototype.eval = function(env) {
+ return this.desugar().eval(env);
+ };
+ ast.Expression.prototype.stringify = function() {
+ return this.desugar().stringify();
+ };
+ ast.Expression.prototype.desugar = function() {
+ return this;
+ };
ast.Constant = function(value) {
expectType(value, ast.Value);
this.type ="Constant";
this.value = value;
- this.eval = function(env) {
- return new interpreter.ConstantThunk(this.value);
- };
};
+ ast.Constant.prototype = new ast.Expression();
+ ast.Constant.prototype.eval = function(env) {
+ return this.value.eval(env);
+ };
+ ast.Constant.prototype.stringify = function() {
+ return this.value.stringify();
+ };
+
ast.Lambda = function(pattern, expression) {
expectType(pattern, ast.Pattern);
expectType(expression, ast.Expression);
@@ -57,8 +76,12 @@
this.expression = expression;
this.eval = function(env) {
- return new interpreter.Closure(env, this);
+ return new interpreter.LambdaAbstraction(env, this.pattern, this.expression);
};
+
+ this.stringify = function() {
+ return "(\\" + this.pattern.stringify() + " -> " + this.expression.stringify() + ")";
+ };
};
ast.Application = function(func, arg) {
expectType(func, ast.Expression);
@@ -67,26 +90,31 @@
this.func = func;
this.arg = arg;
this.eval = function(env) {
- var clos = this.func.eval(env);
- while (clos.expression.type!="Lambda") {
- clos = clos.force();
- };
- var x = clos.expression.pattern;
- var body = clos.expression.expression;
- return body.eval(clos.env.substitute(x, new interpreter.Closure(env, this.arg)));
+ var continuation = this.func.eval(env);
+ while (!(continuation instanceof interpreter.WeakHead)) {
+ continuation = continuation.force();
+ };
+ return continuation.apply(new interpreter.HeapPtr(new interpreter.Closure(env, this.arg)));
};
+ this.stringify = function() {
+ return "(" + this.func.stringify() + ") (" + this.arg.stringify() + ")";
+ };
};
ast.Let = function(declr, expr) {
- expectType(declr, ast.Declaration);
+ expectTypeArray(declr, ast.Declaration);
expectType(expr, ast.Expression);
this.type = "Let";
this.declr = declr;
this.expr = expr;
this.eval = function(env) {
- var newEnv = env.derive();
- newEnv.patternBind(this.declr.pattern, new interpreter.Closure(newEnv, this.declr.expression));
- return this.expr.eval(newEnv);
+ var newEnv = interpreter.loadDeclarations(this.declr, env.derive());
+ return new interpreter.Closure(newEnv, this.expr);
};
+ this.stringify = function() {
+ return "let {" + this.declr.map(function (d) {
+ return d.stringify();
+ }).join(";") + "} in " + this.expr.stringify();
+ };
};
ast.Case = function(expr, cases) {
expectType(expr, ast.Expression);
@@ -95,41 +123,128 @@
this.expr = expr;
this.cases = cases;
this.eval = function(env) {
- var expr = new interpreter.Closure(env, this.expr);
+ var expr = new interpreter.HeapPtr(new interpreter.Closure(env, this.expr));
for (var i in this.cases) {
var newEnv = env.derive();
if (this.cases[i][0].match(newEnv, expr)) {
return new interpreter.Closure(newEnv, this.cases[i][1]);
};
};
- alert("No matching clause");
+ throw new Error("No matching clause");
};
+
+ this.stringify = function() {
+ return "case " + this.expr.stringify() + " of {" +
+ this.cases.map(function(c) {
+ return c[0].stringify() + " -> " + c[1].stringify() + ";";
+ }).join("") + "}";
+ };
};
ast.VariableLookup = function(identifier) {
expectTypeOf(identifier, "string");
this.type = "VariableLookup";
this.identifier = identifier;
this.eval = function(env) {
- return env.lookup(this.identifier);
+ return env.lookup(this.identifier).dereference();
+ };
+
+ this.stringify = function() {
+ return this.identifier;
+ };
+ };
+ ast.Do = function(notations) {
+ expectTypeArray(notations, ast.DoNotation);
+ this.type="Do";
+ this.notations = notations;
+ };
+ ast.Do.prototype = new ast.Expression();
+ ast.Do.prototype.desugar = function() {
+ var rest = this.notations.concat();
+ var first = rest.shift();
+ return (first.partDesugar(rest));
+ };
+
+ ast.List = function(expressions) {
+ expectTypeArray(expressions, ast.Expression);
+ this.type="List";
+ this.expressions = expressions;
+ };
+ ast.List.prototype = new ast.Expression();
+ ast.List.prototype.desugar = function() {
+ // [] = []
+ // [1] = 1:[]
+ // [1,2] = 1:[2]
+ if (this.expressions.length == 0) {
+ return new ast.VariableLookup("[]");
};
+ var first = this.expressions[0];
+ return new ast.Application(new ast.Application(new ast.VariableLookup(":"),
+ first),
+ new ast.List(this.expressions.slice(1))
+ );
+ };
+
+ ast.ArithmeticSequence = function(e1, e2, e3) {
+ expectType(e1, ast.Expression);
+ if (e2) expectType(e2, ast.Expression);
+ if (e3) expectType(e3, ast.Expression);
+ this.type="ArithmeticSequence";
+ this.e1 = e1;
+ this.e2 = e2;
+ this.e3 = e3;
+ };
+ ast.ArithmeticSequence.prototype = new ast.Expression();
+ ast.ArithmeticSequence.prototype.desugar = function() {
+ // [e1..] = enumFrom e1
+ // [e1,e2..] = enumFromThen e1 e2
+ // [e1..e3] = enumFromTo e1 e3
+ // [e1,e2..e3] = enumFromThenTo e1 e2 e3
+ var funname = 'enumFrom';
+ if (this.e2) funname = funname + 'Then';
+ if (this.e3) funname = funname + 'To';
+ var application = new ast.Application(new ast.VariableLookup(funname), this.e1);
+ if (this.e2) application = new ast.Application(application, this.e2);
+ if (this.e3) application = new ast.Application(application, this.e3);
+ return application;
};
+
+ ast.ListComprehension = function(ret, notations) {
+ expectType(ret, ast.Expression);
+ expectTypeArray(notations, ast.ListNotation);
+ this.type="ListComprehensions";
+ this.ret = ret;
+ this.notations = notations;
+ };
+ ast.ListComprehension.prototype = new ast.Expression();
+ ast.ListComprehension.prototype.desugar = function() {
+ if (this.notations.length == 0) {
+ return (new ast.Application(new ast.VariableLookup("return"), this.ret));
+ }
+ var first = this.notations[0];
+ return new ast.Do([first.partDesugar(), new ast.DoExpr(new ast.ListComprehension(this.ret,
+ this.notations.slice(1)))]);
+ };
+
+
+
ast.Primitive = function(func) {
expectTypeOf(func, "function");
this.type="Primitive";
this.func = func;
this.eval = function(env) {
return this.func(env);
};
- };
- ast.Constant.prototype = new ast.Expression();
+ this.stringify = function() {
+ return "{primitive function}";
+ };
+ };
ast.Lambda.prototype = new ast.Expression();
ast.Application.prototype = new ast.Expression();
ast.Let.prototype = new ast.Expression();
ast.Case.prototype = new ast.Expression();
ast.VariableLookup.prototype = new ast.Expression();
ast.Primitive.prototype = new ast.Expression();
-
/* ast.Constant.prototype.constructor = ast.Constant;
ast.Lambda.prototype.constructor = ast.Lambda;
ast.Application.prototype.constructor = ast.Application;
@@ -139,23 +254,147 @@
ast.Primitive.prototype.constructor = ast.Primitive; */
/*
+ data DoNotation = DoLet [Declaration]
+ | DoBind Pattern Expression
+ | DoExpr Expression
+ */
+ ast.DoNotation = function(){};
+
+ ast.DoLet = function(declrs) {
+ expectTypeArray(declrs, ast.Declaration);
+ this.type="DoLet";
+ this.declrs = declrs;
+ };
+ ast.DoLet.prototype = new ast.DoNotation();
+ ast.DoLet.prototype.partDesugar = function(rest) {
+ // let declr ; do ==> let declr in do
+ return new ast.Let(this.declrs, new ast.Do(rest));
+ };
+
+ ast.DoBind = function(pattern, expression) {
+ expectType(pattern, ast.Pattern);
+ expectType(expression, ast.Expression);
+ this.type="DoBind";
+ this.pattern = pattern;
+ this.expression = expression;
+ };
+ ast.DoBind.prototype = new ast.DoNotation();
+ ast.DoBind.prototype.partDesugar = function(rest) {
+ // x <- expr ; do ==> expr >>= (a -> case a of x -> do; _ -> fail)
+ return new ast.Application(
+ new ast.Application(
+ new ast.VariableLookup(">>="),
+ this.expression
+ ),
+ new ast.Lambda(new ast.VariableBinding("__todoGenerateunique"),
+ new ast.Case(new ast.VariableLookup("__todoGenerateunique"),
+ [[this.pattern, new ast.Do(rest)],
+ [new ast.Wildcard(),new ast.Application(new ast.VariableLookup("fail"), new ast.VariableLookup("undefined"))]])
+ )
+ );
+ };
+
+ ast.DoExpr = function(expr) {
+ expectType(expr, ast.Expression);
+ this.type="DoExpr";
+ this.expr = expr;
+ };
+ ast.DoExpr.prototype = new ast.DoNotation();
+ ast.DoExpr.prototype.partDesugar = function(rest) {
+ if (rest.length == 0) {
+ return this.expr;
+ };
+ // expr ; do ==> expr >> do
+ return new ast.Application(new ast.Application(new ast.VariableLookup(">>"), this.expr), new ast.Do(rest));
+ };
+
+ /*
+ data ListNotation = ListGuard Expression
+ | ListBind Pattern Expression
+ | ListLet Pattern Expression
+ */
+
+ ast.ListNotation = function() {};
+
+ ast.ListGuard = function(expr) {
+ expectType(expr, ast.Expression);
+ this.type="ListGuard";
+ this.expr = expr;
+ };
+ ast.ListGuard.prototype = new ast.ListNotation();
+ ast.ListGuard.prototype.partDesugar = function() {
+ return new ast.DoExpr(new ast.Application(new ast.VariableLookup("guard"),
+ this.expr));
+ };
+
+ ast.ListBind = function(pattern, expr) {
+ expectType(pattern, ast.Pattern);
+ expectType(expr, ast.Expression);
+ this.type="ListBind";
+ this.pattern = pattern;
+ this.expr = expr;
+ };
+ ast.ListBind.prototype = new ast.ListNotation();
+ ast.ListBind.prototype.partDesugar = function() {
+ // x <- expr ==> x <- expr ...
+ return new ast.DoBind(this.pattern, this.expr);
+ };
+
+ ast.ListLet = function(decls) {
+ expectType(decls, ast.Declaration);
+ this.type="ListLet";
+ this.decls = decls
+ };
+ ast.ListLet.prototype = new ast.ListNotation();
+ ast.ListLet.prototype.partDesugar = function() {
+ // let p = expr ==> let p = expr ...
+ return new ast.DoLet(this.decls);
+ };
+
+
+
+ /*
data Value = Num Int
*/
- ast.Value = function(){};
-
+ ast.Value = function() {};
ast.Num = function(num) {
expectTypeOf(num, "number");
this.type = "Num";
this.num = num;
- this.equals = function(n) {
- return this.num == n.num;
+ this.match = function(env, n) {
+ return (new ast.PatternConstructor("I#", [new ast.ConstantPattern(new ast.PrimitiveValue(this.num))])).match(env, n);
+ };
+
+ this.eval = function(env) {
+ return new interpreter.Data("I#", [new interpreter.HeapPtr(new interpreter.Closure(env, new ast.Constant(new ast.PrimitiveValue(this.num))))]);
+ };
+
+ this.stringify = function() {
+ return this.num;
+ };
+ };
+ ast.PrimitiveValue = function(value) {
+ this.type="PrimitiveValue";
+ this.value = value;
+ this.eval = function(env) {
+ return this.value;
};
+ this.match = function(env, v) {
+ return this.value == v.dereference();
+ };
+
+ this.stringify = function()
+ {
+ return this.value + "#";
+ };
};
ast.Num.prototype = new ast.Value();
+ ast.PrimitiveValue.prototype = new ast.Value();
/*
data Declaration = Variable Pattern Expression
+ | Function Identifier [Pattern] [(Guard, Expression)]|Expression
| Data Identifier [Constructor]
*/
@@ -167,6 +406,10 @@
this.type = "Variable";
this.pattern = pattern;
this.expression = expression;
+
+ this.stringify = function() {
+ return this.pattern.stringify() + " = " + this.expression.stringify();
+ };
};
ast.Data = function(identifier, constructors) {
@@ -177,9 +420,43 @@
this.constructors = constructors;
};
+ // expression can either be an expression or a list of [guard, expression]
+ // where guard is an expression of type Boolean.
+ ast.Function = function(identifier, patterns, expression) {
+ expectTypeOf(identifier, "string");
+ expectTypeArray(patterns, ast.Pattern);
+ // expression can be two different kinds... TODO: fix this?
+ this.type = "Function";
+ this.identifier = identifier;
+ this.patterns = patterns;
+ this.expression = expression;
+ this.patternMatch = function(env, givenArgs) {
+ for (var i in this.patterns) {
+ if (!this.patterns[i].match(env, givenArgs[i])) {
+ return false;
+ }
+ };
+ return true;
+ };
+
+ this.stringify = function() {
+ var exprstr;
+ if (this.expression instanceof Array) {
+ exprstr = this.expression.map(function(e) {
+ return e[0].stringify() + " -> " + e[1].stringify();
+ }).join("|");
+ } else {
+ exprstr = this.expression.stringify();
+ };
+ return this.identifier + this.patterns.map(function(p) {
+ return p.stringify();
+ }).join(" ") + " = " + exprstr;
+ };
+ };
+
ast.Variable.prototype = new ast.Declaration();
ast.Data.prototype = new ast.Declaration();
-
+ ast.Function.prototype = new ast.Declaration();
/*
data Constructor = Constructor Identifier Integer
@@ -208,14 +485,12 @@
this.identifier = identifier;
this.patterns = patterns;
this.match = function(env, expr) {
- while(expr.type!="Data") {
- expr=expr.force();
- };
- if (this.identifier!=expr.identifier) {
+ var weakHead = expr.dereference();
+ if (this.identifier!=weakHead.identifier) {
return false;
};
for (var i in this.patterns) {
- if (!this.patterns[i].match(env, expr.thunks[i])) {
+ if (!this.patterns[i].match(env, weakHead.ptrs[i])) {
return false;
};
};
@@ -229,6 +504,12 @@
};
return vars;
};
+
+ this.stringify = function() {
+ return this.identifier + " " + this.patterns.map(function(p) {
+ return p.stringify();
+ }).join(" ");
+ };
};
ast.VariableBinding = function(identifier) {
expectTypeOf(identifier, "string");
@@ -241,6 +522,10 @@
this.vars = function() {
return [this.identifier];
};
+
+ this.stringify = function() {
+ return this.identifier;
+ };
};
ast.Combined = function(identifier, pattern) {
expectTypeOf(identifier, "string");
@@ -255,20 +540,24 @@
this.vars = function() {
return [this.identifier].concat(this.pattern.vars());
};
+ this.stringify = function() {
+ return this.identifier + "@(" + this.pattern.stringify() + ")";
+ };
};
ast.ConstantPattern = function(value) {
expectType(value, ast.Value);
this.type = "ConstantPattern";
this.value = value;
this.match = function(env, expr) {
- while(expr.type!="ConstantThunk") {
- expr = expr.force();
- };
- return (this.value.equals(expr.value));
+ return (this.value.match(env, expr));
};
this.vars = function() {
return [];
};
+
+ this.stringify = function() {
+ return this.value.stringify();
+ };
};
ast.Wildcard = function() {
this.type = "Wildcard";
@@ -278,11 +567,14 @@
this.vars = function() {
return [];
};
+ this.stringify = function() {
+ return "_";
+ };
};
ast.PatternConstructor.prototype = new ast.Pattern();
ast.VariableBinding.prototype = new ast.Pattern();
ast.Combined.prototype = new ast.Pattern();
ast.ConstantPattern.prototype = new ast.Pattern();
ast.Wildcard.prototype = new ast.Pattern();
-})(haskell.ast,haskell.interpreter);
+})(haskell.ast,haskell.interpreter, haskell.utilities);
View
126 haskell.hiji.js
@@ -1,9 +1,17 @@
+// TODO omm man bläddrar upp i historyn så ska det man skrivit in sparas
var ENTER = '13';
var UP = '38';
var DOWN = '40';
var is_module_loaded = false;
var modules = new Array();
+
+var commands = new Array();
+commands[":l"] = "LOAD";
+commands[":load"] = "LOAD";
+commands[":h"] = "HELP";
+commands[":help"] = "HELP";
+
(function($){
var evaluateHaskell = function(line, env)
@@ -40,36 +48,47 @@ var modules = new Array();
// history
var hiss = new historry;
- // load history from cookie
- hiss_cookie = $.cookie("hiss");
- if(hiss_cookie != null){
- hiss.history_array = JSON.parse(hiss_cookie);
+
+ try{
+ // load history from cookie
+ hiss_cookie = $.cookie("hiss");
+ if(hiss_cookie != null){
+ hiss.history_array = JSON.parse(hiss_cookie);
+ }
+ }
+ catch(err){
+ console.log("Error: History not loaded from cookie");
}
var env = new haskell.interpreter.RootEnv();
- haskell.interpreter.primitives(env);
+ haskell.primitives.init(env);
- // ladda prelude
- load_module('Prelude.hs');
+ load_module('hs/Prelude.hs');
+
modules[0] = "Prelude";
+
this.html("<ol>" + makeInput(modules) + "</ol>");
$("input:text:visible:first").focus();
this.keydown(function(e){
var input = $('input', this);
var line = input.attr("value");
- if(e.keyCode==UP){
+ if(e.which==UP){
input.attr("value", hiss.older(line));
}
- if(e.keyCode==DOWN){
+ if(e.which==DOWN){
input.attr("value", hiss.newer(line));
}
- if (e.keyCode==ENTER){
-
+ if (e.which==ENTER){
// history
hiss.addHistory(line);
- $.cookie("hiss", JSON.stringify(hiss.history_array), {expires: 3 });
+ try{
+ $.cookie("hiss", JSON.stringify(hiss.history_array), {expires: 3 });
+ }
+ catch(err){
+ console.log("Error: History not saved to cookie");
+ }
input.attr("value","");
if(isCommand(line)){
@@ -78,7 +97,56 @@ var modules = new Array();
{
try {
var newLine = makeEntered(modules, line);
- var output = makeOutput(evaluateHaskell(line, env));
+
+ var showResult = function(result) {
+ if (result.type == "Data") {
+ var str = result.identifier;
+ var op = " ";
+
+ if (str == "I#") {
+ str = "";
+ } else if (str == ":") {
+ str = "";
+ op = ",";
+ }
+
+ if (result.ptrs) {
+ var first = true;
+ for (var i = 0; i < result.ptrs.length; i++) {
+ if (str.length == 0 && first) {
+ str = showResult(result.ptrs[i].dereference());
+ if (typeof str.str != "undefined")
+ str = str.str;
+ first = false;
+ } else {
+ var res = showResult(result.ptrs[i].dereference());
+ if (res.str)
+ res = res.str;
+ str = str + op + res;
+ }
+ }
+ }
+
+ return { str: str, isList: op == "," };
+ } if (result.force) {
+ return result.force();
+ } else if (result.ptrs) {
+ return result.ptrs[0].dereference();
+ } else {
+ return result;
+ }
+ }
+
+ var result = showResult(evaluateHaskell(line, env));
+ if (result.isList) {
+ result = result.str;
+ result = result.substring(0, result.length - 3);
+ result = "[" + result + "]";
+ } else if (result.str) {
+ result = result.str;
+ }
+
+ var output = makeOutput(result);
$('.input', this).after(output).replaceWith(newLine);
$("ol",this).append(makeInput(modules));
}
@@ -127,11 +195,11 @@ var modules = new Array();
function runCommand(i, input2, line){
var input = trim(i);
- var command = input.substr(0,2);
- var arg = trim(input.substr(2));
- var module_name = arg.substr(0, arg.lastIndexOf('.'));
+ var command = input.indexOf(" ") != -1 ? input.substr(0, input.indexOf(" ")) : input;
// load module
- if(command == ':l'){
+ if(commands[command] == "LOAD"){
+ var arg = trim(input.substr(command.length));
+ var module_name = arg.substr(0, arg.lastIndexOf('.'));
load_module(arg);
if(is_module_loaded){
var module_already_in_modules = false;
@@ -157,20 +225,36 @@ var modules = new Array();
$('.input').after(output).replaceWith(newLine);
$("ol").append(makeInput(modules));
}
+ }else if(commands[command] == "HELP"){
+ var newLine = makeEntered(modules, line);
+ var output_row = new Array();
+ output_row.push(makeOutput("Help"));
+ output_row.push(makeOutput(" "));
+ output_row.push(makeOutput("Commands:"));
+ output_row.push(makeOutput(":l [Module] ... load a module"));
+ var str = "$('.input')";
+ for (var i = output_row.length-1; i>=0; i--){
+ str += ".after(" + output_row[i] + ")";
+ // $('.input').after(output_row[i]).after(output).replaceWith(newLine);
+ }
+ str += ".replaceWith(newLine);";
+ alert(str);
+ eval(str);
+ // var output = makeOutput("HELP HELP HELP" + "<br>" + "asdas");
+ // $('.input').after(output1).after(output).replaceWith(newLine);
+ // $('.input').after(output).replaceWith(newLine);
+ // $('.input').after(output).replaceWith(newLine);
+ $("ol").append(makeInput(modules));
}
}
};
})(jQuery);
-
-// do nicer
function trim(str){
return str.replace(/^\s+|\s+$/g,"");
}
-
-
// historry-class with nice name
// !!!WARNING!!! NICE NAME. conflict with javascript
historry = function(input){
View
315 haskell.interpreter.js
@@ -1,130 +1,73 @@
-(function(interpreter, ast){
- interpreter.primitives = function(env) {
- env.bind("+", createPrimitive(env, ["a", "b"],
- function(env) {
- var a = forceTo(env.lookup("a"), "ConstantThunk");
- var b = forceTo(env.lookup("b"), "ConstantThunk");
- return new interpreter.ConstantThunk(new ast.Num(a.value.num+b.value.num));
- }));
- env.bind("-", createPrimitive(env, ["a", "b"],
- function(env) {
- var a = forceTo(env.lookup("a"), "ConstantThunk");
- var b = forceTo(env.lookup("b"), "ConstantThunk");
- return new interpreter.ConstantThunk(new ast.Num(a.value.num-b.value.num));
- }));
- env.bind("*", createPrimitive(env, ["a", "b"],
- function(env) {
- var a = forceTo(env.lookup("a"), "ConstantThunk");
- var b = forceTo(env.lookup("b"), "ConstantThunk");
- return new interpreter.ConstantThunk(new ast.Num(a.value.num*b.value.num));
- }));
- env.bind("alert", createPrimitive(env, ["l"],
- function(env) {
- var l = forceTo(env.lookup("l"), "ConstantThunk");
- alert(l.value.num);
- return new interpreter.Data("()", []);
- }));
- env.bind(":", createDataConstructor(env, ":", 2));
- env.bind("[]", createDataConstructor(env, "[]", 0));
-
- };
-
- // Creates env from an ast and returns it !
- interpreter.prepare = function(astt, env) {
- for (var i in astt.declarations) {
- var decl = astt.declarations[i];
+(function(interpreter, ast, primitives, utilities){
+
+ interpreter.loadDeclarations = function(declrs, env) {
+ var lastfunname = null;
+ var lastfunenv = [];
+ // TODO: Remove duplication of Function addition.
+ for (var i in declrs) {
+ var decl = declrs[i];
+ if (decl.type=="Function") {
+ if (lastfunname == decl.identifier) {
+ lastfunenv.push(decl);
+ } else {
+ if (lastfunenv.length > 0) {
+ // perhaps the intial HeapPtr shouldn't point to a weakhead, but here it does...
+ env.bind(lastfunname, new interpreter.HeapPtr(new interpreter.DelayedApplication(env, lastfunenv[0].patterns.length, lastfunenv, [])));
+ }
+ lastfunname = decl.identifier;
+ lastfunenv = [decl];
+ }
+ continue;
+ }
+ if (lastfunenv.length > 0) {
+ // perhaps the intial HeapPtr shouldn't point to a weakhead, but here it does...
+ env.bind(lastfunname, new interpreter.HeapPtr(new interpreter.DelayedApplication(env, lastfunenv[0].patterns.length, lastfunenv, [])));
+ lastfunname = "";
+ lastfunenv = [];
+ }
if (decl.type=="Variable") {
- env.patternBind(decl.pattern, new interpreter.Closure(env, decl.expression));
+ env.patternBind(decl.pattern, new interpreter.HeapPtr(new interpreter.Closure(env, decl.expression)));
}
else if (decl.type=="Data") {
for (var i in decl.constructors) {
constr = decl.constructors[i];
- env.bind(constr.identifier, createDataConstructor(env, constr.identifier, constr.number));
- };
- };
- };
+ env.bind(constr.identifier, primitives.createDataConstructorKludge(env, constr.identifier, constr.number));
+ }
+ }
+ }
+ if (lastfunenv.length > 0) {
+ // perhaps the intial HeapPtr shouldn't point to a weakhead, but here it does...
+ env.bind(lastfunname, new interpreter.HeapPtr(new interpreter.DelayedApplication(env, lastfunenv[0].patterns.length, lastfunenv, [])));
+ }
return env;
};
+ // Creates env from an ast and returns it !
+ interpreter.prepare = function(astt, env) {
+ return interpreter.loadDeclarations(astt.declarations, env);
+ };
+
+ // Executes a haskell program
interpreter.execute = function(astt) {
var env = new interpreter.RootEnv();
// Only fun defs atm
interpreter.prepare(astt, env);
- interpreter.primitives(env);
- return env.lookup("main").force();
+ primitives.init(env);
+ return env.lookup("main").dereference();
};
-
+ // Evaluates an expression under an env
interpreter.eval = function(astt, env) {
- return (new interpreter.Closure(env, astt)).force();
+ return (new interpreter.HeapPtr(new interpreter.Closure(env, astt))).dereference();
};
- function createPrimitive(env, args, func) {
- var expr = new ast.Primitive(func);
- var argsR = [].concat(args).reverse();
- for (var i in argsR) {
- expr = new ast.Lambda(new ast.VariableBinding(argsR[i]), expr);
- };
- return new interpreter.Closure(env, expr);
- };
- function createDataConstructor(env, ident, num) {
- var args = [];
- for (var i = 0; i<num; i++) {
- args[i] = "__p" + i;
- };
- var prim = function(env) {
- var givenArgs=[];
- for (var i in args) {
- givenArgs[i] = env.lookup(args[i]);
- };
- return new interpreter.Data(ident, givenArgs);
- };
- return createPrimitive(env, args, prim);
- };
- function forceTo(thunk, type) {
- while(thunk.type!=type) {
- thunk=thunk.force();
- };
- return thunk;
- };
-
-
- interpreter.test = function() {
- // inc = \x -> x + 1
- // inc2 = \x -> inc (inc x)
- // main = print (inc2 2)
- // map = (\f -> let map' = (\l -> case l of
- // (x:xs) -> f x : map' xs
- // [] -> []
- // ) in map')
- var astt = new ast.Module([
- new ast.Variable(new ast.VariableBinding("inc"),
- new ast.Lambda(new ast.VariableBinding("x"),
- new ast.Application(new ast.Application(new ast.VariableLookup("+"),
- new ast.VariableLookup("x")),
- new ast.Constant(new ast.Num(1))))),
- new ast.Variable(new ast.VariableBinding("inc2"),
- new ast.Lambda(new ast.VariableBinding("x"),
- new ast.Application(new ast.VariableLookup("inc"),
- new ast.Application(new ast.VariableLookup("inc"),
- new ast.VariableLookup("x"))))),
- new ast.Variable(new ast.VariableBinding("main"),
- new ast.Application(new ast.VariableLookup("alert"),
- new ast.Application(new ast.VariableLookup("inc2"),
- new ast.Constant(new ast.Num(2)))))
- ]);
- interpreter.execute(astt);
- };
-
-
-
// Live data
/*
- data Env = RootEnv [(Identifier, Pattern, Thunk)|(Identifier, Thunk)]
- | ChildEnv [(Identifier, Pattern, Thunk)|(Identifier, Thunk)] Env
+ data Env = RootEnv [(Identifier, Pattern, HeapPtr)|(Identifier, HeapPtr)]
+ | ChildEnv [(Identifier, Pattern, HeapPtr)|(Identifier, HeapPtr)] Env
*/
interpreter.Env = function() {
-
+
};
interpreter.Env.prototype.substitute = function(pattern, expression) {
@@ -143,6 +86,7 @@
}
};
interpreter.Env.prototype.bind = function(identifier, expr) {
+ utilities.expectType(expr, interpreter.HeapPtr);
this.env[identifier] = expr;
};
interpreter.Env.prototype.lookup = function(identifier) {
@@ -152,13 +96,13 @@
var found = this.env[identifier];
if (found.type == "unforced") {
if (!found[0].match(this, found[1])) {
- alert("Unrefutable pattern failed");
+ throw new Error("Unrefutable pattern failed");
};
};
return this.env[identifier];
};
interpreter.Env.prototype.onUndefined = function(identifier) {
- return undefined;
+ throw new Error("Identifier not in env " + identifier );
};
@@ -167,56 +111,169 @@
this.type = "RootEnv";
};
interpreter.RootEnv.prototype = new interpreter.Env();
- interpreter.RootEnv.prototype.constructor = interpreter.RootEnv;
-
+ var childId = 0;
interpreter.ChildEnv = function(parent) {
this.env = {};
this.type = "ChildEnv";
this.parent = parent;
+ this.id = childId++;
};
interpreter.ChildEnv.prototype = new interpreter.Env();
- interpreter.ChildEnv.prototype.constructor = interpreter.ChildEnv;
interpreter.ChildEnv.prototype.onUndefined = function(identifier) {
return this.parent.lookup(identifier);
};
+ /* data HeapPtr = HeapPtr Thunk WeakHead */
+ // There's no actuall heap pointer here
+ // The name is just used to highlight that it's
+ // use is the same as the heap pointer in a
+ // standard haskell implementation.
+ // "dereferencing" a HeapPtr returns the forced
+ // version of the thunk it points to as well
+ // as updates the pointer to the whnf.
+ interpreter.HeapPtr = function(thunk) {
+ this.thunk = thunk;
+ this.weakHead = undefined;
+ // Dereferencing a HeapPtr returns a whnf
+ this.dereference = function() {
+ if (this.weakHead == undefined) {
+ // We'll drive the execution here instead of recursing in the force method
+ var continuation = this.thunk;
+ while (continuation instanceof interpreter.Thunk) {
+ continuation = continuation.force();
+ }
+ this.weakHead = continuation;
+ this.thunk = null;
+ }
+ return this.weakHead;
+ };
+
+ this.stringify = function() {
+ if (this.weakHead == undefined) {
+ return this.thunk.stringify();
+ }
+ if (this.weakHead.stringify == undefined) {
+ return this.weakHead;
+ }
+ return this.weakHead.stringify();
+ };
+ };
+
/*
data Thunk = Closure Env Expression
| ConstantThunk Value
- | Data Identifier [Thunk]
+ | Data Identifier [HeapPtr]
| Primitive Env Function
+ | PrimData -- Javascript data
*/
+ interpreter.Thunk = function() {};
interpreter.Closure = function(env, expression) {
+ utilities.expectType(env, interpreter.Env);
+ utilities.expectType(expression, ast.Expression);
this.type = "Closure";
this.env = env;
this.expression = expression;
- this.forced = undefined;
- };
- interpreter.Closure.prototype.force = function() {
- if (this.forced == undefined) {
- this.forced = this.expression.eval(this.env);
- }
- // Forcing a closure is the same as evaluating its expression under the closures env
- return this.forced;
+ // force returns the whnf
+ this.force = function() {
+ // Forcing a closure is the same as evaluating its expression under the closures env
+ return this.expression.eval(this.env);
+ };
+
+ this.stringify = function() {
+ return this.expression.stringify();
+ };
};
interpreter.ConstantThunk = function(value) {
this.type = "ConstantThunk";
this.value = value;
+ this.force = function() {
+ return this;
+ };
};
- interpreter.ConstantThunk.prototype.force = function() {
- return this;
- };
- interpreter.Data = function(identifier, thunks) {
+ interpreter.Closure.prototype = new interpreter.Thunk();
+ interpreter.ConstantThunk.prototype = new interpreter.Thunk();
+
+ /*
+ data WeakHead = Data Identifier [HeapPtr]
+ | LambdaAbstraction Env Pattern Expression
+ | Primitive
+ */
+ interpreter.WeakHead = function() {};
+
+ interpreter.Data = function(identifier, ptrs) {
+ utilities.expectTypeArray(ptrs, interpreter.HeapPtr);
this.type = "Data";
this.identifier = identifier;
- this.thunks = thunks;
+ this.ptrs = ptrs;
+ this.getPtrs = function() {
+ return this.ptrs;
+ };
+
+ this.stringify = function() {
+ return "(" + this.identifier + " " + this.ptrs.map(function(ptr) {
+ return ptr.stringify();
+ }).join(" ") + ")";
+ };
};
- interpreter.Data.prototype.force = function() {
- // Data is already forced...
- return this;
+ interpreter.Data.prototype = new interpreter.WeakHead();
+
+ interpreter.LambdaAbstraction = function(env, pattern, expression)
+ {
+ this.type="LambdaAbstraction";
+ this.env = env;
+ this.pattern = pattern;
+ this.expression = expression;
+ this.apply = function(argument) {
+ var newEnv = this.env.substitute(this.pattern, argument);
+ return new interpreter.Closure(newEnv, this.expression);
+ };
+
+ this.stringify = function() {
+ return "(\\" + this.pattern.stringify() + " -> " + this.expression.stringify() + ")"
+ };
};
-})(haskell.interpreter, haskell.ast);
+ interpreter.LambdaAbstraction.prototype = new interpreter.WeakHead();
+
+ // A delayed application represents pattern/guard matches which aren't
+ // desugered. Eg: f 1 = 2; f 2 = 3;
+ interpreter.DelayedApplication = function(env, numArgs, funcs, givenArgs) {
+ this.type="DelayedApplication";
+ this.env = env;
+ this.funcs = funcs;
+ this.numArgs = numArgs;
+ this.givenArgs = givenArgs;
+ this.apply = function(argument) {
+ var givenArgs = this.givenArgs.concat();
+ givenArgs.push(argument);
+ if (this.numArgs == 1) {
+ for (var i in this.funcs) {
+ var newEnv = this.env.derive();
+ if (this.funcs[i].patternMatch(newEnv, givenArgs)) {
+ var matchedFunc = this.funcs[i];
+ if (matchedFunc.expression instanceof Array) {
+ for (var j in matchedFunc.expression) {
+ var guard = matchedFunc.expression[j][0];
+ var expression = matchedFunc.expression[j][1];
+ var guardResult = guard.eval(newEnv);
+ if (guardResult.identifier == "True") {
+ return new interpreter.Closure(newEnv, expression);
+ }
+ }
+ } else {
+ return new interpreter.Closure(newEnv, matchedFunc.expression);
+ }
+ }
+ }
+ throw new Error("Failed pattern match");
+ } else {
+ return new interpreter.DelayedApplication(this.env, this.numArgs - 1, this.funcs, givenArgs);
+ }
+ };
+ };
+ interpreter.DelayedApplication.prototype = new interpreter.WeakHead();
+
+})(haskell.interpreter, haskell.ast, haskell.primitives, haskell.utilities);
View
2,016 haskell.parser.js
@@ -1,117 +1,112 @@
// The parser
-/*
-Todo:
- - List comp.
-*/
-
-(function(parser, ast) {
- parser.lastInternalName = 0;
+(function(parser, ast) {
+ parser.lastInternalName = 0;
+
+ parser.generateInternalName = function() {
+ var parser = haskell.parser;
+
+ var name = "__v" + parser.lastInternalName.toString();
+ parser.lastInternalName++;
+ return name;
+ };
+
+ parser.fixity = {};
+ parser.fixity.left = 0;
+ parser.fixity.right = 1;
+ parser.fixity.none = 2;
+
+ parser.Operator = function(prec, fixity, op) {
+ this.prec = prec;
+ this.fixity = fixity;
+ this.op = op;
+ };
- parser.generateInternalName = function() {
- var parser = haskell.parser;
-
- var name = "__v" + parser.lastInternalName.toString();
- parser.lastInternalName++;
- return name;
- };
-
- parser.fixity = {};
- parser.fixity.left = 0;
- parser.fixity.right = 1;
- parser.fixity.none = 2;
-
- parser.Operator = function(prec, fixity, op) {
- this.prec = prec;
- this.fixity = fixity;
- this.op = op;
- };
-
parser.opTable = {};
/**
- * Parses Haskell code
- *
- * Reserved variables in the form __name
+ * Parses Haskell code
+ *
+ * Reserved variables in the form __name
*
* \code Code to parse
* \return The ast
*/
- parser.parse = function(code, options) {
- var enableHash = false;
-
- if (options != undefined) {
- if (options.enableHash) {
- enableHash = true;
- }
- }
-
- var reservedid = choice("case", "class", "data", "default", "deriving", "do", "else", "if", "import", "in",
- "infix", "infixl", "infixr", "instance", "let", "module", "newtype", "of", "then",
- "type", "where", "_");
-
+ parser.parse = function(code, options) {
+ var enableHash = false;
+
+ if (options != undefined) {
+ if (options.enableHash) {
+ enableHash = true;
+ }
+ }
+
+ var reservedid = choice("case", "class", "data", "default", "deriving", "do", "else", "if", "import", "in",
+ "infix", "infixl", "infixr", "instance", "let", "module", "newtype", "of", "then",
+ "type", "where", "_");
+
var reservedop = choice("..", ":", "::", "=", "\\", "|", "<-", "->", "@", "~", "=>");
-
- var integer = action(repeat1(range('0', '9')), function(ast) { return new haskell.ast.Num(parseInt(ast.join(""))); });
- var integerlit = function(state) {
- if (enableHash) {
- return choice( action(sequence(repeat1(range('0', '9')), '#'), function(ast) {
- return parseInt(ast[0].join(""));
- }),
- integer)(state);
- } else {
- return integer(state);
- }
+
+ var integer = action(repeat1(range('0', '9')), function(ast) { return new haskell.ast.Num(parseInt(ast.join(""))); });
+ var integerlit = function(state) {
+ if (enableHash) {
+ return choice( action(sequence(repeat1(range('0', '9')), '#'), function(ast) {
+ return new haskell.ast.PrimitiveValue(parseInt(ast[0].join("")));
+ }),
+ integer)(state);
+ } else {
+ return integer(state);
+ }
};
- var ident_ = function(state) {
- if (enableHash) {
- return action(sequence(repeat0(choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), '\'')), optional('#')), function(ast) {
- if (ast[1] != false) {
- return ast[0].join("") + '#';
- } else {
- return ast[0].join("");
- }
- })(state);
- } else {
- return action(repeat0(choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), '\'')), function(ast) { return ast.join(""); })(state);
- }
- };
-
+ var ident_ = function(state) {
+ if (enableHash) {
+ return action(sequence(repeat0(choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), '\'')), optional('#')), function(ast) {
+ if (ast[1] != false) {
+ return ast[0].join("") + '#';
+ } else {
+ return ast[0].join("");
+ }
+ })(state);
+ } else {
+ return action(repeat0(choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), '\'')), function(ast) { return ast.join(""); })(state);
+ }
+ };
+
var ident = action(butnot(sequence(range('a', 'z'), ident_), reservedid), function(ast) { return ast.join(""); });
-
- var char_ = choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), ' ', '\\n');
-
- var charlit = function(state) {
- var chr = sequence('\'', char_, '\'');
- if (enableHash) {
- return choice(action(sequence(chr, '#'), function(ast) { return ast[0]; }),
- chr)(state);
- } else {
- return chr(state);
- }
- }
-
- var string_ = action(repeat0(char_), function(ast) { return ast.join(""); });
-
- var stringlit = function(state) {
- var str = sequence('"', string_, '"');
- if (enableHash) {
- return choice(action(sequence(str, '#'), function(ast) { return ast[0]; }),
- str)(state);
- } else {
- return str(state);
- }
- };
-
- var exponent = sequence(choice('e', 'E'), optional(choice('+', '-')), integer); // todo: fix
-
- var float_ = choice(sequence(integer, expect('.'), integer, optional(exponent)),
- sequence(integer, exponent));
-
- var literal = choice(ws(integerlit), ws(charlit), ws(stringlit), ws(float_));
-
- var symbol = choice('!', '#', '$', '%', '&', '*', '+', '.', '/', '<', '=', '>', '?', '@', '\\', '^', '|', '-', '~');
+
+ var char_ = choice(range('A', 'Z'), range('a', 'z'), range('0', '9'), ' ', '\\n');
+
+ var charlit = function(state) {
+ var chr = sequence('\'', char_, '\'');
+ if (enableHash) {
+ return choice(action(sequence(chr, '#'), function(ast) { return ast[0]; }),
+ chr)(state);
+ } else {
+ return chr(state);
+ }
+ }
+
+ var string_ = action(repeat0(char_), function(ast) { return ast.join(""); });
+
+ var stringlit = function(state) {
+ var str = sequence('"', string_, '"');
+ if (enableHash) {
+ return choice(action(sequence(str, '#'), function(ast) { return ast[0]; }),
+ str)(state);
+ } else {
+ return str(state);
+ }
+ };
+
+ var exponent = sequence(choice('e', 'E'), optional(choice('+', '-')), integer); // todo: fix
+
+ var float_ = choice(sequence(integer, expect('.'), integer, optional(exponent)),
+ sequence(integer, exponent));
+
+ var literal = choice(ws(integerlit), ws(charlit), ws(stringlit), ws(float_));
+
+ var symbol = choice('!', '#', '$', '%', '&', '*', '+', '.', '/', '<', '=', '>', '?', '@', '\\', '^', '|', '-', '~');
var sym = action(repeat1(symbol), function(ast) { return ast.join(""); });
var modid = action(sequence(range('A', 'Z'), ident_), function(ast) { return ast.join(""); });
@@ -124,156 +119,158 @@ Todo:
var qtycon = action(sequence(range('A', 'Z'), ident_), function(ast) { return ast.join(""); });
- var qtycls = ident;
-
var conid = action(sequence(range('A', 'Z'), ident_), function(ast) { return ast.join(""); });
- var consym = butnot(sym, reservedop);
-
- var qconsym = consym;
+ var consym = butnot(sym, reservedop);
+
+ var tycls = conid;
+
+ var qtycls = tycls;
+
+ var qconsym = consym;
var qconid = conid;
var tycon = qtycon;
- var tyvar = ident;
-
- var tycls = epsilon_p;
+ var tyvar = varid;
- var gconsym = choice(':', qconsym);
-
- var qconop = choice(gconsym, sequence(expect(ws('`')), qconid, expect(ws('`'))));
-
var gconsym = choice(':', qconsym);
-
+
var qconop = choice(gconsym, sequence(expect(ws('`')), qconid, expect(ws('`'))));
-
+
+ var qvarop = choice(qvarsym, sequence(expect(ws('`')), qvarid, expect(ws('`'))));
+
var qop = choice(qvarop, qconop);
- var conop = choice(consym, sequence(expect(ws('`')), conid, expect(ws('`'))));
+ var conop = choice(consym, sequence(expect(ws('`')), conid, expect(ws('`'))));
+ var varop = choice(varsym, sequence(expect(ws('`')), varid, expect(ws('`'))));
+
var op = choice(varop, conop);
- var qcon = choice(qconid, sequence(expect(ws('(')), gconsym, expect(ws(')'))));
-
- var op_paran_action = function(p) {
- return action(p, function(ast) {
- return ast[0];
- });
+ var qcon = choice(qconid, sequence(expect(ws('(')), gconsym, expect(ws(')'))));
+
+ var op_paran_action = function(p) {
+ return action(p, function(ast) {
+ return ast[0];
+ });
}
var con = choice(conid, op_paran_action(sequence(expect(ws('(')), consym, expect(ws(')')))));
var qvar = choice(qvarid, op_paran_action(sequence(expect(ws('(')), qvarsym, expect(ws(')')))));
var var_ = choice(varid, op_paran_action(sequence(expect(ws('(')), varsym, expect(ws(')')))));
-
- var gcon = choice( ws("()"),
- ws("[]"),
- sequence(ws('('), repeat1(ws(',')), ws(')')),
+
+ var gcon = choice( ws("()"),
+ ws("[]"),
+ sequence(ws('('), repeat1(ws(',')), ws(')')),
ws(qcon)
);
-
- var fpat = undefined;
-
- var list_action = function(p) {
- return action(p, function(ast) {
- // 0,1,2
- // 0 : 1 : 2 : []
- // ((: 0) 1)
-
- ast = ast[0];
-
- var cons = new haskell.ast.VariableLookup(":");
- var empty = new haskell.ast.VariableLookup("[]");
-
- if (ast.length == 0 || ast == false) {
- return empty;
- }
-
- var fun = empty;
- for (var i = ast.length - 1; i >= 0; i--) {
- var f = new haskell.ast.Application(cons, ast[i]);
- fun = new haskell.ast.Application(f, fun);
- }
-
- return fun;
- });
- }
-
- var list_pattern_action = function(p) {
- return action(p, function(ast) {
- ast = ast[0];
-
- var cons = ":";
- var empty = "[]";
-
- if (ast.length == 0 || ast == false) {
- return new haskell.ast.PatternConstructor(empty, new Array());
- }
-
- var fun = new haskell.ast.PatternConstructor(empty, new Array());
- for (var i = ast.length - 1; i >= 0; i--) {
- fun = new haskell.ast.PatternConstructor(cons, [ast[i], fun]);
- }
-
- return fun;
- });
- }
-
- var ident_pattern_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.VariableBinding(ast);
- });
- }
-
- var constant_pattern_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.ConstantPattern(ast);
- });
- }
-
- var combined_pattern_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.Combined(ast[0], ast[1]);
- });
- }
-
- var wildcard_pattern_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.Wildcard();
- });
- }
-
- var cons_pattern_action = function(ast) {
- return function(lhs, rhs) {
- // lhs : rhs
- var cons = ':';
- return new haskell.ast.PatternConstructor(cons, [lhs, rhs]);
+
+ var fpat = undefined;
+
+ var list_action = function(p) {
+ return action(p, function(ast) {
+ if (ast[0] == false) ast[0] = [];
+ return new haskell.ast.List(ast[0]);
+ // 0,1,2
+ // 0 : 1 : 2 : []
+ // ((: 0) 1)
+
+ ast = ast[0];
+
+ var cons = new haskell.ast.VariableLookup(":");
+ var empty = new haskell.ast.VariableLookup("[]");
+
+ if (ast.length == 0 || ast == false) {
+ return empty;
+ }
+
+ var fun = empty;
+ for (var i = ast.length - 1; i >= 0; i--) {
+ var f = new haskell.ast.Application(cons, ast[i]);
+ fun = new haskell.ast.Application(f, fun);
+ }
+
+ return fun;
+ });
+ }
+
+ var list_pattern_action = function(p) {
+ return action(p, function(ast) {
+ ast = ast[0];
+
+ var cons = ":";
+ var empty = "[]";
+
+ if (ast.length == 0 || ast == false) {
+ return new haskell.ast.PatternConstructor(empty, new Array());
+ }
+
+ var fun = new haskell.ast.PatternConstructor(empty, new Array());
+ for (var i = ast.length - 1; i >= 0; i--) {
+ fun = new haskell.ast.PatternConstructor(cons, [ast[i], fun]);
+ }
+
+ return fun;
+ });
+ }
+
+ var ident_pattern_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.VariableBinding(ast);
+ });
+ }
+
+ var constant_pattern_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.ConstantPattern(ast);
});
}
-
- var apat = function(state) { return apat(state) };
+
+ var combined_pattern_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.Combined(ast[0], ast[1]);
+ });
+ }
+
+ var wildcard_pattern_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.Wildcard();
+ });
}
-
- var apat = choice( combined_pattern_action(sequence(var_, expect(ws('@')), ws(apat))),
+
+ var cons_pattern_action = function(ast) {
+ return function(lhs, rhs) {
+ // lhs : rhs
+ var cons = ':';
+ return new haskell.ast.PatternConstructor(cons, [lhs, rhs]);
+ };
+ }
+
+ var apat = function(state) { return apat(state) };
+ var pat = function(state) { return pat(state); };
+
+ var apat = choice( combined_pattern_action(sequence(var_, expect(ws('@')), ws(apat))),
action(ws(gcon), function(ast) { return new haskell.ast.PatternConstructor(ast, new Array()); }),
- constant_pattern_action(ws(literal)),
- ident_pattern_action(ws(ident)),
- wildcard_pattern_action (ws('_')), // wildcard
- action(sequence(expect(ws('(')), pat, expect(ws(')'))), function(ast) { return ast[0]; }), // parans
+ constant_pattern_action(ws(literal)),
+ ident_pattern_action(ws(ident)),
+ wildcard_pattern_action (ws('_')), // wildcard
+ action(sequence(expect(ws('(')), pat, expect(ws(')'))), function(ast) { return ast[0]; }), // parans
sequence(expect(ws('(')), ws(pat), repeat1(sequence(ws(','), ws(pat))), expect(ws(')'))), // tuple
list_pattern_action(sequence(expect(ws('[')), optional(wlist(pat, ',')), expect(ws(']')))) // list
- );
-
- var gcon_pat_action = function(p) {
- return action(p, function(ast) {
- var constructor = ast[0];
- var patterns = ast[1];
- return new haskell.ast.PatternConstructor(constructor, patterns);
- });
- };
-
- var pat_10 = choice(gcon_pat_action(sequence(ws(gcon), repeat1(ws(apat)))),
- action(sequence(chainl(ws(apat), action(ws(':'), cons_pattern_action))), function(ast) { return ast[0]; }),
- apat
+ );
+
+ var gcon_pat_action = function(p) {
+ return action(p, function(ast) {
+ var constructor = ast[0];
+ var patterns = ast[1];
+ return new haskell.ast.PatternConstructor(constructor, patterns);
+ });
+ };
+
+ var pat_10 = choice(gcon_pat_action(sequence(ws(gcon), repeat1(ws(apat)))),
+ action(sequence(chainl(ws(apat), action(ws(':'), cons_pattern_action))), function(ast) { return ast[0]; }),
+ apat
);
var rpat = undefined;
@@ -283,150 +280,236 @@ Todo:
var pat = pat_10;
var fbind = undefined;
-
+
+ // Redefined later with the proper definition
+ var decls = function(state) { return decls(state); };
+
+ var stmt_exp_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.DoExpr(ast);
+ });
+ }
+
+ var stmt_bind_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.DoBind(ast[0], ast[1]);
+ });
+ }
+
+ var stmt_let_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.DoLet(ast[0][0]);
+ });
+ };
+
var infixexp = function(state) { return infixexp(state); };
-
+
+ var stmt = choice( stmt_bind_action(sequence(ws(pat), expect(ws("<-")), ws(infixexp))),
+ stmt_exp_action(ws(infixexp)),
+ stmt_let_action(sequence(expect(ws("let")), ws(decls)))
+ );
+
var stmts = list(stmt, ws(";"));
- var gdpat = undefined;
-
- // todo: fix all alternatives !!!!1 and where!
- var alt_action = function(p) {
- return action(p, function(ast) {
- return ast;
- });
- };
-
+ var gdpat = undefined;
+
+ // todo: fix all alternatives !!!!1 and where!
+ var alt_action = function(p) {
+ return action(p, function(ast) {
+ return ast;
+ });
+ };
+
var exp = function(state) { return exp(state); };
- var alt = sequence(ws(pat), expect(ws("->")), ws(exp));
+ var alt = sequence(ws(pat), expect(ws("->")), ws(exp));
var alts = list(ws(alt), ws(';'));
- var qval = undefined;
-
- var infixexp = function(state) { return infixexp(state); };
-
- var right_section_action = function(p) {
- return action(p, function(ast) {
- // (+ x)
- // \y -> y + x
-
- var arg_name = parser.generateInternalName();
- var op_name = ast[0];
-
- var fun_exp = new haskell.ast.Application(new haskell.ast.VariableLookup(op_name), new haskell.ast.VariableLookup(arg_name));
- fun_exp = new haskell.ast.Application(fun_exp, ast[1]);
-
- var arg = new haskell.ast.VariableBinding(arg_name);
- var fun = new haskell.ast.Lambda(arg, fun_exp);
-
- return fun;
- });
- };
-
- var left_section_action = function(p) {
- return action(p, function(ast) {
- // (x +)
- // \y -> x + y
-
- var arg_name = parser.generateInternalName();
- var op_name = ast[1];
-
- var fun_exp = new haskell.ast.Application(new haskell.ast.VariableLookup(op_name), ast[0]);
- fun_exp = new haskell.ast.Application(fun_exp, new haskell.ast.VariableLookup(arg_name));
-
- var arg = new haskell.ast.VariableBinding(arg_name);
- var fun = new haskell.ast.Lambda(arg, fun_exp);
-
- return fun;
- });
- };
-
- var qvar_exp_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.VariableLookup(ast);
- });
- };
-
- var aexp_constant_action = function(p) {
- return action(p, function(ast) {
- return new haskell.ast.Constant(ast);
- });
+ var qval = undefined;
+
+ var right_section_action = function(p) {
+ return action(p, function(ast) {
+ // (+ x)
+ // \y -> y + x
+
+ var arg_name = parser.generateInternalName();
+ var op_name = ast[0];
+
+ var fun_exp = new haskell.ast.Application(new haskell.ast.VariableLookup(op_name), new haskell.ast.VariableLookup(arg_name));
+ fun_exp = new haskell.ast.Application(fun_exp, ast[1]);
+
+ var arg = new haskell.ast.VariableBinding(arg_name);
+ var fun = new haskell.ast.Lambda(arg, fun_exp);
+
+ return fun;
+ });
+ };
+
+ var left_section_action = function(p) {
+ return action(p, function(ast) {
+ // (x +)
+ // \y -> x + y
+
+ var arg_name = parser.generateInternalName();
+ var op_name = ast[1];
+
+ var fun_exp = new haskell.ast.Application(new haskell.ast.VariableLookup(op_name), ast[0]);
+ fun_exp = new haskell.ast.Application(fun_exp, new haskell.ast.VariableLookup(arg_name));
+
+ var arg = new haskell.ast.VariableBinding(arg_name);
+ var fun = new haskell.ast.Lambda(arg, fun_exp);
+
+ return fun;
+ });
+ };
+
+ var qual_generator_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.ListBind(ast[0], ast[1]);
+ });
+ }
+
+ var qual_let_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.ListLet(ast[0]);
+ });
+ }
+
+ var qual_exp_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.ListGuard(ast);
+ });
+ }
+
+ var qual = choice( qual_generator_action(sequence(ws(pat), expectws("<-"), ws(exp))),
+ qual_let_action(sequence(expectws("let"), ws(decls))),
+ qual_exp_action(ws(exp))
+ );
+
+ var qvar_exp_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.VariableLookup(ast);
+ });
+ };
+
+ var aexp_constant_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.Constant(ast);
+ });
+ };
+
+ var aexp_list_comp_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.ListComprehension(ast[0], ast[1]);
+ });
+ }
+
+ var aexp_arithmetic_action = function(p) {
+ return action(p, function(ast) {
+ if (ast[1]) {
+ ast[1] = ast[1][0];
+ }
+ return new haskell.ast.ArithmeticSequence(ast[0], ast[1], ast[2]);
+ });
+ }
+
+ var aexp_empty_tuple_action = function(p) {
+ return action(p, function(ast) {
+ return ast;
+ });
+ };
+
+ var aexp_tuple_action = function(p) {
+ return action(p, function(ast) {
+ return ast;
+ });
};
var aexp = choice( qvar_exp_action(ws(qvar)),
qvar_exp_action(ws(gcon)),
aexp_constant_action(ws(literal)),
- action(sequence(expect(ws('(')), ws(exp), expect(ws(')'))), function(ast) { return ast[0]; }), // parans
- sequence(ws('('), ws(exp), ws(','), ws(exp), repeat0(sequence(ws(','), ws(exp))) , ws(')')), // tuple
- list_action(sequence(expect(ws('[')), optional(wlist(exp, ',')), expect(ws(']')))), // list constructor
- left_section_action(sequence(expect(ws('(')), ws(infixexp), ws(qop), expect(ws(')')))), // left section
- right_section_action(sequence(expect(ws('(')), ws(qop), ws(infixexp), expect(ws(')')))) // right section, todo: look into resolution of infixexp in this case, see Haskell Report Chapter 3
- // Todo:
- // Arithmetic sequence
- // List comprehension
+ action(sequence(expect(ws('(')), ws(exp), expect(ws(')'))), function(ast) { return ast[0]; }), // parans
+ aexp_empty_tuple_action(sequence(expectws('('), expectws(')'))), // empty tuple
+ aexp_tuple_action(sequence(expectws('('), ws(exp), repeat1(sequence(ws(','), ws(exp))) , expectws(')'))), // tuple
+ list_action(sequence(expect(ws('[')), optional(wlist(exp, ',')), expect(ws(']')))), // list constructor
+ left_section_action(sequence(expect(ws('(')), ws(infixexp), ws(qop), expect(ws(')')))), // left section
+ right_section_action(sequence(expect(ws('(')), ws(qop), ws(infixexp), expect(ws(')')))), // right section, todo: look into resolution of infixexp in this case, see Haskell Report Chapter 3
+ aexp_arithmetic_action(sequence(expectws('['), ws(exp), optional(sequence(expectws(','), ws(exp))), expectws('..'), optional(ws(exp)), expectws(']'))), // arithmetic sequence
+ aexp_list_comp_action(sequence(expectws('['), ws(exp), expectws('|'), list(qual, ws(',')), expectws(']'))) // list comprehension
+ // Todo:
// Labeled construction
// Labeled update
- );
-
- var fexp = action(repeat1(ws(aexp)), function(ast) {
- if (ast.length == 1) {
+ );
+
+ var fexp = action(repeat1(ws(aexp)), function(ast) {
+ if (ast.length == 1) {
return ast[0];
- } else {
- // f x y -> (f x) y
- var f = new haskell.ast.Application(ast[0], ast[1]);
- for (var i = 2; i < ast.length; i ++) {
- f = new haskell.ast.Application(f, ast[i]);
- }
- return f;
+ } else {
+ // f x y -> (f x) y
+ var f = new haskell.ast.Application(ast[0], ast[1]);
+ for (var i = 2; i < ast.length; i ++) {
+ f = new haskell.ast.Application(f, ast[i]);
+ }
+ return f;
}
});
var rexp = undefined;
-
- var lexp = undefined;
-
- var lambda_exp_action = function(p) {
- return action(p, function(ast) {
- // \x y -> exp
- // \x -> \y -> exp
-
- var fun = ast[1];
- var patterns = ast[0];
-
- for (var i = patterns.length - 1; i >= 0; i--) {
- fun = new haskell.ast.Lambda(patterns[i], fun);
- }
-
- return fun;
+
+ var lexp = undefined;
+
+ var lambda_exp_action = function(p) {
+ return action(p, function(ast) {
+ // \x y -> exp
+ // \x -> \y -> exp
+
+ var fun = ast[1];
+ var patterns = ast[0];
+
+ for (var i = patterns.length - 1; i >= 0; i--) {
+ fun = new haskell.ast.Lambda(patterns[i], fun);
+ }
+
+ return fun;
+ });
+ };
+
+
+ var let_action = function(p) {
+ return action(p, function(ast) {
+ var decl = ast[0][0];
+ var exp = ast[1];
+
+ return new haskell.ast.Let(decl, exp);
+ });
+ };
+
+ var case_action = function(p) {
+ return action(p, function(ast) {
+ var cond = ast[0];
+ var alts = ast[1];
+
+ return new haskell.ast.Case(cond, alts);
+ });
+ }
+
+ var do_action = function(p) {
+ return action(p, function(ast) {
+ return new haskell.ast.Do(ast[0]);
+ });
+ };
+
+ var if_action = function(p) {
+ return action(p, function(ast) {
+ return ast;
});
- };
-
- var decls = function(state) { return decls(state); };
-
- var let_action = function(p) {
- return action(p, function(ast) {
- var decl = ast[0][0];
- var exp = ast[1];
-
- return new haskell.ast.Let(decl, exp);
- });
- };
-
- var case_action = function(p) {
- return