ridl 2.2.4

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,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