SAS: Added CASL support (#2112) This adds CASL support, a scripting language used within PROC CAS in SAS. https://go.documentation.sas.com/?cdcId=pgmsascdc&cdcVersion=9.4_3.4&docsetId=pgmdiff&docsetTarget=p06ibhzb2bklaon1a86ili3wpil9.htm&locale=en
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
diff --git a/components/prism-sas.js b/components/prism-sas.js
index a3a4844..80ae9ed 100644
--- a/components/prism-sas.js
+++ b/components/prism-sas.js
@@ -29,12 +29,22 @@
var punctuation = /[$%@.(){}\[\];,\\]/;
+ var func = {
+ pattern: /%?\w+(?=\()/,
+ alias: 'keyword'
+ };
+
var args = {
+ 'function' : func,
'arg-value': {
- pattern: /(=)[A-Z]+/i,
+ pattern: /(\s*=\s*)[A-Z\.]+/i,
lookbehind: true
},
'operator': /=/,
+ 'macro-variable': {
+ pattern: /&[^\.]*\./i,
+ alias: 'string'
+ },
'arg': {
pattern: /[A-Z]+/i,
alias: 'keyword'
@@ -45,6 +55,29 @@
'string': string
};
+ var format = {
+ pattern: /\b(?:format|put)\b=?[\w'$.]+/im,
+ inside: {
+ 'keyword': /^(?:format|put)(?=\=)/i,
+ 'equals': /=/,
+ 'format': {
+ pattern: /(?:\w|\$\d)+\.\d?/i,
+ alias: 'number'
+ }
+ }
+ };
+
+ var altformat = {
+ pattern: /\b(?:format|put)\s+[\w']+(?:\s+[$.\w]+)+(?=;)/i,
+ inside: {
+ 'keyword': /^(?:format|put)/i,
+ 'format': {
+ pattern: /[\w$]+\.\d?/,
+ alias: 'number'
+ }
+ }
+ };
+
var globalStatements = {
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: true,
@@ -57,6 +90,34 @@
alias: 'keyword'
};
+ var actionSets = 'accessControl|cdm|aggregation|aStore|ruleMining|audio|autotune|bayesianNetClassifier|bioMedImage|boolRule|builtins|cardinality|sccasl|clustering|copula|countreg|dataDiscovery|dataPreprocess|dataSciencePilot|dataStep|decisionTree|deepLearn|deepNeural|varReduce|simSystem|ds2|deduplication|ecm|entityRes|espCluster|explainModel|factmac|fastKnn|fcmpact|fedSql|freqTab|gam|gleam|graphSemiSupLearn|gVarCluster|hiddenMarkovModel|hyperGroup|image|iml|ica|kernalPca|langModel|ldaTopic|sparseML|mlTools|mixed|modelPublishing|mbc|network|optNetwork|neuralNet|nonlinear|nmf|nonParametricBayes|optimization|panel|pls|percentile|pca|phreg|qkb|qlim|quantreg|recommend|tsReconcile|deepRnn|regression|reinforcementLearn|robustPca|sampling|sparkEmbeddedProcess|search(?:Analytics)?|sentimentAnalysis|sequence|configuration|session(?:Prop)?|severity|simple|smartData|sandwich|spatialreg|stabilityMonitoring|spc|loadStreams|svDataDescription|svm|table|conditionalRandomFields|text(?:Rule(?:Develop|Score)|Mining|Parse|Topic|Util|Filters|Frequency)|tsInfo|timeData|transpose|uniTimeSeries';
+
+ var casActions = {
+ pattern: RegExp('(^|\\s)(?:action\\s+)?(?:<act>)\\.[a-z]+\\b[^;]+'.replace(/<act>/g, actionSets), 'i'),
+ lookbehind: true,
+ inside: {
+ 'keyword': RegExp('(?:<act>)\\.[a-z]+\\b'.replace(/<act>/g, actionSets), 'i'),
+ 'action': {
+ pattern: /(?:action)/i,
+ alias: 'keyword'
+ },
+ 'function': func,
+ 'arg-value': args['arg-value'],
+ 'operator': args.operator,
+ 'comment': comment,
+ 'argument': args.arg,
+ 'number': number,
+ 'numeric-constant': numericConstant,
+ 'punctuation': punctuation,
+ 'string': string
+ }
+ };
+
+ var keywords = {
+ pattern: /((?:^|\s)=?)(?:after|analysis|and|array|barchart|barwidth|begingraph|by|call|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|continue|data(?=\=)|define|delete|describe|document|do\s+over|do|dol|drop|dul|end(?:source|comp)?|entryTitle|else|eval(?:uate)?|exec(?:ute)?|exit|fill(?:attrs)?|file(?:name)?|flist|fnc|function(?:list)?|goto|global|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|leave|legendlabel|length|libname|loadactionset|merge|midpoints|name|noobs|nowd|_?null_|ods|options|or|otherwise|out(?:put)?|over(?:lay)?|plot|put|print|raise|ranexp|rannor|rbreak|retain|return|select|set|session|sessref|source|statgraph|sum|summarize|table|temp|terminate|then\s+do|then|title\d?|to|var|when|where|xaxisopts|yaxisopts|y2axisopts)\b/i,
+ lookbehind: true,
+ };
+
Prism.languages.sas = {
'datalines': {
pattern: /^(\s*)(?:(?:data)?lines|cards);[\s\S]+?^\s*;/im,
@@ -130,6 +191,43 @@
}
},
+ 'proc-cas': {
+ pattern: /(^proc\s+cas(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|data);|(?![\s\S]))/im,
+ lookbehind: true,
+ inside: {
+ 'statement-var': {
+ pattern: /((?:^|\s)=?)saveresult\s+[^;]+/im,
+ lookbehind: true,
+ inside: {
+ 'statement': {
+ pattern: /^saveresult\s+\S+/i,
+ inside: {
+ keyword: /^(?:saveresult)/i
+ }
+ },
+ rest: args
+ }
+ },
+ 'cas-actions': casActions,
+ 'statement': {
+ pattern: /((?:^|\s)=?)(?:default|(?:un)?set|on|output|upload)[^;]+/im,
+ lookbehind: true,
+ inside: args
+ },
+ 'step': step,
+ 'keyword': keywords,
+ 'function': func,
+ 'comment': comment,
+ 'format': format,
+ 'altformat': altformat,
+ 'global-statements': globalStatements,
+ 'number': number,
+ 'numeric-constant': numericConstant,
+ 'punctuation': punctuation,
+ 'string': string
+ }
+ },
+
'proc-args': {
pattern: RegExp(/(^proc\s+\w+\s+)(?!\s)(?:[^;"']|<str>)+;/.source.replace(/<str>/g, stringPattern), 'im'),
lookbehind: true,
@@ -176,33 +274,12 @@
lookbehind: true,
inside: args
},
- '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': numericConstant,
+ 'cas-actions': casActions,
'comment': comment,
+ 'function': func,
+ 'format': format,
+ 'altformat': altformat,
+ 'numeric-constant': numericConstant,
'datetime': {
// '1jan2013'd, '9:25:19pm't, '18jan2003:9:27:05am'dt
pattern: RegExp(stringPattern + '(?:dt?|t)'),
@@ -210,10 +287,7 @@
},
'string': string,
'step': step,
- '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|eval(?:uate)?|exec(?:ute)?|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,
- },
+ 'keyword': keywords,
// In SAS Studio syntax highlighting, these operators are styled like keywords
'operator-keyword': {
pattern: /\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,
diff --git a/components/prism-sas.min.js b/components/prism-sas.min.js
index 91ee6c0..bab73d6 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"},s=[/\/\*[\s\S]*?\*\//,{pattern:/(^\s*|;\s*)\*[^;]*;/m,lookbehind:!0}],i={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:i},l={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"},d={pattern:/(^|\s)(?:submit(?:\s+(?:load|parseonly|norun))?|endsubmit)\b/i,lookbehind:!0,alias:"keyword"};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":l,"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:i}},"proc-groovy":{pattern:/(^proc\s+groovy(?:\s+[\w|=]+)?;)(?:\s*submit)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{groovy:{pattern:RegExp("(^[ \t]*submit(?:\\s+(?:load|parseonly|norun))?)(?:<str>|[^\"'])+?(?=endsubmit;)".replace(/<str>/g,t),"im"),lookbehind:!0,alias:"language-groovy",inside:e.languages.groovy},"submit-statement":d,"global-statements":l,number:a,"numeric-constant":n,punctuation:r,string:i}},"proc-lua":{pattern:/(^proc\s+lua(?:\s+[\w|=]+)?;)(?:\s*submit)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{lua:{pattern:RegExp("(^[ \t]*submit(?:\\s+(?:load|parseonly|norun))?)(?:<str>|[^\"'])+?(?=endsubmit;)".replace(/<str>/g,t),"im"),lookbehind:!0,alias:"language-lua",inside:e.languages.lua},"submit-statement":d,"global-statements":l,number:a,"numeric-constant":n,punctuation:r,string:i}},"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:s,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:s,datetime:{pattern:RegExp(t+"(?:dt?|t)"),alias:"number"},string:i,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|eval(?:uate)?|exec(?:ute)?|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
+!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+)(?:proc\s+\w+|quit|run|data(?!\=))\b/i,alias:"keyword",lookbehind:!0},s=[/\/\*[\s\S]*?\*\//,{pattern:/(^\s*|;\s*)\*[^;]*;/m,lookbehind:!0}],r={pattern:RegExp(t),greedy:!0},o=/[$%@.(){}\[\];,\\]/,l={pattern:/%?\w+(?=\()/,alias:"keyword"},d={function:l,"arg-value":{pattern:/(\s*=\s*)[A-Z\.]+/i,lookbehind:!0},operator:/=/,"macro-variable":{pattern:/&[^\.]*\./i,alias:"string"},arg:{pattern:/[A-Z]+/i,alias:"keyword"},number:a,"numeric-constant":n,punctuation:o,string:r},c={pattern:/\b(?:format|put)\b=?[\w'$.]+/im,inside:{keyword:/^(?:format|put)(?=\=)/i,equals:/=/,format:{pattern:/(?:\w|\$\d)+\.\d?/i,alias:"number"}}},p={pattern:/\b(?:format|put)\s+[\w']+(?:\s+[$.\w]+)+(?=;)/i,inside:{keyword:/^(?:format|put)/i,format:{pattern:/[\w$]+\.\d?/,alias:"number"}}},u={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"},m={pattern:/(^|\s)(?:submit(?:\s+(?:load|parseonly|norun))?|endsubmit)\b/i,lookbehind:!0,alias:"keyword"},b="accessControl|cdm|aggregation|aStore|ruleMining|audio|autotune|bayesianNetClassifier|bioMedImage|boolRule|builtins|cardinality|sccasl|clustering|copula|countreg|dataDiscovery|dataPreprocess|dataSciencePilot|dataStep|decisionTree|deepLearn|deepNeural|varReduce|simSystem|ds2|deduplication|ecm|entityRes|espCluster|explainModel|factmac|fastKnn|fcmpact|fedSql|freqTab|gam|gleam|graphSemiSupLearn|gVarCluster|hiddenMarkovModel|hyperGroup|image|iml|ica|kernalPca|langModel|ldaTopic|sparseML|mlTools|mixed|modelPublishing|mbc|network|optNetwork|neuralNet|nonlinear|nmf|nonParametricBayes|optimization|panel|pls|percentile|pca|phreg|qkb|qlim|quantreg|recommend|tsReconcile|deepRnn|regression|reinforcementLearn|robustPca|sampling|sparkEmbeddedProcess|search(?:Analytics)?|sentimentAnalysis|sequence|configuration|session(?:Prop)?|severity|simple|smartData|sandwich|spatialreg|stabilityMonitoring|spc|loadStreams|svDataDescription|svm|table|conditionalRandomFields|text(?:Rule(?:Develop|Score)|Mining|Parse|Topic|Util|Filters|Frequency)|tsInfo|timeData|transpose|uniTimeSeries",g={pattern:RegExp("(^|\\s)(?:action\\s+)?(?:<act>)\\.[a-z]+\\b[^;]+".replace(/<act>/g,b),"i"),lookbehind:!0,inside:{keyword:RegExp("(?:<act>)\\.[a-z]+\\b".replace(/<act>/g,b),"i"),action:{pattern:/(?:action)/i,alias:"keyword"},function:l,"arg-value":d["arg-value"],operator:d.operator,comment:s,argument:d.arg,number:a,"numeric-constant":n,punctuation:o,string:r}},k={pattern:/((?:^|\s)=?)(?:after|analysis|and|array|barchart|barwidth|begingraph|by|call|cas|cbarline|cfill|class(?:lev)?|close|column|computed?|contains|continue|data(?=\=)|define|delete|describe|document|do\s+over|do|dol|drop|dul|end(?:source|comp)?|entryTitle|else|eval(?:uate)?|exec(?:ute)?|exit|fill(?:attrs)?|file(?:name)?|flist|fnc|function(?:list)?|goto|global|group(?:by)?|headline|headskip|histogram|if|infile|keep|keylabel|keyword|label|layout|leave|legendlabel|length|libname|loadactionset|merge|midpoints|name|noobs|nowd|_?null_|ods|options|or|otherwise|out(?:put)?|over(?:lay)?|plot|put|print|raise|ranexp|rannor|rbreak|retain|return|select|set|session|sessref|source|statgraph|sum|summarize|table|temp|terminate|then\s+do|then|title\d?|to|var|when|where|xaxisopts|yaxisopts|y2axisopts)\b/i,lookbehind:!0};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":u,"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:o,string:r}},"proc-groovy":{pattern:/(^proc\s+groovy(?:\s+[\w|=]+)?;)(?:\s*submit)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{groovy:{pattern:RegExp("(^[ \t]*submit(?:\\s+(?:load|parseonly|norun))?)(?:<str>|[^\"'])+?(?=endsubmit;)".replace(/<str>/g,t),"im"),lookbehind:!0,alias:"language-groovy",inside:e.languages.groovy},"submit-statement":m,"global-statements":u,number:a,"numeric-constant":n,punctuation:o,string:r}},"proc-lua":{pattern:/(^proc\s+lua(?:\s+[\w|=]+)?;)(?:\s*submit)[\s\S]+?(?=^(?:proc\s+\w+|quit|run|data);|(?![\s\S]))/im,lookbehind:!0,inside:{lua:{pattern:RegExp("(^[ \t]*submit(?:\\s+(?:load|parseonly|norun))?)(?:<str>|[^\"'])+?(?=endsubmit;)".replace(/<str>/g,t),"im"),lookbehind:!0,alias:"language-lua",inside:e.languages.lua},"submit-statement":m,"global-statements":u,number:a,"numeric-constant":n,punctuation:o,string:r}},"proc-cas":{pattern:/(^proc\s+cas(?:\s+[\w|=]+)?;)[\s\S]+?(?=^(?:proc\s+\w+|quit|data);|(?![\s\S]))/im,lookbehind:!0,inside:{"statement-var":{pattern:/((?:^|\s)=?)saveresult\s+[^;]+/im,lookbehind:!0,inside:{statement:{pattern:/^saveresult\s+\S+/i,inside:{keyword:/^(?:saveresult)/i}},rest:d}},"cas-actions":g,statement:{pattern:/((?:^|\s)=?)(?:default|(?:un)?set|on|output|upload)[^;]+/im,lookbehind:!0,inside:d},step:i,keyword:k,function:l,comment:s,format:c,altformat:p,"global-statements":u,number:a,"numeric-constant":n,punctuation:o,string:r}},"proc-args":{pattern:RegExp("(^proc\\s+\\w+\\s+)(?!\\s)(?:[^;\"']|<str>)+;".replace(/<str>/g,t),"im"),lookbehind:!0,inside:d},"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:s,number:a,"numeric-constant":n}},"options-args":{pattern:/(^options)[-'"|/\\<>*+=:()\w\s]*(?=;)/im,lookbehind:!0,inside:d},"cas-actions":g,comment:s,function:l,format:c,altformat:p,"numeric-constant":n,datetime:{pattern:RegExp(t+"(?:dt?|t)"),alias:"number"},string:r,step:i,keyword:k,"operator-keyword":{pattern:/\b(?:eq|ne|gt|lt|ge|le|in|not)\b/i,alias:"operator"},number:a,operator:/\*\*?|\|\|?|!!?|¦¦?|<[>=]?|>[<=]?|[-+\/=&]|[~¬^]=?/i,punctuation:o}}(Prism);
\ No newline at end of file
diff --git a/tests/languages/sas/keyword_feature.test b/tests/languages/sas/keyword_feature.test
index 2b19e9e..b0fca4c 100644
--- a/tests/languages/sas/keyword_feature.test
+++ b/tests/languages/sas/keyword_feature.test
@@ -1,4 +1,4 @@
-action after analysis and array barchart barwidth begingraph by
+after analysis and array barchart barwidth begingraph by
cas cbarline cfill class classlev close column compute computed contains data=
define document do do over dol drop dul end entryTitle else endcomp eval
evaluate exec execute fill fillattrs filename group groupby headline headskip
@@ -10,7 +10,7 @@ then do title to var where xaxisopts yaxisopts y2axisopts
----------------------------------------------------
[
- ["keyword", "action"], ["keyword", "after"], ["keyword", "analysis"],
+ ["keyword", "after"], ["keyword", "analysis"],
["keyword", "and"], ["keyword", "array"], ["keyword", "barchart"],
["keyword", "barwidth"], ["keyword", "begingraph"], ["keyword", "by"],
["keyword", "cas"], ["keyword", "cbarline"], ["keyword", "cfill"],
diff --git a/tests/languages/sas/proccas_feature.test b/tests/languages/sas/proccas_feature.test
new file mode 100644
index 0000000..5bc03d3
--- /dev/null
+++ b/tests/languages/sas/proccas_feature.test
@@ -0,0 +1,141 @@
+proc cas;
+ session casauto;
+ builtins.actionSetInfo result=results;
+ print results.setinfo[,{'actionset', 'label'}];
+run;
+quit;
+
+proc cas;
+ session casauto;
+ output log;
+ table.loadTable / path="iris.sashdat";
+ simple.summary result=iris / table={name="iris"};
+ tableIris=findtable(iris);
+ saveresult tableIris csv="sum.csv";
+run;
+quit;
+
+proc cas;
+ action table.fileinfo / path="%.csv";
+run;
+quit;
+
+----------------------------------------------------
+
+[
+ ["step", "proc cas"],
+ ["punctuation", ";"],
+ ["proc-cas",
+ [
+ ["keyword", "session"],
+ " casauto",
+ ["punctuation", ";"],
+ ["cas-actions", [
+ ["keyword", "builtins.actionSetInfo"],
+ ["argument", "result"],
+ ["operator", "="],
+ ["arg-value", "results"]
+ ]
+ ],
+ ["punctuation", ";"],
+ ["keyword", "print"],
+ " results",
+ ["punctuation", "."],
+ "setinfo",
+ ["punctuation", "["],
+ ["punctuation", ","],
+ ["punctuation", "{"],
+ ["string", "'actionset'"],
+ ["punctuation", ","],
+ ["string", "'label'"],
+ ["punctuation", "}"],
+ ["punctuation", "]"],
+ ["punctuation", ";"],
+ ["step", "run"],
+ ["punctuation", ";"]
+ ]
+ ],
+ ["step", "quit"],
+ ["punctuation", ";"],
+ ["step", "proc cas"],
+ ["punctuation", ";"],
+ ["proc-cas",
+ [
+ ["keyword", "session"],
+ " casauto",
+ ["punctuation", ";"],
+ ["statement", [
+ ["arg", "output"],
+ ["arg", "log"]
+ ]],
+ ["punctuation", ";"],
+ ["cas-actions", [
+ ["keyword", "table.loadTable"],
+ " / ",
+ ["argument", "path"],
+ ["operator", "="],
+ ["string", "\"iris.sashdat\""]
+ ]
+ ],
+ ["punctuation", ";"],
+ ["cas-actions", [
+ ["keyword", "simple.summary"],
+ ["argument", "result"],
+ ["operator", "="],
+ ["arg-value", "iris"],
+ " / ",
+ ["argument", "table"],
+ ["operator", "="],
+ ["punctuation", "{"],
+ ["argument", "name"],
+ ["operator", "="],
+ ["string", "\"iris\""],
+ ["punctuation", "}"]
+ ]
+ ],
+ ["punctuation", ";"],
+ "\r\n tableIris=",
+ ["function", "findtable"],
+ ["punctuation", "("],
+ "iris",
+ ["punctuation", ")"],
+ ["punctuation", ";"],
+ ["statement-var", [
+ [ "statement", [
+ ["keyword", "saveresult"],
+ " tableIris"
+ ]
+ ],
+ ["arg", "csv"],
+ ["operator", "="],
+ ["string", "\"sum.csv\""]
+ ]],
+ ["punctuation", ";"],
+ ["step", "run"],
+ ["punctuation", ";"]
+ ]
+ ],
+ ["step", "quit"],
+ ["punctuation", ";"],
+ ["step", "proc cas"],
+ ["punctuation", ";"],
+ ["proc-cas",
+ [
+ ["cas-actions",
+ [
+ ["action", "action"],
+ ["keyword", "table.fileinfo"],
+ " / ",
+ ["argument", "path"],
+ ["operator", "="],
+ ["string", "\"%.csv\""]
+ ]
+ ],
+ ["punctuation", ";"],
+ ["step", "run"],
+ ["punctuation", ";"]
+ ]
+ ],
+ ["step", "quit"],
+ ["punctuation", ";"]
+]