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 @@ +

Parser

+

To use this language, use the class "language-parser".

+ +

Comments

+
$foo[bar] # Some comment
+ +

Variables and functions

+
@navigation[]
+$sections[^table::load[sections.cfg]]
+$sections.uri
+ +

Literals

+
$foo(3+$bar)
+^switch[$sMode]{
+	^case[def]{$result(true)}
+}
+^if(in "/news/"){}
+ +

Escape sequences

+
^^
+^"
+^;
+ +

Embedded in markup

+
<nav>
+	<ul>
+	^sections.menu{
+		<li>
+			<a href="$sections.uri">$sections.name</a>
+		</li>
+	}
+	</ul>
+</nav>
+ +

Full example

+
@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)]
+ +

Known failures

+

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. +

+ +

Comment-like substrings

+
("fo #o")
+ +

Tag-like substrings

+
("fo<div>o")
+ +

Code block starting with a comment

+
# Doesn't work
+# Does work
+
 # Does work when prefixed with a space
+ +

Comments inside expressions break literals and operators

+
^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 + +
+ +---------------------------------------------------- + +[ + ["escape", "^$"], + ["escape", "^^"], + ["escape", "^;"], + ["escape", "^@"], + ["escape", "^("], + ["escape", "^)"], + ["escape", "^["], + ["escape", "^]"], + ["escape", "^{"], + ["escape", "^}"], + ["escape", "^\""], + ["escape", "^'"], + ["escape", "^:"], + ["escape", "^#"], + ["escape", "^#20"], + ["escape", "^#af"], + ["escape", "^#AF"], + + ["escape", "^^"], "date::now\r\n", + ["escape", "^$"], "foobar\r\n\r\n", + + ["tag", [ + ["tag", [ + ["punctuation", "<"], + "div" + ]], + ["attr-name", ["class"]], + ["attr-value", [ + ["punctuation", "="], + ["punctuation", "\""], + "foo", + ["escape", "^^"], + "bar", + ["punctuation", "\""] + ]], + ["punctuation", ">"] + ]] +] + +---------------------------------------------------- + +Checks for escapes. \ No newline at end of file diff --git a/tests/languages/parser/expression_feature.test b/tests/languages/parser/expression_feature.test new file mode 100644 index 0000000000..e9a229fe5e --- /dev/null +++ b/tests/languages/parser/expression_feature.test @@ -0,0 +1,58 @@ +((3-(9-2))*4) +^eval(4+2) + +
+ +---------------------------------------------------- + +[ + ["expression", [ + ["punctuation", "("], + ["punctuation", "("], + ["number", "3"], + ["operator", "-"], + ["punctuation", "("], + ["number", "9"], + ["operator", "-"], + ["number", "2"], + ["punctuation", ")"], + ["punctuation", ")"], + ["operator", "*"], + ["number", "4"], + ["punctuation", ")"] + ]], + ["keyword", "^eval"], + + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "+"], + ["number", "2"], + ["punctuation", ")"] + ]], + + ["tag", [ + ["tag", [ + ["punctuation", "<"], + "div" + ]], + ["attr-name", ["class"]], + ["attr-value", [ + ["punctuation", "="], + ["punctuation", "\""], + "foo-", + ["keyword", "^eval"], + ["expression", [ + ["punctuation", "("], + ["number", "4"], ["operator", "+"], ["number", "2"], + ["punctuation", ")"] + ]], + ["punctuation", "\""] + ]], + ["punctuation", ">"] + ]] +] + +---------------------------------------------------- + +Checks for expressions, up to 3 levels of depth. \ No newline at end of file diff --git a/tests/languages/parser/function_feature.test b/tests/languages/parser/function_feature.test new file mode 100644 index 0000000000..9cf470bc7e --- /dev/null +++ b/tests/languages/parser/function_feature.test @@ -0,0 +1,48 @@ +@foo[] +@GET_foo[] +@SET_foo[] +^foo[] +^Foo::create[] +^date::now[] +^foo_bar.menu{} + +(^foo[]) + +
+ +---------------------------------------------------- + +[ + ["function", ["@foo"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["@", ["keyword", "GET_"], "foo"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["@", ["keyword", "SET_"], "foo"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["^foo"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["^Foo", ["punctuation", "::"], "create"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["^date", ["punctuation", "::"], "now"]], ["punctuation", "["], ["punctuation", "]"], + ["function", ["^foo_bar", ["punctuation", "."], "menu"]], ["punctuation", "{"], ["punctuation", "}"], + + ["expression", [ + ["punctuation", "("], + ["function", ["^foo"]], ["punctuation", "["], ["punctuation", "]"], + ["punctuation", ")"] + ]], + + ["tag", [ + ["tag", [ + ["punctuation", "<"], + "div" + ]], + ["attr-name", ["class"]], + ["attr-value", [ + ["punctuation", "="], + ["punctuation", "\""], + ["function", ["^foo"]], ["parser-punctuation", "["], ["parser-punctuation", "]"], + ["punctuation", "\""] + ]], + ["punctuation", ">"] + ]] +] + +---------------------------------------------------- + +Checks for functions and methods. \ No newline at end of file diff --git a/tests/languages/parser/keyword_feature.test b/tests/languages/parser/keyword_feature.test new file mode 100644 index 0000000000..ae1e9def9c --- /dev/null +++ b/tests/languages/parser/keyword_feature.test @@ -0,0 +1,70 @@ +^case +^eval +^for +^if +^switch +^throw + +@BASE +@CLASS +@GET +@GET_DEFAULT +@OPTIONS +@SET_DEFAULT +@USE + +(^eval(2+2)) + +
+ +---------------------------------------------------- + +[ + ["keyword", "^case"], + ["keyword", "^eval"], + ["keyword", "^for"], + ["keyword", "^if"], + ["keyword", "^switch"], + ["keyword", "^throw"], + + ["keyword", "@BASE"], + ["keyword", "@CLASS"], + ["keyword", "@GET"], + ["keyword", "@GET_DEFAULT"], + ["keyword", "@OPTIONS"], + ["keyword", "@SET_DEFAULT"], + ["keyword", "@USE"], + + ["expression", [ + ["punctuation", "("], + ["keyword", "^eval"], + ["punctuation", "("], + ["number", "2"], ["operator", "+"], ["number", "2"], + ["punctuation", ")"], + ["punctuation", ")"] + ]], + + ["tag", [ + ["tag", [ + ["punctuation", "<"], + "div" + ]], + ["attr-name", ["class"]], + ["attr-value", [ + ["punctuation", "="], + ["punctuation", "\""], + ["keyword", "^if"], + ["expression", [ + ["punctuation", "("], ["variable", ["$foo"]], ["punctuation", ")"] + ]], + ["parser-punctuation", "{"], "bar", ["parser-punctuation", "}"], + ["parser-punctuation", "{"], "baz", ["parser-punctuation", "}"], + ["punctuation", "\""] + ]], + ["punctuation", ">"] + ]] +] + +---------------------------------------------------- + +Checks for keywords. \ No newline at end of file diff --git a/tests/languages/parser/number_feature.test b/tests/languages/parser/number_feature.test new file mode 100644 index 0000000000..7bb3cccf71 --- /dev/null +++ b/tests/languages/parser/number_feature.test @@ -0,0 +1,51 @@ +(42) +(3.14159) +(3e5) +(0.8E-12) +(3.9e+2) +(0xbadface) +(0XBADFACE) + +---------------------------------------------------- + +[ + ["expression", [ + ["punctuation", "("], + ["number", "42"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "3.14159"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "3e5"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "0.8E-12"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "3.9e+2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "0xbadface"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "0XBADFACE"], + ["punctuation", ")"] + ]] +] + +---------------------------------------------------- + +Checks for numbers inside expressions. \ No newline at end of file diff --git a/tests/languages/parser/operator_feature.test b/tests/languages/parser/operator_feature.test new file mode 100644 index 0000000000..9245edbd92 --- /dev/null +++ b/tests/languages/parser/operator_feature.test @@ -0,0 +1,257 @@ +(~42) +(+42) +(-42) +(4/2) +(9\2) +(9%2) +(!true) +(4!|2) +(true!||false) +(4!=2) +(4&2) +(true&&false) +(4|2) +(true||false) +(4==2) +(4<2) +(4<=2) +(4<<2) +(4>2) +(4>=2) +(4>>2) +(-f "foo") +(-d "foo") +(def $foo) +(4 eq 2) +(4 ge 2) +(4 gt 2) +(in "foo") +($foo is string) +(4 le 2) +(4 lt 2) +(4 ne 2) + +---------------------------------------------------- + +[ + ["expression", [ + ["punctuation", "("], + ["operator", "~"], + ["number", "42"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "+"], + ["number", "42"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "-"], + ["number", "42"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "/"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "9"], + ["operator", "\\"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "9"], + ["operator", "%"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "!"], + ["boolean", "true"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "!|"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["boolean", "true"], + ["operator", "!||"], + ["boolean", "false"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "!="], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "&"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["boolean", "true"], + ["operator", "&&"], + ["boolean", "false"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "|"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["boolean", "true"], + ["operator", "||"], + ["boolean", "false"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "=="], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "<"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "<="], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "<<"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", ">"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", ">="], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", ">>"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "-f"], + ["string", "\"foo\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "-d"], + ["string", "\"foo\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "def"], + ["variable", ["$foo"]], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "eq"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "ge"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "gt"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["operator", "in"], + ["string", "\"foo\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["variable", ["$foo"]], + ["operator", "is"], + " string", + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "le"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "lt"], + ["number", "2"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["number", "4"], + ["operator", "ne"], + ["number", "2"], + ["punctuation", ")"] + ]] +] + +---------------------------------------------------- + +Checks for operators inside expressions. \ No newline at end of file diff --git a/tests/languages/parser/parser-comment_feature.test b/tests/languages/parser/parser-comment_feature.test new file mode 100644 index 0000000000..94e772cc73 --- /dev/null +++ b/tests/languages/parser/parser-comment_feature.test @@ -0,0 +1,17 @@ +Foo +# +# Foobar + +---------------------------------------------------- + +[ + "Foo\r\n", + ["parser-comment", "#"], + ["parser-comment", "# Foobar"] +] + +---------------------------------------------------- + +Checks for comments. +The first line of this test is needed, since we require a whitespace before the hash +and tests are trimmed. \ No newline at end of file diff --git a/tests/languages/parser/string_feature.test b/tests/languages/parser/string_feature.test new file mode 100644 index 0000000000..2d32ab55c3 --- /dev/null +++ b/tests/languages/parser/string_feature.test @@ -0,0 +1,47 @@ +("") +("foo^"bar") +("foo +bar") +('') +('foo^'bar') +('foo +bar') + +---------------------------------------------------- + +[ + ["expression", [ + ["punctuation", "("], + ["string", "\"\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["string", "\"foo^\"bar\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["string", "\"foo\r\nbar\""], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["string", "''"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["string", "'foo^'bar'"], + ["punctuation", ")"] + ]], + ["expression", [ + ["punctuation", "("], + ["string", "'foo\r\nbar'"], + ["punctuation", ")"] + ]] +] + +---------------------------------------------------- + +Checks for strings inside expressions. \ No newline at end of file diff --git a/tests/languages/parser/variable_feature.test b/tests/languages/parser/variable_feature.test new file mode 100644 index 0000000000..e2544fdb7f --- /dev/null +++ b/tests/languages/parser/variable_feature.test @@ -0,0 +1,55 @@ +$foo +$foo[bar] +$foo_bar[ + $.baz[foo] + $.1[bar] +] +$foo.$bar +$foo.[$bar.baz] +$math:PI + +($foo) + +
+ +---------------------------------------------------- + +[ + ["variable", ["$foo"]], + ["variable", ["$foo"]], ["punctuation", "["], "bar", ["punctuation", "]"], + ["variable", ["$foo_bar"]], ["punctuation", "["], + ["variable", ["$", ["punctuation", "."], "baz"]], + ["punctuation", "["], "foo", ["punctuation", "]"], + ["variable", ["$", ["punctuation", "."], "1"]], + ["punctuation", "["], "bar", ["punctuation", "]"], + ["punctuation", "]"], + ["variable", ["$foo", ["punctuation", "."]]], ["variable", ["$bar"]], + ["variable", ["$foo", ["punctuation", "."]]], ["punctuation", "["], + ["variable", ["$bar", ["punctuation", "."], "baz"]], ["punctuation", "]"], + ["variable", ["$math", ["punctuation", ":"], "PI"]], + + ["expression", [ + ["punctuation", "("], + ["variable", ["$foo"]], + ["punctuation", ")"] + ]], + + ["tag", [ + ["tag", [ + ["punctuation", "<"], + "div" + ]], + ["attr-name", ["class"]], + ["attr-value", [ + ["punctuation", "="], + ["punctuation", "\""], + ["variable", ["$foo"]], + ["punctuation", "\""] + ]], + ["punctuation", ">"] + ]] +] + +---------------------------------------------------- + +Checks for variables. \ No newline at end of file