1"""
2 pygments.lexers.modeling
3 ~~~~~~~~~~~~~~~~~~~~~~~~
4
5 Lexers for modeling languages.
6
7 :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10
11import re
12
13from pygments.lexer import RegexLexer, include, bygroups, using, default
14from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
15 Number, Punctuation, Whitespace
16
17from pygments.lexers.html import HtmlLexer
18from pygments.lexers import _stan_builtins
19
20__all__ = ['ModelicaLexer', 'BugsLexer', 'JagsLexer', 'StanLexer']
21
22
23class ModelicaLexer(RegexLexer):
24 """
25 For Modelica source code.
26 """
27 name = 'Modelica'
28 url = 'http://www.modelica.org/'
29 aliases = ['modelica']
30 filenames = ['*.mo']
31 mimetypes = ['text/x-modelica']
32 version_added = '1.1'
33
34 flags = re.DOTALL | re.MULTILINE
35
36 _name = r"(?:'(?:[^\\']|\\.)+'|[a-zA-Z_]\w*)"
37
38 tokens = {
39 'whitespace': [
40 (r'[\s\ufeff]+', Text),
41 (r'//[^\n]*\n?', Comment.Single),
42 (r'/\*.*?\*/', Comment.Multiline)
43 ],
44 'root': [
45 include('whitespace'),
46 (r'"', String.Double, 'string'),
47 (r'[()\[\]{},;]+', Punctuation),
48 (r'\.?[*^/+-]|\.|<>|[<>:=]=?', Operator),
49 (r'\d+(\.?\d*[eE][-+]?\d+|\.\d*)', Number.Float),
50 (r'\d+', Number.Integer),
51 (r'(abs|acos|actualStream|array|asin|assert|AssertionLevel|atan|'
52 r'atan2|backSample|Boolean|cardinality|cat|ceil|change|Clock|'
53 r'Connections|cos|cosh|cross|delay|diagonal|div|edge|exp|'
54 r'ExternalObject|fill|floor|getInstanceName|hold|homotopy|'
55 r'identity|inStream|integer|Integer|interval|inverse|isPresent|'
56 r'linspace|log|log10|matrix|max|min|mod|ndims|noClock|noEvent|'
57 r'ones|outerProduct|pre|previous|product|Real|reinit|rem|rooted|'
58 r'sample|scalar|semiLinear|shiftSample|sign|sin|sinh|size|skew|'
59 r'smooth|spatialDistribution|sqrt|StateSelect|String|subSample|'
60 r'sum|superSample|symmetric|tan|tanh|terminal|terminate|time|'
61 r'transpose|vector|zeros)\b', Name.Builtin),
62 (r'(algorithm|annotation|break|connect|constant|constrainedby|der|'
63 r'discrete|each|else|elseif|elsewhen|encapsulated|enumeration|'
64 r'equation|exit|expandable|extends|external|firstTick|final|flow|for|if|'
65 r'import|impure|in|initial|inner|input|interval|loop|nondiscrete|outer|'
66 r'output|parameter|partial|protected|public|pure|redeclare|'
67 r'replaceable|return|stream|then|when|while)\b',
68 Keyword.Reserved),
69 (r'(and|not|or)\b', Operator.Word),
70 (r'(block|class|connector|end|function|model|operator|package|'
71 r'record|type)\b', Keyword.Reserved, 'class'),
72 (r'(false|true)\b', Keyword.Constant),
73 (r'within\b', Keyword.Reserved, 'package-prefix'),
74 (_name, Name)
75 ],
76 'class': [
77 include('whitespace'),
78 (r'(function|record)\b', Keyword.Reserved),
79 (r'(if|for|when|while)\b', Keyword.Reserved, '#pop'),
80 (_name, Name.Class, '#pop'),
81 default('#pop')
82 ],
83 'package-prefix': [
84 include('whitespace'),
85 (_name, Name.Namespace, '#pop'),
86 default('#pop')
87 ],
88 'string': [
89 (r'"', String.Double, '#pop'),
90 (r'\\[\'"?\\abfnrtv]', String.Escape),
91 (r'(?i)<\s*html\s*>([^\\"]|\\.)+?(<\s*/\s*html\s*>|(?="))',
92 using(HtmlLexer)),
93 (r'<|\\?[^"\\<]+', String.Double)
94 ]
95 }
96
97
98class BugsLexer(RegexLexer):
99 """
100 Pygments Lexer for OpenBugs and WinBugs
101 models.
102 """
103
104 name = 'BUGS'
105 aliases = ['bugs', 'winbugs', 'openbugs']
106 filenames = ['*.bug']
107 url = 'https://www.mrc-bsu.cam.ac.uk/software/bugs/openbugs'
108 version_added = '1.6'
109
110 _FUNCTIONS = (
111 # Scalar functions
112 'abs', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctanh',
113 'cloglog', 'cos', 'cosh', 'cumulative', 'cut', 'density', 'deviance',
114 'equals', 'expr', 'gammap', 'ilogit', 'icloglog', 'integral', 'log',
115 'logfact', 'loggam', 'logit', 'max', 'min', 'phi', 'post.p.value',
116 'pow', 'prior.p.value', 'probit', 'replicate.post', 'replicate.prior',
117 'round', 'sin', 'sinh', 'solution', 'sqrt', 'step', 'tan', 'tanh',
118 'trunc',
119 # Vector functions
120 'inprod', 'interp.lin', 'inverse', 'logdet', 'mean', 'eigen.vals',
121 'ode', 'prod', 'p.valueM', 'rank', 'ranked', 'replicate.postM',
122 'sd', 'sort', 'sum',
123 # Special
124 'D', 'I', 'F', 'T', 'C')
125 """ OpenBUGS built-in functions
126
127 From http://www.openbugs.info/Manuals/ModelSpecification.html#ContentsAII
128
129 This also includes
130
131 - T, C, I : Truncation and censoring.
132 ``T`` and ``C`` are in OpenBUGS. ``I`` in WinBUGS.
133 - D : ODE
134 - F : Functional http://www.openbugs.info/Examples/Functionals.html
135
136 """
137
138 _DISTRIBUTIONS = ('dbern', 'dbin', 'dcat', 'dnegbin', 'dpois',
139 'dhyper', 'dbeta', 'dchisqr', 'ddexp', 'dexp',
140 'dflat', 'dgamma', 'dgev', 'df', 'dggamma', 'dgpar',
141 'dloglik', 'dlnorm', 'dlogis', 'dnorm', 'dpar',
142 'dt', 'dunif', 'dweib', 'dmulti', 'ddirch', 'dmnorm',
143 'dmt', 'dwish')
144 """ OpenBUGS built-in distributions
145
146 Functions from
147 http://www.openbugs.info/Manuals/ModelSpecification.html#ContentsAI
148 """
149
150 tokens = {
151 'whitespace': [
152 (r"\s+", Text),
153 ],
154 'comments': [
155 # Comments
156 (r'#.*$', Comment.Single),
157 ],
158 'root': [
159 # Comments
160 include('comments'),
161 include('whitespace'),
162 # Block start
163 (r'(model)(\s+)(\{)',
164 bygroups(Keyword.Namespace, Text, Punctuation)),
165 # Reserved Words
166 (r'(for|in)(?![\w.])', Keyword.Reserved),
167 # Built-in Functions
168 (r'({})(?=\s*\()'.format(r'|'.join(_FUNCTIONS + _DISTRIBUTIONS)),
169 Name.Builtin),
170 # Regular variable names
171 (r'[A-Za-z][\w.]*', Name),
172 # Number Literals
173 (r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?', Number),
174 # Punctuation
175 (r'\[|\]|\(|\)|:|,|;', Punctuation),
176 # Assignment operators
177 # SLexer makes these tokens Operators.
178 (r'<-|~', Operator),
179 # Infix and prefix operators
180 (r'\+|-|\*|/', Operator),
181 # Block
182 (r'[{}]', Punctuation),
183 ]
184 }
185
186 def analyse_text(text):
187 if re.search(r"^\s*model\s*{", text, re.M):
188 return 0.7
189 else:
190 return 0.0
191
192
193class JagsLexer(RegexLexer):
194 """
195 Pygments Lexer for JAGS.
196 """
197
198 name = 'JAGS'
199 aliases = ['jags']
200 filenames = ['*.jag', '*.bug']
201 url = 'https://mcmc-jags.sourceforge.io'
202 version_added = '1.6'
203
204 # JAGS
205 _FUNCTIONS = (
206 'abs', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctanh',
207 'cos', 'cosh', 'cloglog',
208 'equals', 'exp', 'icloglog', 'ifelse', 'ilogit', 'log', 'logfact',
209 'loggam', 'logit', 'phi', 'pow', 'probit', 'round', 'sin', 'sinh',
210 'sqrt', 'step', 'tan', 'tanh', 'trunc', 'inprod', 'interp.lin',
211 'logdet', 'max', 'mean', 'min', 'prod', 'sum', 'sd', 'inverse',
212 'rank', 'sort', 't', 'acos', 'acosh', 'asin', 'asinh', 'atan',
213 # Truncation/Censoring (should I include)
214 'T', 'I')
215 # Distributions with density, probability and quartile functions
216 _DISTRIBUTIONS = tuple(f'[dpq]{x}' for x in
217 ('bern', 'beta', 'dchiqsqr', 'ddexp', 'dexp',
218 'df', 'gamma', 'gen.gamma', 'logis', 'lnorm',
219 'negbin', 'nchisqr', 'norm', 'par', 'pois', 'weib'))
220 # Other distributions without density and probability
221 _OTHER_DISTRIBUTIONS = (
222 'dt', 'dunif', 'dbetabin', 'dbern', 'dbin', 'dcat', 'dhyper',
223 'ddirch', 'dmnorm', 'dwish', 'dmt', 'dmulti', 'dbinom', 'dchisq',
224 'dnbinom', 'dweibull', 'ddirich')
225
226 tokens = {
227 'whitespace': [
228 (r"\s+", Text),
229 ],
230 'names': [
231 # Regular variable names
232 (r'[a-zA-Z][\w.]*\b', Name),
233 ],
234 'comments': [
235 # do not use stateful comments
236 (r'(?s)/\*.*?\*/', Comment.Multiline),
237 # Comments
238 (r'#.*$', Comment.Single),
239 ],
240 'root': [
241 # Comments
242 include('comments'),
243 include('whitespace'),
244 # Block start
245 (r'(model|data)(\s+)(\{)',
246 bygroups(Keyword.Namespace, Text, Punctuation)),
247 (r'var(?![\w.])', Keyword.Declaration),
248 # Reserved Words
249 (r'(for|in)(?![\w.])', Keyword.Reserved),
250 # Builtins
251 # Need to use lookahead because . is a valid char
252 (r'({})(?=\s*\()'.format(r'|'.join(_FUNCTIONS
253 + _DISTRIBUTIONS
254 + _OTHER_DISTRIBUTIONS)),
255 Name.Builtin),
256 # Names
257 include('names'),
258 # Number Literals
259 (r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?', Number),
260 (r'\[|\]|\(|\)|:|,|;', Punctuation),
261 # Assignment operators
262 (r'<-|~', Operator),
263 # # JAGS includes many more than OpenBUGS
264 (r'\+|-|\*|\/|\|\|[&]{2}|[<>=]=?|\^|%.*?%', Operator),
265 (r'[{}]', Punctuation),
266 ]
267 }
268
269 def analyse_text(text):
270 if re.search(r'^\s*model\s*\{', text, re.M):
271 if re.search(r'^\s*data\s*\{', text, re.M):
272 return 0.9
273 elif re.search(r'^\s*var', text, re.M):
274 return 0.9
275 else:
276 return 0.3
277 else:
278 return 0
279
280
281class StanLexer(RegexLexer):
282 """Pygments Lexer for Stan models.
283
284 The Stan modeling language is specified in the *Stan Modeling Language
285 User's Guide and Reference Manual, v2.17.0*,
286 `pdf <https://github.com/stan-dev/stan/releases/download/v2.17.0/stan-reference-2.17.0.pdf>`__.
287 """
288
289 name = 'Stan'
290 aliases = ['stan']
291 filenames = ['*.stan']
292 url = 'https://mc-stan.org'
293 version_added = '1.6'
294
295 tokens = {
296 'whitespace': [
297 (r"\s+", Text),
298 ],
299 'comments': [
300 (r'(?s)/\*.*?\*/', Comment.Multiline),
301 # Comments
302 (r'(//|#).*$', Comment.Single),
303 ],
304 'root': [
305 (r'"[^"]*"', String),
306 # Comments
307 include('comments'),
308 # block start
309 include('whitespace'),
310 # Block start
311 (r'({})(\s*)(\{{)'.format(r'|'.join(('functions', 'data', r'transformed\s+?data',
312 'parameters', r'transformed\s+parameters',
313 'model', r'generated\s+quantities'))),
314 bygroups(Keyword.Namespace, Text, Punctuation)),
315 # target keyword
316 (r'target\s*\+=', Keyword),
317 # jacobian += statement
318 (r'jacobian\s*\+=', Keyword),
319 # Reserved Words
320 (r'({})\b'.format(r'|'.join(_stan_builtins.KEYWORDS)), Keyword),
321 # Truncation
322 (r'T(?=\s*\[)', Keyword),
323 # Data types
324 (r'({})\b'.format(r'|'.join(_stan_builtins.TYPES)), Keyword.Type),
325 # < should be punctuation, but elsewhere I can't tell if it is in
326 # a range constraint
327 (r'(<)(\s*)(upper|lower|offset|multiplier)(\s*)(=)',
328 bygroups(Operator, Whitespace, Keyword, Whitespace, Punctuation)),
329 (r'(,)(\s*)(upper)(\s*)(=)',
330 bygroups(Punctuation, Whitespace, Keyword, Whitespace, Punctuation)),
331 # Punctuation
332 (r"[;,\[\]()]", Punctuation),
333 # Builtin
334 (r'({})(?=\s*\()'.format('|'.join(_stan_builtins.FUNCTIONS)), Name.Builtin),
335 (r'(~)(\s*)({})(?=\s*\()'.format('|'.join(_stan_builtins.DISTRIBUTIONS)),
336 bygroups(Operator, Whitespace, Name.Builtin)),
337 # Special names ending in __, like lp__
338 (r'[A-Za-z]\w*__\b', Name.Builtin.Pseudo),
339 (r'({})\b'.format(r'|'.join(_stan_builtins.RESERVED)), Keyword.Reserved),
340 # user-defined functions
341 (r'[A-Za-z]\w*(?=\s*\()]', Name.Function),
342 # Imaginary Literals
343 (r'[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?i', Number.Float),
344 (r'\.[0-9]+([eE][+-]?[0-9]+)?i', Number.Float),
345 (r'[0-9]+i', Number.Float),
346 # Real Literals
347 (r'[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?', Number.Float),
348 (r'\.[0-9]+([eE][+-]?[0-9]+)?', Number.Float),
349 # Integer Literals
350 (r'[0-9]+', Number.Integer),
351 # Regular variable names
352 (r'[A-Za-z]\w*\b', Name),
353 # Assignment operators
354 (r'<-|(?:\+|-|\.?/|\.?\*|=)?=|~', Operator),
355 # Infix, prefix and postfix operators (and = )
356 (r"\+|-|\.?\*|\.?/|\\|'|\.?\^|!=?|<=?|>=?|\|\||&&|%|\?|:|%/%|!", Operator),
357 # Block delimiters
358 (r'[{}]', Punctuation),
359 # Distribution |
360 (r'\|', Punctuation)
361 ]
362 }
363
364 def analyse_text(text):
365 if re.search(r'^\s*parameters\s*\{', text, re.M):
366 return 1.0
367 else:
368 return 0.0