modeling.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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
  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. # jacobian += statement
  284. (r'jacobian\s*\+=', Keyword),
  285. # Reserved Words
  286. (r'({})\b'.format(r'|'.join(_stan_builtins.KEYWORDS)), Keyword),
  287. # Truncation
  288. (r'T(?=\s*\[)', Keyword),
  289. # Data types
  290. (r'({})\b'.format(r'|'.join(_stan_builtins.TYPES)), Keyword.Type),
  291. # < should be punctuation, but elsewhere I can't tell if it is in
  292. # a range constraint
  293. (r'(<)(\s*)(upper|lower|offset|multiplier)(\s*)(=)',
  294. bygroups(Operator, Whitespace, Keyword, Whitespace, Punctuation)),
  295. (r'(,)(\s*)(upper)(\s*)(=)',
  296. bygroups(Punctuation, Whitespace, Keyword, Whitespace, Punctuation)),
  297. # Punctuation
  298. (r"[;,\[\]()]", Punctuation),
  299. # Builtin
  300. (r'({})(?=\s*\()'.format('|'.join(_stan_builtins.FUNCTIONS)), Name.Builtin),
  301. (r'(~)(\s*)({})(?=\s*\()'.format('|'.join(_stan_builtins.DISTRIBUTIONS)),
  302. bygroups(Operator, Whitespace, Name.Builtin)),
  303. # Special names ending in __, like lp__
  304. (r'[A-Za-z]\w*__\b', Name.Builtin.Pseudo),
  305. (r'({})\b'.format(r'|'.join(_stan_builtins.RESERVED)), Keyword.Reserved),
  306. # user-defined functions
  307. (r'[A-Za-z]\w*(?=\s*\()]', Name.Function),
  308. # Imaginary Literals
  309. (r'[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?i', Number.Float),
  310. (r'\.[0-9]+([eE][+-]?[0-9]+)?i', Number.Float),
  311. (r'[0-9]+i', Number.Float),
  312. # Real Literals
  313. (r'[0-9]+(\.[0-9]*)?([eE][+-]?[0-9]+)?', Number.Float),
  314. (r'\.[0-9]+([eE][+-]?[0-9]+)?', Number.Float),
  315. # Integer Literals
  316. (r'[0-9]+', Number.Integer),
  317. # Regular variable names
  318. (r'[A-Za-z]\w*\b', Name),
  319. # Assignment operators
  320. (r'<-|(?:\+|-|\.?/|\.?\*|=)?=|~', Operator),
  321. # Infix, prefix and postfix operators (and = )
  322. (r"\+|-|\.?\*|\.?/|\\|'|\.?\^|!=?|<=?|>=?|\|\||&&|%|\?|:|%/%|!", Operator),
  323. # Block delimiters
  324. (r'[{}]', Punctuation),
  325. # Distribution |
  326. (r'\|', Punctuation)
  327. ]
  328. }
  329. def analyse_text(text):
  330. if re.search(r'^\s*parameters\s*\{', text, re.M):
  331. return 1.0
  332. else:
  333. return 0.0