smartdown
Version:
A library for translating, rendering and interacting with Smartdown documents. Smartdown is an extension of Markdown that provides richer media support and reactive programming capability.
1,721 lines (1,657 loc) • 566 kB
JavaScript
/*************************************************************
*
* MathJax/extensions/TeX/xypic.js
*
* Implements Xy-pic environment.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2014 Isao Sonobe <sonoisa@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function () {
var FP = MathJax.Extension.fp = {
version: "0.1"
};
/************ Matcher **************/
FP.Matcher = MathJax.Object.Subclass({
Init: function () { this.cases = []; },
Case: function (klass, f) {
this.cases.push([klass, f]);
return this;
},
match: function (x) {
if (x instanceof Object && "isa" in x) {
var i, count, klass, op;
i = 0;
count = this.cases.length;
while (i < count) {
klass = this.cases[i][0];
if (x.isa(klass)) {
op = klass.unapply(x);
if (op.isDefined) {
return this.cases[i][1](op.get);
}
}
i = i + 1;
}
}
throw FP.MatchError(x);
}
});
/************ Option **************/
FP.Option = MathJax.Object.Subclass({});
FP.Option.Some = FP.Option.Subclass({
Init: function (value) {
this.get = value;
},
isEmpty: false,
isDefined: true,
getOrElse: function (ignore) { return this.get; },
flatMap: function (k) {
return k(this.get);
},
map: function (f) {
return FP.Option.Some(f(this.get));
},
foreach: function (f) {
f(this.get);
},
toString: function () {
return "Some(" + this.get + ")";
}
}, {
unapply: function (x) { return FP.Option.Some(x.get); }
});
FP.Option.None = FP.Option.Subclass({
Init: function () {},
isEmpty: true,
isDefined: false,
getOrElse: function (value) { return value; },
flatMap: function (k) { return this; },
foreach: function (f) {},
map: function (k) { return this; },
toString: function () { return "None"; }
}, {
unapply: function (x) { return FP.Option.Some(x); }
});
FP.Option.Augment({}, {
empty: FP.Option.None()
});
/************ List **************/
FP.List = MathJax.Object.Subclass({});
FP.List.Cons = FP.List.Subclass({
Init: function (head, tail) {
this.head = head;
this.tail = tail;
},
isEmpty: false,
at: function (index) {
if (index < 0 || index >= this.length()) {
throw Error("no such element at " + index + ". index must be lower than " + this.length() + ".");
}
var t = this;
for (var i = 0; i < index; i++) {
t = t.tail;
}
return t.head;
},
length: function () {
var t = this;
var l = 0;
while (!t.isEmpty) {
l++;
t = t.tail;
}
return l;
},
prepend: function (element) {
return FP.List.Cons(element, this);
},
append: function (element) {
var result = FP.List.Cons(element, FP.List.empty);
this.reverse().foreach(function (e) {
result = FP.List.Cons(e, result);
});
return result;
},
concat: function (that) {
var result = that;
this.reverse().foreach(function (e) {
result = FP.List.Cons(e, result);
});
return result;
},
foldLeft: function (x0, f) {
var r, c;
r = f(x0, this.head);
c = this.tail;
while (!c.isEmpty) {
r = f(r, c.head);
c = c.tail;
}
return r;
},
foldRight: function (x0, f) {
if (this.tail.isEmpty) {
return f(this.head, x0);
} else {
return f(this.head, this.tail.foldRight(x0, f));
}
},
map: function (f) {
return FP.List.Cons(f(this.head), this.tail.map(f));
},
flatMap: function (k) {
return k(this.head).concat(this.tail.flatMap(k));
},
foreach: function (f) {
var e = this;
while (!e.isEmpty) {
f(e.head);
e = e.tail;
}
},
reverse: function () {
var r = FP.List.empty;
this.foreach(function (c) {
r = FP.List.Cons(c, r);
});
return r;
},
mkString: function () {
var open, delim, close;
switch (arguments.length) {
case 0:
open = delim = close = "";
break;
case 1:
delim = arguments[0];
open = close = "";
break;
case 2:
open = arguments[0];
delim = arguments[1];
close = "";
break;
default:
open = arguments[0];
delim = arguments[1];
close = arguments[2];
break;
}
var desc, nxt;
desc = open + this.head.toString();
nxt = this.tail;
while (nxt.isa(FP.List.Cons)) {
desc += delim + nxt.head.toString();
nxt = nxt.tail;
}
desc += close;
return desc;
},
toString: function () {
return this.mkString("[", ", ", "]");
}
}, {
unapply: function (x) { return FP.Option.Some([x.head, x.tail]); }
});
FP.List.Nil = FP.List.Subclass({
isEmpty: true,
at: function (index) {
throw Error("cannot get element from an empty list.");
},
length: function () { return 0; },
prepend: function (element) {
return FP.List.Cons(element, FP.List.empty);
},
append: function (element) {
return FP.List.Cons(element, FP.List.empty);
},
concat: function (that) {
return that;
},
foldLeft: function (x0, f) { return x0; },
foldRight: function (x0, f) { return x0; },
flatMap: function (f) { return this; },
map: function (f) { return this; },
foreach: function (f) {},
reverse: function () { return this; },
mkString: function () {
switch (arguments.length) {
case 0:
case 1:
return "";
case 2:
return arguments[0]
default:
return arguments[0]+arguments[2];
}
},
toString: function () { return '[]'; }
}, {
unapply: function (x) { return FP.Option.Some(x); }
});
FP.List.Augment({}, {
empty: FP.List.Nil(),
fromArray: function (as) {
var list, i;
list = FP.List.empty;
i = as.length - 1;
while (i >= 0) {
list = FP.List.Cons(as[i], list);
i -= 1;
}
return list;
}
});
/************ MatchError **************/
FP.MatchError = MathJax.Object.Subclass({
Init: function (obj) { this.obj = obj; },
// getMessage: function () {
// if (this.obj === null) {
// return "null"
// } else {
// return obj.toString() + " (of class " + obj. + ")"
// }
// }
toString: function () { return "MatchError(" + this.obj + ")"; }
});
/************ OffsetPosition **************/
FP.OffsetPosition = MathJax.Object.Subclass({
Init: function (source, offset) {
// assert(source.length >= offset)
this.source = source;
if (offset === undefined) { this.offset = 0; } else { this.offset = offset; }
this._index = null;
this._line = null;
},
index: function () {
if (this._index !== null) { return this._index; }
this._index = [];
this._index.push(0);
var i = 0;
while (i < this.source.length) {
if (this.source.charAt(i) === '\n') { this._index.push(i + 1); }
i += 1;
}
this._index.push(this.source.length);
return this._index;
},
line: function () {
var lo, hi, mid;
if (this._line !== null) { return this._line; }
lo = 0;
hi = this.index().length - 1;
while (lo + 1 < hi) {
mid = (hi + lo) >> 1;
if (this.offset < this.index()[mid]) {
hi = mid;
} else {
lo = mid;
}
}
this._line = lo + 1;
return this._line;
},
column: function () {
return this.offset - this.index()[this.line() - 1] + 1;
},
lineContents: function () {
var i, l;
i = this.index();
l = this.line();
return this.source.substring(i[l - 1], i[l]);
},
toString: function () { return this.line().toString() + '.' + this.column(); },
longString: function () {
var desc, i;
desc = this.lineContents() + '\n';
i = 0;
while (i < this.column()) {
if (this.lineContents().charAt(i) === '\t') {
desc += '\t';
} else {
desc += ' ';
}
i += 1;
}
desc += '^';
return desc;
},
isLessThan: function (that) {
if (that.isa(FP.OffsetPosition)) {
return this.offset < that.offset;
} else {
return (
this.line() < that.line() ||
(this.line() === that.line() && this.column() < that.column())
);
}
}
});
/************ StringReader **************/
FP.StringReader = MathJax.Object.Subclass({
Init: function (source, offset, context) {
this.source = source;
this.offset = offset;
this.context = context;
},
first: function () {
if (this.offset < this.source.length) {
return this.source.charAt(this.offset);
} else {
return FP.StringReader.EofCh;
}
},
rest: function () {
if (this.offset < this.source.length) {
return FP.StringReader(this.source, this.offset + 1, this.context);
} else {
return this;
}
},
pos: function () { return FP.OffsetPosition(this.source, this.offset); },
atEnd: function () { return this.offset >= this.source.length; },
drop: function (n) {
var r, count;
r = this;
count = n;
while (count > 0) {
r = r.rest();
count -= 1;
}
return r;
}
}, {
EofCh: '\x03'
});
/************ Parsers **************/
FP.Parsers = MathJax.Object.Subclass({}, {
parse: function (p, input) {
return p.apply(input);
},
parseAll: function (p, input) {
return p.andl(function () { return FP.Parsers.eos(); }).apply(input);
},
parseString: function (p, str) {
var input = FP.StringReader(str, 0, { lastNoSuccess: undefined });
return FP.Parsers.parse(p, input);
},
parseAllString: function (p, str) {
var input = FP.StringReader(str, 0, { lastNoSuccess: undefined });
return FP.Parsers.parseAll(p, input);
},
_handleWhiteSpace: function (input) {
var whiteSpaceRegex = input.context.whiteSpaceRegex;
var source = input.source;
var offset = input.offset;
var m = whiteSpaceRegex.exec(source.substring(offset, source.length));
if (m !== null) {
return offset + m[0].length;
} else {
return offset;
}
},
literal: function (str) {
return FP.Parsers.Parser(function (input) {
var source, offset, start, i, j, found;
source = input.source;
offset = input.offset;
start = FP.Parsers._handleWhiteSpace(input);
i = 0;
j = start;
while (i < str.length && j < source.length &&
str.charAt(i) === source.charAt(j)) {
i += 1;
j += 1;
}
if (i === str.length) {
return FP.Parsers.Success(str, input.drop(j - offset));
} else {
if (start === source.length) {
found = "end of source";
} else {
found = "`" + source.charAt(start) + "'";
}
return FP.Parsers.Failure(
"`" + str + "' expected but " + found + " found",
input.drop(start - offset)
);
}
});
},
regex: function (rx /* must start with ^ */) {
if (rx.toString().substring(0, 2) !== "/^") {
throw ("regex must start with `^' but " + rx);
}
return FP.Parsers.Parser(function (input) {
var source, offset, m, found;
source = input.source;
offset = input.offset;
m = rx.exec(source.substring(offset, source.length));
if (m !== null) {
return FP.Parsers.Success(m[0], input.drop(m[0].length));
} else {
if (offset === source.length) {
found = "end of source";
} else {
found = "`" + source.charAt(offset) + "'";
}
return FP.Parsers.Failure(
"string matching regex " + rx + " expected but " + found + " found",
input
);
}
});
},
regexLiteral: function (rx /* must start with ^ */) {
if (rx.toString().substring(0, 2) !== "/^") {
throw ("regex must start with `^' but " + rx);
}
return FP.Parsers.Parser(function (input) {
var source, offset, start, m, found;
source = input.source;
offset = input.offset;
start = FP.Parsers._handleWhiteSpace(input);
m = rx.exec(source.substring(start, source.length));
if (m !== null) {
return FP.Parsers.Success(m[0], input.drop(start + m[0].length - offset));
} else {
if (start === source.length) {
found = "end of source";
} else {
found = "`" + source.charAt(start) + "'";
}
return FP.Parsers.Failure(
"string matching regex " + rx + " expected but " + found + " found",
input.drop(start - offset)
);
}
});
},
eos: function () {
return FP.Parsers.Parser(function (input) {
var source, offset, start;
source = input.source;
offset = input.offset;
start = FP.Parsers._handleWhiteSpace(input);
if (source.length === start) {
return FP.Parsers.Success("", input);
} else {
return FP.Parsers.Failure("end of source expected but `" +
source.charAt(start) + "' found", input);
}
});
},
commit: function (/*lazy*/ p) {
return FP.Parsers.Parser(function (input) {
var res = p()(input);
return (FP.Matcher()
.Case(FP.Parsers.Success, function (x) { return res; })
.Case(FP.Parsers.Error, function (x) { return res; })
.Case(FP.Parsers.Failure, function (x) {
return FP.Parsers.Error(x[0], x[1]);
}).match(res)
);
});
},
//elem: function (kind, p)
elem: function (e) { return FP.Parsers.accept(e).named('"' + e + '"'); },
accept: function (e) {
return FP.Parsers.acceptIf(
function (x) { return x === e; },
function (x) { return "`" + e + "' expected but `" + x + "' found"; }
);
},
acceptIf: function (p, err) {
return FP.Parsers.Parser(function (input) {
if (p(input.first())) {
return FP.Parsers.Success(input.first(), input.rest());
} else {
return FP.Parsers.Failure(err(input.first()), input);
}
});
},
//acceptMatch: function (expected, f)
//acceptSeq: function (es)
failure: function (msg) {
return FP.Parsers.Parser(function (input) {
return FP.Parsers.Failure(msg, input);
});
},
err: function (msg) {
return FP.Parsers.Parser(function (input) {
return FP.Parsers.Error(msg, input);
});
},
success: function (v) {
return FP.Parsers.Parser(function (input) {
return FP.Parsers.Success(v, input);
});
},
log: function (/*lazy*/ p, name) {
return FP.Parsers.Parser(function (input) {
console.log("trying " + name + " at " + input);
var r = p().apply(input);
console.log(name + " --> " + r);
return r;
});
},
rep: function (/*lazy*/ p) {
var s = FP.Parsers.success(FP.List.empty);
return FP.Parsers.rep1(p).or(function () { return s; });
},
rep1: function (/*lazy*/ p) {
return FP.Parsers.Parser(function (input) {
var elems, i, p0, res;
elems = [];
i = input;
p0 = p();
res = p0.apply(input);
if (res.isa(FP.Parsers.Success)) {
while (res.isa(FP.Parsers.Success)) {
elems.push(res.result);
i = res.next;
res = p0.apply(i);
}
return FP.Parsers.Success(FP.List.fromArray(elems), i);
} else {
return res;
}
});
},
//rep1: function (/*lazy*/ first, /*lazy*/ p)
repN: function (num, /*lazy*/ p) {
if (num === 0) {
return FP.Parsers.success(FP.List.empty);
}
return FP.Parsers.Parser(function (input) {
var elems, i, p0, res;
elems = [];
i = input;
p0 = p();
res = p0.apply(i);
while (res.isa(FP.Parsers.Success)) {
elems.push(res.result);
i = res.next;
if (num === elems.length) {
return FP.Parsers.Success(FP.List.fromArray(elems), i);
}
res = p0.apply(i);
}
return res; // NoSuccess
});
},
repsep: function (/*lazy*/ p, /*lazy*/ q) {
var s = FP.Parsers.success(FP.List.empty);
return FP.Parsers.rep1sep(p, q).or(function () { return s; });
},
rep1sep: function (/*lazy*/ p, /*lazy*/ q) {
return p().and(FP.Parsers.rep(q().andr(p))).to(function (res) {
return FP.List.Cons(res.head, res.tail);
});
},
// chainl1: function (/*lazy*/ p, /*lazy*/ q) {
// return this.chainl1(p, p, q)
// },
chainl1: function (/*lazy*/ first, /*lazy*/ p, /*lazy*/ q) {
return first().and(FP.Parsers.rep(q().and(p))).to(function (res) {
return res.tail.foldLeft(res.head, function (a, fb) { return fb.head(a, fb.tail); });
});
},
chainr1: function (/*lazy*/ p, /*lazy*/ q, combine, first) {
return p().and(this.rep(q().and(p))).to(function (res) {
return FP.List.Cons(FP.Parsers.Pair(combine, res.head),
res.tail).foldRight(first, function (fa, b) { return fa.head(fa.tail, b); }
);
});
},
opt: function (/*lazy*/ p) {
return p().to(function (x) {
return FP.Option.Some(x);
}).or(function () {
return FP.Parsers.success(FP.Option.empty);
});
},
not: function (/*lazy*/ p) {
return FP.Parsers.Parser(function (input) {
var r = p().apply(input);
if (r.successful) {
return FP.Parsers.Failure("Expected failure", input);
} else {
return FP.Parsers.Success(FP.Option.empty, input);
}
});
},
guard: function (/*lazy*/ p) {
return FP.Parsers.Parser(function (input) {
var r = p().apply(input);
if (r.successful) {
return FP.Parsers.Success(r.result, input);
} else {
return r;
}
});
},
//positioned: function (/*lazy*/ p)
//phrase: function (p)
mkList: function (pair) { return FP.List.Cons(pair.head, pair.tail); },
fun: function (x) { return function () { return x; }; },
lazyParser: function (x) {
var lit, r;
if (x instanceof String || (typeof x) === "string") {
lit = FP.Parsers.literal(x);
return function () { return lit; };
} else if (x instanceof Function) {
// x is deemed to be a function which has the return value as Parser.
return x;
} else if (x instanceof Object) {
if("isa" in x && x.isa(FP.Parsers.Parser)) {
return function () { return x; };
} else if (x instanceof RegExp) {
r = FP.Parsers.regexLiteral(x);
return function () { return r; };
} else {
return FP.Parsers.err("unhandlable type");
}
} else {
return FP.Parsers.err("unhandlable type");
}
},
seq: function () {
var count, parser, i;
count = arguments.length;
if (count === 0) { return FP.Parsers.err("at least one element must be specified"); }
parser = FP.Parsers.lazyParser(arguments[0])();
i = 1;
while (i < count) {
parser = parser.and(FP.Parsers.lazyParser(arguments[i]));
i += 1;
}
return parser;
},
or: function () {
var count, parser, i;
count = arguments.length;
if (count === 0) { return FP.Parsers.err("at least one element must be specified"); }
parser = FP.Parsers.lazyParser(arguments[0])();
i = 1;
while (i < count) {
parser = parser.or(FP.Parsers.lazyParser(arguments[i]));
i += 1;
}
return parser;
}
});
/************ Pair **************/
FP.Parsers.Pair = MathJax.Object.Subclass({
Init: function (head, tail) {
this.head = head;
this.tail = tail;
},
toString: function () { return '(' + this.head + '~' + this.tail + ')'; }
}, {
unapply: function (x) { return FP.Option.Some([x.head, x.tail]); }
});
/************ ParseResult **************/
FP.Parsers.ParseResult = MathJax.Object.Subclass({
Init: function () {},
isEmpty: function () { return !this.successful; },
getOrElse: function (/*lazy*/ defaultValue) {
if (this.isEmpty) { return defaultValue(); } else { return this.get(); }
}
});
/************ Success **************/
FP.Parsers.Success = FP.Parsers.ParseResult.Subclass({
Init: function (result, next) {
this.result = result;
this.next = next;
},
map: function (f) { return FP.Parsers.Success(f(this.result), this.next); },
mapPartial: function (f, err) {
try {
return FP.Parsers.Success(f(this.result), this.next);
} catch (e) {
if ("isa" in e && e.isa(FP.MatchError)) {
return FP.Parsers.Failure(err(this.result), this.next);
} else {
throw e;
}
}
},
flatMapWithNext: function (f) { return f(this.result).apply(this.next); },
append: function (/*lazy*/ a) { return this; },
get: function () { return this.result; },
successful: true,
toString: function () { return '[' + this.next.pos() + '] parsed: ' + this.result; }
}, {
unapply: function (x) { return FP.Option.Some([x.result, x.next]); }
});
/************ NoSuccess **************/
FP.Parsers.NoSuccess = FP.Parsers.ParseResult.Subclass({
Init: function () {},
_setLastNoSuccess: function () {
var context = this.next.context;
if (context.lastNoSuccess === undefined || !this.next.pos().isLessThan(context.lastNoSuccess.next.pos())) {
context.lastNoSuccess = this;
}
},
map: function (f) { return this; },
mapPartial: function (f, error) { return this; },
flatMapWithNext: function (f) { return this; },
get: function () { return FP.Parsers.error("No result when parsing failed"); },
successful: false
});
/************ Failure **************/
FP.Parsers.Failure = FP.Parsers.NoSuccess.Subclass({
Init: function (msg, next) {
this.msg = msg;
this.next = next;
this._setLastNoSuccess();
},
append: function (/*lazy*/ a) {
var alt = a();
if (alt.isa(FP.Parsers.Success)) {
return alt;
} else if (alt.isa(FP.Parsers.NoSuccess)) {
if (alt.next.pos().isLessThan(this.next.pos())) {
return this;
} else {
return alt;
}
} else {
throw FP.MatchError(alt);
}
},
toString: function () { return ('[' + this.next.pos() + '] failure: ' +
this.msg + '\n\n' + this.next.pos().longString()); }
}, {
unapply: function (x) { return FP.Option.Some([x.msg, x.next]); }
});
/************ Error **************/
FP.Parsers.Error = FP.Parsers.NoSuccess.Subclass({
Init: function (msg, next) {
this.msg = msg;
this.next = next;
this._setLastNoSuccess();
},
append: function (/*lazy*/ a) { return this; },
toString: function () { return ('[' + this.next.pos() + '] error: ' +
this.msg + '\n\n' + this.next.pos().longString()); }
}, {
unapply: function (x) { return FP.Option.Some([x.msg, x.next]); }
});
/************ Parser **************/
FP.Parsers.Parser = MathJax.Object.Subclass({
Init: function (f) { this.apply = f; },
name: '',
named: function (name) { this.name = name; return this; },
toString: function () { return 'Parser (' + this.name + ')'; },
flatMap: function (f) {
var app = this.apply;
return FP.Parsers.Parser(function (input) {
return app(input).flatMapWithNext(f);
});
},
map: function (f) {
var app = this.apply;
return FP.Parsers.Parser(function (input) {
return app(input).map(f);
});
},
append: function (/*lazy*/ p) {
var app = this.apply;
return FP.Parsers.Parser(function (input) {
return app(input).append(function () {
return p().apply(input);
});
});
},
and: function (/*lazy*/ p) {
return this.flatMap(function (a) {
return p().map(function (b) {
return FP.Parsers.Pair(a, b);
});
}).named('~');
},
andr: function (/*lazy*/ p) {
return this.flatMap(function (a) {
return p().map(function (b) {
return b;
});
}).named('~>');
},
andl: function (/*lazy*/ p) {
return this.flatMap(function (a) {
return p().map(function (b) {
return a;
});
}).named('<~');
},
or: function (/*lazy*/ q) { return this.append(q).named("|"); },
andOnce: function (/*lazy*/ p) {
var flatMap = this.flatMap;
return FP.Parsers.OnceParser(function () {
return flatMap(function (a) {
return FP.Parsers.commit(p).map(function (b) {
return FP.Parsers.Pair(a, b);
});
}).named('~!');
});
},
longestOr: function (/*lazy*/ q0) {
var app = this.apply;
return FP.Parsers.Parser(function (input) {
var res1, res2;
res1 = app(input);
res2 = q0()(input);
if (res1.successful) {
if (res2.successful) {
if (res2.next.pos().isLessThan(res1.next.pos())) {
return res1;
} else {
return res2;
}
} else {
return res1;
}
} else if (res2.successful) {
return res2;
} else if (res1.isa(FP.Parsers.Error)) {
return res1;
} else {
if (res2.next.pos().isLessThan(res1.next.pos())) {
return res1;
} else {
return res2;
}
}
}).named("|||");
},
to: function (f) { return this.map(f).named(this.toString() + '^^'); },
ret: function (/*lazy*/ v) {
var app = this.apply;
return FP.Parsers.Parser(function (input) {
return app(input).map(function (x) { return v(); });
}).named(this.toString() + "^^^");
},
toIfPossible: function (f, error) {
if (error === undefined) {
error = function (r) { return "Constructor function not defined at " + r; };
}
var app = this.apply;
return FP.Parsers.Parser(function (input) {
return app(input).mapPartial(f, error);
}).named(this.toString() + "^?");
},
into: function (fq) { return this.flatMap(fq); },
rep: function () {
var p = this;
return FP.Parsers.rep(function () { return p; });
},
chain: function (/*lazy*/ sep) {
var p, lp;
p = this;
lp = function () { return p; };
return FP.Parsers.chainl1(lp, lp, sep);
},
rep1: function () {
var p = this;
return FP.Parsers.rep1(function () { return p; });
},
opt: function () {
var p = this;
return FP.Parsers.opt(function () { return p; });
}
});
/************ OnceParser **************/
FP.Parsers.OnceParser = FP.Parsers.Parser.Subclass({
Init: function (f) { this.apply = f; },
and: function (p) {
var flatMap = this.flatMap;
return FP.Parsers.OnceParser(function () {
return flatMap(function (a) {
return FP.Parsers.commit(p).map(function (b) {
return FP.Parsers.Pair(a, b);
});
});
}).named('~');
}
});
MathJax.Hub.Startup.signal.Post("Functional Programming library Ready");
})();
MathJax.Extension.xypic = {
version: "0.1",
constants: {
whiteSpaceRegex: /^(\s+|%[^\r\n]*(\r\n|\r|\n)?)+/,
unsupportedBrowserErrorMessage: "Unsupported Browser. Please open with Firefox/Safari/Chrome/Opera"
},
signalHandler: {
signals: [],
hookedSignals: [],
chains: [],
chainSignal: function (successor, predecessors) {
for (var i = 0; i < predecessors.length; i++) {
MathJax.Extension.xypic.signalHandler.addSignal(predecessors[i]);
}
MathJax.Extension.xypic.signalHandler.chains.push({succ:successor, pred:predecessors});
},
addSignal: function (signal) {
var signals = MathJax.Extension.xypic.signalHandler.signals;
for (var i = 0; i < signals.length; i++) {
if (signals[i] === signal) {
return;
}
}
MathJax.Extension.xypic.signalHandler.signals.push(signal);
var handler = MathJax.Extension.xypic.signalHandler.handleSignal(signal);
MathJax.Hub.Register.StartupHook(signal, handler);
},
handleSignal: function (signal) {
return function () {
MathJax.Extension.xypic.signalHandler.hookedSignals.push(signal);
MathJax.Extension.xypic.signalHandler.handleChains();
}
},
handleChains: function () {
var i = 0;
var chains = MathJax.Extension.xypic.signalHandler.chains;
var remainingChains = [];
var invokableSignals = [];
while (i < chains.length) {
var c = chains[i];
var pred = c.pred;
var invokable = true;
for (var j = 0; j < pred.length; j++) {
var p = pred[j];
if (!MathJax.Extension.xypic.signalHandler.listenedSignal(p)) {
invokable = false;
break;
}
}
if (invokable) {
invokableSignals.push(c.succ);
} else {
remainingChains.push(c);
}
i++;
}
MathJax.Extension.xypic.signalHandler.chains = remainingChains;
for (i = 0; i < invokableSignals.length; i++) {
MathJax.Hub.Startup.signal.Post(invokableSignals[i]);
}
},
listenedSignal: function (signal) {
var signals = MathJax.Extension.xypic.signalHandler.hookedSignals;
for (var i = 0; i < signals.length; i++) {
if (signals[i] === signal) {
return true;
}
}
return false;
}
}
}
// "TeX Xy-pic" depends on "Functional Programming library" and "TeX Jax".
MathJax.Extension.xypic.signalHandler.chainSignal("TeX Xy-pic Require", ["Functional Programming library Ready", "TeX Jax Ready"]);
// "HTML-CSS Xy-pic Config" depends on "TeX Xy-pic" and "HTML-CSS Jax".
MathJax.Extension.xypic.signalHandler.chainSignal("HTML-CSS Xy-pic Config Require", ["TeX Xy-pic Ready", "HTML-CSS Jax Ready"]);
// "SVG Xy-pic Config" depends on "TeX Xy-pic" and "SVG Jax".
MathJax.Extension.xypic.signalHandler.chainSignal("SVG Xy-pic Config Require", ["TeX Xy-pic Ready", "SVG Jax Ready"]);
// "Device-Independent Xy-pic" depends on "TeX Xy-pic" OR "SVG Jax".
MathJax.Extension.xypic.signalHandler.chainSignal("Device-Independent Xy-pic Require", ["HTML-CSS Xy-pic Config Ready"]);
MathJax.Extension.xypic.signalHandler.chainSignal("Device-Independent Xy-pic Require", ["SVG Xy-pic Config Ready"]);
// "HTML-CSS Xy-pic" depends on "HTML-CSS Xy-pic Config" and "Device-Independent Xy-pic".
MathJax.Extension.xypic.signalHandler.chainSignal("HTML-CSS Xy-pic Require", ["HTML-CSS Xy-pic Config Ready", "Device-Independent Xy-pic Ready"]);
// "SVG Xy-pic" depends on "SVG Xy-pic Config" and "Device-Independent Xy-pic".
MathJax.Extension.xypic.signalHandler.chainSignal("SVG Xy-pic Require", ["SVG Xy-pic Config Ready", "Device-Independent Xy-pic Ready"]);
MathJax.Hub.Register.StartupHook("TeX Xy-pic Require",function () {
var FP = MathJax.Extension.fp;
var MML = MathJax.ElementJax.mml;
var TEX = MathJax.InputJax.TeX;
var TEXDEF = TEX.Definitions;
var xypic = MathJax.Extension.xypic;
var AST = xypic.AST = MathJax.Object.Subclass({});
MathJax.Hub.Insert(TEXDEF, {
macros: {
//hole: ['Macro', '{\\bbox[3pt]{}}']
hole: ['Macro', '{\\style{visibility:hidden}{x}}'],
objectstyle: ['Macro', '\\textstyle'],
labelstyle: ['Macro', '\\scriptstyle'],
twocellstyle: ['Macro', '\\scriptstyle'],
xybox: 'Xybox',
xymatrix: 'Xymatrix',
newdir: 'XypicNewdir',
includegraphics: 'Xyincludegraphics'
},
environment: {
xy: ['ExtensionEnv', null, 'XYpic']
}
});
// override MathJax.InputJax.TeX.formatError function to display parse error.
var tex_formatError = TEX.formatError;
TEX.formatError = function (err, math, displaystyle, script) {
if (err.xyjaxError !== undefined) {
return err.toMML();
} else {
return tex_formatError(err, math, displaystyle, script);
}
}
xypic.memoize = function (object, funcName) {
var func = object[funcName];
var memo = function () {
var value = func.call(this);
var constFunc = function () {
return value;
}
constFunc.reset = reset;
object[funcName] = constFunc;
return value;
}
var reset = function () {
object[funcName] = memo;
}
memo.reset = reset;
reset();
};
AST.xypic = MML.mbase.Subclass({
Init: function (cmd) {
this.data = [];
this.cmd = cmd;
},
type: "xypic",
inferRow: false,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
notation: MML.NOTATION.LONGDIV,
texClass: MML.TEXCLASS.ORD
},
setTeXclass: MML.mbase.setSeparateTeXclasses,
toString: function () { return this.type + "(" + this.cmd + ")"; }
});
AST.xypic.newdir = MML.mbase.Subclass({
Init: function (cmd) {
this.data = [];
this.cmd = cmd;
},
type: "newdir",
inferRow: false,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
notation: MML.NOTATION.LONGDIV,
texClass: MML.TEXCLASS.ORD
},
setTeXclass: MML.mbase.setSeparateTeXclasses,
toString: function () { return this.type + "(" + this.cmd + ")"; }
});
AST.xypic.includegraphics = MML.mbase.Subclass({
Init: function (cmd) {
this.data = [];
this.cmd = cmd;
},
type: "includegraphics",
inferRow: false,
defaults: {
mathbackground: MML.INHERIT,
mathcolor: MML.INHERIT,
notation: MML.NOTATION.LONGDIV,
texClass: MML.TEXCLASS.ORD
},
setTeXclass: MML.mbase.setSeparateTeXclasses,
toString: function () { return this.type + "(" + this.cmd + ")"; }
});
// <pos-decor> ::= <pos> <decor>
AST.PosDecor = MathJax.Object.Subclass({
Init: function (pos, decor) {
this.pos = pos;
this.decor = decor;
},
toString: function () {
return this.pos.toString() + " " + this.decor;
}
});
// <pos>
AST.Pos = MathJax.Object.Subclass({});
// <pos> ::= <coord> <pos2>*
AST.Pos.Coord = MathJax.Object.Subclass({
Init: function (coord, pos2s) {
this.coord = coord;
this.pos2s = pos2s;
},
toString: function () {
return this.coord.toString() + " " + this.pos2s.mkString(" ");
}
});
// <pos2> ::= '+' <coord>
AST.Pos.Plus = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "+(" + this.coord + ")";
}
});
// <pos2> ::= '-' <coord>
AST.Pos.Minus = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "-(" + this.coord + ")";
}
});
// <pos2> ::= '!' <coord>
AST.Pos.Skew = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "!(" + this.coord + ")";
}
});
// <pos2> ::= '.' <coord>
AST.Pos.Cover = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return ".(" + this.coord + ")";
}
});
// <pos2> ::= ',' <coord>
AST.Pos.Then = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return ",(" + this.coord + ")";
}
});
// <pos2> ::= ';' <coord>
AST.Pos.SwapPAndC = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return ";(" + this.coord + ")";
}
});
// <pos2> ::= ':' <coord>
AST.Pos.SetBase = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return ":(" + this.coord + ")";
}
});
// <pos2> ::= '::' <coord>
AST.Pos.SetYBase = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "::(" + this.coord + ")";
}
});
// <pos2> ::= '**' <object>
AST.Pos.ConnectObject = MathJax.Object.Subclass({
Init: function (object) {
this.object = object;
},
toString: function () {
return "**(" + this.object + ")";
}
});
// <pos2> ::= '*' <object>
AST.Pos.DropObject = MathJax.Object.Subclass({
Init: function (object) {
this.object = object;
},
toString: function () {
return "*(" + this.object + ")";
}
});
// <pos2> ::= '?' <place>
AST.Pos.Place = MathJax.Object.Subclass({
Init: function (place) {
this.place = place;
},
toString: function () {
return "?(" + this.place + ")";
}
});
// <pos2> ::= '@+' <coord>
AST.Pos.PushCoord = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "@+(" + this.coord + ")";
}
});
// <pos2> ::= '@-' <coord>
AST.Pos.EvalCoordThenPop = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "@-(" + this.coord + ")";
}
});
// <pos2> ::= '@=' <coord>
AST.Pos.LoadStack = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "@=(" + this.coord + ")";
}
});
// <pos2> ::= '@@' <coord>
AST.Pos.DoCoord = MathJax.Object.Subclass({
Init: function (coord) {
this.coord = coord;
},
toString: function () {
return "@@(" + this.coord + ")";
}
});
// <pos2> ::= '@i'
AST.Pos.InitStack = MathJax.Object.Subclass({
Init: function () {
},
toString: function () {
return "@i";
}
});
// <pos2> ::= '@('
AST.Pos.EnterFrame = MathJax.Object.Subclass({
Init: function () {
},
toString: function () {
return "@(";
}
});
// <pos2> ::= '@)'
AST.Pos.LeaveFrame = MathJax.Object.Subclass({
Init: function () {
},
toString: function () {
return "@)";
}
});
// <pos2> ::= '=' '"' <id> '"'
AST.Pos.SavePos = MathJax.Object.Subclass({
Init: function (id) {
this.id = id;
},
toString: function () {
return '="' + this.id + '"';
}
});
// <pos2> ::= '=' <coord> '"' <id> '"'
AST.Pos.SaveMacro = MathJax.Object.Subclass({
Init: function (macro, id) {
this.macro = macro;
this.id = id;
},
toString: function () {
return "=(" + this.macro + ' "' + this.id + '")';
}
});
// <pos2> ::= '=:' '"' <id> '"'
AST.Pos.SaveBase = MathJax.Object.Subclass({
Init: function (id) {
this.id = id;
},
toString: function () {
return '=:"' + this.id + '"';
}
});
// <pos2> ::= '=@' '"' <id> '"'
AST.Pos.SaveStack = MathJax.Object.Subclass({
Init: function (id) {
this.id = id;
},
toString: function () {
return '=@"' + this.id + '"';
}
});
// <coord>
AST.Coord = MathJax.Object.Subclass({});
// <coord> ::= <vector>
AST.Coord.Vector = MathJax.Object.Subclass({
Init: function (vector) {
this.vector = vector;
},
toString: function () {
return this.vector.toString();
}
});
// <coord> ::= <empty> | 'c'
AST.Coord.C = MathJax.Object.Subclass({
toString: function () {
return "c";
}
});
// <coord> ::= 'p'
AST.Coord.P = MathJax.Object.Subclass({
toString: function () {
return "p";
}
});
// <coord> ::= 'x'
AST.Coord.X = MathJax.Object.Subclass({
toString: function () {
return "x";
}
});
// <coord> ::= 'y'
AST.Coord.Y = MathJax.Object.Subclass({
toString: function () {
return "y";
}
});
// <coord> ::= '"' <id> '"'
AST.Coord.Id = MathJax.Object.Subclass({
Init: function (id) {
this.id = id;
},
toString: function () {
return '"' + this.id + '"';
}
});
// <coord> ::= '{' <pos> <decor> '}'
AST.Coord.Group = MathJax.Object.Subclass({
Init: function (posDecor) {
this.posDecor = posDecor;
},
toString: function () {
return '{' + this.posDecor + '}';
}
});
// <coord> ::= 's' <digit>
// <coord> ::= 's' '{' <nonnegative-number> '}'
AST.Coord.StackPosition = MathJax.Object.Subclass({
Init: function (number) {
this.number = number;
},
toString: function () {
return 's{' + this.number + '}';
}
});
// coordinate for xymatrix
// <coord> ::= '[' ('"'<prefix>'"')? <number> ',' <number> ']'
AST.Coord.DeltaRowColumn = MathJax.Object.Subclass({
/**
* @param {String} prefix name of the xymatrix
* @param {Number} dr rows below
* @param {Number} dc columns right
*/
Init: function (prefix, dr, dc) {
this.prefix = prefix;
this.dr = dr;
this.dc = dc;
},
toString: function () {
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.dr + "," + this.dc + "]";
}
});
// coordinate for xymatrix
// <coord> ::= '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )* ']'
AST.Coord.Hops = MathJax.Object.Subclass({
/**
* @param {String} prefix name of the xymatrix
* @param {List[String]} hops hops
*/
Init: function (prefix, hops) {
this.prefix = prefix;
this.hops = hops;
},
toString: function () {
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.hops.mkString("") + "]";
}
});
// coordinate for xymatrix
// <coord> ::= '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )+ <place> ']'
AST.Coord.HopsWithPlace = MathJax.Object.Subclass({
/**
* @param {String} prefix name of the xymatrix
* @param {List[String]} hops hops
* @param {AST.Pos.Place} place place
*/
Init: function (prefix, hops, place) {
this.prefix = prefix;
this.hops = hops;
this.place = place;
},
toString: function () {
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.hops.mkString("") + this.place + "]";
}
});
// <vector>
AST.Vector = MathJax.Object.Subclass({});
// <vector> ::= '(' <factor> ',' <factor> ')'
AST.Vector.InCurBase = MathJax.Object.Subclass({
Init: function (x, y) {
this.x = x;
this.y = y;
},
toString: function () {
return "(" + this.x + ", " + this.y + ")";
}
});
// <vector> ::= '<' <dimen> ',' <dimen> '>'
// <vector> ::= '<' <dimen> '>'
AST.Vector.Abs = MathJax.Object.Subclass({
Init: function (x, y) {
this.x = x;
this.y = y;
},
toString: function () {
return "<" + this.x + ", " + this.y + ">";
}
});
// <vector> ::= 'a' '(' <number> ')'
AST.Vector.Angle = MathJax.Object.Subclass({
Init: function (degree) {
this.degree = degree;
},
toString: function () {
return "a(" + this.degree + ")";
}
});
// <vector> ::= '/' <direction> <dimen> '/'
AST.Vector.Dir = MathJax.Object.Subclass({
Init: function (dir, dimen) {
this.dir = dir;
this.dimen = dimen;
},
toString: function () {
return "/" + this.dir + " " + this.dimen + "/";
}
});
// <vector> ::= <corner>
// | <corner> '(' <factor> ')'
AST.Vector.Corner = MathJax.Object.Subclass({
Init: function (corner, factor) {
this.corner = corner;
this.factor = factor;
},
toString: function () {
return this.corner.toString() + "(" + this.factor + ")";
}
});
// <corner> ::= 'L' | 'R' | 'D' | 'U'
// | 'CL' | 'CR' | 'CD' | 'CU'
// | 'LD' | 'RD' | 'LU' | 'RU'
// | 'E' | 'P'
// | 'A'
AST.Corner = MathJax.Object.Subclass({});
AST.Corner.L = MathJax.Object.Subclass({
toString: function () { return "L"; }
});
AST.Corner.R = MathJax.Object.Subclass({
toString: function () { return "R"; }
});
AST.Corner.D = MathJax.Object.Subclass({
toString: function () { return "D"; }
});
AST.Corner.U = MathJax.Object.Subclass({
toString: function () { return "U"; }
});
AST.Corner.CL = MathJax.Object.Subclass({
toString: function () { return "CL"; }
});
AST.Corner.CR = MathJax.Object.Subclass({
toString: function () { return "CR"; }
});
AST.Corner.CD = MathJax.Object.Subclass({
toString: function () { return "CD"; }
});
AST.Corner.CU = MathJax.Object.Subclass({
toString: function () { return "CU"; }
});
AST.Corner.LD = MathJax.Object.Subclass({
toString: function () { return "LD"; }
});
AST.Corner.RD = MathJax.Object.Subclass({
toString: function () { return "RD"; }
});
AST.Corner.LU = MathJax.Object.Subclass({
toString: function () { return "LU"; }
});
AST.Corner.RU = MathJax.Object.Subclass({
toString: function () { return "RU"; }
});
AST.Corner.NearestEdgePoint = MathJax.Object.Subclass({
toString: function () { return "E"; }
});
AST.Corner.PropEdgePoint = MathJax.Object.Subclass({
toString: function () { return "P"; }
});
AST.Corner.Axis = MathJax.Object.Subclass({
toString: function () { return "A"; }
});
// <place> ::= '<' <place>
// <place> ::= '>' <place>
// <place> ::= '(' <factor> ')' <place>
// <place> ::= '!' '{' <pos> '}' <slide>
// <place> ::= <slide>
AST.Place = MathJax.Object.Subclass({
Init: function (shaveP, shaveC, factor, slide) {
this.shaveP = shaveP;
this.shaveC = shaveC;
this.factor = factor;
this.slide = slide;
},
compound: function (that) {
return AST.Place(
this.shaveP + that.shaveP,
this.shaveC + that.shaveC,
that.factor === undefined? this.factor : that.factor,
that.slide);
},
toString: function () {
var desc = "";
for (var l = 0; l < this.shaveP; l++) {
desc += "<";
}
for (var r = 0; r < this.shaveC; r++) {
desc += ">";
}
if (this.factor !== undefined) {
desc += "(" + this.factor + ")";
}
this.slide.dimen.foreach(function (d) {
desc += "/" + d + "/";
});
return desc;
}
});
AST.Place.Factor = MathJax.Object.Subclass({
Init: function (factor) {
this.factor = factor;
},
isIntercept: false,
toString: function () {
return this.factor.toString();
}
});
AST.Place.Intercept = MathJax.Object.Subclass({
Init: function (pos) {
this.pos = pos;
},
isIntercept: true,
toString: function () {
return "!{" + this.pos + "}";
}
});
// <slide> ::= <empty>
// <slide> ::= '/' <dimen> '/'
AST.Slide = MathJax.Object.Subclass({
Init: function (dimen) {
this.dimen = dimen;
},
toString: function () {
return this.dimen.getOrElse("");
}
});
// <object> ::= <modifier>* <objectbox>
AST.Object = MathJax.Object.Subclass({
Init: function (modifiers, object) {
this.modifiers = modifiers;
this.object = object;
},
dirVariant: function () { return this.object.dirVariant(); },
dirMain: function () { return this.object.dirMain(); },
isDir: function () { return this.object.isDir(); },
toString: function () {
return this.modifiers.mkString() + this.object.toString();
}
});
// <objectbox>
AST.ObjectBox = MathJax.Object.Subclass({
dirVariant: function () { return undefined; },
dirMain: function () { return undefined; },
isDir: function () { return false; },
isEmpty: false
});
// <objectbox> ::= '{' <text> '}'
// <objectbox> ::= <TeX box> '{' <text> '}'
AST.ObjectBox.Text = AST.ObjectBox.Subclass({
Init: function (math) {
this.math = math;
},
toString: function () { return "{" + this.math.toString() + "}"; }
});
AST.ObjectBox.Empty = AST.ObjectBox.Subclass({
isEmpty: true,
toString: function () { return "{}"; }
});
// <objectbox> ::= 'xymatrix' <xymatrix>
AST.ObjectBox.Xymatrix = AST.ObjectBox.Subclass({
/**
* @param {AST.Command.Xymatrix} xymatrix xymatrix
*/
Init: function (xymatrix) {
this.xymatrix = xymatrix;
},
toString: function () { return this.xymatrix.toString(); }
});
// <objectbox> ::= '\txt' <width> <styl