ul4.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. """
  2. pygments.lexers.ul4
  3. ~~~~~~~~~~~~~~~~~~~
  4. Lexer for the UL4 templating language.
  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, DelegatingLexer, bygroups, words, include
  10. from pygments.token import Comment, Text, Keyword, String, Number, Literal, \
  11. Name, Other, Operator
  12. from pygments.lexers.web import HtmlLexer, XmlLexer, CssLexer, JavascriptLexer
  13. from pygments.lexers.python import PythonLexer
  14. __all__ = ['UL4Lexer', 'HTMLUL4Lexer', 'XMLUL4Lexer', 'CSSUL4Lexer',
  15. 'JavascriptUL4Lexer', 'PythonUL4Lexer']
  16. class UL4Lexer(RegexLexer):
  17. """
  18. Generic lexer for UL4.
  19. """
  20. flags = re.MULTILINE | re.DOTALL
  21. name = 'UL4'
  22. aliases = ['ul4']
  23. filenames = ['*.ul4']
  24. url = 'https://python.livinglogic.de/UL4.html'
  25. version_added = '2.12'
  26. tokens = {
  27. "root": [
  28. (
  29. # Template header without name:
  30. # ``<?ul4?>``
  31. r"(<\?)(\s*)(ul4)(\s*)(\?>)",
  32. bygroups(Comment.Preproc, Text.Whitespace, Keyword,
  33. Text.Whitespace, Comment.Preproc),
  34. ),
  35. (
  36. # Template header with name (potentially followed by the signature):
  37. # ``<?ul4 foo(bar=42)?>``
  38. r"(<\?)(\s*)(ul4)(\s*)([a-zA-Z_][a-zA-Z_0-9]*)?",
  39. bygroups(Comment.Preproc, Text.Whitespace, Keyword,
  40. Text.Whitespace, Name.Function),
  41. "ul4", # Switch to "expression" mode
  42. ),
  43. (
  44. # Comment:
  45. # ``<?note?>...<?end note?>``
  46. r"<\?\s*note\s*\?>",
  47. Comment,
  48. "note", # Switch to "note" mode
  49. ),
  50. (
  51. # Comment:
  52. # ``<?note foobar?>``
  53. r"<\?\s*note\s.*?\?>",
  54. Comment,
  55. ),
  56. (
  57. # Template documentation:
  58. # ``<?doc?>...<?end doc?>``
  59. r"<\?\s*doc\s*\?>",
  60. String.Doc,
  61. "doc",
  62. ),
  63. (
  64. # Template documentation:
  65. # ``<?doc foobar?>``
  66. r"<\?\s*doc\s.*?\?>",
  67. String.Doc,
  68. ),
  69. (
  70. # ``<?ignore?>`` tag for commenting out code:
  71. # ``<?ignore?>...<?end ignore?>``
  72. r"<\?\s*ignore\s*\?>",
  73. Comment,
  74. "ignore", # Switch to "ignore" mode
  75. ),
  76. (
  77. # ``<?def?>`` tag for defining local templates
  78. # ``<?def foo(bar=42)?>...<?end def?>``
  79. r"(<\?)(\s*)(def)(\s*)([a-zA-Z_][a-zA-Z_0-9]*)?",
  80. bygroups(Comment.Preproc, Text.Whitespace, Keyword,
  81. Text.Whitespace, Name.Function),
  82. "ul4", # Switch to "expression" mode
  83. ),
  84. (
  85. # The rest of the supported tags
  86. r"(<\?)(\s*)(printx|print|for|if|elif|else|while|code|renderblocks?|render)\b",
  87. bygroups(Comment.Preproc, Text.Whitespace, Keyword),
  88. "ul4", # Switch to "expression" mode
  89. ),
  90. (
  91. # ``<?end?>`` tag for ending ``<?def?>``, ``<?for?>``,
  92. # ``<?if?>``, ``<?while?>``, ``<?renderblock?>`` and
  93. # ``<?renderblocks?>`` blocks.
  94. r"(<\?)(\s*)(end)\b",
  95. bygroups(Comment.Preproc, Text.Whitespace, Keyword),
  96. "end", # Switch to "end tag" mode
  97. ),
  98. (
  99. # ``<?whitespace?>`` tag for configuring whitespace handlng
  100. r"(<\?)(\s*)(whitespace)\b",
  101. bygroups(Comment.Preproc, Text.Whitespace, Keyword),
  102. "whitespace", # Switch to "whitespace" mode
  103. ),
  104. # Plain text
  105. (r"[^<]+", Other),
  106. (r"<", Other),
  107. ],
  108. # Ignore mode ignores everything upto the matching ``<?end ignore?>`` tag
  109. "ignore": [
  110. # Nested ``<?ignore?>`` tag
  111. (r"<\?\s*ignore\s*\?>", Comment, "#push"),
  112. # ``<?end ignore?>`` tag
  113. (r"<\?\s*end\s+ignore\s*\?>", Comment, "#pop"),
  114. # Everything else
  115. (r"[^<]+", Comment),
  116. (r".", Comment),
  117. ],
  118. # Note mode ignores everything upto the matching ``<?end note?>`` tag
  119. "note": [
  120. # Nested ``<?note?>`` tag
  121. (r"<\?\s*note\s*\?>", Comment, "#push"),
  122. # ``<?end note?>`` tag
  123. (r"<\?\s*end\s+note\s*\?>", Comment, "#pop"),
  124. # Everything else
  125. (r"[^<]+", Comment),
  126. (r".", Comment),
  127. ],
  128. # Doc mode ignores everything upto the matching ``<?end doc?>`` tag
  129. "doc": [
  130. # Nested ``<?doc?>`` tag
  131. (r"<\?\s*doc\s*\?>", String.Doc, "#push"),
  132. # ``<?end doc?>`` tag
  133. (r"<\?\s*end\s+doc\s*\?>", String.Doc, "#pop"),
  134. # Everything else
  135. (r"[^<]+", String.Doc),
  136. (r".", String.Doc),
  137. ],
  138. # UL4 expressions
  139. "ul4": [
  140. # End the tag
  141. (r"\?>", Comment.Preproc, "#pop"),
  142. # Start triple quoted string constant
  143. ("'''", String, "string13"),
  144. ('"""', String, "string23"),
  145. # Start single quoted string constant
  146. ("'", String, "string1"),
  147. ('"', String, "string2"),
  148. # Floating point number
  149. (r"\d+\.\d*([eE][+-]?\d+)?", Number.Float),
  150. (r"\.\d+([eE][+-]?\d+)?", Number.Float),
  151. (r"\d+[eE][+-]?\d+", Number.Float),
  152. # Binary integer: ``0b101010``
  153. (r"0[bB][01]+", Number.Bin),
  154. # Octal integer: ``0o52``
  155. (r"0[oO][0-7]+", Number.Oct),
  156. # Hexadecimal integer: ``0x2a``
  157. (r"0[xX][0-9a-fA-F]+", Number.Hex),
  158. # Date or datetime: ``@(2000-02-29)``/``@(2000-02-29T12:34:56.987654)``
  159. (r"@\(\d\d\d\d-\d\d-\d\d(T(\d\d:\d\d(:\d\d(\.\d{6})?)?)?)?\)", Literal.Date),
  160. # Color: ``#fff``, ``#fff8f0`` etc.
  161. (r"#[0-9a-fA-F]{8}", Literal.Color),
  162. (r"#[0-9a-fA-F]{6}", Literal.Color),
  163. (r"#[0-9a-fA-F]{3,4}", Literal.Color),
  164. # Decimal integer: ``42``
  165. (r"\d+", Number.Integer),
  166. # Operators
  167. (r"//|==|!=|>=|<=|<<|>>|\+=|-=|\*=|/=|//=|<<=|>>=|&=|\|=|^=|=|[\[\]{},:*/().~%&|<>^+-]", Operator),
  168. # Keywords
  169. (words(("for", "in", "if", "else", "not", "is", "and", "or"), suffix=r"\b"), Keyword),
  170. # Builtin constants
  171. (words(("None", "False", "True"), suffix=r"\b"), Keyword.Constant),
  172. # Variable names
  173. (r"[a-zA-Z_][a-zA-Z0-9_]*", Name),
  174. # Whitespace
  175. (r"\s+", Text.Whitespace),
  176. ],
  177. # ``<?end ...?>`` tag for closing the last open block
  178. "end": [
  179. (r"\?>", Comment.Preproc, "#pop"),
  180. (words(("for", "if", "def", "while", "renderblock", "renderblocks"), suffix=r"\b"), Keyword),
  181. (r"\s+", Text),
  182. ],
  183. # Content of the ``<?whitespace ...?>`` tag:
  184. # ``keep``, ``strip`` or ``smart``
  185. "whitespace": [
  186. (r"\?>", Comment.Preproc, "#pop"),
  187. (words(("keep", "strip", "smart"), suffix=r"\b"), Comment.Preproc),
  188. (r"\s+", Text.Whitespace),
  189. ],
  190. # Inside a string constant
  191. "stringescapes": [
  192. (r"""\\[\\'"abtnfr]""", String.Escape),
  193. (r"\\x[0-9a-fA-F]{2}", String.Escape),
  194. (r"\\u[0-9a-fA-F]{4}", String.Escape),
  195. (r"\\U[0-9a-fA-F]{8}", String.Escape),
  196. ],
  197. # Inside a triple quoted string started with ``'''``
  198. "string13": [
  199. (r"'''", String, "#pop"),
  200. include("stringescapes"),
  201. (r"[^\\']+", String),
  202. (r'.', String),
  203. ],
  204. # Inside a triple quoted string started with ``"""``
  205. "string23": [
  206. (r'"""', String, "#pop"),
  207. include("stringescapes"),
  208. (r'[^\\"]+', String),
  209. (r'.', String),
  210. ],
  211. # Inside a single quoted string started with ``'``
  212. "string1": [
  213. (r"'", String, "#pop"),
  214. include("stringescapes"),
  215. (r"[^\\']+", String),
  216. (r'.', String),
  217. ],
  218. # Inside a single quoted string started with ``"``
  219. "string2": [
  220. (r'"', String, "#pop"),
  221. include("stringescapes"),
  222. (r'[^\\"]+', String),
  223. (r'.', String),
  224. ],
  225. }
  226. class HTMLUL4Lexer(DelegatingLexer):
  227. """
  228. Lexer for UL4 embedded in HTML.
  229. """
  230. name = 'HTML+UL4'
  231. aliases = ['html+ul4']
  232. filenames = ['*.htmlul4']
  233. url = 'https://python.livinglogic.de/UL4.html'
  234. version_added = ''
  235. def __init__(self, **options):
  236. super().__init__(HtmlLexer, UL4Lexer, **options)
  237. class XMLUL4Lexer(DelegatingLexer):
  238. """
  239. Lexer for UL4 embedded in XML.
  240. """
  241. name = 'XML+UL4'
  242. aliases = ['xml+ul4']
  243. filenames = ['*.xmlul4']
  244. url = 'https://python.livinglogic.de/UL4.html'
  245. version_added = ''
  246. def __init__(self, **options):
  247. super().__init__(XmlLexer, UL4Lexer, **options)
  248. class CSSUL4Lexer(DelegatingLexer):
  249. """
  250. Lexer for UL4 embedded in CSS.
  251. """
  252. name = 'CSS+UL4'
  253. aliases = ['css+ul4']
  254. filenames = ['*.cssul4']
  255. url = 'https://python.livinglogic.de/UL4.html'
  256. version_added = ''
  257. def __init__(self, **options):
  258. super().__init__(CssLexer, UL4Lexer, **options)
  259. class JavascriptUL4Lexer(DelegatingLexer):
  260. """
  261. Lexer for UL4 embedded in Javascript.
  262. """
  263. name = 'Javascript+UL4'
  264. aliases = ['js+ul4']
  265. filenames = ['*.jsul4']
  266. url = 'https://python.livinglogic.de/UL4.html'
  267. version_added = ''
  268. def __init__(self, **options):
  269. super().__init__(JavascriptLexer, UL4Lexer, **options)
  270. class PythonUL4Lexer(DelegatingLexer):
  271. """
  272. Lexer for UL4 embedded in Python.
  273. """
  274. name = 'Python+UL4'
  275. aliases = ['py+ul4']
  276. filenames = ['*.pyul4']
  277. url = 'https://python.livinglogic.de/UL4.html'
  278. version_added = ''
  279. def __init__(self, **options):
  280. super().__init__(PythonLexer, UL4Lexer, **options)