csquare-cast 0.2.2

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,255 @@
1
+ ######################################################################
2
+ #
3
+ # C.default_parser and the parse_* methods.
4
+ #
5
+ # Yeah, this could be so much faster.
6
+ #
7
+ ######################################################################
8
+
9
+ module C
10
+ @@default_parser = Parser.new
11
+ def self.default_parser
12
+ @@default_parser
13
+ end
14
+ def self.default_parser=(val)
15
+ @@default_parser = val
16
+ end
17
+
18
+ class Node
19
+ #
20
+ # Return true if `str' is parsed to something `==' to this Node.
21
+ # str is first converted to a String using #to_s, then given to
22
+ # self.class.parse (along with the optional `parser').
23
+ #
24
+ def match?(str, parser=nil)
25
+ node = self.class.parse(str.to_s, parser) rescue (return false)
26
+ self == node
27
+ end
28
+ #
29
+ # Same as #match?.
30
+ #
31
+ def =~(*args)
32
+ match?(*args)
33
+ end
34
+ private
35
+ end
36
+ class NodeList
37
+ #
38
+ # As defined in Node.
39
+ #
40
+ def match?(arr, parser=nil)
41
+ arr = arr.to_a
42
+ return false if arr.length != self.length
43
+ each_with_index do |node, i|
44
+ node.match?(arr[i], parser) or return false
45
+ end
46
+ return true
47
+ end
48
+ end
49
+
50
+ def self.parse(s, parser=nil)
51
+ TranslationUnit.parse(s, parser)
52
+ end
53
+
54
+ class TranslationUnit
55
+ def self.parse(s, parser=nil)
56
+ parser ||= C.default_parser
57
+ parser.parse(s)
58
+ end
59
+ end
60
+
61
+ class Declaration
62
+ def self.parse(s, parser=nil)
63
+ parser ||= C.default_parser
64
+ ents = parser.parse(s).entities
65
+ if ents.length == 1 && # int i; int j;
66
+ ents[0].is_a?(Declaration) # void f() {}
67
+ return ents[0].detach
68
+ else
69
+ raise ParseError, "invalid Declaration"
70
+ end
71
+ end
72
+ end
73
+
74
+ class Parameter
75
+ def self.parse(s, parser=nil)
76
+ parser ||= C.default_parser
77
+ ents = parser.parse("void f(#{s}) {}").entities
78
+ if ents.length == 1 && # ) {} void (
79
+ ents[0].is_a?(FunctionDef) && # ); void(
80
+ ents[0].type.params && #
81
+ ents[0].type.params.length <= 1 # x,y
82
+ param = ents[0].type.params[0]
83
+ if param.nil?
84
+ return Parameter.new(Void.new)
85
+ else
86
+ return param.detach
87
+ end
88
+ else
89
+ raise ParseError, "invalid Parameter"
90
+ end
91
+ end
92
+ end
93
+
94
+ class Declarator
95
+ def self.parse(s, parser=nil)
96
+ parser ||= C.default_parser
97
+ # if there's a ':', declare in a struct so we can populate num_bits
98
+ if s =~ /:/
99
+ ents = parser.parse("struct {int #{s};};").entities
100
+ if ents.length == 1 && # i:1;}; struct {int i
101
+ ents[0].type.members.length == 1 && # i:1; int j
102
+ ents[0].type.members[0].declarators.length == 1 # i:1,j
103
+ return ents[0].type.members[0].declarators[0].detach
104
+ end
105
+ else
106
+ ents = parser.parse("int #{s};").entities
107
+ if ents.length == 1 && # f; int f;
108
+ ents[0].declarators.length == 1 # i,j
109
+ return ents[0].declarators[0].detach
110
+ end
111
+ end
112
+ raise ParseError, "invalid Declarator"
113
+ end
114
+ end
115
+
116
+ class FunctionDef
117
+ def self.parse(s, parser=nil)
118
+ parser ||= C.default_parser
119
+ ents = parser.parse(s).entities
120
+ if ents.length == 1 && # void f(); void g();
121
+ ents[0].is_a?(FunctionDef) # int i;
122
+ return ents[0].detach
123
+ else
124
+ raise ParseError, "invalid FunctionDef"
125
+ end
126
+ end
127
+ end
128
+
129
+ class Enumerator
130
+ def self.parse(s, parser=nil)
131
+ parser ||= C.default_parser
132
+ ents = parser.parse("enum {#{s}};").entities
133
+ if ents.length == 1 && # } enum {
134
+ ents[0].is_a?(Declaration) && # } f() {
135
+ ents[0].type.members.length == 1 # X, Y
136
+ return ents[0].type.members[0].detach
137
+ else
138
+ raise ParseError, "invalid Enumerator"
139
+ end
140
+ end
141
+ end
142
+
143
+ class MemberInit
144
+ def self.parse(s, parser=nil)
145
+ parser ||= C.default_parser
146
+ ents = parser.parse("int f() {struct s x = {#{s}};}").entities
147
+ if ents.length == 1 && # } int f() {
148
+ ents[0].def.stmts.length == 1 && # }} f() {{
149
+ ents[0].def.stmts[0].declarators.length == 1 && # 1}, y
150
+ ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 # 1, 2
151
+ return ents[0].def.stmts[0].declarators[0].init.member_inits[0].detach
152
+ else
153
+ raise ParseError, "invalid MemberInit"
154
+ end
155
+ end
156
+ end
157
+
158
+ class Member
159
+ def self.parse(s, parser=nil)
160
+ parser ||= C.default_parser
161
+ ents = parser.parse("int f() {struct s x = {.#{s} = 1};}").entities
162
+ if ents.length == 1 && # a = 1};} int f() {struct s x = {a
163
+ ents[0].def.stmts.length == 1 && # a = 1}; struct s y = {.a
164
+ #ents[0].def.stmts[0].length == 1 && # a = 1}, x = {.a
165
+ ents[0].def.stmts[0].declarators.length == 1 && # a = 1}, x = {.a
166
+ ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 && # x = 1, y
167
+ ents[0].def.stmts[0].declarators[0].init.member_inits[0].member && # 1
168
+ ents[0].def.stmts[0].declarators[0].init.member_inits[0].member.length == 1 # a .b
169
+ return ents[0].def.stmts[0].declarators[0].init.member_inits[0].member[0].detach
170
+ else
171
+ raise ParseError, "invalid Member"
172
+ end
173
+ end
174
+ end
175
+
176
+ class Statement
177
+ def self.parse(s, parser=nil)
178
+ parser ||= C.default_parser
179
+ ents = parser.parse("void f() {#{s}}").entities
180
+ if ents.length == 1 && # } void f() {
181
+ ents[0].def.stmts.length == 1 && # ;;
182
+ ents[0].def.stmts[0].is_a?(self) # int i;
183
+ return ents[0].def.stmts[0].detach
184
+ else
185
+ raise ParseError, "invalid #{self}"
186
+ end
187
+ end
188
+ end
189
+
190
+ class Label
191
+ def self.parse(s, parser=nil)
192
+ parser ||= C.default_parser
193
+ ents = parser.parse("void f() {switch (0) #{s};}").entities
194
+ if ents.length == 1 && # } void f() {
195
+ ents[0].def.stmts.length == 1 && # ;
196
+ ents[0].def.stmts[0].stmt && #
197
+ ents[0].def.stmts[0].stmt.labels.length == 1 && # x
198
+ ents[0].def.stmts[0].stmt.labels[0].is_a?(self)
199
+ return ents[0].def.stmts[0].stmt.labels[0].detach
200
+ else
201
+ raise ParseError, "invalid #{self}"
202
+ end
203
+ end
204
+ end
205
+
206
+ class Expression
207
+ def self.parse(s, parser=nil)
208
+ parser ||= C.default_parser
209
+ if s =~ /\A(\s*(\/\*.*?\*\/)?)*\{/
210
+ # starts with a brace -- must be a CompoundLiteral. in this
211
+ # case, use a Declarator since only those can handle typeless
212
+ # CompoundLiterals.
213
+ ents = parser.parse("int i = #{s};").entities
214
+ if ents.length == 1 && # 1; int i = 1
215
+ ents[0].declarators.length == 1 && # 1, j = 2
216
+ ents[0].declarators[0].init.is_a?(self)
217
+ return ents[0].declarators[0].init.detach
218
+ else
219
+ raise ParseError, "invalid #{self}"
220
+ end
221
+ else
222
+ ents = parser.parse("void f() {#{s};}").entities
223
+ if ents.length == 1 && # } void f() {
224
+ ents[0].def.stmts.length == 1 && # ;
225
+ ents[0].def.stmts[0].is_a?(ExpressionStatement) && # int i
226
+ ents[0].def.stmts[0].expr.is_a?(self)
227
+ return ents[0].def.stmts[0].expr.detach
228
+ else
229
+ raise ParseError, "invalid #{self}"
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ class Type
236
+ def self.parse(s, parser=nil)
237
+ parser ||= C.default_parser
238
+ ents = parser.parse("void f() {(#{s})x;}").entities
239
+ if ents.length == 1 && # 1);} void f() {(int
240
+ ents[0].def.stmts.length == 1 && # 1); (int
241
+ ents[0].def.stmts[0].expr.type.is_a?(self)
242
+ return ents[0].def.stmts[0].expr.type.detach
243
+ else
244
+ raise ParseError, "invalid #{self}"
245
+ end
246
+ end
247
+ end
248
+
249
+ # Make sure we didn't miss any
250
+ CORE_C_NODE_CLASSES.each do |c|
251
+ c.methods.include? 'parse' or
252
+ c.methods.include? :parse or
253
+ raise "#{c}#parse not defined"
254
+ end
255
+ end
@@ -0,0 +1,78 @@
1
+ require 'open3'
2
+ require 'rbconfig'
3
+
4
+ ##############################################################################
5
+ #
6
+ # A wrapper around the C preprocessor: RbConfig::CONFIG["CPP"]
7
+ #
8
+ ##############################################################################
9
+
10
+ module C
11
+ class Preprocessor
12
+ INCLUDE_REGEX = /(?:[^ ]|\\ )+\.h/i
13
+ COMPILER = RbConfig::CONFIG["CC"]
14
+
15
+ class Error < StandardError
16
+ end
17
+
18
+ class << self
19
+ attr_accessor :command
20
+ end
21
+
22
+ attr_accessor :pwd, :include_path, :macros
23
+
24
+ def initialize
25
+ @include_path = []
26
+ @macros = {}
27
+ end
28
+ def preprocess(text, line_markers = false)
29
+ args = %w{-E}
30
+ args << "-P" unless line_markers
31
+ run args, text
32
+ =begin
33
+ if clean_gnu_artifacts
34
+ output.gsub!(/\b__asm\((?:"[^"]*"|[^)"]*)*\)/, '')
35
+ output.gsub!(/\b__attribute__\(\((?:[^()]|\([^()]+\))+\)\)/, '')
36
+ output.gsub!(/ __inline /, ' ')
37
+ end
38
+ =end
39
+ end
40
+ def get_all_includes(text)
41
+ args = %w{-E -M}
42
+ split_includes run(args, text)
43
+ end
44
+ def get_system_includes(text)
45
+ get_all_includes(text) - get_project_includes(text)
46
+ end
47
+ def get_project_includes(text)
48
+ args = %w{-E -MM}
49
+ split_includes run(args, text)
50
+ end
51
+ def preprocess_file(file_name)
52
+ preprocess(File.read(file_name))
53
+ end
54
+
55
+ private # -------------------------------------------------------
56
+
57
+ def run(args, input)
58
+ options = {:stdin_data => input}
59
+ options[:chdir] = pwd if pwd
60
+ output, error, result = Open3.capture3(COMPILER, *args, *include_args, *macro_args, '-', options)
61
+ raise Error, error unless result.success?
62
+ output
63
+ end
64
+ def include_args
65
+ include_path.map do |path|
66
+ "-I#{path}"
67
+ end
68
+ end
69
+ def macro_args
70
+ macros.map do |key, val|
71
+ "-D#{key}#{val.nil? ? '' : "=#{val}"}"
72
+ end
73
+ end
74
+ def split_includes(text)
75
+ text.scan(INCLUDE_REGEX)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,186 @@
1
+ ######################################################################
2
+ #
3
+ # Alternative to the standard ruby tempfile library, which lets you
4
+ # specify a filename suffix.
5
+ #
6
+ ######################################################################
7
+
8
+ require 'delegate'
9
+ require 'tmpdir'
10
+ require 'thread'
11
+
12
+ # A class for managing temporary files. This library is written to be
13
+ # thread safe.
14
+ module C
15
+ class Tempfile < DelegateClass(File)
16
+ MAX_TRY = 10
17
+ @@cleanlist = []
18
+
19
+ # Creates a temporary file of mode 0600 in the temporary directory
20
+ # whose name is basename.pid.n.suffix and opens with mode "w+". A
21
+ # Tempfile object works just like a File object.
22
+ #
23
+ # If tmpdir is omitted, the temporary directory is determined by
24
+ # Dir::tmpdir provided by 'tmpdir.rb'.
25
+ # When $SAFE > 0 and the given tmpdir is tainted, it uses
26
+ # /tmp. (Note that ENV values are tainted by default)
27
+ def initialize(basename, tmpdir=Dir::tmpdir, suffix=nil)
28
+ if $SAFE > 0 and tmpdir.tainted?
29
+ tmpdir = '/tmp'
30
+ end
31
+
32
+ lock = nil
33
+ tmpname = nil
34
+ n = failure = 0
35
+
36
+ Thread.exclusive do
37
+ begin
38
+ begin
39
+ tmpname = File.join(tmpdir, make_tmpname(basename, n, suffix))
40
+ lock = tmpname + '.lock'
41
+ n += 1
42
+ end while @@cleanlist.include?(tmpname) or
43
+ File.exist?(lock) or File.exist?(tmpname)
44
+
45
+ Dir.mkdir(lock)
46
+ rescue
47
+ failure += 1
48
+ retry if failure < MAX_TRY
49
+ raise "cannot generate tempfile `%s'" % tmpname
50
+ end
51
+ end
52
+
53
+ @data = [tmpname]
54
+ @clean_proc = Tempfile.callback(@data)
55
+ ObjectSpace.define_finalizer(self, @clean_proc)
56
+
57
+ @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
58
+ @tmpname = tmpname
59
+ @@cleanlist << @tmpname
60
+ @data[1] = @tmpfile
61
+ @data[2] = @@cleanlist
62
+
63
+ super(@tmpfile)
64
+
65
+ # Now we have all the File/IO methods defined, you must not
66
+ # carelessly put bare puts(), etc. after this.
67
+
68
+ Dir.rmdir(lock)
69
+ end
70
+
71
+ def make_tmpname(basename, n, suffix)
72
+ sprintf('%s%d.%d%s', basename, $$, n, suffix)
73
+ end
74
+ private :make_tmpname
75
+
76
+ # Opens or reopens the file with mode "r+".
77
+ def open
78
+ @tmpfile.close if @tmpfile
79
+ @tmpfile = File.open(@tmpname, 'r+')
80
+ @data[1] = @tmpfile
81
+ __setobj__(@tmpfile)
82
+ end
83
+
84
+ def _close # :nodoc:
85
+ @tmpfile.close if @tmpfile
86
+ @data[1] = @tmpfile = nil
87
+ end
88
+ protected :_close
89
+
90
+ # Closes the file. If the optional flag is true, unlinks the file
91
+ # after closing.
92
+ #
93
+ # If you don't explicitly unlink the temporary file, the removal
94
+ # will be delayed until the object is finalized.
95
+ def close(unlink_now=false)
96
+ if unlink_now
97
+ close!
98
+ else
99
+ _close
100
+ end
101
+ end
102
+
103
+ # Closes and unlinks the file.
104
+ def close!
105
+ _close
106
+ @clean_proc.call
107
+ ObjectSpace.undefine_finalizer(self)
108
+ end
109
+
110
+ # Unlinks the file. On UNIX-like systems, it is often a good idea
111
+ # to unlink a temporary file immediately after creating and opening
112
+ # it, because it leaves other programs zero chance to access the
113
+ # file.
114
+ def unlink
115
+ # keep this order for thread safeness
116
+ begin
117
+ File.unlink(@tmpname) if File.exist?(@tmpname)
118
+ @@cleanlist.delete(@tmpname)
119
+ @data = @tmpname = nil
120
+ ObjectSpace.undefine_finalizer(self)
121
+ rescue Errno::EACCES
122
+ # may not be able to unlink on Windows; just ignore
123
+ end
124
+ end
125
+ alias delete unlink
126
+
127
+ # Returns the full path name of the temporary file.
128
+ def path
129
+ @tmpname
130
+ end
131
+
132
+ # Returns the size of the temporary file. As a side effect, the IO
133
+ # buffer is flushed before determining the size.
134
+ def size
135
+ if @tmpfile
136
+ @tmpfile.flush
137
+ @tmpfile.stat.size
138
+ else
139
+ 0
140
+ end
141
+ end
142
+ alias length size
143
+
144
+ class << self
145
+ def callback(data) # :nodoc:
146
+ pid = $$
147
+ lambda{
148
+ if pid == $$
149
+ path, tmpfile, cleanlist = *data
150
+
151
+ print "removing ", path, "..." if $DEBUG
152
+
153
+ tmpfile.close if tmpfile
154
+
155
+ # keep this order for thread safeness
156
+ File.unlink(path) if File.exist?(path)
157
+ cleanlist.delete(path) if cleanlist
158
+
159
+ print "done\n" if $DEBUG
160
+ end
161
+ }
162
+ end
163
+
164
+ # If no block is given, this is a synonym for new().
165
+ #
166
+ # If a block is given, it will be passed tempfile as an argument,
167
+ # and the tempfile will automatically be closed when the block
168
+ # terminates. In this case, open() returns nil.
169
+ def open(*args)
170
+ tempfile = new(*args)
171
+
172
+ if block_given?
173
+ begin
174
+ yield(tempfile)
175
+ ensure
176
+ tempfile.close
177
+ end
178
+
179
+ nil
180
+ else
181
+ tempfile
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end