puppet 0.23.1 → 0.23.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 (55) hide show
  1. data/CHANGELOG +31 -0
  2. data/bin/puppetd +2 -1
  3. data/conf/redhat/puppet.spec +9 -6
  4. data/conf/redhat/server.init +4 -5
  5. data/examples/code/mac_dscl.pp +28 -0
  6. data/examples/code/mac_dscl_revert.pp +26 -0
  7. data/examples/code/mac_netinfo.pp +5 -0
  8. data/examples/code/mac_pkgdmg.pp +7 -0
  9. data/ext/puppet-test +69 -2
  10. data/lib/puppet.rb +2 -2
  11. data/lib/puppet/configuration.rb +5 -1
  12. data/lib/puppet/network/server/mongrel.rb +3 -3
  13. data/lib/puppet/parser/ast.rb +2 -2
  14. data/lib/puppet/parser/ast/component.rb +3 -3
  15. data/lib/puppet/parser/ast/node.rb +2 -2
  16. data/lib/puppet/parser/collector.rb +2 -2
  17. data/lib/puppet/parser/interpreter.rb +38 -215
  18. data/lib/puppet/parser/parser.rb +11 -228
  19. data/lib/puppet/parser/parser_support.rb +447 -0
  20. data/lib/puppet/parser/resource/param.rb +2 -2
  21. data/lib/puppet/provider.rb +5 -3
  22. data/lib/puppet/provider/cron/crontab.rb +22 -9
  23. data/lib/puppet/provider/group/directoryservice.rb +23 -0
  24. data/lib/puppet/provider/interface/redhat.rb +251 -0
  25. data/lib/puppet/provider/interface/sunos.rb +116 -0
  26. data/lib/puppet/provider/mount.rb +4 -1
  27. data/lib/puppet/provider/nameservice/directoryservice.rb +341 -0
  28. data/lib/puppet/provider/package/dpkg.rb +2 -2
  29. data/lib/puppet/provider/package/openbsd.rb +2 -2
  30. data/lib/puppet/provider/package/rpm.rb +2 -4
  31. data/lib/puppet/provider/package/sun.rb +2 -2
  32. data/lib/puppet/provider/parsedfile.rb +32 -29
  33. data/lib/puppet/provider/user/directoryservice.rb +116 -0
  34. data/lib/puppet/rails/host.rb +1 -1
  35. data/lib/puppet/reference/configuration.rb +7 -4
  36. data/lib/puppet/type/interface.rb +57 -0
  37. data/lib/puppet/type/pfile/group.rb +2 -2
  38. data/lib/puppet/util/config.rb +10 -3
  39. data/lib/puppet/util/fileparsing.rb +2 -2
  40. data/test/language/ast/hostclass.rb +1 -17
  41. data/test/language/interpreter.rb +18 -388
  42. data/test/language/node.rb +8 -8
  43. data/test/language/parser.rb +444 -45
  44. data/test/lib/puppettest/parsertesting.rb +2 -2
  45. data/test/lib/puppettest/support/collection.rb +2 -2
  46. data/test/network/server/mongrel_test.rb +24 -3
  47. data/test/rails/collection.rb +34 -1
  48. data/test/ral/providers/cron/crontab.rb +198 -40
  49. data/test/ral/providers/mount/parsed.rb +69 -46
  50. data/test/ral/providers/parsedfile.rb +20 -28
  51. data/test/ral/types/cron.rb +20 -24
  52. data/test/ral/types/interface.rb +40 -0
  53. data/test/ral/types/package.rb +6 -2
  54. data/test/util/config.rb +106 -30
  55. metadata +14 -2
@@ -29,236 +29,19 @@ module Puppet
29
29
 
30
30
  class Parser < Racc::Parser
31
31
 
32
- module_eval <<'..end grammar.ra modeval..id72fb6a61b8', 'grammar.ra', 640
33
- require 'puppet/parser/functions'
32
+ module_eval <<'..end grammar.ra modeval..idc5e5087e93', 'grammar.ra', 640
34
33
 
35
- attr_reader :file, :interp
36
- attr_accessor :files
37
-
38
- # Add context to a message; useful for error messages and such.
39
- def addcontext(message, obj = nil)
40
- obj ||= @lexer
41
-
42
- message += " on line %s" % obj.line
43
- if file = obj.file
44
- message += " in file %s" % file
45
- end
46
-
47
- return message
48
- end
49
-
50
- # Create an AST array out of all of the args
51
- def aryfy(*args)
52
- if args[0].instance_of?(AST::ASTArray)
53
- result = args.shift
54
- args.each { |arg|
55
- result.push arg
56
- }
57
- else
58
- result = ast AST::ASTArray, :children => args
59
- end
60
-
61
- return result
62
- end
63
-
64
- # Create an AST object, and automatically add the file and line information if
65
- # available.
66
- def ast(klass, hash = nil)
67
- hash ||= {}
68
- unless hash.include?(:line)
69
- hash[:line] = @lexer.line
70
- end
71
-
72
- unless hash.include?(:file)
73
- if file = @lexer.file
74
- hash[:file] = file
75
- end
76
- end
77
-
78
- return klass.new(hash)
79
- end
80
-
81
- # Raise a Parse error.
82
- def error(message)
83
- if brace = @lexer.expected
84
- message += "; expected '%s'"
85
- end
86
- except = Puppet::ParseError.new(message)
87
- except.line = @lexer.line
88
- if @lexer.file
89
- except.file = @lexer.file
90
- end
91
-
92
- raise except
93
- end
94
-
95
- def file=(file)
96
- unless FileTest.exists?(file)
97
- unless file =~ /\.pp$/
98
- file = file + ".pp"
99
- end
100
- unless FileTest.exists?(file)
101
- raise Puppet::Error, "Could not find file %s" % file
102
- end
103
- end
104
- if @files.detect { |f| f.file == file }
105
- raise Puppet::AlreadyImportedError.new("Import loop detected")
106
- else
107
- @files << Puppet::Util::LoadedFile.new(file)
108
- @lexer.file = file
109
- end
110
- end
111
-
112
- # Import our files.
113
- def import(file)
114
- if Puppet[:ignoreimport]
115
- return AST::ASTArray.new(:children => [])
116
- end
117
- # use a path relative to the file doing the importing
118
- if @lexer.file
119
- dir = @lexer.file.sub(%r{[^/]+$},'').sub(/\/$/, '')
120
- else
121
- dir = "."
122
- end
123
- if dir == ""
124
- dir = "."
125
- end
126
- result = ast AST::ASTArray
127
-
128
- # We can't interpolate at this point since we don't have any
129
- # scopes set up. Warn the user if they use a variable reference
130
- pat = file
131
- if pat.index("$")
132
- Puppet.warning(
133
- "The import of #{pat} contains a variable reference;" +
134
- " variables are not interpolated for imports " +
135
- "in file #{@lexer.file} at line #{@lexer.line}"
136
- )
137
- end
138
- files = Puppet::Module::find_manifests(pat, dir)
139
- if files.size == 0
140
- raise Puppet::ImportError.new("No file(s) found for import " +
141
- "of '#{pat}'")
142
- end
143
-
144
- files.collect { |file|
145
- parser = Puppet::Parser::Parser.new(interp)
146
- parser.files = self.files
147
- Puppet.debug("importing '%s'" % file)
148
-
149
- unless file =~ /^#{File::SEPARATOR}/
150
- file = File.join(dir, file)
151
- end
152
- begin
153
- parser.file = file
154
- rescue Puppet::AlreadyImportedError
155
- # This file has already been imported to just move on
156
- next
157
- end
158
-
159
- # This will normally add code to the 'main' class.
160
- parser.parse
161
- }
162
- end
163
-
164
- def initialize(interpreter)
165
- @interp = interpreter
166
- initvars()
167
- end
168
-
169
- # Initialize or reset all of our variables.
170
- def initvars
171
- @lexer = Puppet::Parser::Lexer.new()
172
- @files = []
173
- end
174
-
175
- # The fully qualifed name, with the full namespace.
176
- def classname(name)
177
- [@lexer.namespace, name].join("::").sub(/^::/, '')
178
- end
179
-
180
- def on_error(token,value,stack)
181
- #on '%s' at '%s' in\n'%s'" % [token,value,stack]
182
- #error = "line %s: parse error after '%s'" %
183
- # [@lexer.line,@lexer.last]
184
- error = "Syntax error at '%s'" % [value]
185
-
186
- if brace = @lexer.expected
187
- error += "; expected '%s'" % brace
188
- end
189
-
190
- except = Puppet::ParseError.new(error)
191
- except.line = @lexer.line
192
- if @lexer.file
193
- except.file = @lexer.file
194
- end
195
-
196
- raise except
197
- end
198
-
199
- # how should I do error handling here?
200
- def parse(string = nil)
201
- if string
202
- self.string = string
203
- end
204
- begin
205
- main = yyparse(@lexer,:scan)
206
- rescue Racc::ParseError => except
207
- error = Puppet::ParseError.new(except)
208
- error.line = @lexer.line
209
- error.file = @lexer.file
210
- error.set_backtrace except.backtrace
211
- raise error
212
- rescue Puppet::ParseError => except
213
- except.line ||= @lexer.line
214
- except.file ||= @lexer.file
215
- raise except
216
- rescue Puppet::Error => except
217
- # and this is a framework error
218
- except.line ||= @lexer.line
219
- except.file ||= @lexer.file
220
- raise except
221
- rescue Puppet::DevError => except
222
- except.line ||= @lexer.line
223
- except.file ||= @lexer.file
224
- raise except
225
- rescue => except
226
- error = Puppet::DevError.new(except.message)
227
- error.line = @lexer.line
228
- error.file = @lexer.file
229
- error.set_backtrace except.backtrace
230
- raise error
231
- end
232
- if main
233
- # Store the results as the top-level class.
234
- interp.newclass("", :code => main)
235
- return main
236
- end
237
- ensure
238
- @lexer.clear
239
- end
240
-
241
- # See if any of the files have changed.
242
- def reparse?
243
- if file = @files.detect { |file| file.changed? }
244
- return file.stamp
245
- else
246
- return false
247
- end
248
- end
249
-
250
- def string=(string)
251
- @lexer.string = string
252
- end
34
+ # It got too annoying having code in a file that needs to be compiled.
35
+ require 'puppet/parser/parser_support'
253
36
 
254
37
  # Make emacs happy
255
38
  # Local Variables:
256
39
  # mode: ruby
257
40
  # End:
258
41
 
259
- # $Id: parser.rb 2694 2007-07-14 18:09:26Z luke $
42
+ # $Id: parser.rb 2742 2007-08-03 23:49:53Z luke $
260
43
 
261
- ..end grammar.ra modeval..id72fb6a61b8
44
+ ..end grammar.ra modeval..idc5e5087e93
262
45
 
263
46
  ##### racc 1.4.5 generates ###
264
47
 
@@ -1741,7 +1524,7 @@ module_eval <<'.,.,', 'grammar.ra', 496
1741
1524
 
1742
1525
  module_eval <<'.,.,', 'grammar.ra', 506
1743
1526
  def _reduce_135( val, _values, result )
1744
- interp.newdefine classname(val[1]), :arguments => val[2], :code => val[4]
1527
+ newdefine classname(val[1]), :arguments => val[2], :code => val[4]
1745
1528
  @lexer.indefine = false
1746
1529
  result = nil
1747
1530
 
@@ -1752,7 +1535,7 @@ module_eval <<'.,.,', 'grammar.ra', 506
1752
1535
 
1753
1536
  module_eval <<'.,.,', 'grammar.ra', 510
1754
1537
  def _reduce_136( val, _values, result )
1755
- interp.newdefine classname(val[1]), :arguments => val[2]
1538
+ newdefine classname(val[1]), :arguments => val[2]
1756
1539
  @lexer.indefine = false
1757
1540
  result = nil
1758
1541
  result
@@ -1763,7 +1546,7 @@ module_eval <<'.,.,', 'grammar.ra', 518
1763
1546
  def _reduce_137( val, _values, result )
1764
1547
  # Our class gets defined in the parent namespace, not our own.
1765
1548
  @lexer.namepop
1766
- interp.newclass classname(val[1]), :code => val[4], :parent => val[2]
1549
+ newclass classname(val[1]), :code => val[4], :parent => val[2]
1767
1550
  result = nil
1768
1551
  result
1769
1552
  end
@@ -1773,7 +1556,7 @@ module_eval <<'.,.,', 'grammar.ra', 523
1773
1556
  def _reduce_138( val, _values, result )
1774
1557
  # Our class gets defined in the parent namespace, not our own.
1775
1558
  @lexer.namepop
1776
- interp.newclass classname(val[1]), :parent => val[2]
1559
+ newclass classname(val[1]), :parent => val[2]
1777
1560
  result = nil
1778
1561
  result
1779
1562
  end
@@ -1781,7 +1564,7 @@ module_eval <<'.,.,', 'grammar.ra', 523
1781
1564
 
1782
1565
  module_eval <<'.,.,', 'grammar.ra', 528
1783
1566
  def _reduce_139( val, _values, result )
1784
- interp.newnode val[1], :parent => val[2], :code => val[4]
1567
+ newnode val[1], :parent => val[2], :code => val[4]
1785
1568
  result = nil
1786
1569
  result
1787
1570
  end
@@ -1789,7 +1572,7 @@ module_eval <<'.,.,', 'grammar.ra', 528
1789
1572
 
1790
1573
  module_eval <<'.,.,', 'grammar.ra', 531
1791
1574
  def _reduce_140( val, _values, result )
1792
- interp.newnode val[1], :parent => val[2]
1575
+ newnode val[1], :parent => val[2]
1793
1576
  result = nil
1794
1577
  result
1795
1578
  end
@@ -0,0 +1,447 @@
1
+ class Puppet::Parser::Parser
2
+ require 'puppet/parser/functions'
3
+
4
+ ASTSet = Struct.new(:classes, :definitions, :nodes)
5
+
6
+ # Define an accessor method for each table. We hide the existence of
7
+ # the struct.
8
+ [:classes, :definitions, :nodes].each do |name|
9
+ define_method(name) do
10
+ @astset.send(name)
11
+ end
12
+ end
13
+
14
+ AST = Puppet::Parser::AST
15
+
16
+ attr_reader :file, :interp
17
+ attr_accessor :files
18
+
19
+
20
+ # Add context to a message; useful for error messages and such.
21
+ def addcontext(message, obj = nil)
22
+ obj ||= @lexer
23
+
24
+ message += " on line %s" % obj.line
25
+ if file = obj.file
26
+ message += " in file %s" % file
27
+ end
28
+
29
+ return message
30
+ end
31
+
32
+ # Create an AST array out of all of the args
33
+ def aryfy(*args)
34
+ if args[0].instance_of?(AST::ASTArray)
35
+ result = args.shift
36
+ args.each { |arg|
37
+ result.push arg
38
+ }
39
+ else
40
+ result = ast AST::ASTArray, :children => args
41
+ end
42
+
43
+ return result
44
+ end
45
+
46
+ # Create an AST object, and automatically add the file and line information if
47
+ # available.
48
+ def ast(klass, hash = nil)
49
+ hash ||= {}
50
+ unless hash.include?(:line)
51
+ hash[:line] = @lexer.line
52
+ end
53
+
54
+ unless hash.include?(:file)
55
+ if file = @lexer.file
56
+ hash[:file] = file
57
+ end
58
+ end
59
+
60
+ return klass.new(hash)
61
+ end
62
+
63
+ # The fully qualifed name, with the full namespace.
64
+ def classname(name)
65
+ [@lexer.namespace, name].join("::").sub(/^::/, '')
66
+ end
67
+
68
+ def clear
69
+ initvars
70
+ end
71
+
72
+ # Raise a Parse error.
73
+ def error(message)
74
+ if brace = @lexer.expected
75
+ message += "; expected '%s'"
76
+ end
77
+ except = Puppet::ParseError.new(message)
78
+ except.line = @lexer.line
79
+ if @lexer.file
80
+ except.file = @lexer.file
81
+ end
82
+
83
+ raise except
84
+ end
85
+
86
+ def file=(file)
87
+ unless FileTest.exists?(file)
88
+ unless file =~ /\.pp$/
89
+ file = file + ".pp"
90
+ end
91
+ unless FileTest.exists?(file)
92
+ raise Puppet::Error, "Could not find file %s" % file
93
+ end
94
+ end
95
+ if @files.detect { |f| f.file == file }
96
+ raise Puppet::AlreadyImportedError.new("Import loop detected")
97
+ else
98
+ @files << Puppet::Util::LoadedFile.new(file)
99
+ @lexer.file = file
100
+ end
101
+ end
102
+
103
+ # Find a class definition, relative to the current namespace.
104
+ def findclass(namespace, name)
105
+ fqfind namespace, name, classes
106
+ end
107
+
108
+ # Find a component definition, relative to the current namespace.
109
+ def finddefine(namespace, name)
110
+ fqfind namespace, name, definitions
111
+ end
112
+
113
+ # This is only used when nodes are looking up the code for their
114
+ # parent nodes.
115
+ def findnode(name)
116
+ fqfind "", name, nodes
117
+ end
118
+
119
+ # The recursive method used to actually look these objects up.
120
+ def fqfind(namespace, name, table)
121
+ namespace = namespace.downcase
122
+ name = name.downcase
123
+ if name =~ /^::/ or namespace == ""
124
+ classname = name.sub(/^::/, '')
125
+ unless table[classname]
126
+ self.load(classname)
127
+ end
128
+ return table[classname]
129
+ end
130
+ ary = namespace.split("::")
131
+
132
+ while ary.length > 0
133
+ newname = (ary + [name]).join("::").sub(/^::/, '')
134
+ if obj = table[newname] or (self.load(newname) and obj = table[newname])
135
+ return obj
136
+ end
137
+
138
+ # Delete the second to last object, which reduces our namespace by one.
139
+ ary.pop
140
+ end
141
+
142
+ # If we've gotten to this point without finding it, see if the name
143
+ # exists at the top namespace
144
+ if obj = table[name] or (self.load(name) and obj = table[name])
145
+ return obj
146
+ end
147
+
148
+ return nil
149
+ end
150
+
151
+ # Import our files.
152
+ def import(file)
153
+ if Puppet[:ignoreimport]
154
+ return AST::ASTArray.new(:children => [])
155
+ end
156
+ # use a path relative to the file doing the importing
157
+ if @lexer.file
158
+ dir = @lexer.file.sub(%r{[^/]+$},'').sub(/\/$/, '')
159
+ else
160
+ dir = "."
161
+ end
162
+ if dir == ""
163
+ dir = "."
164
+ end
165
+ result = ast AST::ASTArray
166
+
167
+ # We can't interpolate at this point since we don't have any
168
+ # scopes set up. Warn the user if they use a variable reference
169
+ pat = file
170
+ if pat.index("$")
171
+ Puppet.warning(
172
+ "The import of #{pat} contains a variable reference;" +
173
+ " variables are not interpolated for imports " +
174
+ "in file #{@lexer.file} at line #{@lexer.line}"
175
+ )
176
+ end
177
+ files = Puppet::Module::find_manifests(pat, dir)
178
+ if files.size == 0
179
+ raise Puppet::ImportError.new("No file(s) found for import " +
180
+ "of '#{pat}'")
181
+ end
182
+
183
+ files.collect { |file|
184
+ parser = Puppet::Parser::Parser.new(@astset)
185
+ parser.files = self.files
186
+ Puppet.debug("importing '%s'" % file)
187
+
188
+ unless file =~ /^#{File::SEPARATOR}/
189
+ file = File.join(dir, file)
190
+ end
191
+ begin
192
+ parser.file = file
193
+ rescue Puppet::AlreadyImportedError
194
+ # This file has already been imported to just move on
195
+ next
196
+ end
197
+
198
+ # This will normally add code to the 'main' class.
199
+ parser.parse
200
+ }
201
+ end
202
+
203
+ def initialize(astset = nil)
204
+ initvars()
205
+ if astset
206
+ @astset = astset
207
+ end
208
+ end
209
+
210
+ # Initialize or reset all of our variables.
211
+ def initvars
212
+ @lexer = Puppet::Parser::Lexer.new()
213
+ @files = []
214
+ @loaded = []
215
+
216
+ # This is where we store our classes and definitions and nodes.
217
+ # Clear each hash, just to help the GC a bit.
218
+ if defined?(@astset)
219
+ [:classes, :definitions, :nodes].each do |name|
220
+ @astset.send(name).clear
221
+ end
222
+ end
223
+ @astset = ASTSet.new({}, {}, {})
224
+ end
225
+
226
+ # Try to load a class, since we could not find it.
227
+ def load(classname)
228
+ return false if classname == ""
229
+ filename = classname.gsub("::", File::SEPARATOR)
230
+
231
+ loaded = false
232
+ # First try to load the top-level module
233
+ mod = filename.scan(/^[\w-]+/).shift
234
+ unless @loaded.include?(mod)
235
+ @loaded << mod
236
+ begin
237
+ import(mod)
238
+ Puppet.info "Autoloaded module %s" % mod
239
+ loaded = true
240
+ rescue Puppet::ImportError => detail
241
+ # We couldn't load the module
242
+ end
243
+ end
244
+
245
+ unless filename == mod and ! @loaded.include?(mod)
246
+ @loaded << mod
247
+ # Then the individual file
248
+ begin
249
+ import(filename)
250
+ Puppet.info "Autoloaded file %s from module %s" % [filename, mod]
251
+ loaded = true
252
+ rescue Puppet::ImportError => detail
253
+ # We couldn't load the file
254
+ end
255
+ end
256
+ return loaded
257
+ end
258
+
259
+ # Split an fq name into a namespace and name
260
+ def namesplit(fullname)
261
+ ary = fullname.split("::")
262
+ n = ary.pop || ""
263
+ ns = ary.join("::")
264
+ return ns, n
265
+ end
266
+
267
+ # Create a new class, or merge with an existing class.
268
+ def newclass(name, options = {})
269
+ name = name.downcase
270
+
271
+ if definitions.include?(name)
272
+ raise Puppet::ParseError, "Cannot redefine class %s as a definition" % name
273
+ end
274
+ code = options[:code]
275
+ parent = options[:parent]
276
+
277
+ # If the class is already defined, then add code to it.
278
+ if other = @astset.classes[name]
279
+ # Make sure the parents match
280
+ if parent and other.parentclass and (parent != other.parentclass)
281
+ error("Class %s is already defined at %s:%s; cannot redefine" % [name, other.file, other.line])
282
+ end
283
+
284
+ # This might be dangerous...
285
+ if parent and ! other.parentclass
286
+ other.parentclass = parent
287
+ end
288
+
289
+ # This might just be an empty, stub class.
290
+ if code
291
+ tmp = name
292
+ if tmp == ""
293
+ tmp = "main"
294
+ end
295
+
296
+ Puppet.debug addcontext("Adding code to %s" % tmp)
297
+ # Else, add our code to it.
298
+ if other.code and code
299
+ other.code.children += code.children
300
+ else
301
+ other.code ||= code
302
+ end
303
+ end
304
+ else
305
+ # Define it anew.
306
+ # Note we're doing something somewhat weird here -- we're setting
307
+ # the class's namespace to its fully qualified name. This means
308
+ # anything inside that class starts looking in that namespace first.
309
+ args = {:namespace => name, :classname => name, :parser => self}
310
+ args[:code] = code if code
311
+ args[:parentclass] = parent if parent
312
+ @astset.classes[name] = ast AST::HostClass, args
313
+ end
314
+
315
+ return @astset.classes[name]
316
+ end
317
+
318
+ # Create a new definition.
319
+ def newdefine(name, options = {})
320
+ name = name.downcase
321
+ if @astset.classes.include?(name)
322
+ raise Puppet::ParseError, "Cannot redefine class %s as a definition" %
323
+ name
324
+ end
325
+ # Make sure our definition doesn't already exist
326
+ if other = @astset.definitions[name]
327
+ error("%s is already defined at %s:%s; cannot redefine" % [name, other.file, other.line])
328
+ end
329
+
330
+ ns, whatever = namesplit(name)
331
+ args = {
332
+ :namespace => ns,
333
+ :arguments => options[:arguments],
334
+ :code => options[:code],
335
+ :parser => self,
336
+ :classname => name
337
+ }
338
+
339
+ [:code, :arguments].each do |param|
340
+ args[param] = options[param] if options[param]
341
+ end
342
+
343
+ @astset.definitions[name] = ast AST::Component, args
344
+ end
345
+
346
+ # Create a new node. Nodes are special, because they're stored in a global
347
+ # table, not according to namespaces.
348
+ def newnode(names, options = {})
349
+ names = [names] unless names.instance_of?(Array)
350
+ names.collect do |name|
351
+ name = name.to_s.downcase
352
+ if other = @astset.nodes[name]
353
+ error("Node %s is already defined at %s:%s; cannot redefine" % [other.name, other.file, other.line])
354
+ end
355
+ name = name.to_s if name.is_a?(Symbol)
356
+ args = {
357
+ :name => name,
358
+ :parser => self
359
+ }
360
+ if options[:code]
361
+ args[:code] = options[:code]
362
+ end
363
+ if options[:parent]
364
+ args[:parentclass] = options[:parent]
365
+ end
366
+ @astset.nodes[name] = ast(AST::Node, args)
367
+ @astset.nodes[name].classname = name
368
+ @astset.nodes[name]
369
+ end
370
+ end
371
+
372
+ def on_error(token,value,stack)
373
+ #on '%s' at '%s' in\n'%s'" % [token,value,stack]
374
+ #error = "line %s: parse error after '%s'" %
375
+ # [@lexer.line,@lexer.last]
376
+ error = "Syntax error at '%s'" % [value]
377
+
378
+ if brace = @lexer.expected
379
+ error += "; expected '%s'" % brace
380
+ end
381
+
382
+ except = Puppet::ParseError.new(error)
383
+ except.line = @lexer.line
384
+ if @lexer.file
385
+ except.file = @lexer.file
386
+ end
387
+
388
+ raise except
389
+ end
390
+
391
+ # how should I do error handling here?
392
+ def parse(string = nil)
393
+ if string
394
+ self.string = string
395
+ end
396
+ begin
397
+ main = yyparse(@lexer,:scan)
398
+ rescue Racc::ParseError => except
399
+ error = Puppet::ParseError.new(except)
400
+ error.line = @lexer.line
401
+ error.file = @lexer.file
402
+ error.set_backtrace except.backtrace
403
+ raise error
404
+ rescue Puppet::ParseError => except
405
+ except.line ||= @lexer.line
406
+ except.file ||= @lexer.file
407
+ raise except
408
+ rescue Puppet::Error => except
409
+ # and this is a framework error
410
+ except.line ||= @lexer.line
411
+ except.file ||= @lexer.file
412
+ raise except
413
+ rescue Puppet::DevError => except
414
+ except.line ||= @lexer.line
415
+ except.file ||= @lexer.file
416
+ raise except
417
+ rescue => except
418
+ error = Puppet::DevError.new(except.message)
419
+ error.line = @lexer.line
420
+ error.file = @lexer.file
421
+ error.set_backtrace except.backtrace
422
+ raise error
423
+ end
424
+ if main
425
+ # Store the results as the top-level class.
426
+ newclass("", :code => main)
427
+ end
428
+ return @astset
429
+ ensure
430
+ @lexer.clear
431
+ end
432
+
433
+ # See if any of the files have changed.
434
+ def reparse?
435
+ if file = @files.detect { |file| file.changed? }
436
+ return file.stamp
437
+ else
438
+ return false
439
+ end
440
+ end
441
+
442
+ def string=(string)
443
+ @lexer.string = string
444
+ end
445
+ end
446
+
447
+ # $Id: parser_support.rb 2744 2007-08-04 20:00:19Z luke $