sfp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sfp/Sfplib.rb ADDED
@@ -0,0 +1,357 @@
1
+ module Sfp
2
+ module SfpLangHelper
3
+ attr_accessor :root_dir, :home_dir
4
+ attr_reader :root, :used_classes, :arrays, :conformant
5
+
6
+ def init
7
+ @root = Hash.new
8
+ @now = @root
9
+ @id = 0
10
+ @root['Object'] = { '_self' => 'Object', '_context' => 'class', '_parent' => @root }
11
+ @unexpanded_classes = Array.new
12
+ @used_classes = Array.new
13
+ @arrays = Hash.new
14
+ @conformant = false
15
+ end
16
+
17
+ def next_id
18
+ nid = "c" + @id.to_s
19
+ @id += 1
20
+ return nid
21
+ end
22
+
23
+ def null_value(isa=nil)
24
+ return { '_context' => 'null', '_isa' => isa }
25
+ end
26
+
27
+ def to_ref(path)
28
+ ref = "$." + path
29
+ return ref
30
+ end
31
+
32
+ def to_sfp
33
+ return @root
34
+ end
35
+
36
+ def create_constraint(name, type='and')
37
+ return { '_self' => name,
38
+ '_context' => 'constraint',
39
+ '_type' => type,
40
+ '_parent' => @now
41
+ }
42
+ end
43
+
44
+ def process_file(file)
45
+ filepath = file
46
+ filepath = @root_dir + "/" + file if not @root_dir.nil? and file[0,1] != '/'
47
+ filepath = @home_dir + "/" + file if not @home_dir.nil? and not File.exist?(filepath)
48
+
49
+ raise Exception, 'File not found: ' + file if not File.exist?(filepath)
50
+
51
+ new_home_dir = File.expand_path(File.dirname(filepath))
52
+ parser = Sfp::Parser.new({:root_dir => @root_dir, :home_dir => new_home_dir})
53
+ parser.parse(File.read(filepath))
54
+
55
+ parser.root.each_pair { |key,val|
56
+ if val['_context'] == 'class' or val['_context'] == 'composite'
57
+ @root[key] = val
58
+ elsif val['_context'] == 'state' or val['_context'] == 'constraint'
59
+ if @root.has_key?(key)
60
+ if @root[key]['_context'] != val['_context']
61
+ @root[key] = val
62
+ else
63
+ val['_context'].each_pair { |k2,v2| @root[key][k2] = v2 }
64
+ end
65
+ else
66
+ @root[key] = val
67
+ end
68
+ end
69
+ }
70
+ end
71
+
72
+ def goto_parent(remove_parent=false)
73
+ n = @now
74
+ @now = @now['_parent']
75
+ n.delete('_parent') if remove_parent
76
+ return n
77
+ end
78
+
79
+ def expand_classes
80
+ @unexpanded_classes.each { |c|
81
+ sclass = @root.at?(c['_extends'])
82
+ c.inherits( sclass )
83
+ c['_super'] = (sclass.has_key?('_super') ? sclass['_super'].clone : Array.new)
84
+ c['_super'] << c['_extends']
85
+ }
86
+ end
87
+
88
+ def expand_object(obj)
89
+ return false if not Sfp::Helper.expand_object(obj, @root)
90
+ @used_classes = @used_classes.concat(obj['_classes']).uniq
91
+ end
92
+
93
+ def deep_clone(value)
94
+ if value.is_a?(Hash)
95
+ result = value.clone
96
+ value.each { |k,v|
97
+ if k != '_parent'
98
+ result[k] = deep_clone(v)
99
+ result[k]['_parent'] = result if result[k].is_a?(Hash) and result[k].has_key?('_parent')
100
+ end
101
+ }
102
+ result
103
+ elsif value.is_a?(Array)
104
+ result = Array.new
105
+ value.each { |v| result << deep_clone(v) }
106
+ result
107
+ else
108
+ value
109
+ end
110
+ end
111
+ end
112
+
113
+ module Helper
114
+ def self.deep_clone(value)
115
+ if value.is_a?(Hash)
116
+ result = value.clone
117
+ value.each { |k,v|
118
+ if k != '_parent'
119
+ result[k] = deep_clone(v)
120
+ result[k]['_parent'] = result if result[k].is_a?(Hash) and result[k].has_key?('_parent')
121
+ end
122
+ }
123
+ result
124
+ elsif value.is_a?(Array)
125
+ result = Array.new
126
+ value.each { |v| result << deep_clone(v) }
127
+ result
128
+ else
129
+ value
130
+ end
131
+ end
132
+
133
+ def self.to_json(sfp)
134
+ root = Sfp::Helper.deep_clone(sfp)
135
+ root.accept(Sfp::Visitor::ParentEliminator.new)
136
+ return JSON.generate(root)
137
+ end
138
+
139
+ def self.to_pretty_json(sfp)
140
+ root = Sfp::Helper.deep_clone(sfp)
141
+ root.accept(Sfp::Visitor::ParentEliminator.new)
142
+ return JSON.pretty_generate(root)
143
+ end
144
+
145
+ def self.expand_object(obj, root)
146
+ return false if obj == nil or root == nil or
147
+ not obj.has_key?('_isa') or obj['_isa'] == nil
148
+ objclass = root.at?(obj['_isa'])
149
+ if objclass.nil? or objclass.is_a?(Sfp::Unknown) or objclass.is_a?(Sfp::Undefined)
150
+ raise Exception, 'Super class is not found: ' + obj['_self'] + ' < ' + obj['_isa']
151
+ end
152
+ obj.inherits( objclass )
153
+ obj['_classes'] = (objclass.has_key?('_super') ? objclass['_super'].clone : Array.new)
154
+ obj['_classes'] << obj['_isa']
155
+ return true
156
+ end
157
+ end
158
+
159
+
160
+ class Null
161
+ attr_accessor :type
162
+ end
163
+
164
+ # Instance of this class will be returned as the value of a non-exist variable
165
+ class Undefined
166
+ attr_accessor :path
167
+ def initialize(path=nil); @path = path; end
168
+ def to_s; (@path.nil? ? "<sfp::undefined>" : "<sfp::undefined[#{@path}]>"); end
169
+ end
170
+
171
+ # Instance of this class will be return as the value of an unknown variable
172
+ # in open-world assumption.
173
+ class Unknown
174
+ attr_accessor :path
175
+ def initialize(path=nil); @path = path; end
176
+ def to_s; (@path.nil? ? "<sfp::unknown>" : "<sfp::unknown[#{@path}]>"); end
177
+ end
178
+ end
179
+
180
+ # return a fullpath of reference of this context
181
+ Hash.send(:define_method, "ref") {
182
+ return '$' if not self.has_key?('_parent') or self['_parent'] == nil
183
+ me = (self.has_key?('_self') ? self['_self'] : '')
184
+ return self['_parent'].ref + "." + me
185
+ }
186
+
187
+ # accept method as implementation of Visitor pattern
188
+ Hash.send(:define_method, "accept") { |visitor|
189
+ keys = self.keys
190
+ keys.each do |key|
191
+ next if key == '_parent' or not self.has_key?(key)
192
+ value = self[key]
193
+ go_next = visitor.visit(key, value, self)
194
+ value.accept(visitor) if value.is_a?(Hash) and go_next == true
195
+ end
196
+ }
197
+
198
+ # resolve a reference, return nil if there's no value with given address
199
+ Hash.send(:define_method, "at?") { |addr|
200
+ return Sfp::Unknown.new if not addr.is_a?(String)
201
+
202
+ addrs = addr.split('.', 2)
203
+
204
+ if addrs[0] == '$'
205
+ return self.root.at?(addrs[1])
206
+ elsif addrs[0] == 'root'
207
+ return self.root.at?(addrs[1])
208
+ elsif addrs[0] == 'this' or addrs[0] == 'self'
209
+ return self.at?(addrs[1])
210
+ elsif addrs[0] == 'parent'
211
+ return nil if not self.has_key?('_parent')
212
+ return self['_parent'] if addrs[1].nil?
213
+ return self['_parent'].at?(addrs[1])
214
+ elsif self.has_key?(addrs[0])
215
+ if addrs.length == 1
216
+ return self[addrs[0]]
217
+ else
218
+ return self[addrs[0]].at?(addrs[1]) if self[addrs[0]].is_a?(Hash) and addrs[1] != ''
219
+ end
220
+ end
221
+
222
+ return Sfp::Unknown.new
223
+ }
224
+
225
+ Hash.send(:define_method, "type?") { |name|
226
+ return nil if not self.has_key?(name)
227
+ value = self[name]
228
+ if value != nil
229
+ return '$.Boolean' if value.is_a?(TrueClass) or value.is_a?(FalseClass)
230
+ return '$.Integer' if value.is_a?(Numeric)
231
+ return '$.String' if value.is_a?(String) and not value.isref
232
+ return value['_isa'] if value.isobject or value.isnull
233
+ return "(#{value['_isa']})" if value.is_a?(Hash) and value.isset and value.has_key?('_isa')
234
+ end
235
+
236
+ return nil
237
+ }
238
+
239
+ # return root context of this context
240
+ Hash.send(:define_method, "root") {
241
+ return self if not self.has_key?('_parent') or self['_parent'] == nil
242
+ return self['_parent'].root
243
+ }
244
+
245
+ # return true if this context is a constraint, otherwise false
246
+ Hash.send(:define_method, "isconstraint") {
247
+ return (self.has_key?('_context') and self['_context'] == 'constraint')
248
+ }
249
+
250
+ Hash.send(:define_method, "isset") {
251
+ return (self.has_key?('_context') and self['_context'] == 'set')
252
+ }
253
+
254
+ Hash.send(:define_method, "isprocedure") {
255
+ return (self.has_key?('_context') and self['_context'] == 'procedure')
256
+ }
257
+
258
+ # return true if this context is a class, otherwise false
259
+ Hash.send(:define_method, "isclass") {
260
+ return (self.has_key?('_context') and self['_context'] == 'class')
261
+ }
262
+
263
+ # return superclass' reference if this context is a sub-class, otherwise nil
264
+ Hash.send(:define_method, "extends") {
265
+ return self['_extends'] if self.isclass and self.has_key?('_extends')
266
+ return nil
267
+ }
268
+
269
+ # return true if this class has been expanded, otherwise false
270
+ Hash.send(:define_method, "expanded") {
271
+ @expanded = false if not defined?(@expanded)
272
+ return @expanded
273
+ }
274
+
275
+ # copy attributes and procedures from superclass to itself
276
+ Hash.send(:define_method, 'inherits') { |parent|
277
+ return if not parent.is_a?(Hash)
278
+ parent.each_pair { |key,value|
279
+ next if key[0,1] == '_' or self.has_key?(key)
280
+ if value.is_a?(Hash)
281
+ self[key] = Sfp::Helper.deep_clone(value)
282
+ self[key]['_parent'] = self
283
+ else
284
+ self[key] = value
285
+ end
286
+ }
287
+ @expanded = true
288
+ }
289
+
290
+ # return true if this context is an object, otherwise false
291
+ Hash.send(:define_method, 'isobject') {
292
+ return (self.has_key?('_context') and self['_context'] == 'object')
293
+ }
294
+
295
+ Hash.send(:define_method, 'isa') {
296
+ return nil if not self.isobject or not self.has_key?('_isa')
297
+ return self['_isa']
298
+ }
299
+
300
+ Hash.send(:define_method, 'isvalue') {
301
+ return self.isobject
302
+ }
303
+
304
+ Hash.send(:define_method, 'isnull') {
305
+ return (self.has_key?('_context') and self['_context'] == 'null')
306
+ }
307
+
308
+ Hash.send(:define_method, 'iseither') {
309
+ return (self['_context'] == 'either')
310
+ }
311
+
312
+ Hash.send(:define_method, 'tostring') {
313
+ return 'null' if self.isnull
314
+ return self.ref
315
+ }
316
+
317
+ # add path to the end of a reference
318
+ String.send(:define_method, "push") { |value|
319
+ return self.to_s + "." + value
320
+ }
321
+
322
+ # return first element and keep the rest
323
+ String.send(:define_method, 'explode') {
324
+ return self.split('.', 2)
325
+ }
326
+
327
+ # return an array of [ parent, last_element]
328
+ String.send(:define_method, 'pop_ref') {
329
+ return self.extract
330
+ }
331
+
332
+ # return an array of [ parent, last_element ]
333
+ String.send(:define_method, 'extract') {
334
+ return self if not self.isref
335
+ parts = self.split('.')
336
+ return self if parts.length <= 1
337
+ last = parts[ parts.length - 1 ]
338
+ len = self.length - last.length - 1
339
+ return [self[0, len], last]
340
+ }
341
+
342
+
343
+ # return true if this string is a reference, otherwise false
344
+ String.send(:define_method, 'isref') {
345
+ s = self.to_s
346
+ return true if (s.length > 0 and s[0,1] == '$')
347
+ return false
348
+ }
349
+
350
+ # return the parent of this path
351
+ # e.g.: if self == 'a.b.c.d', it will return 'a.b.c'
352
+ String.send(:define_method, 'to_top') {
353
+ return self if self == '$'
354
+ parts = self.split('.')
355
+ return self[0, self.length - parts[parts.length-1].length - 1]
356
+ }
357
+
data/lib/sfp/parser.rb ADDED
@@ -0,0 +1,128 @@
1
+ module Sfp
2
+ # main class which processes configuration description in SFP language either
3
+ # in file or as a string
4
+ class Parser
5
+ # enable this class to process SFP into FDR (SAS+)
6
+ include Sfp::SasTranslator
7
+
8
+ attr_accessor :root_dir, :home_dir, :conformant
9
+
10
+ def initialize(params={})
11
+ @root_dir = (params[:root_dir].is_a?(String) ?
12
+ params[:root_dir].strip :
13
+ nil)
14
+ @home_dir = (params[:home_dir].is_a?(String) ?
15
+ params[:home_dir].strip :
16
+ nil)
17
+ @root = params[:root]
18
+ @conformant = !!params[:conformant]
19
+ end
20
+
21
+ # @param string : a string in SFP language
22
+ def parse(string)
23
+ lexer = SfpLang::Lexer.new(string)
24
+ tokens = ANTLR3::CommonTokenStream.new(lexer)
25
+ parser = SfpLang::Parser.new(tokens)
26
+ parser.root_dir = @root_dir
27
+ parser.home_dir = @home_dir
28
+ parser.sfp
29
+ @root = parser.root
30
+ @conformant = parser.conformant
31
+ @parser_arrays = parser.arrays
32
+ end
33
+
34
+ =begin
35
+ # Parse SFP file and return its JSON representation
36
+ def self.parse_file(file)
37
+ return file_to_sfp(file)
38
+ end
39
+
40
+ def self.file_to_sfp(file)
41
+ parser = Parser.new
42
+ parser.parse_file(file)
43
+ return parser.to_sfp
44
+ end
45
+
46
+ def self.to_sfp(string)
47
+ parser = Parser.new
48
+ parser.parse(string)
49
+ return parser.to_sfp
50
+ end
51
+
52
+ # parse SFP file
53
+ def parse_file(file)
54
+ f = File.open(file, 'rb')
55
+ lexer = SFP::Lexer.new(f)
56
+ tokens = ANTLR3::CommonTokenStream.new(lexer)
57
+ parser = SFP::Parser.new(tokens)
58
+ parser.root_dir = (@root_dir == nil or @root_dir == '' ?
59
+ File.expand_path('.') : @root_dir)
60
+ parser.home_dir = File.dirname(f.path)
61
+ parser.sfp
62
+ @conformant = parser.conformant
63
+ @root = parser.root
64
+ @parser_arrays = parser.arrays
65
+ end
66
+
67
+ # parse SFP in a string
68
+ def parse(text)
69
+ lexer = SFP::Lexer.new(text)
70
+ tokens = ANTLR3::CommonTokenStream.new(lexer)
71
+ parser = SFP::Parser.new(tokens)
72
+ parser.root_dir = (@root_dir == nil or @root_dir == '' ?
73
+ File.expand_path(File.dirname('.')) : @root_dir)
74
+ parser.home_dir = parser.root_dir
75
+ parser.sfp
76
+ @root = parser.root
77
+ @parser_arrays = parser.arrays
78
+ end
79
+
80
+ # dump the parsed specification into standard output
81
+ def dump(root=nil)
82
+ return if root == nil
83
+ root = Nuri::Sfp.deep_clone(@root)
84
+ root.accept(ParentEliminator.new)
85
+ puts JSON.pretty_generate(root)
86
+ end
87
+
88
+ def self.dump(root)
89
+ return if root == nil
90
+ root = Nuri::Sfp.deep_clone(root)
91
+ root.accept(ParentEliminator.new)
92
+ puts JSON.pretty_generate(root)
93
+ end
94
+
95
+ def to_sfp
96
+ @root
97
+ end
98
+
99
+ def to_json
100
+ root = self.to_sfp
101
+ return if root == nil
102
+ root = Nuri::Sfp.deep_clone(root)
103
+ return Nuri::Sfp.to_json(root)
104
+ end
105
+ =end
106
+
107
+ def to_json(params={})
108
+ return '' if @root.nil?
109
+ return Sfp::Helper.to_pretty_json(@root) if params[:pretty]
110
+ return Sfp::Helper.to_json(@root)
111
+ end
112
+ end
113
+
114
+ =begin
115
+ def self.to_json(sfp)
116
+ root = Sfp::Helper.deep_clone(sfp)
117
+ root.accept(Nuri::Sfp::ParentEliminator.new)
118
+ return JSON.generate(root)
119
+ end
120
+
121
+ def self.to_pretty_json(sfp)
122
+ root = Nuri::Sfp.deep_clone(sfp)
123
+ root.accept(Nuri::Sfp::ParentEliminator.new)
124
+ return JSON.pretty_generate(root)
125
+ end
126
+ =end
127
+
128
+ end