Commit 07020c7a3dd1b5494f375e9408ccf29175361bf3

cedporter 2019-10-07T08:39:40

SAS: Minor improvements (#2085) * Reorder comment array to fix edge case added to comment_feature.test * Adjust datalines to allow for possible preceding spaces before the closing semicolon * Move comment in SAS object for correct syntax matching precedence * Add several more keywords

diff --git a/components/prism-sas.js b/components/prism-sas.js
index 27b2855..e84757e 100644
--- a/components/prism-sas.js
+++ b/components/prism-sas.js
@@ -15,11 +15,11 @@
 	};
 
 	var comment = [
+		/\/\*[\s\S]*?\*\//,
 		{
 			pattern: /(^\s*|;\s*)\*[^;]*;/m,
 			lookbehind: true
-		},
-		/\/\*[\s\S]+?\*\//
+		}
 	];
 
 	var string = {
@@ -53,7 +53,7 @@
 
 	Prism.languages.sas = {
 		'datalines': {
-			pattern: /^(\s*)(?:(?:data)?lines|cards);[\s\S]+?^;/im,
+			pattern: /^(\s*)(?:(?:data)?lines|cards);[\s\S]+?^\s*;/im,
 			lookbehind: true,
 			alias: 'string',
 			inside: {
@@ -127,7 +127,6 @@
 				'numeric-constant': numericConstant
 			}
 		},
-		'comment': comment,
 		'options-args': {
 			pattern: /(^options)[-'"|/\\<>*+=:()\w\s]*(?=;)/im,
 			lookbehind: true,
@@ -159,6 +158,7 @@
 			}
 		},
 		'numeric-constant': numericConstant,
+		'comment': comment,
 		'datetime': {
 			// '1jan2013'd, '9:25:19pm't, '18jan2003:9:27:05am'dt
 			pattern: RegExp(stringPattern + '(?:dt?|t)'),
@@ -167,7 +167,7 @@
 		'string': string,
 		'step': step,
 		'keyword': {
-			pattern: /((?:^|\s)=?)(?:action|after|analysis|and|array|barchart|barwidth|begingraph|by|cas|cbarline|cfill|close|column|computed?|contains|data(?=\=)|define|document|do\s+over|do|dol|drop|dul|end|entryTitle|else|endcomp|fill(?:attrs)?|filename|group(?:by)?|headline|headskip|histogram|if|infile|keep|label|layout|legendlabel|length|libname|merge|midpoints|name|noobs|nowd|ods|options|or|out(?:put)?|overlay|plot|ranexp|rannor|rbreak|retain|set|session|sessref|statgraph|sum|summarize|table|temp|then\sdo|then|title\d?|to|var|where|xaxisopts|yaxisopts|y2axisopts)\b/i,
+			pattern: /((?:^|\s)=?)(?:action|after|analysis|and|array|barchart|barwidth|begingraph|by|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|data(?=\=)|define|document|do\s+over|do|dol|drop|dul|end|entryTitle|else|endcomp|fill(?:attrs)?|filename|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|legendlabel|length|libname|merge|midpoints|name|noobs|nowd|ods|options|or|out(?:put)?|overlay|plot|ranexp|rannor|rbreak|retain|set|session|sessref|statgraph|sum|summarize|table|temp|then\s+do|then|title\d?|to|var|where|xaxisopts|yaxisopts|y2axisopts)\b/i,
 			lookbehind: true,
 		},
 		// In SAS Studio syntax highlighting, these operators are styled like keywords
diff --git a/components/prism-sas.min.js b/components/prism-sas.min.js
index b354cee..b220789 100644
--- a/components/prism-sas.min.js
+++ b/components/prism-sas.min.js
@@ -1 +1 @@
-!function(e){var t="(?:\"(?:\"\"|[^\"])*\"(?!\")|'(?:''|[^'])*'(?!'))",a=/\b(?:\d[\da-f]*x|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,n={pattern:RegExp(t+"[bx]"),alias:"number"},i=[{pattern:/(^\s*|;\s*)\*[^;]*;/m,lookbehind:!0},/\/\*[\s\S]+?\*\//],r={pattern:RegExp(t),greedy:!0},s=/[$%@.(){}\[\];,\\]/,o={"arg-value":{pattern:/(=)[A-Z]+/i,lookbehind:!0},operator:/=/,arg:{pattern:/[A-Z]+/i,alias:"keyword"},number:a,"numeric-constant":n,punctuation:s,string:r};e.languages.sas={datalines:{pattern:/^(\s*)(?:(?:data)?lines|cards);[\s\S]+?^;/im,lookbehind:!0,alias:"string",inside:{keyword:{pattern:/^(?:(?:data)?lines|cards)/i},punctuation:/;/}},"proc-sql":{pattern:/(^proc\s+(?:fed)?sql(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{sql:{pattern:RegExp("^[ \t]*(?:select|alter\\s+table|(?:create|describe|drop)\\s+(?:index|table(?:\\s+constraints)?|view)|create\\s+unique\\s+index|insert\\s+into|update)(?:<str>|[^;\"'])+;".replace(/<str>/g,t),"im"),alias:"language-sql",inside:e.languages.sql},"global-statements":{pattern:/((?:^|[\s])=?)(?:catname|checkpoint execute_always|dm|endsas|filename|footnote|%include|libname|%list|lock|missing|options|page|resetline|%run|sasfile|skip|sysecho|title\d?)\b/i,lookbehind:!0,alias:"keyword"},"sql-statements":{pattern:/(^|\s)(?:disconnect\s+from|exec(?:ute)?|begin|commit|rollback|reset|validate)\b/i,lookbehind:!0,alias:"keyword"},number:a,"numeric-constant":n,punctuation:s,string:r}},"proc-args":{pattern:RegExp("(^proc\\s+\\w+\\s+)(?!\\s)(?:[^;\"']|<str>)+;".replace(/<str>/g,t),"im"),lookbehind:!0,inside:o},"macro-keyword":{pattern:/((?:^|\s)=?)%(?:ABORT|BQUOTE|BY|CMS|COPY|DISPLAY|DO|ELSE|END|EVAL|GLOBAL|GO|GOTO|IF|INC|INCLUDE|INDEX|INPUT|KTRIM|LENGTH|LET|LIST|LOCAL|NRBQUOTE|NRQUOTE|NRSTR|PUT|QKTRIM|QSCAN|QSUBSTR|QSYSFUNC|QUOTE|QUPCASE|RETURN|RUN|SCAN|STR|SUBSTR|SUPERQ|SYMDEL|SYMGLOBL|SYMLOCAL|SYMEXIST|SYSCALL|SYSEVALF|SYSEXEC|SYSFUNC|SYSGET|SYSRPUT|THEN|TO|TSO|UNQUOTE|UNTIL|UPCASE|WHILE|WINDOW)\b/i,lookbehind:!0,alias:"keyword"},"macro-declaration":{pattern:/^%macro[^;]+(?=;)/im,inside:{keyword:/%macro/i}},"macro-end":{pattern:/^%mend[^;]+(?=;)/im,inside:{keyword:/%mend/i}},macro:{pattern:/%_\w+(?=\()/,alias:"keyword"},input:{pattern:/\binput\s+[-\w\s/*.$&]+;/i,inside:{input:{alias:"keyword",pattern:/^input/i},comment:i,number:a,"numeric-constant":n}},comment:i,"options-args":{pattern:/(^options)[-'"|/\\<>*+=:()\w\s]*(?=;)/im,lookbehind:!0,inside:o},function:{pattern:/%?\w+(?=\()/,alias:"keyword"},format:{pattern:/\b(?:format|put)\b=?[\w'$.]+/im,inside:{keyword:/^(?:format|put)(?=\=)/i,equals:/=/,format:{pattern:/(?:\w|\$\d)+\.\d?/i,alias:"number"}}},altformat:{pattern:/\b(?:format|put)\s+[\w']+(?:\s+[$.\w]+)+(?=;)/i,inside:{keyword:/^(?:format|put)/i,format:{pattern:/[\w$]+\.\d?/,alias:"number"}}},"numeric-constant":n,datetime:{pattern:RegExp(t+"(?:dt?|t)"),alias:"number"},string:r,step:{pattern:/(^|\s+)(?:proc\s+\w+|quit|run|data(?!\=))\b/i,alias:"keyword",lookbehind:!0},keyword:{pattern:/((?:^|\s)=?)(?:action|after|analysis|and|array|barchart|barwidth|begingraph|by|cas|cbarline|cfill|close|column|computed?|contains|data(?=\=)|define|document|do\s+over|do|dol|drop|dul|end|entryTitle|else|endcomp|fill(?:attrs)?|filename|group(?:by)?|headline|headskip|histogram|if|infile|keep|label|layout|legendlabel|length|libname|merge|midpoints|name|noobs|nowd|ods|options|or|out(?:put)?|overlay|plot|ranexp|rannor|rbreak|retain|set|session|sessref|statgraph|sum|summarize|table|temp|then\sdo|then|title\d?|to|var|where|xaxisopts|yaxisopts|y2axisopts)\b/i,lookbehind:!0},"operator-keyword":{pattern:/\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,alias:"operator"},number:a,operator:/\*\*?|\|\|?|!!?|¦¦?|<[>=]?|>[<=]?|[-+\/=&]|[~¬^]=?/i,punctuation:s}}(Prism);
\ No newline at end of file
+!function(e){var t="(?:\"(?:\"\"|[^\"])*\"(?!\")|'(?:''|[^'])*'(?!'))",a=/\b(?:\d[\da-f]*x|\d+(?:\.\d+)?(?:e[+-]?\d+)?)\b/i,n={pattern:RegExp(t+"[bx]"),alias:"number"},i=[/\/\*[\s\S]*?\*\//,{pattern:/(^\s*|;\s*)\*[^;]*;/m,lookbehind:!0}],s={pattern:RegExp(t),greedy:!0},r=/[$%@.(){}\[\];,\\]/,o={"arg-value":{pattern:/(=)[A-Z]+/i,lookbehind:!0},operator:/=/,arg:{pattern:/[A-Z]+/i,alias:"keyword"},number:a,"numeric-constant":n,punctuation:r,string:s};e.languages.sas={datalines:{pattern:/^(\s*)(?:(?:data)?lines|cards);[\s\S]+?^\s*;/im,lookbehind:!0,alias:"string",inside:{keyword:{pattern:/^(?:(?:data)?lines|cards)/i},punctuation:/;/}},"proc-sql":{pattern:/(^proc\s+(?:fed)?sql(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{sql:{pattern:RegExp("^[ \t]*(?:select|alter\\s+table|(?:create|describe|drop)\\s+(?:index|table(?:\\s+constraints)?|view)|create\\s+unique\\s+index|insert\\s+into|update)(?:<str>|[^;\"'])+;".replace(/<str>/g,t),"im"),alias:"language-sql",inside:e.languages.sql},"global-statements":{pattern:/((?:^|[\s])=?)(?:catname|checkpoint execute_always|dm|endsas|filename|footnote|%include|libname|%list|lock|missing|options|page|resetline|%run|sasfile|skip|sysecho|title\d?)\b/i,lookbehind:!0,alias:"keyword"},"sql-statements":{pattern:/(^|\s)(?:disconnect\s+from|exec(?:ute)?|begin|commit|rollback|reset|validate)\b/i,lookbehind:!0,alias:"keyword"},number:a,"numeric-constant":n,punctuation:r,string:s}},"proc-args":{pattern:RegExp("(^proc\\s+\\w+\\s+)(?!\\s)(?:[^;\"']|<str>)+;".replace(/<str>/g,t),"im"),lookbehind:!0,inside:o},"macro-keyword":{pattern:/((?:^|\s)=?)%(?:ABORT|BQUOTE|BY|CMS|COPY|DISPLAY|DO|ELSE|END|EVAL|GLOBAL|GO|GOTO|IF|INC|INCLUDE|INDEX|INPUT|KTRIM|LENGTH|LET|LIST|LOCAL|NRBQUOTE|NRQUOTE|NRSTR|PUT|QKTRIM|QSCAN|QSUBSTR|QSYSFUNC|QUOTE|QUPCASE|RETURN|RUN|SCAN|STR|SUBSTR|SUPERQ|SYMDEL|SYMGLOBL|SYMLOCAL|SYMEXIST|SYSCALL|SYSEVALF|SYSEXEC|SYSFUNC|SYSGET|SYSRPUT|THEN|TO|TSO|UNQUOTE|UNTIL|UPCASE|WHILE|WINDOW)\b/i,lookbehind:!0,alias:"keyword"},"macro-declaration":{pattern:/^%macro[^;]+(?=;)/im,inside:{keyword:/%macro/i}},"macro-end":{pattern:/^%mend[^;]+(?=;)/im,inside:{keyword:/%mend/i}},macro:{pattern:/%_\w+(?=\()/,alias:"keyword"},input:{pattern:/\binput\s+[-\w\s/*.$&]+;/i,inside:{input:{alias:"keyword",pattern:/^input/i},comment:i,number:a,"numeric-constant":n}},"options-args":{pattern:/(^options)[-'"|/\\<>*+=:()\w\s]*(?=;)/im,lookbehind:!0,inside:o},function:{pattern:/%?\w+(?=\()/,alias:"keyword"},format:{pattern:/\b(?:format|put)\b=?[\w'$.]+/im,inside:{keyword:/^(?:format|put)(?=\=)/i,equals:/=/,format:{pattern:/(?:\w|\$\d)+\.\d?/i,alias:"number"}}},altformat:{pattern:/\b(?:format|put)\s+[\w']+(?:\s+[$.\w]+)+(?=;)/i,inside:{keyword:/^(?:format|put)/i,format:{pattern:/[\w$]+\.\d?/,alias:"number"}}},"numeric-constant":n,comment:i,datetime:{pattern:RegExp(t+"(?:dt?|t)"),alias:"number"},string:s,step:{pattern:/(^|\s+)(?:proc\s+\w+|quit|run|data(?!\=))\b/i,alias:"keyword",lookbehind:!0},keyword:{pattern:/((?:^|\s)=?)(?:action|after|analysis|and|array|barchart|barwidth|begingraph|by|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|data(?=\=)|define|document|do\s+over|do|dol|drop|dul|end|entryTitle|else|endcomp|fill(?:attrs)?|filename|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|legendlabel|length|libname|merge|midpoints|name|noobs|nowd|ods|options|or|out(?:put)?|overlay|plot|ranexp|rannor|rbreak|retain|set|session|sessref|statgraph|sum|summarize|table|temp|then\s+do|then|title\d?|to|var|where|xaxisopts|yaxisopts|y2axisopts)\b/i,lookbehind:!0},"operator-keyword":{pattern:/\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,alias:"operator"},number:a,operator:/\*\*?|\|\|?|!!?|¦¦?|<[>=]?|>[<=]?|[-+\/=&]|[~¬^]=?/i,punctuation:r}}(Prism);
\ No newline at end of file
diff --git a/tests/languages/sas/comment_feature.test b/tests/languages/sas/comment_feature.test
index dea1e0a..166bf1e 100644
--- a/tests/languages/sas/comment_feature.test
+++ b/tests/languages/sas/comment_feature.test
@@ -3,15 +3,18 @@ foo; * foobar;
 /* foo
 bar */
 
+/*options cashost="cloud.example.com" casport=5570;*/
+
 ----------------------------------------------------
 
 [
 	["comment", "* foobar;"],
 	"\r\nfoo", ["punctuation", ";"],
 	["comment", "* foobar;"],
-	["comment", "/* foo\r\nbar */"]
+	["comment", "/* foo\r\nbar */"],
+	["comment", "/*options cashost=\"cloud.example.com\" casport=5570;*/"]
 ]
 
 ----------------------------------------------------
 
-Checks for comments.
\ No newline at end of file
+Checks for comments.
diff --git a/tests/languages/sas/keyword_feature.test b/tests/languages/sas/keyword_feature.test
index f4bbfa3..c56ee84 100644
--- a/tests/languages/sas/keyword_feature.test
+++ b/tests/languages/sas/keyword_feature.test
@@ -1,11 +1,11 @@
 action after analysis and array barchart barwidth begingraph by
-cas cbarline cfill close column compute computed contains data= define
+cas cbarline cfill class classlev close column compute computed contains data= define
 document do do over dol drop dul end entryTitle else endcomp fill fillattrs
-filename group groupby headline headskip histogram if infile keep label layout
-legendlabel length libname merge midpoints name noobs nowd ods or out output
-overlay plot ranexp rannor rbreak retain set session sessref statgraph
-sum summarize table temp then then do title to var where xaxisopts yaxisopts
-y2axisopts
+filename group groupby headline headskip histogram if infile keep keylabel
+keyword label layout legendlabel length libname merge midpoints name noobs nowd
+ods or out output overlay plot ranexp rannor rbreak retain set session sessref
+statgraph sum summarize table temp then then do title to var where xaxisopts
+yaxisopts y2axisopts
 
 ----------------------------------------------------
 
@@ -14,6 +14,7 @@ y2axisopts
 	["keyword", "and"], ["keyword", "array"], ["keyword", "barchart"],
 	["keyword", "barwidth"], ["keyword", "begingraph"], ["keyword", "by"],
 	["keyword", "cas"], ["keyword", "cbarline"], ["keyword", "cfill"],
+	["keyword", "class"], ["keyword", "classlev"],
 	["keyword", "close"], ["keyword", "column"], ["keyword", "compute"],
 	["keyword", "computed"], ["keyword", "contains"], ["keyword", "data"],
 	["operator", "="], ["keyword", "define"],	["keyword", "document"], ["keyword", "do"],
@@ -22,7 +23,8 @@ y2axisopts
 	["keyword", "endcomp"], ["keyword", "fill"], ["keyword", "fillattrs"],
 	["keyword", "filename"], ["keyword", "group"], ["keyword", "groupby"],
 	["keyword", "headline"], ["keyword", "headskip"], ["keyword", "histogram"],
-	["keyword", "if"],	["keyword", "infile"], ["keyword", "keep"], ["keyword", "label"],
+	["keyword", "if"],	["keyword", "infile"], ["keyword", "keep"],
+	["keyword", "keylabel"], ["keyword", "keyword"], ["keyword", "label"],
 	["keyword", "layout"], ["keyword", "legendlabel"], ["keyword", "length"],
 	["keyword", "libname"], ["keyword", "merge"], ["keyword", "midpoints"],
 	["keyword", "name"], ["keyword", "noobs"], ["keyword", "nowd"], ["keyword", "ods"],