summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2014-10-23 22:34:07 -0700
committerJohn MacFarlane <jgm@berkeley.edu>2014-10-23 23:29:30 -0700
commit6607a88478812c9e37537da9eb6b0e4a5412bfe4 (patch)
treee25902f2f817a1adf5ca9d4453df0ba3a46b486d /js
parentacfdce9fa8159ec950ec91bd68e8f56b869c0167 (diff)
inlines.js: Implemented stack-based emph parsing.
Diffstat (limited to 'js')
-rw-r--r--js/lib/inlines.js135
1 files changed, 62 insertions, 73 deletions
diff --git a/js/lib/inlines.js b/js/lib/inlines.js
index 34f1560..4d73d3e 100644
--- a/js/lib/inlines.js
+++ b/js/lib/inlines.js
@@ -262,93 +262,82 @@ 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 i = this.emph_stack.length - 1;
+ while (i >= 0) {
- 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;
+ var opener = this.emph_stack[i];
+ 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.emph_stack.splice(i, this.emph_stack.length - i);
+ 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.emph_stack.splice(i + 1, this.emph_stack.length - (i + 1));
+ return true;
+
+ }
+
}
+ i--;
+ }
}
- // 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) {
+
+ // Add entry to stack for this opener
+ this.emph_stack.push({ cc: cc,
+ numdelims: numdelims,
+ pos: inlines.length - 1 });
- if (last_emphasis_closer) {
- this.last_emphasis_closer[c] = last_emphasis_closer;
}
+
return true;
+
};
// Attempt to parse link title (sans quotes), returning the string
@@ -696,7 +685,7 @@ var parseInlines = function(s, refmap) {
this.pos = 0;
this.refmap = refmap || {};
this.memo = {};
- this.last_emphasis_closer = { '*': s.length, '_': s.length };
+ this.emph_stack = [];
var inlines = [];
while (this.parseInline(inlines, false)) {
}
@@ -708,7 +697,7 @@ function InlineParser(){
return {
subject: '',
label_nest_level: 0, // used by parseLinkLabel method
- last_emphasis_closer: null, // used by parseEmphasis method
+ emph_stack: [], // used by parseEmphasis method
pos: 0,
refmap: {},
memo: {},