rouge-alda 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +28 -0
  3. data/LICENSE +186 -0
  4. data/bin/rougify +18 -0
  5. data/lib/rouge/cli.rb +432 -0
  6. data/lib/rouge/demos/abap +6 -0
  7. data/lib/rouge/demos/actionscript +4 -0
  8. data/lib/rouge/demos/alda +10 -0
  9. data/lib/rouge/demos/apache +21 -0
  10. data/lib/rouge/demos/apiblueprint +33 -0
  11. data/lib/rouge/demos/applescript +2 -0
  12. data/lib/rouge/demos/awk +4 -0
  13. data/lib/rouge/demos/biml +38 -0
  14. data/lib/rouge/demos/bsl +7 -0
  15. data/lib/rouge/demos/c +8 -0
  16. data/lib/rouge/demos/ceylon +7 -0
  17. data/lib/rouge/demos/cfscript +18 -0
  18. data/lib/rouge/demos/clojure +5 -0
  19. data/lib/rouge/demos/cmake +7 -0
  20. data/lib/rouge/demos/coffeescript +5 -0
  21. data/lib/rouge/demos/common_lisp +1 -0
  22. data/lib/rouge/demos/conf +4 -0
  23. data/lib/rouge/demos/console +6 -0
  24. data/lib/rouge/demos/coq +13 -0
  25. data/lib/rouge/demos/cpp +8 -0
  26. data/lib/rouge/demos/crystal +45 -0
  27. data/lib/rouge/demos/csharp +5 -0
  28. data/lib/rouge/demos/css +4 -0
  29. data/lib/rouge/demos/d +16 -0
  30. data/lib/rouge/demos/dart +6 -0
  31. data/lib/rouge/demos/diff +7 -0
  32. data/lib/rouge/demos/digdag +19 -0
  33. data/lib/rouge/demos/docker +9 -0
  34. data/lib/rouge/demos/dot +5 -0
  35. data/lib/rouge/demos/eiffel +30 -0
  36. data/lib/rouge/demos/elixir +1 -0
  37. data/lib/rouge/demos/elm +4 -0
  38. data/lib/rouge/demos/erb +1 -0
  39. data/lib/rouge/demos/erlang +7 -0
  40. data/lib/rouge/demos/factor +5 -0
  41. data/lib/rouge/demos/fortran +22 -0
  42. data/lib/rouge/demos/fsharp +12 -0
  43. data/lib/rouge/demos/gherkin +17 -0
  44. data/lib/rouge/demos/glsl +14 -0
  45. data/lib/rouge/demos/go +7 -0
  46. data/lib/rouge/demos/gradle +10 -0
  47. data/lib/rouge/demos/graphql +17 -0
  48. data/lib/rouge/demos/groovy +9 -0
  49. data/lib/rouge/demos/hack +5 -0
  50. data/lib/rouge/demos/haml +5 -0
  51. data/lib/rouge/demos/handlebars +7 -0
  52. data/lib/rouge/demos/haskell +6 -0
  53. data/lib/rouge/demos/hcl +7 -0
  54. data/lib/rouge/demos/html +8 -0
  55. data/lib/rouge/demos/http +14 -0
  56. data/lib/rouge/demos/hylang +10 -0
  57. data/lib/rouge/demos/idlang +8 -0
  58. data/lib/rouge/demos/igorpro +9 -0
  59. data/lib/rouge/demos/ini +4 -0
  60. data/lib/rouge/demos/io +11 -0
  61. data/lib/rouge/demos/irb +4 -0
  62. data/lib/rouge/demos/irb_output +2 -0
  63. data/lib/rouge/demos/java +5 -0
  64. data/lib/rouge/demos/javascript +1 -0
  65. data/lib/rouge/demos/jinja +9 -0
  66. data/lib/rouge/demos/json +1 -0
  67. data/lib/rouge/demos/json-doc +1 -0
  68. data/lib/rouge/demos/jsonnet +28 -0
  69. data/lib/rouge/demos/jsp +29 -0
  70. data/lib/rouge/demos/jsx +17 -0
  71. data/lib/rouge/demos/julia +11 -0
  72. data/lib/rouge/demos/kotlin +3 -0
  73. data/lib/rouge/demos/lasso +12 -0
  74. data/lib/rouge/demos/liquid +11 -0
  75. data/lib/rouge/demos/literate_coffeescript +3 -0
  76. data/lib/rouge/demos/literate_haskell +7 -0
  77. data/lib/rouge/demos/llvm +20 -0
  78. data/lib/rouge/demos/lua +12 -0
  79. data/lib/rouge/demos/m68k +16 -0
  80. data/lib/rouge/demos/make +6 -0
  81. data/lib/rouge/demos/markdown +4 -0
  82. data/lib/rouge/demos/mathematica +8 -0
  83. data/lib/rouge/demos/matlab +6 -0
  84. data/lib/rouge/demos/moonscript +16 -0
  85. data/lib/rouge/demos/mosel +10 -0
  86. data/lib/rouge/demos/mxml +22 -0
  87. data/lib/rouge/demos/nasm +26 -0
  88. data/lib/rouge/demos/nginx +5 -0
  89. data/lib/rouge/demos/nim +27 -0
  90. data/lib/rouge/demos/nix +19 -0
  91. data/lib/rouge/demos/objective_c +18 -0
  92. data/lib/rouge/demos/ocaml +12 -0
  93. data/lib/rouge/demos/pascal +14 -0
  94. data/lib/rouge/demos/perl +5 -0
  95. data/lib/rouge/demos/php +3 -0
  96. data/lib/rouge/demos/plaintext +1 -0
  97. data/lib/rouge/demos/plist +142 -0
  98. data/lib/rouge/demos/pony +17 -0
  99. data/lib/rouge/demos/powershell +49 -0
  100. data/lib/rouge/demos/praat +26 -0
  101. data/lib/rouge/demos/prolog +9 -0
  102. data/lib/rouge/demos/prometheus +9 -0
  103. data/lib/rouge/demos/properties +7 -0
  104. data/lib/rouge/demos/protobuf +5 -0
  105. data/lib/rouge/demos/puppet +6 -0
  106. data/lib/rouge/demos/python +6 -0
  107. data/lib/rouge/demos/q +2 -0
  108. data/lib/rouge/demos/qml +9 -0
  109. data/lib/rouge/demos/r +8 -0
  110. data/lib/rouge/demos/racket +24 -0
  111. data/lib/rouge/demos/ruby +9 -0
  112. data/lib/rouge/demos/rust +12 -0
  113. data/lib/rouge/demos/sass +3 -0
  114. data/lib/rouge/demos/scala +3 -0
  115. data/lib/rouge/demos/scheme +4 -0
  116. data/lib/rouge/demos/scss +5 -0
  117. data/lib/rouge/demos/sed +4 -0
  118. data/lib/rouge/demos/shell +2 -0
  119. data/lib/rouge/demos/sieve +10 -0
  120. data/lib/rouge/demos/slim +17 -0
  121. data/lib/rouge/demos/smalltalk +6 -0
  122. data/lib/rouge/demos/smarty +12 -0
  123. data/lib/rouge/demos/sml +4 -0
  124. data/lib/rouge/demos/sqf +14 -0
  125. data/lib/rouge/demos/sql +1 -0
  126. data/lib/rouge/demos/swift +5 -0
  127. data/lib/rouge/demos/tap +5 -0
  128. data/lib/rouge/demos/tcl +1 -0
  129. data/lib/rouge/demos/terraform +31 -0
  130. data/lib/rouge/demos/tex +1 -0
  131. data/lib/rouge/demos/toml +9 -0
  132. data/lib/rouge/demos/tsx +17 -0
  133. data/lib/rouge/demos/tulip +13 -0
  134. data/lib/rouge/demos/turtle +26 -0
  135. data/lib/rouge/demos/twig +9 -0
  136. data/lib/rouge/demos/typescript +1 -0
  137. data/lib/rouge/demos/vala +8 -0
  138. data/lib/rouge/demos/vb +4 -0
  139. data/lib/rouge/demos/verilog +27 -0
  140. data/lib/rouge/demos/vhdl +23 -0
  141. data/lib/rouge/demos/viml +14 -0
  142. data/lib/rouge/demos/vue +11 -0
  143. data/lib/rouge/demos/wollok +11 -0
  144. data/lib/rouge/demos/xml +2 -0
  145. data/lib/rouge/demos/yaml +4 -0
  146. data/lib/rouge/formatter.rb +76 -0
  147. data/lib/rouge/formatters/html.rb +38 -0
  148. data/lib/rouge/formatters/html_inline.rb +31 -0
  149. data/lib/rouge/formatters/html_legacy.rb +45 -0
  150. data/lib/rouge/formatters/html_linewise.rb +28 -0
  151. data/lib/rouge/formatters/html_pygments.rb +18 -0
  152. data/lib/rouge/formatters/html_table.rb +62 -0
  153. data/lib/rouge/formatters/null.rb +20 -0
  154. data/lib/rouge/formatters/terminal256.rb +181 -0
  155. data/lib/rouge/guesser.rb +57 -0
  156. data/lib/rouge/guessers/disambiguation.rb +106 -0
  157. data/lib/rouge/guessers/filename.rb +27 -0
  158. data/lib/rouge/guessers/glob_mapping.rb +45 -0
  159. data/lib/rouge/guessers/mimetype.rb +16 -0
  160. data/lib/rouge/guessers/modeline.rb +46 -0
  161. data/lib/rouge/guessers/source.rb +31 -0
  162. data/lib/rouge/guessers/util.rb +34 -0
  163. data/lib/rouge/lexer.rb +462 -0
  164. data/lib/rouge/lexers/abap.rb +240 -0
  165. data/lib/rouge/lexers/actionscript.rb +196 -0
  166. data/lib/rouge/lexers/alda.rb +43 -0
  167. data/lib/rouge/lexers/apache/keywords.yml +764 -0
  168. data/lib/rouge/lexers/apache.rb +73 -0
  169. data/lib/rouge/lexers/apiblueprint.rb +49 -0
  170. data/lib/rouge/lexers/apple_script.rb +369 -0
  171. data/lib/rouge/lexers/awk.rb +162 -0
  172. data/lib/rouge/lexers/biml.rb +43 -0
  173. data/lib/rouge/lexers/bsl.rb +82 -0
  174. data/lib/rouge/lexers/c.rb +213 -0
  175. data/lib/rouge/lexers/ceylon.rb +124 -0
  176. data/lib/rouge/lexers/cfscript.rb +154 -0
  177. data/lib/rouge/lexers/clojure.rb +113 -0
  178. data/lib/rouge/lexers/cmake.rb +207 -0
  179. data/lib/rouge/lexers/coffeescript.rb +175 -0
  180. data/lib/rouge/lexers/common_lisp.rb +346 -0
  181. data/lib/rouge/lexers/conf.rb +25 -0
  182. data/lib/rouge/lexers/console.rb +137 -0
  183. data/lib/rouge/lexers/coq.rb +188 -0
  184. data/lib/rouge/lexers/cpp.rb +79 -0
  185. data/lib/rouge/lexers/crystal.rb +430 -0
  186. data/lib/rouge/lexers/csharp.rb +115 -0
  187. data/lib/rouge/lexers/css.rb +274 -0
  188. data/lib/rouge/lexers/d.rb +177 -0
  189. data/lib/rouge/lexers/dart.rb +105 -0
  190. data/lib/rouge/lexers/diff.rb +33 -0
  191. data/lib/rouge/lexers/digdag.rb +70 -0
  192. data/lib/rouge/lexers/docker.rb +51 -0
  193. data/lib/rouge/lexers/dot.rb +69 -0
  194. data/lib/rouge/lexers/eiffel.rb +66 -0
  195. data/lib/rouge/lexers/elixir.rb +134 -0
  196. data/lib/rouge/lexers/elm.rb +90 -0
  197. data/lib/rouge/lexers/erb.rb +53 -0
  198. data/lib/rouge/lexers/erlang.rb +115 -0
  199. data/lib/rouge/lexers/factor.rb +303 -0
  200. data/lib/rouge/lexers/fortran.rb +178 -0
  201. data/lib/rouge/lexers/fsharp.rb +119 -0
  202. data/lib/rouge/lexers/gherkin/keywords.rb +16 -0
  203. data/lib/rouge/lexers/gherkin.rb +138 -0
  204. data/lib/rouge/lexers/glsl.rb +136 -0
  205. data/lib/rouge/lexers/go.rb +175 -0
  206. data/lib/rouge/lexers/gradle.rb +38 -0
  207. data/lib/rouge/lexers/graphql.rb +254 -0
  208. data/lib/rouge/lexers/groovy.rb +113 -0
  209. data/lib/rouge/lexers/hack.rb +49 -0
  210. data/lib/rouge/lexers/haml.rb +230 -0
  211. data/lib/rouge/lexers/handlebars.rb +80 -0
  212. data/lib/rouge/lexers/haskell.rb +198 -0
  213. data/lib/rouge/lexers/hcl.rb +163 -0
  214. data/lib/rouge/lexers/html.rb +140 -0
  215. data/lib/rouge/lexers/http.rb +81 -0
  216. data/lib/rouge/lexers/hylang.rb +94 -0
  217. data/lib/rouge/lexers/idlang.rb +312 -0
  218. data/lib/rouge/lexers/igorpro.rb +664 -0
  219. data/lib/rouge/lexers/ini.rb +54 -0
  220. data/lib/rouge/lexers/io.rb +69 -0
  221. data/lib/rouge/lexers/irb.rb +67 -0
  222. data/lib/rouge/lexers/java.rb +88 -0
  223. data/lib/rouge/lexers/javascript.rb +283 -0
  224. data/lib/rouge/lexers/jinja.rb +138 -0
  225. data/lib/rouge/lexers/json.rb +30 -0
  226. data/lib/rouge/lexers/json_doc.rb +24 -0
  227. data/lib/rouge/lexers/jsonnet.rb +152 -0
  228. data/lib/rouge/lexers/jsp.rb +120 -0
  229. data/lib/rouge/lexers/jsx.rb +104 -0
  230. data/lib/rouge/lexers/julia.rb +167 -0
  231. data/lib/rouge/lexers/kotlin.rb +127 -0
  232. data/lib/rouge/lexers/lasso/keywords.yml +446 -0
  233. data/lib/rouge/lexers/lasso.rb +215 -0
  234. data/lib/rouge/lexers/liquid.rb +288 -0
  235. data/lib/rouge/lexers/literate_coffeescript.rb +34 -0
  236. data/lib/rouge/lexers/literate_haskell.rb +37 -0
  237. data/lib/rouge/lexers/llvm.rb +81 -0
  238. data/lib/rouge/lexers/lua/builtins.rb +24 -0
  239. data/lib/rouge/lexers/lua.rb +126 -0
  240. data/lib/rouge/lexers/m68k.rb +144 -0
  241. data/lib/rouge/lexers/make.rb +113 -0
  242. data/lib/rouge/lexers/markdown.rb +155 -0
  243. data/lib/rouge/lexers/mathematica/builtins.rb +13 -0
  244. data/lib/rouge/lexers/mathematica.rb +96 -0
  245. data/lib/rouge/lexers/matlab/builtins.rb +13 -0
  246. data/lib/rouge/lexers/matlab.rb +72 -0
  247. data/lib/rouge/lexers/moonscript.rb +115 -0
  248. data/lib/rouge/lexers/mosel.rb +232 -0
  249. data/lib/rouge/lexers/mxml.rb +69 -0
  250. data/lib/rouge/lexers/nasm.rb +199 -0
  251. data/lib/rouge/lexers/nginx.rb +72 -0
  252. data/lib/rouge/lexers/nim.rb +153 -0
  253. data/lib/rouge/lexers/nix.rb +211 -0
  254. data/lib/rouge/lexers/objective_c.rb +195 -0
  255. data/lib/rouge/lexers/ocaml.rb +101 -0
  256. data/lib/rouge/lexers/pascal.rb +67 -0
  257. data/lib/rouge/lexers/perl.rb +201 -0
  258. data/lib/rouge/lexers/php/builtins.rb +196 -0
  259. data/lib/rouge/lexers/php.rb +194 -0
  260. data/lib/rouge/lexers/plain_text.rb +27 -0
  261. data/lib/rouge/lexers/plist.rb +47 -0
  262. data/lib/rouge/lexers/pony.rb +94 -0
  263. data/lib/rouge/lexers/powershell.rb +679 -0
  264. data/lib/rouge/lexers/praat.rb +351 -0
  265. data/lib/rouge/lexers/prolog.rb +61 -0
  266. data/lib/rouge/lexers/prometheus.rb +123 -0
  267. data/lib/rouge/lexers/properties.rb +52 -0
  268. data/lib/rouge/lexers/protobuf.rb +71 -0
  269. data/lib/rouge/lexers/puppet.rb +129 -0
  270. data/lib/rouge/lexers/python.rb +247 -0
  271. data/lib/rouge/lexers/q.rb +125 -0
  272. data/lib/rouge/lexers/qml.rb +74 -0
  273. data/lib/rouge/lexers/r.rb +90 -0
  274. data/lib/rouge/lexers/racket.rb +545 -0
  275. data/lib/rouge/lexers/ruby.rb +439 -0
  276. data/lib/rouge/lexers/rust.rb +198 -0
  277. data/lib/rouge/lexers/sass/common.rb +181 -0
  278. data/lib/rouge/lexers/sass.rb +75 -0
  279. data/lib/rouge/lexers/scala.rb +143 -0
  280. data/lib/rouge/lexers/scheme.rb +113 -0
  281. data/lib/rouge/lexers/scss.rb +35 -0
  282. data/lib/rouge/lexers/sed.rb +173 -0
  283. data/lib/rouge/lexers/shell.rb +190 -0
  284. data/lib/rouge/lexers/sieve.rb +97 -0
  285. data/lib/rouge/lexers/slim.rb +229 -0
  286. data/lib/rouge/lexers/smalltalk.rb +117 -0
  287. data/lib/rouge/lexers/smarty.rb +81 -0
  288. data/lib/rouge/lexers/sml.rb +345 -0
  289. data/lib/rouge/lexers/sqf/commands.rb +15 -0
  290. data/lib/rouge/lexers/sqf.rb +109 -0
  291. data/lib/rouge/lexers/sql.rb +141 -0
  292. data/lib/rouge/lexers/swift.rb +182 -0
  293. data/lib/rouge/lexers/tap.rb +89 -0
  294. data/lib/rouge/lexers/tcl.rb +193 -0
  295. data/lib/rouge/lexers/terraform.rb +105 -0
  296. data/lib/rouge/lexers/tex.rb +70 -0
  297. data/lib/rouge/lexers/toml.rb +68 -0
  298. data/lib/rouge/lexers/tsx.rb +20 -0
  299. data/lib/rouge/lexers/tulip.rb +108 -0
  300. data/lib/rouge/lexers/turtle.rb +64 -0
  301. data/lib/rouge/lexers/twig.rb +40 -0
  302. data/lib/rouge/lexers/typescript/common.rb +34 -0
  303. data/lib/rouge/lexers/typescript.rb +23 -0
  304. data/lib/rouge/lexers/vala.rb +78 -0
  305. data/lib/rouge/lexers/vb.rb +165 -0
  306. data/lib/rouge/lexers/verilog.rb +165 -0
  307. data/lib/rouge/lexers/vhdl.rb +98 -0
  308. data/lib/rouge/lexers/viml/keywords.rb +14 -0
  309. data/lib/rouge/lexers/viml.rb +102 -0
  310. data/lib/rouge/lexers/vue.rb +124 -0
  311. data/lib/rouge/lexers/wollok.rb +104 -0
  312. data/lib/rouge/lexers/xml.rb +58 -0
  313. data/lib/rouge/lexers/yaml.rb +374 -0
  314. data/lib/rouge/plugins/redcarpet.rb +31 -0
  315. data/lib/rouge/regex_lexer.rb +442 -0
  316. data/lib/rouge/template_lexer.rb +21 -0
  317. data/lib/rouge/text_analyzer.rb +50 -0
  318. data/lib/rouge/theme.rb +214 -0
  319. data/lib/rouge/themes/base16.rb +131 -0
  320. data/lib/rouge/themes/colorful.rb +68 -0
  321. data/lib/rouge/themes/github.rb +72 -0
  322. data/lib/rouge/themes/gruvbox.rb +168 -0
  323. data/lib/rouge/themes/igor_pro.rb +21 -0
  324. data/lib/rouge/themes/molokai.rb +83 -0
  325. data/lib/rouge/themes/monokai.rb +93 -0
  326. data/lib/rouge/themes/monokai_sublime.rb +92 -0
  327. data/lib/rouge/themes/pastie.rb +70 -0
  328. data/lib/rouge/themes/thankful_eyes.rb +75 -0
  329. data/lib/rouge/themes/tulip.rb +70 -0
  330. data/lib/rouge/token.rb +183 -0
  331. data/lib/rouge/util.rb +102 -0
  332. data/lib/rouge/version.rb +8 -0
  333. data/lib/rouge.rb +84 -0
  334. data/rouge.gemspec +25 -0
  335. metadata +384 -0
@@ -0,0 +1,442 @@
1
+ # -*- coding: utf-8 -*- #
2
+ # frozen_string_literal: true
3
+
4
+ module Rouge
5
+ # @abstract
6
+ # A stateful lexer that uses sets of regular expressions to
7
+ # tokenize a string. Most lexers are instances of RegexLexer.
8
+ class RegexLexer < Lexer
9
+ # A rule is a tuple of a regular expression to test, and a callback
10
+ # to perform if the test succeeds.
11
+ #
12
+ # @see StateDSL#rule
13
+ class Rule
14
+ attr_reader :callback
15
+ attr_reader :re
16
+ attr_reader :beginning_of_line
17
+ def initialize(re, callback)
18
+ @re = re
19
+ @callback = callback
20
+ @beginning_of_line = re.source[0] == ?^
21
+ end
22
+
23
+ def inspect
24
+ "#<Rule #{@re.inspect}>"
25
+ end
26
+ end
27
+
28
+ # a State is a named set of rules that can be tested for or
29
+ # mixed in.
30
+ #
31
+ # @see RegexLexer.state
32
+ class State
33
+ attr_reader :name, :rules
34
+ def initialize(name, rules)
35
+ @name = name
36
+ @rules = rules
37
+ end
38
+
39
+ def inspect
40
+ "#<#{self.class.name} #{@name.inspect}>"
41
+ end
42
+ end
43
+
44
+ class StateDSL
45
+ attr_reader :rules
46
+ def initialize(name, &defn)
47
+ @name = name
48
+ @defn = defn
49
+ @rules = []
50
+ @loaded = false
51
+ end
52
+
53
+ def to_state(lexer_class)
54
+ load!
55
+ rules = @rules.map do |rule|
56
+ rule.is_a?(String) ? lexer_class.get_state(rule) : rule
57
+ end
58
+ State.new(@name, rules)
59
+ end
60
+
61
+ def prepended(&defn)
62
+ parent_defn = @defn
63
+ StateDSL.new(@name) do
64
+ instance_eval(&defn)
65
+ instance_eval(&parent_defn)
66
+ end
67
+ end
68
+
69
+ def appended(&defn)
70
+ parent_defn = @defn
71
+ StateDSL.new(@name) do
72
+ instance_eval(&parent_defn)
73
+ instance_eval(&defn)
74
+ end
75
+ end
76
+
77
+ protected
78
+ # Define a new rule for this state.
79
+ #
80
+ # @overload rule(re, token, next_state=nil)
81
+ # @overload rule(re, &callback)
82
+ #
83
+ # @param [Regexp] re
84
+ # a regular expression for this rule to test.
85
+ # @param [String] tok
86
+ # the token type to yield if `re` matches.
87
+ # @param [#to_s] next_state
88
+ # (optional) a state to push onto the stack if `re` matches.
89
+ # If `next_state` is `:pop!`, the state stack will be popped
90
+ # instead.
91
+ # @param [Proc] callback
92
+ # a block that will be evaluated in the context of the lexer
93
+ # if `re` matches. This block has access to a number of lexer
94
+ # methods, including {RegexLexer#push}, {RegexLexer#pop!},
95
+ # {RegexLexer#token}, and {RegexLexer#delegate}. The first
96
+ # argument can be used to access the match groups.
97
+ def rule(re, tok=nil, next_state=nil, &callback)
98
+ if tok.nil? && callback.nil?
99
+ raise "please pass `rule` a token to yield or a callback"
100
+ end
101
+
102
+ callback ||= case next_state
103
+ when :pop!
104
+ proc do |stream|
105
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
106
+ @output_stream.call(tok, stream[0])
107
+ puts " popping stack: 1" if @debug
108
+ @stack.pop or raise 'empty stack!'
109
+ end
110
+ when :push
111
+ proc do |stream|
112
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
113
+ @output_stream.call(tok, stream[0])
114
+ puts " pushing :#{@stack.last.name}" if @debug
115
+ @stack.push(@stack.last)
116
+ end
117
+ when Symbol
118
+ proc do |stream|
119
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
120
+ @output_stream.call(tok, stream[0])
121
+ state = @states[next_state] || self.class.get_state(next_state)
122
+ puts " pushing :#{state.name}" if @debug
123
+ @stack.push(state)
124
+ end
125
+ when nil
126
+ proc do |stream|
127
+ puts " yielding #{tok.qualname}, #{stream[0].inspect}" if @debug
128
+ @output_stream.call(tok, stream[0])
129
+ end
130
+ else
131
+ raise "invalid next state: #{next_state.inspect}"
132
+ end
133
+
134
+ rules << Rule.new(re, callback)
135
+ end
136
+
137
+ # Mix in the rules from another state into this state. The rules
138
+ # from the mixed-in state will be tried in order before moving on
139
+ # to the rest of the rules in this state.
140
+ def mixin(state)
141
+ rules << state.to_s
142
+ end
143
+
144
+ private
145
+ def load!
146
+ return if @loaded
147
+ @loaded = true
148
+ instance_eval(&@defn)
149
+ end
150
+ end
151
+
152
+ # The states hash for this lexer.
153
+ # @see state
154
+ def self.states
155
+ @states ||= {}
156
+ end
157
+
158
+ def self.state_definitions
159
+ @state_definitions ||= InheritableHash.new(superclass.state_definitions)
160
+ end
161
+ @state_definitions = {}
162
+
163
+ def self.replace_state(name, new_defn)
164
+ states[name] = nil
165
+ state_definitions[name] = new_defn
166
+ end
167
+
168
+ # The routines to run at the beginning of a fresh lex.
169
+ # @see start
170
+ def self.start_procs
171
+ @start_procs ||= InheritableList.new(superclass.start_procs)
172
+ end
173
+ @start_procs = []
174
+
175
+ # Specify an action to be run every fresh lex.
176
+ #
177
+ # @example
178
+ # start { puts "I'm lexing a new string!" }
179
+ def self.start(&b)
180
+ start_procs << b
181
+ end
182
+
183
+ # Define a new state for this lexer with the given name.
184
+ # The block will be evaluated in the context of a {StateDSL}.
185
+ def self.state(name, &b)
186
+ name = name.to_s
187
+ state_definitions[name] = StateDSL.new(name, &b)
188
+ end
189
+
190
+ def self.prepend(name, &b)
191
+ name = name.to_s
192
+ dsl = state_definitions[name] or raise "no such state #{name.inspect}"
193
+ replace_state(name, dsl.prepended(&b))
194
+ end
195
+
196
+ def self.append(name, &b)
197
+ name = name.to_s
198
+ dsl = state_definitions[name] or raise "no such state #{name.inspect}"
199
+ replace_state(name, dsl.appended(&b))
200
+ end
201
+
202
+ # @private
203
+ def self.get_state(name)
204
+ return name if name.is_a? State
205
+
206
+ states[name.to_sym] ||= begin
207
+ defn = state_definitions[name.to_s] or raise "unknown state: #{name.inspect}"
208
+ defn.to_state(self)
209
+ end
210
+ end
211
+
212
+ # @private
213
+ def get_state(state_name)
214
+ self.class.get_state(state_name)
215
+ end
216
+
217
+ # The state stack. This is initially the single state `[:root]`.
218
+ # It is an error for this stack to be empty.
219
+ # @see #state
220
+ def stack
221
+ @stack ||= [get_state(:root)]
222
+ end
223
+
224
+ # The current state - i.e. one on top of the state stack.
225
+ #
226
+ # NB: if the state stack is empty, this will throw an error rather
227
+ # than returning nil.
228
+ def state
229
+ stack.last or raise 'empty stack!'
230
+ end
231
+
232
+ # reset this lexer to its initial state. This runs all of the
233
+ # start_procs.
234
+ def reset!
235
+ @stack = nil
236
+ @current_stream = nil
237
+
238
+ puts "start blocks" if @debug && self.class.start_procs.any?
239
+ self.class.start_procs.each do |pr|
240
+ instance_eval(&pr)
241
+ end
242
+ end
243
+
244
+ # This implements the lexer protocol, by yielding [token, value] pairs.
245
+ #
246
+ # The process for lexing works as follows, until the stream is empty:
247
+ #
248
+ # 1. We look at the state on top of the stack (which by default is
249
+ # `[:root]`).
250
+ # 2. Each rule in that state is tried until one is successful. If one
251
+ # is found, that rule's callback is evaluated - which may yield
252
+ # tokens and manipulate the state stack. Otherwise, one character
253
+ # is consumed with an `'Error'` token, and we continue at (1.)
254
+ #
255
+ # @see #step #step (where (2.) is implemented)
256
+ def stream_tokens(str, &b)
257
+ stream = StringScanner.new(str)
258
+
259
+ @current_stream = stream
260
+ @output_stream = b
261
+ @states = self.class.states
262
+ @null_steps = 0
263
+
264
+ until stream.eos?
265
+ if @debug
266
+ puts "lexer: #{self.class.tag}"
267
+ puts "stack: #{stack.map(&:name).map(&:to_sym).inspect}"
268
+ puts "stream: #{stream.peek(20).inspect}"
269
+ end
270
+
271
+ success = step(state, stream)
272
+
273
+ if !success
274
+ puts " no match, yielding Error" if @debug
275
+ b.call(Token::Tokens::Error, stream.getch)
276
+ end
277
+ end
278
+ end
279
+
280
+ # The number of successive scans permitted without consuming
281
+ # the input stream. If this is exceeded, the match fails.
282
+ MAX_NULL_SCANS = 5
283
+
284
+ # Runs one step of the lex. Rules in the current state are tried
285
+ # until one matches, at which point its callback is called.
286
+ #
287
+ # @return true if a rule was tried successfully
288
+ # @return false otherwise.
289
+ def step(state, stream)
290
+ state.rules.each do |rule|
291
+ if rule.is_a?(State)
292
+ puts " entering mixin #{rule.name}" if @debug
293
+ return true if step(rule, stream)
294
+ puts " exiting mixin #{rule.name}" if @debug
295
+ else
296
+ puts " trying #{rule.inspect}" if @debug
297
+
298
+ # XXX HACK XXX
299
+ # StringScanner's implementation of ^ is b0rken.
300
+ # see http://bugs.ruby-lang.org/issues/7092
301
+ # TODO: this doesn't cover cases like /(a|^b)/, but it's
302
+ # the most common, for now...
303
+ next if rule.beginning_of_line && !stream.beginning_of_line?
304
+
305
+ if (size = stream.skip(rule.re))
306
+ puts " got #{stream[0].inspect}" if @debug
307
+
308
+ instance_exec(stream, &rule.callback)
309
+
310
+ if size.zero?
311
+ @null_steps += 1
312
+ if @null_steps > MAX_NULL_SCANS
313
+ puts " too many scans without consuming the string!" if @debug
314
+ return false
315
+ end
316
+ else
317
+ @null_steps = 0
318
+ end
319
+
320
+ return true
321
+ end
322
+ end
323
+ end
324
+
325
+ false
326
+ end
327
+
328
+ # Yield a token.
329
+ #
330
+ # @param tok
331
+ # the token type
332
+ # @param val
333
+ # (optional) the string value to yield. If absent, this defaults
334
+ # to the entire last match.
335
+ def token(tok, val=@current_stream[0])
336
+ yield_token(tok, val)
337
+ end
338
+
339
+ # @deprecated
340
+ #
341
+ # Yield a token with the next matched group. Subsequent calls
342
+ # to this method will yield subsequent groups.
343
+ def group(tok)
344
+ raise "RegexLexer#group is deprecated: use #groups instead"
345
+ end
346
+
347
+ # Yield tokens corresponding to the matched groups of the current
348
+ # match.
349
+ def groups(*tokens)
350
+ tokens.each_with_index do |tok, i|
351
+ yield_token(tok, @current_stream[i+1])
352
+ end
353
+ end
354
+
355
+ # Delegate the lex to another lexer. The #lex method will be called
356
+ # with `:continue` set to true, so that #reset! will not be called.
357
+ # In this way, a single lexer can be repeatedly delegated to while
358
+ # maintaining its own internal state stack.
359
+ #
360
+ # @param [#lex] lexer
361
+ # The lexer or lexer class to delegate to
362
+ # @param [String] text
363
+ # The text to delegate. This defaults to the last matched string.
364
+ def delegate(lexer, text=nil)
365
+ puts " delegating to #{lexer.inspect}" if @debug
366
+ text ||= @current_stream[0]
367
+
368
+ lexer.lex(text, :continue => true) do |tok, val|
369
+ puts " delegated token: #{tok.inspect}, #{val.inspect}" if @debug
370
+ yield_token(tok, val)
371
+ end
372
+ end
373
+
374
+ def recurse(text=nil)
375
+ delegate(self.class, text)
376
+ end
377
+
378
+ # Push a state onto the stack. If no state name is given and you've
379
+ # passed a block, a state will be dynamically created using the
380
+ # {StateDSL}.
381
+ def push(state_name=nil, &b)
382
+ push_state = if state_name
383
+ get_state(state_name)
384
+ elsif block_given?
385
+ StateDSL.new(b.inspect, &b).to_state(self.class)
386
+ else
387
+ # use the top of the stack by default
388
+ self.state
389
+ end
390
+
391
+ puts " pushing :#{push_state.name}" if @debug
392
+ stack.push(push_state)
393
+ end
394
+
395
+ # Pop the state stack. If a number is passed in, it will be popped
396
+ # that number of times.
397
+ def pop!(times=1)
398
+ raise 'empty stack!' if stack.empty?
399
+
400
+ puts " popping stack: #{times}" if @debug
401
+
402
+ stack.pop(times)
403
+
404
+ nil
405
+ end
406
+
407
+ # replace the head of the stack with the given state
408
+ def goto(state_name)
409
+ raise 'empty stack!' if stack.empty?
410
+
411
+ puts " going to state :#{state_name} " if @debug
412
+ stack[-1] = get_state(state_name)
413
+ end
414
+
415
+ # reset the stack back to `[:root]`.
416
+ def reset_stack
417
+ puts ' resetting stack' if @debug
418
+ stack.clear
419
+ stack.push get_state(:root)
420
+ end
421
+
422
+ # Check if `state_name` is in the state stack.
423
+ def in_state?(state_name)
424
+ state_name = state_name.to_s
425
+ stack.any? do |state|
426
+ state.name == state_name.to_s
427
+ end
428
+ end
429
+
430
+ # Check if `state_name` is the state on top of the state stack.
431
+ def state?(state_name)
432
+ state_name.to_s == state.name
433
+ end
434
+
435
+ private
436
+ def yield_token(tok, val)
437
+ return if val.nil? || val.empty?
438
+ puts " yielding #{tok.qualname}, #{val.inspect}" if @debug
439
+ @output_stream.yield(tok, val)
440
+ end
441
+ end
442
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*- #
2
+ # frozen_string_literal: true
3
+
4
+ module Rouge
5
+ # @abstract
6
+ # A TemplateLexer is one that accepts a :parent option, to specify
7
+ # which language is being templated. The lexer class can specify its
8
+ # own default for the parent lexer, which is otherwise defaulted to
9
+ # HTML.
10
+ class TemplateLexer < RegexLexer
11
+ # the parent lexer - the one being templated.
12
+ def parent
13
+ return @parent if instance_variable_defined? :@parent
14
+ @parent = lexer_option(:parent) || Lexers::HTML.new(@options)
15
+ end
16
+
17
+ option :parent, "the parent language (default: html)"
18
+
19
+ start { parent.reset! }
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ # -*- coding: utf-8 -*- #
2
+ # frozen_string_literal: true
3
+
4
+ module Rouge
5
+ class TextAnalyzer < String
6
+ # Find a shebang. Returns nil if no shebang is present.
7
+ def shebang
8
+ return @shebang if instance_variable_defined? :@shebang
9
+
10
+ self =~ /\A\s*#!(.*)$/
11
+ @shebang = $1
12
+ end
13
+
14
+ # Check if the given shebang is present.
15
+ #
16
+ # This normalizes things so that `text.shebang?('bash')` will detect
17
+ # `#!/bash`, '#!/bin/bash', '#!/usr/bin/env bash', and '#!/bin/bash -x'
18
+ def shebang?(match)
19
+ return false unless shebang
20
+ match = /\b#{match}(\s|$)/
21
+ match === shebang
22
+ end
23
+
24
+ # Return the contents of the doctype tag if present, nil otherwise.
25
+ def doctype
26
+ return @doctype if instance_variable_defined? :@doctype
27
+
28
+ self =~ %r(\A\s*
29
+ (?:<\?.*?\?>\s*)? # possible <?xml...?> tag
30
+ <!DOCTYPE\s+(.+?)>
31
+ )xm
32
+ @doctype = $1
33
+ end
34
+
35
+ # Check if the doctype matches a given regexp or string
36
+ def doctype?(type=//)
37
+ type === doctype
38
+ end
39
+
40
+ # Return true if the result of lexing with the given lexer contains no
41
+ # error tokens.
42
+ def lexes_cleanly?(lexer)
43
+ lexer.lex(self) do |(tok, _)|
44
+ return false if tok.name == 'Error'
45
+ end
46
+
47
+ true
48
+ end
49
+ end
50
+ end