dataMetaDom 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,397 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ %w(fileutils set dataMetaXtra dataMetaDom/docs dataMetaDom/ver).each { |r| require r }
4
+
5
+ module DataMetaDom
6
+
7
+ =begin rdoc
8
+ A mapping - of values from one data type to values of another data types. Supports only DataMeta DOM standard types
9
+
10
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
11
+ =end
12
+ class Mapping < VerDoccable
13
+
14
+ # Empty binding for evaluation to avoid exposing class variables
15
+ BINDING_NONE = DataMetaXtra.nilBinding
16
+
17
+ =begin rdoc
18
+ Name of this mapping data type including namespace if any.
19
+ =end
20
+ attr_accessor :name
21
+ =begin rdoc
22
+ DataType "from" (source)
23
+ =end
24
+ attr_accessor :fromT
25
+ =begin rdoc
26
+ DataType "to" (target)
27
+ =end
28
+ attr_accessor :toT
29
+
30
+ =begin rdoc
31
+ The hash of the "from" (source) values to the "to" (target) values.
32
+ =end
33
+ attr_accessor :base
34
+
35
+ =begin rdoc
36
+ Creates an instance for the given full data type name, including namespace if any.
37
+ =end
38
+ def initialize(name)
39
+ #noinspection RubyArgCount
40
+ super()
41
+ @name = name.to_sym; @base = {}
42
+ end
43
+
44
+ =begin rdoc
45
+ Returns the value for the given key as mapped.
46
+ * Parameters:
47
+ * +key+ - the value of the type "from" (source) to get the matching value of the type "to" (target) for.
48
+ =end
49
+ def [](key); @base[key] end
50
+
51
+ =begin rdoc
52
+ Assign the mapped value for the given key, useful for building a mapping from the code.
53
+ * Parameters:
54
+ * +key+ - the value of the type "from" (source)
55
+ * +val+ - the matching value of the type "to" (target).
56
+ =end
57
+ def []=(key, val); base[key] = val end
58
+
59
+ =begin rdoc
60
+ All the values of the type "to" (target) defined on the mapping, sorted
61
+ =end
62
+ def values; @base.values.sort end
63
+
64
+ =begin rdoc
65
+ All the keys of the type "from" (source) defined on the mapping, sorted
66
+ =end
67
+ def keys; @base.keys.sort end
68
+
69
+ =begin rdoc
70
+ Parses the mapping, the keys and the values from the given source.
71
+ * Parameters
72
+ * +source+ - an instance of SourceFile
73
+ =end
74
+ def parseBase(source)
75
+ hashSource = '{'
76
+ while (line = source.nextLine)
77
+ case line
78
+ when /^\s*#{END_KW}\s*$/
79
+ self.ver = source.ver unless self.ver
80
+ self.docs = source.docs.clone
81
+ source.docs.clear
82
+ raise "Version missing for the Mapping #{name}" unless self.ver
83
+ break
84
+ else
85
+ hashSource << line
86
+ end # case
87
+ end # while line
88
+ @base = eval(hashSource + '}', BINDING_NONE)
89
+ self
90
+ end # def parse
91
+ end
92
+
93
+ =begin rdoc
94
+ A Bit Set mapping, one instance holding a set of references to the values packed tightly as a bit set.
95
+ =end
96
+ class BitSet < Mapping
97
+
98
+ =begin rdoc
99
+ Attempts to consume the instance from the given source, returns it if successful, returns nil otherwise.
100
+ * Parameters
101
+ * +model+ - an instance of a Model
102
+ * +src+ - an instance of SourceFile
103
+ =end
104
+ def self.consumed?(model, src)
105
+ src.line =~ /^\s*#{BITSET}\s+(\w+)\s+.+$/ ? model.addEnum(BitSet.new(combineNsBase(DataMetaDom.nsAdjustment(src.namespace, model.options, src), $1)).parse(src)) : nil
106
+ end
107
+
108
+ =begin rdoc
109
+ Returns the keyword for this Mapping implementation, in this case "<tt>bitset</tt>"
110
+ =end
111
+ def sourceKeyWord; BITSET end
112
+
113
+ =begin rdoc
114
+ Parses the current instance from the given source.
115
+ * Parameters
116
+ * +src+ - an instance of SourceFile
117
+ =end
118
+ def parse(src)
119
+ r = src.line.scan(/^\s*\w+\s+\w+\s+(\S+)\s*$/)
120
+ raise 'Invalid bitset specification' unless r && r[0] && r[0][0]
121
+ self.fromT = INT4 #platform type is up to the concrete generator
122
+ self.toT = DataType.parse(src, r[0][0])
123
+ parseBase src
124
+ end
125
+ end
126
+
127
+ =begin rdoc
128
+ A single-value map of a key to a value.
129
+ =end
130
+ class Mappings < Mapping
131
+
132
+ =begin rdoc
133
+ Attempts to consume the instance from the given source, returns it if successful, returns nil otherwise.
134
+ * Parameters
135
+ * +model+ - an instance of a Model
136
+ * +src+ - an instance of SourceFile
137
+ =end
138
+ def self.consumed?(model, src)
139
+ src.line =~ /^\s*#{MAPPING}\s+(\w+)\s+.+$/ ? model.addEnum(Mappings.new(combineNsBase(DataMetaDom.nsAdjustment(src.namespace, model.options, src), $1)).parse(src)) : nil
140
+ end
141
+
142
+ =begin rdoc
143
+ Returns the keyword for this Mapping implementation, in this case "<tt>map</tt>"
144
+ =end
145
+ def sourceKeyWord; MAPPING end
146
+
147
+ =begin rdoc
148
+ Parses the current instance from the given source.
149
+ * Parameters
150
+ * +src+ - an instance of SourceFile
151
+ =end
152
+ def parse(src)
153
+ r = src.line.scan(/^\s*\w+\s+\w+\s+(\S+)\s+(\S+)\s*$/)
154
+ raise 'Invalid map specification' unless r && r[0] && r[0][0] && r[0][1]
155
+ self.fromT = DataType.parse(src, r[0][0])
156
+ self.toT = DataType.parse(src, r[0][1])
157
+ parseBase src
158
+ end
159
+ end
160
+
161
+ =begin rdoc
162
+ A data structure comprised of fields with the notion of identity, indexes, unique and not.
163
+ @!attribute [r] namespace
164
+ @return [String] part of the {#name}, the prefix before last dot, "package" in Java and Scala, "namespace" in C
165
+
166
+ @!attribute [r] baseName
167
+ @return [String] part of the {#name}, the suffix after last dot
168
+
169
+ =end
170
+ class Record < VerDoccable
171
+
172
+ =begin rdoc
173
+ Full Record datatype name, including namespace if any. Should be unique in the model.
174
+ =end
175
+ attr_accessor :name
176
+
177
+ =begin rdoc
178
+ The fields as a map keying a field name to the matching instance of a Field
179
+ =end
180
+ attr_reader :fields
181
+
182
+ =begin rdoc
183
+ An instance of RecIdentity.
184
+ =end
185
+ attr_reader :identity
186
+
187
+ =begin rdoc
188
+ A hash mapping to RecUnique from its key. Meaning, RecUnique.key to the matching RecUnique
189
+ =end
190
+ attr_reader :uniques
191
+
192
+ =begin rdoc
193
+ A hash mapping to RecIndex from its key. Meaning, RecIndex.key to the matching RecIndex
194
+ =end
195
+ attr_reader :indexes
196
+
197
+ =begin rdoc
198
+ An array of Reference
199
+ =end
200
+ attr_reader :refs
201
+
202
+ =begin rdoc
203
+ The unique key for the record, unique across the Model.
204
+ =end
205
+ attr_reader :key
206
+
207
+ attr_reader :namespace
208
+
209
+ attr_reader :baseName
210
+
211
+ =begin rdoc
212
+ Attempts to consume the instance from the given source, returns it if successful, returns nil otherwise.
213
+ * Parameters
214
+ * +model+ - an instance of a Model
215
+ * +src+ - an instance of SourceFile
216
+ =end
217
+ def self.consumed?(model, src)
218
+ if src.line =~ /^\s*#{RECORD}\s+(\w+)$/
219
+ newRecord = Record.new(DataMetaDom.combineNsBase(DataMetaDom.nsAdjustment(src.namespace, model.options, src).to_sym, $1)).parse(model, src)
220
+ $stderr.puts %<WARN: Record redefinition: "#{newRecord.key}"> if model.records[newRecord.key]
221
+ model.addRecord(newRecord)
222
+ else
223
+ nil
224
+ end
225
+ end
226
+
227
+ =begin rdoc
228
+ Creates an instance for the given full data type name, including namespace.
229
+ Namespace is required.
230
+
231
+
232
+ =end
233
+ def initialize(name)
234
+ #noinspection RubyArgCount
235
+ super()
236
+ @namespace, @baseName = DataMetaDom.splitNameSpace(name)
237
+
238
+ raise %Q<Record "#{@baseName}": no namespace; namespaces are required!> unless @namespace
239
+ @name = name.to_sym
240
+ @key = @name
241
+ @fields={}; @uniques={}; @identity=nil; @indexes = {}; @refs=[]
242
+ end
243
+
244
+ =begin rdoc
245
+ Fetches the field by the field key, i.e. Field.name
246
+ =end
247
+ def [](fieldKey); @fields[fieldKey] end
248
+
249
+ =begin rdoc
250
+ Verifies that the list of ids is valid, meaning that there is a field with the given name on this record.
251
+ * Parameter
252
+ * +ids+ - an array of strings, each should be a valid field name already defined on this Record.
253
+ =end
254
+ def assertIds(ids)
255
+ ids.each { |id|
256
+ k = id.to_sym
257
+ raise "Undeclared field '#{id}'" unless @fields.has_key?(k)
258
+ }
259
+ end
260
+
261
+ =begin rdoc
262
+ Set the identity on the Record.
263
+ * Parameter:
264
+ * +newIdy+ - an instance of RecIdentity
265
+ =end
266
+ def identity=(newIdy)
267
+ raise 'There can be only one identity statement in a record' if @identity
268
+ @identity = newIdy
269
+ assertIds(@identity.args)
270
+ @identity.args.each { |id|
271
+ f = @fields[id.to_sym]
272
+
273
+ raise ArgumentError, %|Field "#{
274
+ id}" is made identity; no aggregate types or maps can be identity| if f.aggr? || f.map?
275
+
276
+ raise ArgumentError, %|Optional field "#{
277
+ id}" is made identity; only required fields may be identity| unless f.isRequired
278
+ }
279
+ end
280
+
281
+ =begin rdoc
282
+ Add another unique index to the record.
283
+ * Parameter:
284
+ * +newUq+ - an instance of RecUnique to add ot this record.
285
+ =end
286
+ def addUnique(newUq)
287
+ assertIds(newUq.args)
288
+ raise "Duplicate unique set declaration #{newUq}" if @uniques.has_key?(newUq.key)
289
+ @uniques[newUq.key] = newUq
290
+ end
291
+
292
+ =begin rdoc
293
+ Add another non-unique index to the record.
294
+ * Parameter:
295
+ * +newIx+ - an instance of RecIndex to add to this Record
296
+ =end
297
+ def addIndex(newIx)
298
+ assertIds(newIx.args)
299
+ raise "Duplicate index declaration #{newIx}" if @indexes.has_key?(newIx.key)
300
+ @indexes[newIx.key] = newIx
301
+ end
302
+
303
+ =begin rdoc
304
+ Add another field to this Record's definition along with the source reference if any.
305
+ * Parameters:
306
+ * +newField+ - an instance of Field to add to this Record
307
+ * +source+ - a reference to the SourceFile where this field has been defined, pass +nil+ if
308
+ built from the code.
309
+ =end
310
+ def addField(newField, model, source=nil)
311
+ fieldKey = newField.name
312
+ raise "Duplicate field name '#{fieldKey}' in the Record '#{@name}'" if (@fields.key?(fieldKey))
313
+ @fields[fieldKey] = newField
314
+ unless STANDARD_TYPES.member?(newField.dataType.type)
315
+ ns, base = DataMetaDom.splitNameSpace(newField.dataType.type)
316
+ newNs = DataMetaDom.nsAdjustment(ns, model.options, source)
317
+ reRefName = "#{newNs}.#{base}".to_sym
318
+ newField.dataType.type = reRefName # adjust the type for finding the reference again
319
+ @refs << Reference.new(self, newField, reRefName, source ? source.snapshot : nil)
320
+ end
321
+ end
322
+
323
+ =begin rdoc
324
+ Add several Field definitions to this Record.
325
+ * Parameters:
326
+ * +fields+ - an array of the instances of Field to add to this Record
327
+ =end
328
+ def addFields(fields, model, source=nil); fields.each { |f| addField f, model, source } end
329
+
330
+ =begin rdoc
331
+ Add several non-unique indexes to the record.
332
+ * Parameter:
333
+ * +ixs+ - an array of the instances of RecIndex to add to this Record
334
+ =end
335
+ def addIndexes(ixs); ixs.each { |ix| addIndex ix } end
336
+
337
+ =begin rdoc
338
+ Add several unique indexes to the record.
339
+ * Parameter:
340
+ * +uqs+ - an array of instances of RecUnique to add ot this record.
341
+ =end
342
+ def addUniques(uqs); uqs.each { |uq| addUnique uq } end
343
+
344
+ =begin rdoc
345
+ Parse the Record from the given source into this instance.
346
+ * Parameter:
347
+ * +source+ - an instance of SourceFile to parse from
348
+ =end
349
+ def parse(model, source)
350
+ while (line = source.nextLine)
351
+ next if docConsumed?(source)
352
+ case line
353
+ when /^\s*#{END_KW}\s*$/
354
+ if source.docs
355
+ self.docs = source.docs.clone
356
+ source.docs.clear
357
+ end
358
+ self.ver = source.ver unless self.ver
359
+ raise "Version missing for the Record #{name}" unless self.ver
360
+ return self
361
+ when ''
362
+ next
363
+ else
364
+ isTokenConsumed = false
365
+ RECORD_LEVEL_TOKENS.each { |t|
366
+ isTokenConsumed = t.consumed? source, self
367
+ break if isTokenConsumed
368
+ }
369
+ unless isTokenConsumed
370
+ raise ArgumentError, "Record #{@name}: all field declarations must precede identity" if @identity
371
+ Field.consume(model, source, self)
372
+ end
373
+ resetEntity
374
+ end # case line
375
+ end # while line
376
+ self # for call chaining
377
+ end
378
+
379
+ =begin rdoc
380
+ Textual representation of this instance, with all the fields, attributes and references if any.
381
+ =end
382
+ def to_s
383
+ "Record{#{@name}(#{@fields.values.join(';')},uq=[#{@uniques.map { |u| '[' + u.join(',') + ']' }.join('; ')}]"\
384
+ ";idy=[#{@identity ? @identity.args.join(',') : ''}]; refs=[#{@refs.join(',')}]}, #{self.ver}"
385
+ end
386
+ end
387
+
388
+ =begin rdoc
389
+ DataMeta DOM source tokens on the Model level:
390
+ * Record
391
+ * Enum
392
+ * BitSet
393
+ * Map
394
+ =end
395
+ MODEL_LEVEL_TOKENS=[Record, Enum, BitSet, Mappings]
396
+
397
+ end
@@ -0,0 +1,127 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ %w(fileutils set).each { |r| require r }
4
+
5
+ module DataMetaDom
6
+
7
+ =begin rdoc
8
+ A reference to another entity on this Model, any of:
9
+ * Record
10
+ * Enum
11
+ * BitSet
12
+ * Map
13
+
14
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
15
+ =end
16
+ class Reference
17
+
18
+ =begin rdoc
19
+ Type of a reference - unresolved.
20
+ =end
21
+ UNRESOLVED = :u
22
+
23
+ =begin rdoc
24
+ Type of a reference - to a Record.
25
+ =end
26
+ RECORD = :r
27
+
28
+ =begin rdoc
29
+ Type of a reference - to an Enum, a BitSet or a Map.
30
+ =end
31
+ ENUM_REF = :e
32
+
33
+ =begin rdoc
34
+ The unique key for the reference to use in a hashmap.
35
+ =end
36
+ attr_accessor :key
37
+
38
+ =begin rdoc
39
+ The field the reference originates from, an instance of a Field
40
+ =end
41
+ attr_accessor :fromField
42
+
43
+ =begin rdoc
44
+ The Record the reference originates from, an instance of a Record
45
+ =end
46
+ attr_accessor :fromEntity
47
+
48
+ =begin rdoc
49
+ The target Field of the reference, must be the only one field in the target Record's identity,
50
+ determined by the resolve method.
51
+ =end
52
+ attr_accessor :toFields
53
+
54
+ =begin rdoc
55
+ The target entity for this Reference, determined by the resolve method. If it is a Record,
56
+ the record must have an identity consisting from only one field.
57
+ =end
58
+ attr_accessor :toEntity
59
+
60
+ =begin rdoc
61
+ Reference to the source where this reference has been defined, if any.
62
+ =end
63
+ attr_accessor :sourceRef
64
+
65
+ =begin rdoc
66
+ The type of the reference, UNRESOLVED or RECORD or ENUM_REF.
67
+ =end
68
+ attr_accessor :type
69
+
70
+ =begin rdoc
71
+ Creates an instance with the given parameters.
72
+ * Parameters:
73
+ * +sourceEntity+ - the instance of Record the reference originates from.
74
+ * +sourceField+ - the instance of Field the reference originates from
75
+ * +targetEntitySpec+ - a string, specification of the target entity to be resolved
76
+ * +sourceRef+ - an instance of SourceFile
77
+ =end
78
+ def initialize(sourceEntity, sourceField, targetEntitySpec, sourceRef = nil)
79
+ @sourceRef = sourceRef
80
+ @targetEntitySpec = targetEntitySpec.to_sym; @fromEntity = sourceEntity; @fromField = sourceField
81
+ @type = UNRESOLVED
82
+ self
83
+ end
84
+
85
+ =begin rdoc
86
+ Resolve the target entity and the field on the given Model.
87
+ =end
88
+ def resolve(model)
89
+ #@fromField = @fromEntity[@sourceFieldSpec.to_sym]
90
+ #raise "The field #@sourceFieldSpec is not defined on this entity: #@fromEntity, #@sourceRef" unless @fromField
91
+ @toEntity = model.records[@targetEntitySpec] || model.enums[@targetEntitySpec]
92
+ raise "Target entity #{@targetEntitySpec} is not defined; #{@sourceRef}" unless @toEntity
93
+ case # IMPORTANT!! make sure that you do not inspect and do not use Entity.to_s - this will blow up the stack
94
+ when @toEntity.kind_of?(Enum), @toEntity.kind_of?(BitSet), @toEntity.kind_of?(Mappings)
95
+ @type = ENUM_REF
96
+ @key= "#{@type}/#{@fromEntity.name}.#{@fromField.name}->#{@toEntity.name}"
97
+ when @toEntity.kind_of?(Record)
98
+ idy = @toEntity.identity
99
+ # raise "#@targetEntitySpec does not have an identity, can not be referenced to in IDL; #@sourceRef" unless idy
100
+ #
101
+ # raise "Invalid ref #{@fromEntity.name}.#{@toField.name} -> #@toEntity"\
102
+ # "- it has no singular ID; #@sourceRef" unless idy.args.length == 1
103
+
104
+ @type = RECORD
105
+ @toFields = idy ? idy.args : @toEntity.fields.keys
106
+ # raise "The field #{idy.args[0]} is not defined on this entity: #@toEntity; #@sourceRef" unless @toField
107
+ @key = "#{@type}/#{@fromEntity.name}.#{@fromField.name}->#{@toEntity.name}.#{@toFields.join(',')}"
108
+ else
109
+ raise "Unsupported target entity: #{@toEntity.name}, for #{@sourceRef}"
110
+ end
111
+ end
112
+
113
+ =begin rdoc
114
+ Textual representation of this Reference. Need to be careful because the to_s on the Record includes a list of references
115
+ and if you include a Record in this textual, this will cause infinite recursion with the stack failure.
116
+ =end
117
+ def to_s
118
+ case @type
119
+ when UNRESOLVED; "Unresolved: #{@fromEntity.name}.#{@fromField.name} ==> #@targetEntitySpec; #@sourceRef"
120
+ when RECORD; "Record Ref: #@key"
121
+ when ENUM_REF; "Enum ref: #@key"
122
+ else; raise "Unsupported reference type #@type; #@sourceRef"
123
+ end
124
+ end
125
+ end
126
+
127
+ end
@@ -0,0 +1,150 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ %w(fileutils set dataMetaDom/docs dataMetaDom/ver).each { |r| require r }
4
+
5
+ module DataMetaDom
6
+ =begin rdoc
7
+ A Model coupled with the DataMeta DOM source file info
8
+
9
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
10
+ =end
11
+ class SourceFile < VerDoccable
12
+ =begin rdoc
13
+ The directory to this source file.
14
+ =end
15
+ attr_reader :path
16
+
17
+ =begin rdoc
18
+ The name of this source file in the directory indicated by the path property.
19
+ =end
20
+ attr_reader :name
21
+
22
+ =begin rdoc
23
+ Unique key of this source file to use in hash maps, the absolute path to avoid duplicates by
24
+ different ways to point to the file, turned into a symbol.
25
+ =end
26
+ attr_reader :key
27
+
28
+ =begin rdoc
29
+ The namespace associated with the source file.
30
+ =end
31
+ attr_reader :namespace
32
+
33
+ =begin rdoc
34
+ Current source line.
35
+ =end
36
+ attr_reader :line
37
+
38
+ =begin rdoc
39
+ Current source line number
40
+ =end
41
+ attr_reader :lineNum
42
+
43
+ =begin rdoc
44
+ Create an instance with the given parameters.
45
+ * Parameters:
46
+ * +path+ - directory where the source file is located
47
+ * +name+ - the base name of this source file
48
+ * +line+ - source line if any, useful when creating the source reference from the code when source is not trivial.
49
+ * +lineNum+ - line number, useful when creating the source reference from the code
50
+ * +namespace+ - namespace associated with this source file, useful when creating the source reference from the code
51
+ =end
52
+ def initialize(path, name, line = nil, lineNum = 0, namespace = nil)
53
+ #noinspection RubyArgCount
54
+ super()
55
+ @path = path
56
+ @name = name
57
+ @namespace = namespace
58
+ # use the Absolute Path to avoid double-dipping via different subdir references
59
+ @key = File.absolute_path("#{@path}#{File::SEPARATOR}#{@name}").to_sym
60
+ @lineNum = lineNum
61
+ @line = line # nil interpolates to an empty string
62
+ end
63
+
64
+ =begin rdoc
65
+ Create a shapshot of the source file information, useful for saving a status about an element currently parsed.
66
+ Can not use this instance - as the parsing progresses, the stateful information will change.
67
+ =end
68
+ def snapshot # for the history
69
+ snap = SourceFile.new(@path, @name, @line, @lineNum, @namespace)
70
+ snap.ver = Ver.new(self.ver.full)
71
+ snap
72
+ end
73
+
74
+ =begin rdoc
75
+ Parses this DataMeta DOM source into the given Model.
76
+ =end
77
+ def parse model
78
+ while nextLine
79
+ puts "Source: #{@line}" if $DEBUG
80
+ next if docConsumed?(self)
81
+ if (newVer = VerDoccable.verConsumed?(self))
82
+ raise RuntimeError, "Only one version definition allowed, second one found in line #{@lineNum}" if self.ver
83
+ self.ver = newVer
84
+ model.ver = newVer # plant it straight into the model per the latest design
85
+ raise ArgumentError,
86
+ %<Model version already defined as #{model.ver} but the file #{@path} tries to redefine it to #{newVer}.
87
+ This is not allowed: all included files should define same version> unless model.ver && newVer == model.ver
88
+ next
89
+ end
90
+ case @line
91
+ # treat the namespace operator as a special case
92
+ when /^\s*#{NAMESPACE}\s+([\w\.]+)$/
93
+ @namespace = $1
94
+ next
95
+ when /^\s*#{INCLUDE}\s+(\S+)$/
96
+ model.sources.queue "#{$1}.dmDom"
97
+ next
98
+ else
99
+ isTokenOk = false
100
+ MODEL_LEVEL_TOKENS.each { |c|
101
+ isTokenOk = c.consumed?(model, self)
102
+ if isTokenOk
103
+ resetEntity
104
+ break
105
+ end
106
+ }
107
+ raise "Syntax error; #{model.diagn}" unless isTokenOk
108
+
109
+ end
110
+
111
+ end # while
112
+ end
113
+
114
+ =begin rdoc
115
+ Advances a line, skipping empty lines and comments.
116
+ Parameter:
117
+ * +verbatim+ - pass true to maintain formatting and keep empty lines
118
+ =end
119
+ def nextLine(verbatim = false)
120
+ @file = File.open("#{@path}#{File::SEPARATOR}#{@name}") unless defined?(@file) && @file
121
+ while (line = @file.gets)
122
+ unless line
123
+ @file.close
124
+ nil
125
+ end
126
+ @lineNum += 1
127
+ return (@line = line) if verbatim
128
+ @line = line.chomp.strip
129
+
130
+ case @line
131
+ when '', /^\s*#.*$/ # skip comments and empty lines
132
+ next
133
+ else
134
+ return @line
135
+ end
136
+ end
137
+ end
138
+
139
+ =begin rdoc
140
+ Full name of this source file, absolute path. Derived from the key property turned into a string.
141
+ =end
142
+ def fullName; @key.to_s end
143
+
144
+ =begin rdoc
145
+ Textual representation of this source file reference, includes line number and the current source line.
146
+ =end
147
+ def to_s; "#{fullName}##{@lineNum}{{#{@line}}}" end # file name, line number and line
148
+ end
149
+
150
+ end