modeling.py 13 KB

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