dataMetaDom 1.0.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.
@@ -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