diff --git a/components.js b/components.js index 596e73ceeb..97a59fc7e1 100644 --- a/components.js +++ b/components.js @@ -341,6 +341,11 @@ var components = { "title": "PARI/GP", "owner": "Golmote" }, + "parser": { + "title": "Parser", + "require": "markup", + "owner": "Golmote" + }, "pascal": { "title": "Pascal", "owner": "Golmote" diff --git a/components/prism-markup.js b/components/prism-markup.js index 06f24c2f6b..635715509d 100644 --- a/components/prism-markup.js +++ b/components/prism-markup.js @@ -4,7 +4,7 @@ Prism.languages.markup = { 'doctype': //, 'cdata': //i, 'tag': { - pattern: /<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i, + pattern: /<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i, inside: { 'tag': { pattern: /^<\/?[^\s>\/]+/i, diff --git a/components/prism-markup.min.js b/components/prism-markup.min.js index b1602514e6..9615654000 100644 --- a/components/prism-markup.min.js +++ b/components/prism-markup.min.js @@ -1 +1 @@ -Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; \ No newline at end of file +Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; \ No newline at end of file diff --git a/components/prism-parser.js b/components/prism-parser.js new file mode 100644 index 0000000000..877564334b --- /dev/null +++ b/components/prism-parser.js @@ -0,0 +1,66 @@ +Prism.languages.parser = Prism.languages.extend('markup', { + 'keyword': { + pattern: /(^|[^^])(?:\^(?:case|eval|for|if|switch|throw)\b|@(?:BASE|CLASS|GET(?:_DEFAULT)?|OPTIONS|SET_DEFAULT|USE)\b)/, + lookbehind: true + }, + 'variable': { + pattern: /(^|[^^])\B\$(?:\w+|(?=[.\{]))(?:(?:\.|::?)\w+)*(?:\.|::?)?/, + lookbehind: true, + inside: { + 'punctuation': /\.|:+/ + } + }, + 'function': { + pattern: /(^|[^^])\B[@^]\w+(?:(?:\.|::?)\w+)*(?:\.|::?)?/, + lookbehind: true, + inside: { + 'keyword': { + pattern: /(^@)(?:GET_|SET_)/, + lookbehind: true + }, + 'punctuation': /\.|:+/ + } + }, + 'escape': { + pattern: /\^(?:[$^;@()\[\]{}"':]|#[a-f\d]*)/i, + alias: 'builtin' + }, + 'punctuation': /[\[\](){};]/ +}); +Prism.languages.insertBefore('parser', 'keyword', { + 'parser-comment': { + pattern: /(\s)#.*/, + lookbehind: true, + alias: 'comment' + }, + 'expression': { + // Allow for 3 levels of depth + pattern: /(^|[^^])\((?:[^()]|\((?:[^()]|\((?:[^()])*\))*\))*\)/, + lookbehind: true, + inside: { + 'string': { + pattern: /(^|[^^])(["'])(?:(?!\2)[^^]|\^[\s\S])*\2/, + lookbehind: true + }, + 'keyword': Prism.languages.parser.keyword, + 'variable': Prism.languages.parser.variable, + 'function': Prism.languages.parser.function, + 'boolean': /\b(?:true|false)\b/, + 'number': /\b(?:0x[a-f\d]+|\d+\.?\d*(?:e[+-]?\d+)?)\b/i, + 'escape': Prism.languages.parser.escape, + 'operator': /[~+*\/\\%]|!(?:\|\|?|=)?|&&?|\|\|?|==|<[<=]?|>[>=]?|-[fd]?|\b(?:def|eq|ge|gt|in|is|le|lt|ne)\b/, + 'punctuation': Prism.languages.parser.punctuation + } + } +}); +Prism.languages.insertBefore('inside', 'punctuation', { + 'expression': Prism.languages.parser.expression, + 'keyword': Prism.languages.parser.keyword, + 'variable': Prism.languages.parser.variable, + 'function': Prism.languages.parser.function, + 'escape': Prism.languages.parser.escape, + 'parser-punctuation': { + pattern: Prism.languages.parser.punctuation, + alias: 'punctuation' + } +}, Prism.languages.parser['tag'].inside['attr-value']); \ No newline at end of file diff --git a/components/prism-parser.min.js b/components/prism-parser.min.js new file mode 100644 index 0000000000..3aceb23cc0 --- /dev/null +++ b/components/prism-parser.min.js @@ -0,0 +1 @@ +Prism.languages.parser=Prism.languages.extend("markup",{keyword:{pattern:/(^|[^^])(?:\^(?:case|eval|for|if|switch|throw)\b|@(?:BASE|CLASS|GET(?:_DEFAULT)?|OPTIONS|SET_DEFAULT|USE)\b)/,lookbehind:!0},variable:{pattern:/(^|[^^])\B\$(?:\w+|(?=[.\{]))(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{punctuation:/\.|:+/}},"function":{pattern:/(^|[^^])\B[@^]\w+(?:(?:\.|::?)\w+)*(?:\.|::?)?/,lookbehind:!0,inside:{keyword:{pattern:/(^@)(?:GET_|SET_)/,lookbehind:!0},punctuation:/\.|:+/}},escape:{pattern:/\^(?:[$^;@()\[\]{}"':]|#[a-f\d]*)/i,alias:"builtin"},punctuation:/[\[\](){};]/}),Prism.languages.insertBefore("parser","keyword",{"parser-comment":{pattern:/(\s)#.*/,lookbehind:!0,alias:"comment"},expression:{pattern:/(^|[^^])\((?:[^()]|\((?:[^()]|\((?:[^()])*\))*\))*\)/,lookbehind:!0,inside:{string:{pattern:/(^|[^^])(["'])(?:(?!\2)[^^]|\^[\s\S])*\2/,lookbehind:!0},keyword:Prism.languages.parser.keyword,variable:Prism.languages.parser.variable,"function":Prism.languages.parser.function,"boolean":/\b(?:true|false)\b/,number:/\b(?:0x[a-f\d]+|\d+\.?\d*(?:e[+-]?\d+)?)\b/i,escape:Prism.languages.parser.escape,operator:/[~+*\/\\%]|!(?:\|\|?|=)?|&&?|\|\|?|==|<[<=]?|>[>=]?|-[fd]?|\b(?:def|eq|ge|gt|in|is|le|lt|ne)\b/,punctuation:Prism.languages.parser.punctuation}}}),Prism.languages.insertBefore("inside","punctuation",{expression:Prism.languages.parser.expression,keyword:Prism.languages.parser.keyword,variable:Prism.languages.parser.variable,"function":Prism.languages.parser.function,escape:Prism.languages.parser.escape,"parser-punctuation":{pattern:Prism.languages.parser.punctuation,alias:"punctuation"}},Prism.languages.parser.tag.inside["attr-value"]); \ No newline at end of file diff --git a/examples/prism-parser.html b/examples/prism-parser.html new file mode 100644 index 0000000000..4be737ac59 --- /dev/null +++ b/examples/prism-parser.html @@ -0,0 +1,97 @@ +
To use this language, use the class "language-parser".
+ +$foo[bar] # Some comment
+
+@navigation[]
+$sections[^table::load[sections.cfg]]
+$sections.uri
+
+$foo(3+$bar)
+^switch[$sMode]{
+ ^case[def]{$result(true)}
+}
+^if(in "/news/"){}
+
+^^
+^"
+^;
+
+<nav>
+ <ul>
+ ^sections.menu{
+ <li>
+ <a href="$sections.uri">$sections.name</a>
+ </li>
+ }
+ </ul>
+</nav>
+
+@CLASS
+MyTable
+
+@create[uParam]
+^switch[$uParam.CLASS_NAME]{
+ ^case[string;void]{$t[^table::create{$uParam}]}
+ ^case[table;MyTable]{$t[^table::create[$uParam]]}
+ ^case[DEFAULT]{^throw[MyTable;Unsupported type $uParam.CLASS_NAME]}
+}
+
+# method will return value in different calling contexts
+@GET[sMode]
+^switch[$sMode]{
+ ^case[table]{$result[$t]}
+ ^case[bool]{$result($t!=0)}
+ ^case[def]{$result(true)}
+ ^case[expression;double]{$result($t)}
+ ^case[DEFAULT]{^throw[MyTable;Unsupported mode '$sMode']}
+}
+
+
+# method will handle access to the "columns"
+@GET_DEFAULT[sName]
+$result[$t.$sName]
+
+
+# wrappers for all existing methods are required
+@count[]
+^t.count[]
+
+@menu[jCode;sSeparator]
+^t.menu{$jCode}[$sSeparator]
+
+
+# new functionality
+@remove[iOffset;iLimit]
+$iLimit(^iLimit.int(0))
+$t[^t.select(^t.offset[]<$iOffset || ^t.offset[]>=$iOffset+$iLimit)]
+
+There are certain edge cases where Prism will fail. + There are always such cases in every regex-based syntax highlighter. + However, Prism dares to be open and honest about them. + If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug. +
+ +("fo #o")
+
+("fo<div>o")
+
+# Doesn't work
+# Does work
+ # Does work when prefixed with a space
+
+^if(
+ $age>=4 # not too young
+ && $age<=80 # and not too old
+)
\ No newline at end of file
diff --git a/plugins/autoloader/prism-autoloader.js b/plugins/autoloader/prism-autoloader.js
index 7698bce5c1..85c02d7fec 100644
--- a/plugins/autoloader/prism-autoloader.js
+++ b/plugins/autoloader/prism-autoloader.js
@@ -4,7 +4,7 @@
}
// The dependencies map is built automatically with gulp
- var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","jade":"javascript","java":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/;
+ var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","jade":"javascript","java":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","parser":"markup","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/;
var lang_data = {};
diff --git a/plugins/autoloader/prism-autoloader.min.js b/plugins/autoloader/prism-autoloader.min.js
index 734e27f9dd..59a1a57a25 100644
--- a/plugins/autoloader/prism-autoloader.min.js
+++ b/plugins/autoloader/prism-autoloader.min.js
@@ -1 +1 @@
-!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",jade:"javascript",java:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},n=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},r=function(e,a){var s=c[e];s||(s=c[e]={});var n=a.getAttribute("data-dependencies");!n&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(n=a.parentNode.getAttribute("data-dependencies")),n=n?n.split(/\s*,\s*/g):[],i(n,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,n=e.length,r=function(){n>s?t(e[s],function(){s++,r()},function(){a&&a(e[s])}):s===n&&c&&c(e)};r()},t=function(a,r,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),r&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(r)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=n(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&r(e.language,e.element)})}}();
\ No newline at end of file
+!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",jade:"javascript",java:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",parser:"markup",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},r=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},n=function(e,a){var s=c[e];s||(s=c[e]={});var r=a.getAttribute("data-dependencies");!r&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(r=a.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],i(r,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,r=e.length,n=function(){r>s?t(e[s],function(){s++,n()},function(){a&&a(e[s])}):s===r&&c&&c(e)};n()},t=function(a,n,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),n&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(n)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=r(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&n(e.language,e.element)})}}();
\ No newline at end of file
diff --git a/prism.js b/prism.js
index 71642871dc..dc6c4eb72b 100644
--- a/prism.js
+++ b/prism.js
@@ -449,7 +449,7 @@ Prism.languages.markup = {
'doctype': //,
'cdata': //i,
'tag': {
- pattern: /<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,
+ pattern: /<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,
inside: {
'tag': {
pattern: /^<\/?[^\s>\/]+/i,
diff --git a/tests/languages/parser/boolean_feature.test b/tests/languages/parser/boolean_feature.test
new file mode 100644
index 0000000000..d3b42df8ac
--- /dev/null
+++ b/tests/languages/parser/boolean_feature.test
@@ -0,0 +1,21 @@
+(true)
+(false)
+
+----------------------------------------------------
+
+[
+ ["expression", [
+ ["punctuation", "("],
+ ["boolean", "true"],
+ ["punctuation", ")"]
+ ]],
+ ["expression", [
+ ["punctuation", "("],
+ ["boolean", "false"],
+ ["punctuation", ")"]
+ ]]
+]
+
+----------------------------------------------------
+
+Checks for booleans inside expressions.
\ No newline at end of file
diff --git a/tests/languages/parser/escape_feature.test b/tests/languages/parser/escape_feature.test
new file mode 100644
index 0000000000..69bef55608
--- /dev/null
+++ b/tests/languages/parser/escape_feature.test
@@ -0,0 +1,68 @@
+^$
+^^
+^;
+^@
+^(
+^)
+^[
+^]
+^{
+^}
+^"
+^'
+^:
+^#
+^#20
+^#af
+^#AF
+
+^^date::now
+^$foobar
+
+