modeling.py 14 KB

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