diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/lib/inlines.js | 151 |
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, |