puppet 0.24.1 → 0.24.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (266) hide show
  1. data/CHANGELOG +94 -0
  2. data/Rakefile +0 -4
  3. data/bin/puppet +18 -10
  4. data/bin/puppetd +1 -1
  5. data/bin/puppetdoc +14 -4
  6. data/bin/puppetmasterd +1 -1
  7. data/bin/puppetrun +3 -8
  8. data/bin/ralsh +12 -11
  9. data/conf/freebsd/puppetd +1 -1
  10. data/conf/freebsd/puppetmasterd +1 -1
  11. data/conf/gentoo/puppet/puppet.conf +29 -0
  12. data/conf/namespaceauth.conf +20 -0
  13. data/conf/redhat/puppet.spec +4 -1
  14. data/conf/solaris/smf/puppetd.xml +1 -1
  15. data/conf/solaris/smf/puppetmasterd.xml +1 -1
  16. data/conf/suse/puppet.spec +10 -8
  17. data/examples/root/etc/puppet/{puppetmasterd.conf → puppet.conf} +6 -3
  18. data/ext/logcheck/puppet +7 -0
  19. data/ext/puppet-test +28 -5
  20. data/lib/puppet.rb +2 -1
  21. data/lib/puppet/defaults.rb +12 -5
  22. data/lib/puppet/dsl.rb +43 -45
  23. data/lib/puppet/external/{gratr/rdot.rb → dot.rb} +0 -0
  24. data/lib/puppet/external/nagios.rb +50 -0
  25. data/lib/puppet/external/nagios/base.rb +421 -0
  26. data/lib/puppet/external/nagios/parser.rb +816 -0
  27. data/lib/puppet/file_serving/file_base.rb +16 -3
  28. data/lib/puppet/file_serving/metadata.rb +29 -11
  29. data/lib/puppet/indirector/terminus.rb +1 -0
  30. data/lib/puppet/metatype/closure.rb +4 -0
  31. data/lib/puppet/metatype/evaluation.rb +2 -17
  32. data/lib/puppet/metatype/metaparams.rb +1 -1
  33. data/lib/puppet/network.rb +3 -0
  34. data/lib/puppet/network/client.rb +4 -5
  35. data/lib/puppet/network/client/master.rb +10 -7
  36. data/lib/puppet/network/handler/fileserver.rb +22 -45
  37. data/lib/puppet/network/http_pool.rb +3 -0
  38. data/lib/puppet/network/http_server/mongrel.rb +7 -1
  39. data/lib/puppet/network/http_server/webrick.rb +4 -3
  40. data/lib/puppet/network/xmlrpc/client.rb +12 -1
  41. data/lib/puppet/node/catalog.rb +51 -40
  42. data/lib/puppet/parser/ast.rb +27 -49
  43. data/lib/puppet/parser/ast/astarray.rb +5 -24
  44. data/lib/puppet/parser/ast/caseopt.rb +4 -4
  45. data/lib/puppet/parser/ast/casestatement.rb +4 -5
  46. data/lib/puppet/parser/ast/collection.rb +3 -5
  47. data/lib/puppet/parser/ast/collexpr.rb +3 -5
  48. data/lib/puppet/parser/ast/definition.rb +148 -159
  49. data/lib/puppet/parser/ast/else.rb +2 -3
  50. data/lib/puppet/parser/ast/function.rb +3 -10
  51. data/lib/puppet/parser/ast/hostclass.rb +66 -59
  52. data/lib/puppet/parser/ast/ifstatement.rb +4 -5
  53. data/lib/puppet/parser/ast/leaf.rb +6 -6
  54. data/lib/puppet/parser/ast/node.rb +26 -58
  55. data/lib/puppet/parser/ast/resource.rb +5 -7
  56. data/lib/puppet/parser/ast/resource_defaults.rb +2 -4
  57. data/lib/puppet/parser/ast/resource_override.rb +4 -6
  58. data/lib/puppet/parser/ast/resource_reference.rb +2 -4
  59. data/lib/puppet/parser/ast/resourceparam.rb +2 -4
  60. data/lib/puppet/parser/ast/selector.rb +5 -6
  61. data/lib/puppet/parser/ast/tag.rb +2 -4
  62. data/lib/puppet/parser/ast/vardef.rb +3 -4
  63. data/lib/puppet/parser/collector.rb +5 -5
  64. data/lib/puppet/parser/{compile.rb → compiler.rb} +69 -107
  65. data/lib/puppet/parser/functions.rb +3 -3
  66. data/lib/puppet/parser/interpreter.rb +32 -23
  67. data/lib/puppet/parser/lexer.rb +391 -282
  68. data/lib/puppet/parser/parser.rb +5 -4
  69. data/lib/puppet/parser/parser_support.rb +3 -6
  70. data/lib/puppet/parser/resource.rb +24 -36
  71. data/lib/puppet/parser/resource/param.rb +1 -1
  72. data/lib/puppet/parser/resource/reference.rb +7 -3
  73. data/lib/puppet/parser/scope.rb +12 -7
  74. data/lib/puppet/parser/templatewrapper.rb +1 -1
  75. data/lib/puppet/pgraph.rb +9 -98
  76. data/lib/puppet/provider/interface/redhat.rb +65 -65
  77. data/lib/puppet/provider/mount/parsed.rb +1 -1
  78. data/lib/puppet/provider/naginator.rb +55 -0
  79. data/lib/puppet/provider/nameservice/directoryservice.rb +6 -7
  80. data/lib/puppet/provider/package/fink.rb +0 -2
  81. data/lib/puppet/provider/package/gem.rb +9 -5
  82. data/lib/puppet/provider/package/openbsd.rb +1 -1
  83. data/lib/puppet/provider/package/pkgdmg.rb +3 -8
  84. data/lib/puppet/provider/package/portage.rb +4 -4
  85. data/lib/puppet/provider/package/yumhelper.py +8 -6
  86. data/lib/puppet/provider/parsedfile.rb +7 -1
  87. data/lib/puppet/provider/service/debian.rb +2 -0
  88. data/lib/puppet/provider/service/gentoo.rb +4 -0
  89. data/lib/puppet/provider/service/init.rb +1 -1
  90. data/lib/puppet/provider/sshkey/parsed.rb +2 -0
  91. data/lib/puppet/provider/user/useradd.rb +1 -1
  92. data/lib/puppet/rails.rb +4 -0
  93. data/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb +17 -0
  94. data/lib/puppet/rails/fact_value.rb +4 -0
  95. data/lib/puppet/rails/host.rb +1 -2
  96. data/lib/puppet/rails/param_value.rb +4 -0
  97. data/lib/puppet/rails/resource_tag.rb +4 -0
  98. data/lib/puppet/rails/source_file.rb +4 -1
  99. data/lib/puppet/relationship.rb +5 -1
  100. data/lib/puppet/reports/tagmail.rb +12 -1
  101. data/lib/puppet/resource_reference.rb +1 -1
  102. data/lib/puppet/simple_graph.rb +78 -11
  103. data/lib/puppet/sslcertificates.rb +1 -1
  104. data/lib/puppet/sslcertificates/ca.rb +3 -3
  105. data/lib/puppet/transaction.rb +7 -4
  106. data/lib/puppet/transportable.rb +1 -1
  107. data/lib/puppet/type.rb +3 -10
  108. data/lib/puppet/type/cron.rb +18 -0
  109. data/lib/puppet/type/exec.rb +18 -12
  110. data/lib/puppet/type/{pfile.rb → file.rb} +66 -84
  111. data/lib/puppet/type/file/checksum.rb +271 -0
  112. data/lib/puppet/type/{pfile → file}/content.rb +10 -15
  113. data/lib/puppet/type/{pfile → file}/ensure.rb +15 -8
  114. data/lib/puppet/type/{pfile → file}/group.rb +0 -0
  115. data/lib/puppet/type/{pfile → file}/mode.rb +0 -0
  116. data/lib/puppet/type/{pfile → file}/owner.rb +0 -0
  117. data/lib/puppet/type/{pfile → file}/source.rb +34 -48
  118. data/lib/puppet/type/{pfile → file}/target.rb +0 -0
  119. data/lib/puppet/type/{pfile → file}/type.rb +0 -0
  120. data/lib/puppet/type/{pfilebucket.rb → filebucket.rb} +0 -0
  121. data/lib/puppet/type/host.rb +13 -0
  122. data/lib/puppet/type/mailalias.rb +1 -1
  123. data/lib/puppet/type/nagios_command.rb +3 -0
  124. data/lib/puppet/type/nagios_contact.rb +3 -0
  125. data/lib/puppet/type/nagios_contactgroup.rb +3 -0
  126. data/lib/puppet/type/nagios_host.rb +3 -0
  127. data/lib/puppet/type/nagios_hostextinfo.rb +3 -0
  128. data/lib/puppet/type/nagios_hostgroup.rb +3 -0
  129. data/lib/puppet/type/nagios_hostgroupescalation.rb +3 -0
  130. data/lib/puppet/type/nagios_service.rb +3 -0
  131. data/lib/puppet/type/nagios_servicedependency.rb +3 -0
  132. data/lib/puppet/type/nagios_serviceescalation.rb +3 -0
  133. data/lib/puppet/type/nagios_serviceextinfo.rb +3 -0
  134. data/lib/puppet/type/nagios_timeperiod.rb +3 -0
  135. data/lib/puppet/type/package.rb +4 -12
  136. data/lib/puppet/type/service.rb +9 -0
  137. data/lib/puppet/type/sshkey.rb +3 -3
  138. data/lib/puppet/util/autoload.rb +5 -5
  139. data/lib/puppet/util/checksums.rb +51 -13
  140. data/lib/puppet/util/constant_inflector.rb +14 -0
  141. data/lib/puppet/util/filetype.rb +1 -1
  142. data/lib/puppet/util/graph.rb +3 -9
  143. data/lib/puppet/util/nagios_maker.rb +57 -0
  144. data/lib/puppet/util/settings.rb +19 -16
  145. data/lib/puppet/util/tagging.rb +39 -0
  146. data/test/executables/puppetbin.rb +17 -0
  147. data/test/language/ast.rb +8 -58
  148. data/test/language/ast/casestatement.rb +3 -3
  149. data/test/language/ast/resource.rb +6 -7
  150. data/test/language/ast/resource_reference.rb +12 -12
  151. data/test/language/ast/selector.rb +2 -2
  152. data/test/language/ast/variable.rb +2 -2
  153. data/test/language/functions.rb +24 -24
  154. data/test/language/parser.rb +20 -8
  155. data/test/language/resource.rb +5 -42
  156. data/test/language/scope.rb +21 -37
  157. data/test/language/snippets.rb +7 -0
  158. data/test/lib/puppettest.rb +28 -14
  159. data/test/lib/puppettest/parsertesting.rb +10 -10
  160. data/test/lib/puppettest/support/resources.rb +1 -1
  161. data/test/network/client/master.rb +10 -0
  162. data/test/network/handler/fileserver.rb +51 -49
  163. data/test/network/server/webrick.rb +1 -1
  164. data/test/other/dsl.rb +3 -4
  165. data/test/other/transactions.rb +6 -4
  166. data/test/rails/ast.rb +2 -2
  167. data/test/rails/configuration.rb +1 -1
  168. data/test/rails/railsparameter.rb +2 -0
  169. data/test/rails/railsresource.rb +1 -0
  170. data/test/ral/manager/type.rb +4 -4
  171. data/test/ral/providers/cron/crontab.rb +3 -1
  172. data/test/ral/providers/package.rb +1 -1
  173. data/test/ral/{types → type}/basic.rb +2 -2
  174. data/test/ral/{types → type}/cron.rb +0 -0
  175. data/test/ral/{types → type}/exec.rb +42 -2
  176. data/test/ral/{types → type}/file.rb +34 -79
  177. data/test/ral/{types → type}/file/target.rb +0 -0
  178. data/test/ral/{types → type}/filebucket.rb +0 -0
  179. data/test/ral/{types → type}/fileignoresource.rb +0 -0
  180. data/test/ral/{types → type}/filesources.rb +8 -27
  181. data/test/ral/{types → type}/group.rb +0 -0
  182. data/test/ral/{types → type}/host.rb +16 -0
  183. data/test/ral/{types → type}/mailalias.rb +0 -0
  184. data/test/ral/{types → type}/parameter.rb +0 -0
  185. data/test/ral/{types → type}/port.rb +0 -0
  186. data/test/ral/{types → type}/property.rb +0 -0
  187. data/test/ral/{types → type}/resources.rb +0 -0
  188. data/test/ral/{types → type}/service.rb +0 -0
  189. data/test/ral/{types → type}/sshkey.rb +0 -0
  190. data/test/ral/{types → type}/tidy.rb +1 -0
  191. data/test/ral/{types → type}/user.rb +0 -0
  192. data/test/ral/{types → type}/yumrepo.rb +0 -0
  193. data/test/ral/{types → type}/zone.rb +0 -0
  194. data/test/util/autoload.rb +24 -5
  195. metadata +60 -107
  196. data/conf/gentoo/puppet/puppetca.conf +0 -29
  197. data/conf/gentoo/puppet/puppetd.conf +0 -29
  198. data/conf/gentoo/puppet/puppetmasterd.conf +0 -29
  199. data/examples/root/etc/puppet/puppetd.conf +0 -4
  200. data/lib/puppet/external/gratr.rb +0 -33
  201. data/lib/puppet/external/gratr/adjacency_graph.rb +0 -257
  202. data/lib/puppet/external/gratr/base.rb +0 -34
  203. data/lib/puppet/external/gratr/biconnected.rb +0 -116
  204. data/lib/puppet/external/gratr/chinese_postman.rb +0 -123
  205. data/lib/puppet/external/gratr/common.rb +0 -73
  206. data/lib/puppet/external/gratr/comparability.rb +0 -92
  207. data/lib/puppet/external/gratr/digraph.rb +0 -116
  208. data/lib/puppet/external/gratr/digraph_distance.rb +0 -185
  209. data/lib/puppet/external/gratr/dot.rb +0 -90
  210. data/lib/puppet/external/gratr/edge.rb +0 -145
  211. data/lib/puppet/external/gratr/graph.rb +0 -303
  212. data/lib/puppet/external/gratr/graph_api.rb +0 -83
  213. data/lib/puppet/external/gratr/import.rb +0 -44
  214. data/lib/puppet/external/gratr/labels.rb +0 -90
  215. data/lib/puppet/external/gratr/maximum_flow.rb +0 -64
  216. data/lib/puppet/external/gratr/search.rb +0 -409
  217. data/lib/puppet/external/gratr/strong_components.rb +0 -127
  218. data/lib/puppet/external/gratr/undirected_graph.rb +0 -153
  219. data/lib/puppet/rails/external/tagging/acts_as_taggable.rb +0 -62
  220. data/lib/puppet/rails/external/tagging/init.rb +0 -5
  221. data/lib/puppet/rails/external/tagging/tag.rb +0 -50
  222. data/lib/puppet/rails/external/tagging/tagging.rb +0 -12
  223. data/lib/puppet/rails/puppet_class.rb +0 -6
  224. data/lib/puppet/reference/node_source.rb +0 -9
  225. data/lib/puppet/reference/report.rb +0 -21
  226. data/lib/puppet/type/pfile/checksum.rb +0 -326
  227. data/test/language/ast/definition.rb +0 -166
  228. data/test/language/ast/hostclass.rb +0 -184
  229. data/test/language/compile.rb +0 -569
  230. data/test/language/lexer.rb +0 -276
  231. data/test/lib/mocha.rb +0 -19
  232. data/test/lib/mocha/any_instance_method.rb +0 -35
  233. data/test/lib/mocha/auto_verify.rb +0 -113
  234. data/test/lib/mocha/central.rb +0 -35
  235. data/test/lib/mocha/class_method.rb +0 -62
  236. data/test/lib/mocha/deprecation.rb +0 -22
  237. data/test/lib/mocha/exception_raiser.rb +0 -17
  238. data/test/lib/mocha/expectation.rb +0 -378
  239. data/test/lib/mocha/expectation_error.rb +0 -6
  240. data/test/lib/mocha/infinite_range.rb +0 -25
  241. data/test/lib/mocha/inspect.rb +0 -39
  242. data/test/lib/mocha/instance_method.rb +0 -8
  243. data/test/lib/mocha/is_a.rb +0 -9
  244. data/test/lib/mocha/metaclass.rb +0 -7
  245. data/test/lib/mocha/missing_expectation.rb +0 -27
  246. data/test/lib/mocha/mock.rb +0 -207
  247. data/test/lib/mocha/multiple_yields.rb +0 -20
  248. data/test/lib/mocha/no_yields.rb +0 -11
  249. data/test/lib/mocha/object.rb +0 -110
  250. data/test/lib/mocha/parameter_matchers.rb +0 -9
  251. data/test/lib/mocha/parameter_matchers/all_of.rb +0 -39
  252. data/test/lib/mocha/parameter_matchers/any_of.rb +0 -44
  253. data/test/lib/mocha/parameter_matchers/anything.rb +0 -30
  254. data/test/lib/mocha/parameter_matchers/has_entry.rb +0 -39
  255. data/test/lib/mocha/parameter_matchers/has_key.rb +0 -39
  256. data/test/lib/mocha/parameter_matchers/has_value.rb +0 -39
  257. data/test/lib/mocha/parameter_matchers/includes.rb +0 -37
  258. data/test/lib/mocha/pretty_parameters.rb +0 -28
  259. data/test/lib/mocha/return_values.rb +0 -31
  260. data/test/lib/mocha/setup_and_teardown.rb +0 -23
  261. data/test/lib/mocha/single_return_value.rb +0 -24
  262. data/test/lib/mocha/single_yield.rb +0 -18
  263. data/test/lib/mocha/standalone.rb +0 -32
  264. data/test/lib/mocha/stub.rb +0 -18
  265. data/test/lib/mocha/test_case_adapter.rb +0 -49
  266. data/test/lib/mocha/yield_parameters.rb +0 -31
@@ -1,4 +1,3 @@
1
-
2
1
  # the scanner/lexer
3
2
 
4
3
  require 'strscan'
@@ -7,326 +6,436 @@ require 'puppet'
7
6
 
8
7
  module Puppet
9
8
  class LexError < RuntimeError; end
10
- module Parser
11
- #---------------------------------------------------------------
12
- class Lexer
13
- attr_reader :line, :last, :file
14
-
15
- attr_accessor :indefine
16
-
17
- #%r{\w+} => :WORD,
18
- @@tokens = {
19
- %r{#.*} => :COMMENT,
20
- %r{\[} => :LBRACK,
21
- %r{\]} => :RBRACK,
22
- %r{\{} => :LBRACE,
23
- %r{\}} => :RBRACE,
24
- %r{\(} => :LPAREN,
25
- %r{\)} => :RPAREN,
26
- %r{\"} => :DQUOTE,
27
- %r{\n} => :RETURN,
28
- %r{\'} => :SQUOTE,
29
- %r{=} => :EQUALS,
30
- %r{==} => :ISEQUAL,
31
- %r{>=} => :GREATEREQUAL,
32
- %r{>} => :GREATERTHAN,
33
- %r{<} => :LESSTHAN,
34
- %r{<=} => :LESSEQUAL,
35
- %r{!=} => :NOTEQUAL,
36
- %r{!} => :NOT,
37
- %r{,} => :COMMA,
38
- %r{\.} => :DOT,
39
- %r{:} => :COLON,
40
- %r{@} => :AT,
41
- %r{<<\|} => :LLCOLLECT,
42
- %r{\|>>} => :RRCOLLECT,
43
- %r{<\|} => :LCOLLECT,
44
- %r{\|>} => :RCOLLECT,
45
- %r{;} => :SEMIC,
46
- %r{\?} => :QMARK,
47
- %r{\\} => :BACKSLASH,
48
- %r{=>} => :FARROW,
49
- %r{\+>} => :PARROW,
50
- %r{[a-z][-\w]*} => :NAME,
51
- %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME,
52
- %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
53
- %r{[0-9]+} => :NUMBER,
54
- %r{\$(\w*::)*\w+} => :VARIABLE
55
- }
56
-
57
- @@pairs = {
58
- "{" => "}",
59
- "(" => ")",
60
- "[" => "]",
61
- "<|" => "|>",
62
- "<<|" => "|>>"
63
- }
64
-
65
- @@reverse_pairs = @@pairs.inject({}) { |hash, pair| hash[pair[1]] = pair[0]; hash }
66
-
67
- @@keywords = {
68
- "case" => :CASE,
69
- "class" => :CLASS,
70
- "default" => :DEFAULT,
71
- "define" => :DEFINE,
72
- "false" => :BOOLEAN,
73
- "import" => :IMPORT,
74
- "if" => :IF,
75
- "elsif" => :ELSIF,
76
- "else" => :ELSE,
77
- "inherits" => :INHERITS,
78
- "node" => :NODE,
79
- "true" => :BOOLEAN,
80
- "and" => :AND,
81
- "or" => :OR,
82
- "undef" => :UNDEF
83
- }
84
-
85
- def clear
86
- initvars
87
- end
9
+ end
88
10
 
89
- def expected
90
- if @expected.empty?
91
- nil
92
- else
93
- token = @expected[-1]
94
- @@tokens.each do |value, name|
95
- if token == name
96
- return value
97
- end
98
- end
99
- return token
100
- end
101
- end
11
+ module Puppet::Parser; end
102
12
 
103
- # scan the whole file
104
- # basically just used for testing
105
- def fullscan
106
- array = []
107
-
108
- self.scan { |token,str|
109
- # Ignore any definition nesting problems
110
- @indefine = false
111
- #Puppet.debug("got token '%s' => '%s'" % [token,str])
112
- if token.nil?
113
- return array
114
- else
115
- array.push([token,str])
116
- end
117
- }
118
- return array
13
+ class Puppet::Parser::Lexer
14
+ attr_reader :last, :file
15
+
16
+ attr_accessor :line, :indefine
17
+
18
+ # Our base token class.
19
+ class Token
20
+ attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text
21
+
22
+ def initialize(regex, name)
23
+ if regex.is_a?(String)
24
+ @name, @string = name, regex
25
+ @regex = Regexp.new(Regexp.escape(@string))
26
+ else
27
+ @name, @regex = name, regex
119
28
  end
29
+ end
120
30
 
121
- # this is probably pretty damned inefficient...
122
- # it'd be nice not to have to load the whole file first...
123
- def file=(file)
124
- @file = file
125
- @line = 1
126
- File.open(file) { |of|
127
- str = ""
128
- of.each { |line| str += line }
129
- @scanner = StringScanner.new(str)
130
- }
31
+ def skip?
32
+ self.skip
33
+ end
34
+
35
+ def to_s
36
+ if self.string
37
+ @string
38
+ else
39
+ @name.to_s
131
40
  end
41
+ end
42
+ end
132
43
 
133
- def indefine?
134
- if defined? @indefine
135
- @indefine
136
- else
137
- false
138
- end
44
+ # Maintain a list of tokens.
45
+ class TokenList
46
+ attr_reader :regex_tokens, :string_tokens
47
+
48
+ def [](name)
49
+ @tokens[name]
50
+ end
51
+
52
+ # Create a new token.
53
+ def add_token(name, regex, options = {}, &block)
54
+ token = Token.new(regex, name)
55
+ raise(ArgumentError, "Token %s already exists" % name) if @tokens.include?(name)
56
+ @tokens[token.name] = token
57
+ if token.string
58
+ @string_tokens << token
59
+ @tokens_by_string[token.string] = token
60
+ else
61
+ @regex_tokens << token
139
62
  end
140
63
 
141
- def initialize
142
- initvars()
64
+ options.each do |name, option|
65
+ token.send(name.to_s + "=", option)
143
66
  end
144
67
 
145
- def initvars
146
- @line = 1
147
- @last = ""
148
- @lasttoken = nil
149
- @scanner = nil
150
- @file = nil
151
- # AAARRGGGG! okay, regexes in ruby are bloody annoying
152
- # no one else has "\n" =~ /\s/
153
- @skip = %r{[ \t]+}
68
+ token.meta_def(:convert, &block) if block_given?
69
+
70
+ token
71
+ end
154
72
 
155
- @namestack = []
156
- @indefine = false
73
+ def initialize
74
+ @tokens = {}
75
+ @regex_tokens = []
76
+ @string_tokens = []
77
+ @tokens_by_string = {}
78
+ end
157
79
 
158
- @expected = []
159
- end
80
+ # Look up a token by its value, rather than name.
81
+ def lookup(string)
82
+ @tokens_by_string[string]
83
+ end
160
84
 
161
- # Go up one in the namespace.
162
- def namepop
163
- @namestack.pop
85
+ # Define more tokens.
86
+ def add_tokens(hash)
87
+ hash.each do |regex, name|
88
+ add_token(name, regex)
164
89
  end
90
+ end
165
91
 
166
- # Collect the current namespace.
167
- def namespace
168
- @namestack.join("::")
92
+ # Sort our tokens by length, so we know once we match, we're done.
93
+ # This helps us avoid the O(n^2) nature of token matching.
94
+ def sort_tokens
95
+ @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
96
+ end
97
+ end
98
+
99
+ TOKENS = TokenList.new
100
+ TOKENS.add_tokens(
101
+ '[' => :LBRACK,
102
+ ']' => :RBRACK,
103
+ '{' => :LBRACE,
104
+ '}' => :RBRACE,
105
+ '(' => :LPAREN,
106
+ ')' => :RPAREN,
107
+ '=' => :EQUALS,
108
+ '==' => :ISEQUAL,
109
+ '>=' => :GREATEREQUAL,
110
+ '>' => :GREATERTHAN,
111
+ '<' => :LESSTHAN,
112
+ '<=' => :LESSEQUAL,
113
+ '!=' => :NOTEQUAL,
114
+ '!' => :NOT,
115
+ ',' => :COMMA,
116
+ '.' => :DOT,
117
+ ':' => :COLON,
118
+ '@' => :AT,
119
+ '<<|' => :LLCOLLECT,
120
+ '|>>' => :RRCOLLECT,
121
+ '<|' => :LCOLLECT,
122
+ '|>' => :RCOLLECT,
123
+ ';' => :SEMIC,
124
+ '?' => :QMARK,
125
+ '\\' => :BACKSLASH,
126
+ '=>' => :FARROW,
127
+ '+>' => :PARROW,
128
+ %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME,
129
+ %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF
130
+ )
131
+
132
+ TOKENS.add_tokens "Whatever" => :DQTEXT, "Nomatter" => :SQTEXT, "alsonomatter" => :BOOLEAN
133
+
134
+ TOKENS.add_token :NAME, %r{[a-z][-\w]*} do |lexer, value|
135
+ string_token = self
136
+ # we're looking for keywords here
137
+ if tmp = KEYWORDS.lookup(value)
138
+ string_token = tmp
139
+ if [:TRUE, :FALSE].include?(string_token.name)
140
+ value = eval(value)
141
+ string_token = TOKENS[:BOOLEAN]
169
142
  end
143
+ end
144
+ [string_token, value]
145
+ end
146
+
147
+ TOKENS.add_token :NUMBER, %r{[0-9]+} do |lexer, value|
148
+ [TOKENS[:NAME], value]
149
+ end
150
+
151
+ TOKENS.add_token :COMMENT, %r{#.*}, :skip => true
152
+
153
+ TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true
154
+
155
+ TOKENS.add_token :SQUOTE, "'" do |lexer, value|
156
+ value = lexer.slurpstring(value)
157
+ [TOKENS[:SQTEXT], value]
158
+ end
159
+
160
+ TOKENS.add_token :DQUOTE, '"' do |lexer, value|
161
+ value = lexer.slurpstring(value)
162
+ [TOKENS[:DQTEXT], value]
163
+ end
164
+
165
+ TOKENS.add_token :VARIABLE, %r{\$(\w*::)*\w+} do |lexer, value|
166
+ value = value.sub(/^\$/, '')
167
+ [self, value]
168
+ end
169
+
170
+ TOKENS.sort_tokens
171
+
172
+ @@pairs = {
173
+ "{" => "}",
174
+ "(" => ")",
175
+ "[" => "]",
176
+ "<|" => "|>",
177
+ "<<|" => "|>>"
178
+ }
179
+
180
+ KEYWORDS = TokenList.new
181
+
182
+ KEYWORDS.add_tokens(
183
+ "case" => :CASE,
184
+ "class" => :CLASS,
185
+ "default" => :DEFAULT,
186
+ "define" => :DEFINE,
187
+ "import" => :IMPORT,
188
+ "if" => :IF,
189
+ "elsif" => :ELSIF,
190
+ "else" => :ELSE,
191
+ "inherits" => :INHERITS,
192
+ "node" => :NODE,
193
+ "and" => :AND,
194
+ "or" => :OR,
195
+ "undef" => :UNDEF,
196
+ "false" => :FALSE,
197
+ "true" => :TRUE
198
+ )
199
+
200
+ def clear
201
+ initvars
202
+ end
203
+
204
+ def expected
205
+ return nil if @expected.empty?
206
+ name = @expected[-1]
207
+ raise "Could not find expected token %s" % name unless token = TOKENS.lookup(name)
208
+
209
+ return token
210
+ end
211
+
212
+ # scan the whole file
213
+ # basically just used for testing
214
+ def fullscan
215
+ array = []
216
+
217
+ self.scan { |token, str|
218
+ # Ignore any definition nesting problems
219
+ @indefine = false
220
+ array.push([token,str])
221
+ }
222
+ return array
223
+ end
224
+
225
+ # this is probably pretty damned inefficient...
226
+ # it'd be nice not to have to load the whole file first...
227
+ def file=(file)
228
+ @file = file
229
+ @line = 1
230
+ File.open(file) { |of|
231
+ str = ""
232
+ of.each { |line| str += line }
233
+ @scanner = StringScanner.new(str)
234
+ }
235
+ end
170
236
 
171
- # This value might have :: in it, but we don't care -- it'll be
172
- # handled normally when joining, and when popping we want to pop
173
- # this full value, however long the namespace is.
174
- def namestack(value)
175
- @namestack << value
237
+ def find_string_token
238
+ matched_token = value = nil
239
+
240
+ # We know our longest string token is three chars, so try each size in turn
241
+ # until we either match or run out of chars. This way our worst-case is three
242
+ # tries, where it is otherwise the number of string chars we have. Also,
243
+ # the lookups are optimized hash lookups, instead of regex scans.
244
+ [3, 2, 1].each do |i|
245
+ str = @scanner.peek(i)
246
+ if matched_token = TOKENS.lookup(str)
247
+ value = @scanner.scan(matched_token.regex)
248
+ break
176
249
  end
250
+ end
251
+
252
+ return matched_token, value
253
+ end
177
254
 
178
- def rest
179
- @scanner.rest
255
+ # Find the next token that matches a regex. We look for these first.
256
+ def find_regex_token
257
+ @regex += 1
258
+ matched_token = nil
259
+ value = ""
260
+ length = 0
261
+
262
+ # I tried optimizing based on the first char, but it had
263
+ # a slightly negative affect and was a good bit more complicated.
264
+ TOKENS.regex_tokens.each do |token|
265
+ next unless match_length = @scanner.match?(token.regex)
266
+
267
+ # We've found a longer match
268
+ if match_length > length
269
+ value = @scanner.scan(token.regex)
270
+ length = value.length
271
+ matched_token = token
180
272
  end
273
+ end
181
274
 
182
- # this is the heart of the lexer
183
- def scan
184
- #Puppet.debug("entering scan")
185
- if @scanner.nil?
186
- raise TypeError.new("Invalid or empty string")
187
- end
275
+ return matched_token, value
276
+ end
188
277
 
189
- @scanner.skip(@skip)
190
- until @scanner.eos? do
191
- yielded = false
192
- sendbreak = false # gah, this is a nasty hack
193
- stoken = nil
194
- sregex = nil
195
- value = ""
196
-
197
- # first find out which type of token we've got
198
- @@tokens.each { |regex,token|
199
- # we're just checking, which doesn't advance the scan
200
- # pointer
201
- tmp = @scanner.check(regex)
202
- if tmp.nil?
203
- #puppet.debug("did not match %s to '%s'" %
204
- # [regex,@scanner.rest])
205
- next
206
- end
207
-
208
- # find the longest match
209
- if tmp.length > value.length
210
- value = tmp
211
- stoken = token
212
- sregex = regex
213
- else
214
- # we've already got a longer match
215
- next
216
- end
217
- }
218
-
219
- # error out if we didn't match anything at all
220
- if stoken.nil?
221
- nword = nil
222
- if @scanner.rest =~ /^(\S+)/
223
- nword = $1
224
- elsif@scanner.rest =~ /^(\s+)/
225
- nword = $1
226
- else
227
- nword = @scanner.rest
228
- end
229
- raise "Could not match '%s'" % nword
230
- end
278
+ # Find the next token, returning the string and the token.
279
+ def find_token
280
+ @find += 1
281
+ matched_token, value = find_regex_token
231
282
 
232
- value = @scanner.scan(sregex)
283
+ unless matched_token
284
+ matched_token, value = find_string_token
285
+ end
233
286
 
234
- if value == ""
235
- raise "Didn't match regex on token %s" % stoken
236
- end
287
+ return matched_token, value
288
+ end
237
289
 
238
- # token-specific operations
239
- # if this gets much more complicated, it should
240
- # be moved up to where the tokens themselves are defined
241
- # which will get me about 75% of the way to a lexer generator
242
- ptoken = stoken
243
- case stoken
244
- when :NAME then
245
- wtoken = stoken
246
- # we're looking for keywords here
247
- if @@keywords.include?(value)
248
- wtoken = @@keywords[value]
249
- #Puppet.debug("token '%s'" % wtoken)
250
- if wtoken == :BOOLEAN
251
- value = eval(value)
252
- end
253
- end
254
- ptoken = wtoken
255
- when :NUMBER then
256
- ptoken = :NAME
257
- when :COMMENT then
258
- # just throw comments away
259
- next
260
- when :RETURN then
261
- @line += 1
262
- @scanner.skip(@skip)
263
- next
264
- when :SQUOTE then
265
- #Puppet.debug("searching '%s' after '%s'" % [self.rest,value])
266
- value = self.slurpstring(value)
267
- ptoken = :SQTEXT
268
- #Puppet.debug("got string '%s' => '%s'" % [:DQTEXT,value])
269
- when :DQUOTE then
270
- value = self.slurpstring(value)
271
- ptoken = :DQTEXT
272
- when :VARIABLE then
273
- value = value.sub(/^\$/, '')
274
- end
290
+ def indefine?
291
+ if defined? @indefine
292
+ @indefine
293
+ else
294
+ false
295
+ end
296
+ end
275
297
 
276
- if match = @@pairs[value] and ptoken != :DQUOTE and ptoken != :SQUOTE
277
- @expected << match
278
- elsif exp = @expected[-1] and exp == value and ptoken != :DQUOTE and ptoken != :SQUOTE
279
- @expected.pop
280
- end
298
+ def initialize
299
+ @find = 0
300
+ @regex = 0
301
+ initvars()
302
+ end
281
303
 
282
- yield [ptoken, value]
304
+ def initvars
305
+ @line = 1
306
+ @previous_token = nil
307
+ @scanner = nil
308
+ @file = nil
309
+ # AAARRGGGG! okay, regexes in ruby are bloody annoying
310
+ # no one else has "\n" =~ /\s/
311
+ @skip = %r{[ \t]+}
312
+
313
+ @namestack = []
314
+ @indefine = false
315
+ @expected = []
316
+ end
283
317
 
284
- if @lasttoken == :CLASS
285
- namestack(value)
286
- end
318
+ # Make any necessary changes to the token and/or value.
319
+ def munge_token(token, value)
320
+ @line += 1 if token.incr_line
287
321
 
288
- if @lasttoken == :DEFINE
289
- if indefine?
290
- msg = "Cannot nest definition %s inside %s" % [value, @indefine]
291
- self.indefine = false
292
- raise Puppet::ParseError, msg
293
- end
322
+ skip() if token.skip_text
294
323
 
295
- @indefine = value
296
- end
324
+ return if token.skip
297
325
 
298
- @last = value
299
- @lasttoken = ptoken
326
+ token, value = token.convert(self, value) if token.respond_to?(:convert)
300
327
 
301
- @scanner.skip(@skip)
302
- end
303
- @scanner = nil
304
- yield [false,false]
305
- end
328
+ return unless token
329
+
330
+ return token, value
331
+ end
332
+
333
+ # Go up one in the namespace.
334
+ def namepop
335
+ @namestack.pop
336
+ end
306
337
 
307
- # we've encountered an opening quote...
308
- # slurp in the rest of the string and return it
309
- def slurpstring(quote)
310
- # we search for the next quote that isn't preceded by a
311
- # backslash; the caret is there to match empty strings
312
- str = @scanner.scan_until(/([^\\]|^)#{quote}/)
313
- if str.nil?
314
- raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" %
315
- [self.last,self.rest])
338
+ # Collect the current namespace.
339
+ def namespace
340
+ @namestack.join("::")
341
+ end
342
+
343
+ # This value might have :: in it, but we don't care -- it'll be
344
+ # handled normally when joining, and when popping we want to pop
345
+ # this full value, however long the namespace is.
346
+ def namestack(value)
347
+ @namestack << value
348
+ end
349
+
350
+ def rest
351
+ @scanner.rest
352
+ end
353
+
354
+ # this is the heart of the lexer
355
+ def scan
356
+ #Puppet.debug("entering scan")
357
+ raise Puppet::LexError.new("Invalid or empty string") unless @scanner
358
+
359
+ # Skip any initial whitespace.
360
+ skip()
361
+
362
+ until @scanner.eos? do
363
+ yielded = false
364
+ matched_token, value = find_token
365
+
366
+ # error out if we didn't match anything at all
367
+ if matched_token.nil?
368
+ nword = nil
369
+ # Try to pull a 'word' out of the remaining string.
370
+ if @scanner.rest =~ /^(\S+)/
371
+ nword = $1
372
+ elsif @scanner.rest =~ /^(\s+)/
373
+ nword = $1
316
374
  else
317
- str.sub!(/#{quote}\Z/,"")
318
- str.gsub!(/\\#{quote}/,quote)
375
+ nword = @scanner.rest
319
376
  end
377
+ raise "Could not match '%s'" % nword
378
+ end
320
379
 
321
- return str
380
+ final_token, value = munge_token(matched_token, value)
381
+
382
+ next unless final_token
383
+
384
+ if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE
385
+ @expected << match
386
+ elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE
387
+ @expected.pop
322
388
  end
323
389
 
324
- # just parse a string, not a whole file
325
- def string=(string)
326
- @scanner = StringScanner.new(string)
390
+ yield [final_token.name, value]
391
+
392
+ if @previous_token
393
+ namestack(value) if @previous_token.name == :CLASS
394
+
395
+ if @previous_token.name == :DEFINE
396
+ if indefine?
397
+ msg = "Cannot nest definition %s inside %s" % [value, @indefine]
398
+ self.indefine = false
399
+ raise Puppet::ParseError, msg
400
+ end
401
+
402
+ @indefine = value
403
+ end
327
404
  end
405
+
406
+ @previous_token = final_token
407
+ skip()
328
408
  end
329
- #---------------------------------------------------------------
409
+ @scanner = nil
410
+
411
+ # This indicates that we're done parsing.
412
+ yield [false,false]
413
+ end
414
+
415
+ # Skip any skipchars in our remaining string.
416
+ def skip
417
+ @scanner.skip(@skip)
330
418
  end
331
- end
332
419
 
420
+ # we've encountered an opening quote...
421
+ # slurp in the rest of the string and return it
422
+ def slurpstring(quote)
423
+ # we search for the next quote that isn't preceded by a
424
+ # backslash; the caret is there to match empty strings
425
+ str = @scanner.scan_until(/([^\\]|^)#{quote}/)
426
+ if str.nil?
427
+ raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" %
428
+ [self.last,self.rest])
429
+ else
430
+ str.sub!(/#{quote}\Z/,"")
431
+ str.gsub!(/\\#{quote}/,quote)
432
+ end
433
+
434
+ return str
435
+ end
436
+
437
+ # just parse a string, not a whole file
438
+ def string=(string)
439
+ @scanner = StringScanner.new(string)
440
+ end
441
+ end