ridl 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,276 @@
1
+ #--------------------------------------------------------------------
2
+ # expression.rb - IDL Expression classes
3
+ #
4
+ # Author: Martin Corino
5
+ #
6
+ # This program is free software; you can redistribute it and/or
7
+ # modify it under the terms of the RIDL LICENSE which is
8
+ # included with this program.
9
+ #
10
+ # Copyright (c) Remedy IT Expertise BV
11
+ # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
+ #--------------------------------------------------------------------
13
+ require 'ridl/node'
14
+
15
+ module IDL
16
+ class Expression
17
+ attr_reader :idltype
18
+ attr_reader :value
19
+ def typename; @idltype.typename; end
20
+
21
+ def is_template?
22
+ false
23
+ end
24
+
25
+ def instantiate(_context)
26
+ self
27
+ end
28
+
29
+ class Value < Expression
30
+ def initialize(type, val)
31
+ @idltype = type
32
+ @value = @idltype.narrow(val)
33
+ end
34
+ end
35
+
36
+ class ScopedName < Expression
37
+ attr_reader :node
38
+ def initialize(node)
39
+ if $DEBUG
40
+ unless IDL::AST::Const === node || (IDL::AST::TemplateParam === node && node.idltype.is_a?(IDL::Type::Const))
41
+ raise RuntimeError,
42
+ "#{node.scoped_name} must be constant: #{node.class.name}."
43
+ end
44
+ end
45
+ @node = node
46
+ @idltype = node.idltype
47
+ @value = @idltype.narrow(node.value) unless node.is_template?
48
+ end
49
+ def is_template?
50
+ @node.is_template?
51
+ end
52
+ def instantiate(_context)
53
+ if self.is_template?
54
+ cp = IDL::AST::TemplateParam.concrete_param(_context, @node)
55
+ cp.is_a?(Expression) ? cp : ScopedName.new(cp)
56
+ else
57
+ self
58
+ end
59
+ end
60
+ def is_node?(node_class)
61
+ @node.is_a?(node_class)
62
+ end
63
+ def resolved_node
64
+ @node
65
+ end
66
+ end
67
+
68
+ class Enumerator < Expression
69
+ attr_reader :node
70
+ def initialize(node)
71
+ if $DEBUG
72
+ if not IDL::AST::Enumerator === node
73
+ raise RuntimeError,
74
+ "#{node.scoped_name} must be enumerator: #{node.class.name}."
75
+ end
76
+ end
77
+ @node = node
78
+ @idltype = node.idltype
79
+ @value = node.value
80
+ end
81
+ end
82
+
83
+ class Operation < Expression
84
+ NUMBER_OF_OPERANDS = nil
85
+
86
+ attr_reader :operands
87
+ def initialize(*_operands)
88
+ n = self.class::NUMBER_OF_OPERANDS
89
+
90
+ if _operands.size != n
91
+ raise RuntimeError,
92
+ format("%s must receive %d operand%s.",
93
+ self.typename, n, if (n>1) then "s" else "" end)
94
+ end
95
+
96
+ unless _operands.any? { |o| o.is_template? }
97
+ @idltype = self.class.suite_type(*(_operands.collect{|o| o.idltype.resolved_type}))
98
+ @value = calculate(*(_operands.collect{|o| o.value}))
99
+ else
100
+ @idltype = nil
101
+ @value = nil
102
+ end
103
+ @operands = _operands
104
+ self.set_type
105
+ end
106
+
107
+ def is_template?
108
+ @operands.any? { |o| o.is_template? }
109
+ end
110
+
111
+ def instantiate(_context)
112
+ self.is_template? ? self.class.new(*@operands.collect { |o| o.instantiate(_context) }) : self
113
+ end
114
+
115
+ def Operation.suite_type(*types)
116
+ types.each do |t|
117
+ if not self::Applicable.include? t.class
118
+ raise RuntimeError,
119
+ "#{self.name} cannot be applicable for #{t.typename}"
120
+ end
121
+ end
122
+
123
+ ret = nil
124
+ types = types.collect {|t| t.class }
125
+ self::Applicable.each do |t|
126
+ if types.include? t
127
+ ret = t
128
+ break
129
+ end
130
+ end
131
+ ret
132
+ end
133
+ def set_type
134
+ end
135
+
136
+ class Unary < Operation
137
+ NUMBER_OF_OPERANDS = 1
138
+ Applicable = nil
139
+ end #of class Unary
140
+
141
+ class Integer2 < Operation
142
+ NUMBER_OF_OPERANDS = 2
143
+ Applicable = [
144
+ IDL::Type::LongLong, IDL::Type::ULongLong,
145
+ IDL::Type::Long, IDL::Type::ULong,
146
+ IDL::Type::Short, IDL::Type::UShort,
147
+ IDL::Type::Octet
148
+ ]
149
+
150
+ def Integer2.suite_sign(_t, _v)
151
+ [ [IDL::Type::LongLong, IDL::Type::ULongLong],
152
+ [IDL::Type::Long, IDL::Type::ULong],
153
+ [IDL::Type::Short, IDL::Type::UShort]
154
+ ].each do |t|
155
+ next unless t.include? _t
156
+ return (if _v < 0 then t[0] else t[1] end)
157
+ end
158
+ end
159
+
160
+ def set_type
161
+ if Integer2::Applicable.include? @idltype
162
+ @idltype = self.class.suite_sign(@idltype, @value)
163
+ end
164
+ end
165
+ end
166
+
167
+ class Boolean2 < Integer2
168
+ Applicable = [
169
+ IDL::Type::Boolean
170
+ ] + Integer2::Applicable
171
+
172
+ def Boolean2.checktype(t1, t2)
173
+ superclass.checktype(*types)
174
+
175
+ t = IDL::Type::Boolean
176
+ if (t1 == t && t2 != t) or (t1 != t && t2 == t)
177
+ raise RuntimeError,
178
+ "#{self.name} about #{t1.typename} and #{t2.typename} is illegal."
179
+ end
180
+ end
181
+ end
182
+
183
+ class Float2 < Integer2
184
+ Applicable = [
185
+ IDL::Type::LongDouble, IDL::Type::Double, IDL::Type::Float,
186
+ IDL::Type::Fixed
187
+ ] + Integer2::Applicable
188
+
189
+ def Float2.checktype(t1, t2)
190
+ superclass.checktype(*types)
191
+
192
+ # it's expected that Double, LongDouble is a Float.
193
+ s1,s2 = IDL::Type::Float, IDL::Type::Fixed
194
+ if (t1 === s1 && t2 === s2) or (t1 === s2 && t2 === s1)
195
+ raise RuntimeError,
196
+ "#{self.name} about #{t1.typename} and #{t2.typename} is illegal."
197
+ end
198
+ end
199
+ end
200
+
201
+ class UnaryPlus < Unary
202
+ Applicable = Float2::Applicable
203
+ def calculate(op)
204
+ op
205
+ end
206
+ end
207
+ class UnaryMinus < Unary
208
+ Applicable = Float2::Applicable
209
+ def calculate(op)
210
+ -op
211
+ end
212
+ def set_type
213
+ @idltype = Integer2.suite_sign(@idltype, @value)
214
+ end
215
+ end
216
+ class UnaryNot < Unary
217
+ Applicable = Integer2::Applicable
218
+ def calculate(op)
219
+ if @idltype.is_unsigned?()
220
+ (2**@idltype.bits-1)-op
221
+ else
222
+ ~op
223
+ end
224
+ end
225
+ end
226
+
227
+ class Or < Boolean2
228
+ def calculate(lop,rop); lop | rop; end
229
+ end
230
+ class And < Boolean2
231
+ def calculate(lop,rop); lop & rop; end
232
+ end
233
+ class Xor < Boolean2
234
+ def calculate(lop,rop); lop ^ rop; end
235
+ end
236
+
237
+ class Shift < Integer2
238
+ protected
239
+ def check_rop(rop)
240
+ if not (0...64) === rop
241
+ raise RuntimeError,
242
+ "right operand for shift must be in the range 0 <= right operand < 64: #{rop}."
243
+ end
244
+ end
245
+ end
246
+ class LShift < Shift
247
+ def calculate(lop,rop)
248
+ check_rop(rop)
249
+ lop << rop
250
+ end
251
+ end
252
+ class RShift < Shift
253
+ def calculate(lop,rop)
254
+ check_rop(rop)
255
+ lop >> rop
256
+ end
257
+ end
258
+
259
+ class Add < Float2
260
+ def calculate(lop,rop); lop + rop; end
261
+ end
262
+ class Minus < Float2
263
+ def calculate(lop,rop); lop - rop; end
264
+ end
265
+ class Mult < Float2
266
+ def calculate(lop,rop); lop * rop; end
267
+ end
268
+ class Div < Float2
269
+ def calculate(lop,rop); lop / rop; end
270
+ end
271
+ class Mod < Integer2
272
+ def calculate(lop,rop); lop % rop; end
273
+ end
274
+ end #of class Operation
275
+ end #of class Expression
276
+ end
@@ -0,0 +1,220 @@
1
+ #--------------------------------------------------------------------
2
+ # genfile.rb - Generator file class implementation.
3
+ #
4
+ # Author: Martin Corino
5
+ #
6
+ # This program is free software; you can redistribute it and/or
7
+ # modify it under the terms of the RIDL LICENSE which is
8
+ # included with this program.
9
+ #
10
+ # Copyright (c) Remedy IT Expertise BV
11
+ # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
+ #--------------------------------------------------------------------
13
+ require 'tempfile'
14
+ require 'fileutils'
15
+
16
+ module IDL
17
+
18
+ class GenFile
19
+
20
+ @@stack = []
21
+ @@cur_trans = nil
22
+
23
+ def self.transaction(&block)
24
+ @@cur_trans = []
25
+ @@stack << @@cur_trans
26
+ begin
27
+ block.call if block_given?
28
+ @@cur_trans.each {|fgen| fgen.save }
29
+ @@cur_trans.clear
30
+ ensure
31
+ self.rollback # after successful transaction should be nothing left
32
+ @@stack.pop
33
+ @@cur_trans = @@stack.last
34
+ end
35
+ end
36
+
37
+ def self.rollback
38
+ if @@cur_trans
39
+ @@cur_trans.each {|fgen| fgen.remove }
40
+ @@cur_trans.clear
41
+ end
42
+ end
43
+
44
+ class Content
45
+ def initialize(sections = {})
46
+ # copy content map transforming all keys to symbols
47
+ @sections = sections.inject({}) {|m,(k,v)| m[k.to_sym] = v; m }
48
+ end
49
+
50
+ def sections
51
+ @sections.keys
52
+ end
53
+
54
+ def has_section?(sectionid)
55
+ @sections.has_key?((sectionid || '').to_sym)
56
+ end
57
+
58
+ def [](sectionid)
59
+ @sections[(sectionid || '').to_sym]
60
+ end
61
+
62
+ def each(&block)
63
+ @sections.each(&block)
64
+ end
65
+ end
66
+
67
+ REGEN_MARKER_DEFAULT = '@@{__RIDL_REGEN_MARKER__}'
68
+
69
+ attr_reader :path, :fullpath, :name, :ext, :content
70
+
71
+ def initialize(path, opts = {})
72
+ if path
73
+ @path = path
74
+ @fullpath = File.expand_path(path)
75
+ @name = File.basename(path)
76
+ @ext = File.extname(path).sub(/^\./,'')
77
+ else
78
+ @path = @fullpath = @name = @ext = ''
79
+ end
80
+ @options = {
81
+ :regenerate => false,
82
+ :regen_marker_prefix => '//',
83
+ :regen_marker_postfix => nil,
84
+ :regen_marker => REGEN_MARKER_DEFAULT,
85
+ :regen_keep_header => false,
86
+ :output_file => nil
87
+ }.merge(opts)
88
+ if @options[:regenerate] && File.exists?(@fullpath)
89
+ parse_regeneration_content
90
+ else
91
+ @content = Content.new
92
+ end
93
+ @fout = @options[:output_file] || Tempfile.new(@name)
94
+ @@cur_trans << self
95
+ end
96
+
97
+ def <<(txt)
98
+ @fout << txt if @fout
99
+ self
100
+ end
101
+
102
+ def regen_start_marker(sectionid)
103
+ "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - BEGIN : #{sectionid}#{@options[:regen_marker_postfix]}"
104
+ end
105
+
106
+ def regen_end_marker(sectionid)
107
+ "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - END : #{sectionid}#{@options[:regen_marker_postfix]}"
108
+ end
109
+
110
+ def regen_header_end_marker(sectionid)
111
+ "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - HEADER_END : #{sectionid}#{@options[:regen_marker_postfix]}"
112
+ end
113
+
114
+ def write_regen_section(sectionid, default_content, indent = '', options = {})
115
+ self << indent << regen_start_marker(sectionid) << "\n" unless options[:header]
116
+ if content.has_section?(sectionid)
117
+ self << content[sectionid].join unless content[sectionid].empty?
118
+ else
119
+ default_content = (Array === default_content) ? default_content : default_content.to_s.split("\n")
120
+ self << (default_content.collect {|l| (s = indent.dup) << l << "\n"; s }.join) unless default_content.empty?
121
+ end
122
+ if options[:header]
123
+ self << indent << regen_header_end_marker(sectionid) << "\n"
124
+ else
125
+ self << indent << regen_end_marker(sectionid) << "\n" unless options[:footer]
126
+ end
127
+ end
128
+
129
+ def save
130
+ return if @options[:output_file]
131
+ if @fout
132
+ fgen = @fout
133
+ @fout = nil
134
+ fgen.close(false) # close but do NOT unlink
135
+ if File.exists?(@fullpath)
136
+ # create temporary backup
137
+ ftmp = Tempfile.new(@name)
138
+ ftmp_name = ftmp.path.dup
139
+ ftmp.close(true) # close AND unlink
140
+ FileUtils::mv(@fullpath, ftmp_name) # backup existing file
141
+ # replace original
142
+ begin
143
+ # rename newly generated file
144
+ FileUtils::mv(fgen.path, @fullpath)
145
+ # preserve file mode
146
+ FileUtils::chmod(File.lstat(ftmp_name).mode, @fullpath)
147
+ rescue
148
+ IDL.log(0, %Q{ERROR: FAILED updating #{@path}: #{$!}})
149
+ # restore backup
150
+ FileUtils::mv(ftmp_name, @fullpath)
151
+ raise
152
+ end
153
+ # remove backup
154
+ File.unlink(ftmp_name)
155
+ else
156
+ # just rename newly generated file
157
+ FileUtils::mv(fgen.path, @fullpath)
158
+ # set default mode for new files
159
+ FileUtils::chmod(0666 - File.umask, @fullpath)
160
+ end
161
+ end
162
+ end
163
+
164
+ def remove
165
+ return if @options[:output_file]
166
+ if @fout
167
+ begin
168
+ @fout.close(true)
169
+ rescue
170
+ IDL.log(0, %Q{ERROR: FAILED to clean up temp file #{@fout.path}: #{$!}})
171
+ end
172
+ @fout = nil
173
+ end
174
+ end
175
+
176
+ private
177
+
178
+ def parse_regeneration_content
179
+ markers_sel = %w{BEGIN END}
180
+ _keep_header = (@options[:regen_keep_header] == true)
181
+ markers_sel << 'HEADER_END' if _keep_header
182
+ regen_marker_re = /#{@options[:regen_marker]}\s+[-]\s+(#{markers_sel.join('|')})\s+:\s+(.+)/
183
+ sections = {}
184
+ section = []
185
+ in_section = _keep_header ? ['HEADER', 0] : nil
186
+ linenr = 0
187
+ File.open(@fullpath) do |fio|
188
+ fio.each do |line|
189
+ linenr += 1
190
+ if regen_marker_re =~ line
191
+ case $1
192
+ when 'BEGIN'
193
+ raise RuntimeError, "ERROR: Found unterminated regeneration section starting at #{@path}:#{in_section.last}." if in_section
194
+ in_section = [$2, linenr]
195
+ section = []
196
+ when 'END'
197
+ raise RuntimeError, "ERROR: Found unmatched regeneration end at #{@path}:#{linenr}." unless in_section && ($2 == in_section.first)
198
+ sections[$2] = section
199
+ in_section = nil
200
+ section = []
201
+ when 'HEADER_END'
202
+ raise RuntimeError, "ERROR: Found illegal header end marker at #{@path}:#{linenr}." unless _keep_header && in_section &&
203
+ ('HEADER' == in_section.first ) && (0 == in_section.last)
204
+ sections[$2] = section
205
+ in_section = nil
206
+ section = []
207
+ else
208
+ raise RuntimeError, "ERROR: Found invalid regeneration marker at #{@path}:#{linenr}."
209
+ end
210
+ elsif in_section
211
+ section << line
212
+ end
213
+ end
214
+ end
215
+ sections[in_section.first] = section if in_section
216
+ @content = Content.new(sections)
217
+ end
218
+
219
+ end
220
+ end