Skip to content

Instantly share code, notes, and snippets.

@gerardpaapu
Last active December 15, 2015 21:39
Show Gist options
  • Save gerardpaapu/5327480 to your computer and use it in GitHub Desktop.
Save gerardpaapu/5327480 to your computer and use it in GitHub Desktop.
var Parser = function() {
"use strict";
function require(name) {
if (!(name in modules)) {
throw new Error("Module not found: " + name);
}
return modules[name];
}
var modules = {};
(function(exports) {
var Location, Port;
Port = function() {
function Port(source, _index) {
this.source = source;
this._index = _index != null ? _index : 0;
}
Port.from = function(str) {
if (str instanceof Port) {
return str;
} else {
return new Port(str);
}
};
Port.prototype.take = function(n) {
return this.slice(0, n);
};
Port.prototype.drop = function(n) {
return this.move(n);
};
Port.prototype.isEmpty = function() {
return this.source.length <= this._index;
};
Port.prototype.move = function(n) {
return new Port(this.source, this._index + n);
};
Port.prototype.index = function(n) {
if (n < 0) {
return n;
} else {
return this._index + n;
}
};
Port.prototype.slice = function(a, b) {
switch (arguments.length) {
case 0:
return this.source.slice(this.index(0));
case 1:
return this.source.slice(this.index(a));
default:
return this.source.slice(this.index(a), this.index(b));
}
};
Port.prototype.getLocation = function() {
var column, i, row;
row = 0;
column = 0;
i = 0;
while (i < this._index) {
if (this.source.charAt(i++) === "\n") {
column = 0;
row++;
} else {
column++;
}
}
return new Location(row, column);
};
Port.prototype.toString = function() {
return this.slice(0);
};
return Port;
}();
exports.Port = Port;
Location = function() {
function Location(row, column) {
this.row = row;
this.column = column;
}
return Location;
}();
exports.Location = Location;
}).call(null, modules["./Port"] = {});
(function(exports) {
var typeString;
typeString = function(obj) {
var full;
if (obj != null) {
full = Object.prototype.toString.call(obj);
return full.slice(8, -1);
} else {
return String(obj);
}
};
exports.addMethods = function(Klass) {
var converters;
converters = {};
Klass.addConverter = function(type, fn) {
if (converters[type] != null) {
throw new Error("" + type + " is already defined");
}
return converters[type] = fn;
};
return Klass.from = function(obj) {
var instance, type;
type = typeString(obj);
if (obj instanceof Klass) {
return obj;
} else if (typeof converters[type] === "function") {
instance = converters[type](obj);
if (!(instance instanceof Klass)) {
throw new TypeError("converted value is not a instance of " + Klass);
}
return instance;
} else {
throw new TypeError("No converter from " + type + " is defined");
}
};
};
}).call(null, modules["./From"] = {});
(function(exports) {
var Failure, Result, Success, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) {
function ctor() {
this.constructor = child;
}
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
Result = function() {
function Result() {}
Result.succeedWithValue = function(value) {
return new Success(value);
};
Result.failWithMessage = function(message) {
return new Failure(message);
};
Result.bind = function(m, f) {
return m.bind(f);
};
Result.mzero = function() {
return Result.failWithMessage("failed");
};
Result.mreturn = function(value) {
return Result.succeedWithValue(value);
};
return Result;
}();
Success = function(_super) {
function Success(value) {
this.value = value;
}
__extends(Success, _super);
Success.prototype.didSucceed = true;
Success.prototype.bind = function(fn) {
return fn(this.value);
};
return Success;
}(Result);
Failure = function(_super) {
function Failure(message) {
this.message = message;
}
__extends(Failure, _super);
Failure.prototype.didSucceed = false;
Failure.prototype.bind = function(_) {
return this;
};
return Failure;
}(Result);
exports.Result = Result;
exports.Success = Success;
exports.Failure = Failure;
}).call(null, modules["./Result"] = {});
(function(exports) {
var Continuation, Failure, Message, Parser, Port, Result, Success, _ref, _ref1, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) {
function ctor() {
this.constructor = child;
}
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
_ref = require("./Result"), Result = _ref.Result, Success = _ref.Success, Failure = _ref.Failure;
Parser = function() {
function Parser(parse) {
this.parse = parse;
}
Parser.prototype.parse = function(source) {
throw new Error("Not Implemented");
};
return Parser;
}();
Continuation = function() {
function Continuation(value, source) {
this.value = value;
this.source = source;
}
return Continuation;
}();
Message = function() {
function Message(text, source) {
this.text = text;
this.source = source;
}
return Message;
}();
_ref1 = require("./Result"), Result = _ref1.Result, Success = _ref1.Success, Failure = _ref1.Failure;
Parser.Succeed = function(_super) {
function Succeed(value) {
this.value = value;
}
__extends(Succeed, _super);
Succeed.prototype.parse = function(source) {
var continuation;
continuation = new Continuation(this.value, source);
return new Success(continuation);
};
return Succeed;
}(Parser);
Parser.Fail = function(_super) {
function Fail(text) {
this.text = text;
}
__extends(Fail, _super);
Fail.prototype.parse = function(source) {
var message;
message = new Message(this.text, source);
return new Failure(message);
};
return Fail;
}(Parser);
Port = require("./Port").Port;
Parser.Item = function(_super) {
function Item() {}
__extends(Item, _super);
Item.prototype.parse = function(source) {
var continuation, rest, val;
source = Port.from(source);
if (source.isEmpty()) {
return new Failure("Source empty", source);
} else {
val = source.take(1);
rest = source.drop(1);
continuation = new Continuation(val, rest);
return new Success(continuation);
}
};
return Item;
}(Parser);
Message = function() {
function Message(text, source) {
this.text = text;
this.source = source;
}
return Message;
}();
Continuation = function() {
function Continuation(value, source) {
this.value = value;
this.source = source;
}
return Continuation;
}();
Parser.mzero = function() {
return new Parser.Fail("zero");
};
Parser.mreturn = function(v) {
return new Parser.Succeed(v);
};
Parser.bind = function(m, f) {
var _this = this;
return new Parser(function(source) {
return m.parse(source).bind(function(c) {
var parser;
parser = f(c.value);
return parser.parse(c.source);
});
});
};
Parser.prototype.bind = function(f) {
return Parser.bind(this, f);
};
(function() {
var addMethods;
addMethods = require("./From").addMethods;
return addMethods(Parser);
})();
exports.Parser = Parser;
exports.Message = Message;
exports.Continuation = Continuation;
}).call(null, modules["./Core"] = {});
(function(exports) {
var Continuation, Failure, Message, Parser, Port, Result, Success, cloneRegexp, _ref, _ref1, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) {
function ctor() {
this.constructor = child;
}
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
_ref = require("./Core"), Parser = _ref.Parser, Continuation = _ref.Continuation, Message = _ref.Message;
_ref1 = require("./Result"), Result = _ref1.Result, Success = _ref1.Success, Failure = _ref1.Failure;
Port = require("./Port").Port;
Parser.Exactly = function(_super) {
function Exactly(string) {
this.string = string;
}
__extends(Exactly, _super);
Exactly.prototype.parse = function(source) {
var cont, head, message, reason, rest;
source = Port.from(source);
head = source.slice(0, this.string.length);
if (head === this.string) {
rest = source.move(this.string.length);
cont = new Continuation(head, rest);
return new Success(cont);
} else {
reason = "Source didn't match: '" + this.string + "'";
message = new Message(reason, source);
return new Failure(message);
}
};
return Exactly;
}(Parser);
Parser.addConverter("String", function(str) {
return new Parser.Exactly(str);
});
cloneRegexp = function(source) {
var destination, src;
src = source.source;
if (src.charAt(0) !== "^") {
src = "^" + src;
}
destination = new RegExp(src);
destination.global = source.global;
destination.ignoreCase = source.ignoreCase;
destination.multiline = source.multiline;
return destination;
};
Parser.RegExp = function(_super) {
function RegExp(pattern, index) {
this._pattern = pattern;
this.index = index != null ? index : 0;
}
__extends(RegExp, _super);
RegExp.prototype.getPattern = function() {
return cloneRegexp(this._pattern);
};
RegExp.prototype.parse = function(source) {
var cont, match, message, pattern, reason, rest, val;
source = Port.from(source);
pattern = this.getPattern();
match = pattern.exec(source.slice());
if (match != null) {
val = match[this.index];
rest = source.move(match[0].length);
cont = new Continuation(val, rest);
return new Success(cont);
} else {
reason = "Source didn't match: /" + pattern.source + "/";
message = new Message(reason, source);
return new Failure(message);
}
};
return RegExp;
}(Parser);
Parser.addConverter("RegExp", function(str) {
return new Parser.RegExp(str);
});
}).call(null, modules["./Matchers"] = {});
(function(exports) {
var Any, Continuation, Failure, Location, Message, Or, Parser, Port, Result, Seq, Success, bind, mreturn, mzero, _ref, _ref1, _ref2, __slice = [].slice;
_ref = require("./Core"), Parser = _ref.Parser, Message = _ref.Message, Continuation = _ref.Continuation;
_ref1 = require("./Result"), Success = _ref1.Success, Failure = _ref1.Failure, Result = _ref1.Result;
bind = Parser.bind, mreturn = Parser.mreturn, mzero = Parser.mzero;
_ref2 = require("./Port"), Port = _ref2.Port, Location = _ref2.Location;
Parser.prototype.andThen = function(parser) {
return bind(this, function(v1) {
return bind(parser, function(v2) {
return mreturn([ v1, v2 ]);
});
});
};
Parser.prototype.convert = function(converter) {
return this.bind(function(v) {
return new Parser.Succeed(converter(v));
});
};
Parser.prototype.convertTo = function(Klass) {
return this.convert(function(v) {
return new Klass(v);
});
};
Seq = Parser.Seq = function(parsers) {
var cons, first, rest;
cons = function(a, b) {
return [ a ].concat(b);
};
if (parsers.length === 0) {
return new Parser.Succeed([]);
} else {
first = parsers[0], rest = 2 <= parsers.length ? __slice.call(parsers, 1) : [];
return Parser.from(first).bind(function(head) {
return Seq(rest).bind(function(tail) {
return new Parser.Succeed(cons(head, tail));
});
});
}
};
Parser.addConverter("Array", Seq);
Or = Parser.Or = function(a, b) {
return new Parser(function(source) {
var result;
result = a.parse(source);
if (result.didSucceed) {
return result;
} else {
return b.parse(source);
}
});
};
Parser.prototype.or = function(other) {
return Or(this, other);
};
Parser.prototype.maybe = function(v) {
return Or(this, new Parser.Succeed(v));
};
Any = Parser.Any = function(arr) {
var first, rest;
if (arr.length === 0) {
return new Parser.Fail("no candidates");
} else if (arr.length === 1) {
return arr[0];
} else if (arr.length === 2) {
return Or(arr[0], arr[1]);
} else {
first = arr[0], rest = 2 <= arr.length ? __slice.call(arr, 1) : [];
return Or(first, Any(rest));
}
};
Parser.prototype.onceOrMore = function() {
var cons, _this = this;
cons = function(a, b) {
return [ a ].concat(b);
};
return this.bind(function(head) {
var parseRest;
parseRest = _this.onceOrMore().maybe([]);
return parseRest.bind(function(tail) {
return new Parser.Succeed(cons(head, tail));
});
});
};
Parser.prototype.zeroOrMore = function() {
var any;
any = this.onceOrMore();
return any.maybe([]);
};
Parser.prototype.precededBy = function(prefix) {
var _this = this;
return Parser.from(prefix).bind(function(_) {
return _this;
});
};
Parser.prototype.followedBy = function(suffix) {
return this.bind(function(v1) {
return Parser.from(suffix).bind(function(_) {
return mreturn(v1);
});
});
};
Parser.prototype.surroundedBy = function(left, right) {
return this.precededBy(left).followedBy(right);
};
Parser.prototype.is = function(test) {
return this.bind(function(v1) {
if (test(v1)) {
return mreturn(v1);
} else {
return new Parser.Fail("Failed predicate");
}
});
};
Parser.prototype.isnt = function(test) {
return this.is(function(v) {
return !test(v);
});
};
Parser.prototype.separatedBy = function(comma) {
var squash, tail;
comma = Parser.from(comma);
squash = function(_arg) {
var a, b;
a = _arg[0], b = _arg[1];
return [ a ].concat(b);
};
tail = this.precededBy(comma).zeroOrMore();
return this.andThen(tail).convert(squash);
};
Parser.prototype.withLocation = function(fn) {
var _this = this;
return new Parser(function(_source) {
var start;
_source = Port.from(_source);
start = _source.getLocation();
return _this.parse(_source).bind(function(cont) {
var end, next, source, value, _value;
source = cont.source, value = cont.value;
end = source.getLocation();
_value = fn(value, start, end);
next = new Continuation(_value, source);
return new Success(next);
});
});
};
}).call(null, modules["./Combinators"] = {});
(function(exports) {
var Continuation, Failure, Location, Message, Parser, Port, Result, Success, _ref, _ref1, _ref2;
_ref = require("./Core"), Parser = _ref.Parser, Continuation = _ref.Continuation, Message = _ref.Message;
require("./Matchers");
require("./Combinators");
_ref1 = require("./Port"), Port = _ref1.Port, Location = _ref1.Location;
_ref2 = require("./Result"), Result = _ref2.Result, Success = _ref2.Success, Failure = _ref2.Failure;
exports.Parser = Parser;
exports.Continuation = Continuation;
exports.Message = Message;
exports.Result = Result;
exports.Success = Success;
exports.Failure = Failure;
exports.Port = Port;
exports.Location = Location;
}).call(null, modules["./Parser"] = {});
return require("./Parser");
}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment