summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/lib/inlines.js151
1 files changed, 63 insertions, 88 deletions
diff --git a/js/lib/inlines.js b/js/lib/inlines.js
index 34f1560..5fde099 100644
--- a/js/lib/inlines.js
+++ b/js/lib/inlines.js
@@ -262,93 +262,81 @@ var Str = function(s) {
// Attempt to parse emphasis or strong emphasis.
var parseEmphasis = function(cc,inlines) {
var startpos = this.pos;
- var c ;
- var first_close = 0;
- c = fromCodePoint(cc);
- var numdelims;
- var numclosedelims;
- var delimpos;
-
- // Get opening delimiters.
- res = this.scanDelims(cc);
- numdelims = res.numdelims;
+ var res = this.scanDelims(cc);
+ var numdelims = res.numdelims;
if (numdelims === 0) {
this.pos = startpos;
return false;
}
- if (numdelims >= 4 || !res.can_open) {
- this.pos += numdelims;
- inlines.push(Str(this.subject.slice(startpos, startpos + numdelims)));
- return true;
- }
+ if (res.can_close) {
- this.pos += numdelims;
+ // Walk the stack and find a matching opener, if possible
+ var opener = this.emphasis_openers;
+ while (opener) {
- var delims_to_match = numdelims;
-
- var current = [];
- var firstend;
- var firstpos;
- var state = 0;
- var can_close = false;
- var can_open = false;
- var last_emphasis_closer = null;
- while (this.last_emphasis_closer[c] >= this.pos) {
- res = this.scanDelims(cc);
- numclosedelims = res.numdelims;
-
- if (res.can_close) {
- if (last_emphasis_closer === null ||
- last_emphasis_closer < this.pos) {
- last_emphasis_closer = this.pos;
- }
- if (numclosedelims === 3 && delims_to_match === 3) {
- delims_to_match -= 3;
- this.pos += 3;
- current = [{t: 'Strong', c: [{t: 'Emph', c: current}]}];
- } else if (numclosedelims >= 2 && delims_to_match >= 2) {
- delims_to_match -= 2;
- this.pos += 2;
- firstend = current.length;
- firstpos = this.pos;
- current = [{t: 'Strong', c: current}];
- } else if (numclosedelims >= 1 && delims_to_match >= 1) {
- delims_to_match -= 1;
- this.pos += 1;
- firstend = current.length;
- firstpos = this.pos;
- current = [{t: 'Emph', c: current}];
- } else {
- if (!(this.parseInline(current,true))) {
- break;
- }
- }
- if (delims_to_match === 0) {
- Array.prototype.push.apply(inlines, current);
- return true;
+ if (opener.cc === cc) { // we have a match!
+
+ if (opener.numdelims <= numdelims) { // all openers used
+
+ this.pos += opener.numdelims;
+ var X;
+ switch (opener.numdelims) {
+ case 3:
+ X = function(x) { return Strong([Emph(x)]); };
+ break;
+ case 2:
+ X = Strong;
+ break;
+ case 1:
+ default:
+ X = Emph;
+ break;
}
- } else if (!(this.parseInline(current,true))) {
- break;
+ inlines[opener.pos] = X(inlines.slice(opener.pos + 1));
+ inlines.splice(opener.pos + 1, inlines.length - (opener.pos + 1));
+ // Remove entries after this, to prevent overlapping nesting:
+ this.emphasis_openers = opener.previous;
+ return true;
+
+ } else if (opener.numdelims > numdelims) { // only some openers used
+
+ this.pos += numdelims;
+ opener.numdelims -= numdelims;
+ inlines[opener.pos].c =
+ inlines[opener.pos].c.slice(0, opener.numdelims);
+ var X = numdelims === 2 ? Strong : Emph;
+ inlines[opener.pos + 1] = X(inlines.slice(opener.pos + 1));
+ inlines.splice(opener.pos + 2, inlines.length - (opener.pos + 2));
+ // Remove entries after this, to prevent overlapping nesting:
+ this.emphasis_openers = opener;
+ return true;
+
+ }
+
}
+ opener = opener.previous;
+ }
}
- // we didn't match emphasis: fallback
- inlines.push(Str(this.subject.slice(startpos,
- startpos + delims_to_match)));
- if (delims_to_match < numdelims) {
- Array.prototype.push.apply(inlines, current.slice(0,firstend));
- this.pos = firstpos;
- } else { // delims_to_match === numdelims
- this.pos = startpos + delims_to_match;
- }
+ // If we're here, we didn't match a closer.
+
+ this.pos += numdelims;
+ inlines.push(Str(this.subject.slice(startpos, startpos + numdelims)));
+
+ if (res.can_open) {
- if (last_emphasis_closer) {
- this.last_emphasis_closer[c] = last_emphasis_closer;
+ // Add entry to stack for this opener
+ this.emphasis_openers = { cc: cc,
+ numdelims: numdelims,
+ pos: inlines.length - 1,
+ previous: this.emphasis_openers };
}
+
return true;
+
};
// Attempt to parse link title (sans quotes), returning the string
@@ -629,18 +617,11 @@ var parseReference = function(s, refmap) {
};
// Parse the next inline element in subject, advancing subject position.
-// If memoize is set, memoize the result.
// On success, add the result to the inlines list, and return true.
// On failure, return false.
-var parseInline = function(inlines, memoize) {
+var parseInline = function(inlines) {
var startpos = this.pos;
var origlen = inlines.length;
- var memoized = memoize && this.memo[startpos];
- if (memoized) {
- this.pos = memoized.endpos;
- Array.prototype.push.apply(inlines, memoized.inline);
- return true;
- }
var c = this.peek();
if (c === -1) {
@@ -683,10 +664,6 @@ var parseInline = function(inlines, memoize) {
inlines.push({t: 'Str', c: fromCodePoint(c)});
}
- if (memoize) {
- this.memo[startpos] = { inline: inlines.slice(origlen),
- endpos: this.pos };
- }
return true;
};
@@ -695,10 +672,9 @@ var parseInlines = function(s, refmap) {
this.subject = s;
this.pos = 0;
this.refmap = refmap || {};
- this.memo = {};
- this.last_emphasis_closer = { '*': s.length, '_': s.length };
+ this.emphasis_openers = null;
var inlines = [];
- while (this.parseInline(inlines, false)) {
+ while (this.parseInline(inlines)) {
}
return inlines;
};
@@ -708,10 +684,9 @@ function InlineParser(){
return {
subject: '',
label_nest_level: 0, // used by parseLinkLabel method
- last_emphasis_closer: null, // used by parseEmphasis method
+ emphasis_openers: null, // used by parseEmphasis method
pos: 0,
refmap: {},
- memo: {},
match: match,
peek: peek,
spnl: spnl,