cappruby 0.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,494 @@
1
+ #
2
+ # ruby_builder.rb
3
+ # cappruby
4
+ #
5
+ # Created by Adam Beynon.
6
+ # Copyright 2010 Adam Beynon.
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ # of this software and associated documentation files (the "Software"), to deal
10
+ # in the Software without restriction, including without limitation the rights
11
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ # copies of the Software, and to permit persons to whom the Software is
13
+ # furnished to do so, subject to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be included in
16
+ # all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ # THE SOFTWARE.
25
+ #
26
+
27
+ module CappRuby
28
+
29
+ class RubyBuilder < ::Vienna::RubyParser
30
+
31
+ def initialize(source, project, build_name)
32
+ super
33
+ end
34
+
35
+ class CappIseq
36
+
37
+ def initialize(type)
38
+ # iseq type
39
+ @type = type
40
+ # names => minimixed names (i.e. letters)
41
+ @local_names = { }
42
+ # same, for args
43
+ @arg_names = { }
44
+ # has a value, other than nil, of the str used to set the block param
45
+ # e.g. def method(&adam)' end ... this will be "adam", incase we
46
+ # reference it. The block always points to _$, whether we name it or not
47
+ @block_name = nil
48
+ # current to use for minimized. 'a' is always self, so we start there
49
+ # and increment one time for every new local in context.
50
+ @local_current = 'a'
51
+ # Also, if type is a method, then we need room for a selector aswell:
52
+ if type == RubyBuilder::ISEQ_TYPE_METHOD
53
+ @local_current = @local_current.next
54
+ end
55
+
56
+
57
+ # to store code strings
58
+ @code = []
59
+ end
60
+
61
+ def type
62
+ @type
63
+ end
64
+
65
+ def local_current
66
+ @local_current
67
+ end
68
+
69
+ def local_current=(s)
70
+ @local_current = s
71
+ end
72
+
73
+ def write(str)
74
+ @code << str
75
+ end
76
+
77
+ # When we set this, if we are a blcok, then we need to set our
78
+ # @local current to that of the parent, and then, when we finish, set the
79
+ # parents to be what ours finishes at. This avoids clashing local var
80
+ # names.
81
+ #
82
+ # Doing it this way avoids us including these vars, declared in the block
83
+ # as vars in the method. they are vas just for the block.
84
+ def parent_iseq=(other)
85
+ @parent_iseq = other
86
+
87
+ if @type == RubyBuilder::ISEQ_TYPE_BLOCK
88
+ @local_current = other.local_current
89
+ end
90
+ end
91
+
92
+ # finalizes, as described above
93
+ def finalize
94
+ if @type == RubyBuilder::ISEQ_TYPE_BLOCK
95
+ @parent_iseq.local_current = @local_current
96
+ end
97
+ end
98
+
99
+ # looks u; the local name "str". This checks method arguments as well as
100
+ # local variables defined. If we have the local, then the string version
101
+ # of the minimized name is returned (e.g. _a, _b..... etc), or if we do
102
+ # not have it, then nil is returned.
103
+ #
104
+ # Also of note, this also checks if the str is the name of the block that
105
+ # was declared (if a method). A block &block is not an arg or a local, but
106
+ # can be referecenced if declared as a method "argument". These are stored
107
+ # as the local var _$, if present.
108
+ def lookup_local(str)
109
+ if @local_names.has_key? str
110
+ @local_names[str]
111
+ elsif @arg_names.has_key? str
112
+ @arg_names[str]
113
+ elsif @block_name
114
+ "_$"
115
+ else
116
+ if @type == RubyBuilder::ISEQ_TYPE_BLOCK
117
+ return @parent_iseq.lookup_local(str)
118
+ end
119
+ # if we are a block, check parent...
120
+ nil
121
+ end
122
+ end
123
+
124
+ # push arg name, and returns the "minimized version"
125
+ def push_arg_name(str)
126
+ @local_current = @local_current.next
127
+ @arg_names[str] = "_#{@local_current}"
128
+ "_#{@local_current}"
129
+ end
130
+
131
+ # push local name, and returns the "minimized version"
132
+ def push_local_name(str)
133
+ @local_current = @local_current.next
134
+ @local_names[str] = "_#{@local_current}"
135
+ "_#{@local_current}"
136
+ end
137
+
138
+ # set the block name, if present
139
+ def push_block_name(str)
140
+ @block_name = str
141
+ "_$"
142
+ end
143
+
144
+ def to_s
145
+ r = ""
146
+ # function should accept self. if a method type, then accept "sel" for
147
+ # selector, if block, dont add self, just args. top and class also
148
+ # accept just "self" - self is always _a
149
+ # puts @code
150
+ case @type
151
+ when RubyBuilder::ISEQ_TYPE_TOP
152
+ # _a is self (top self)
153
+ r << "function(_a"
154
+ when RubyBuilder::ISEQ_TYPE_METHOD
155
+ # _a is self, _b is the selector
156
+ r << "function(_a,_b"
157
+ @arg_names.each_value { |v| r << ",#{v}" }
158
+ when RubyBuilder::ISEQ_TYPE_CLASS
159
+ # _a is self (the class just created/modified)
160
+ r << "function(_a"
161
+ when RubyBuilder::ISEQ_TYPE_BLOCK
162
+ # no self, just args etc..
163
+ r << "function("
164
+ r << @arg_names.each_value.to_a.join(",")
165
+ else
166
+ abort "erm, unknwon iseq type"
167
+ end
168
+
169
+ r << "){"
170
+ # locals
171
+ if @local_names.length > 0
172
+ r << "var #{@local_names.each_value.to_a.join(", ")};"
173
+ end
174
+
175
+ r << "#{@code.join("")}}"
176
+
177
+ r
178
+ end
179
+
180
+ end
181
+
182
+ def iseq_stack_push type
183
+ @iseq_current = CappIseq.new type
184
+ @iseq_stack << @iseq_current
185
+ @iseq_current
186
+ end
187
+
188
+ def iseq_stack_pop
189
+ iseq = @iseq_stack.last
190
+ @iseq_stack.pop
191
+ @iseq_current = @iseq_stack.last
192
+ # finalize (var locals etc)
193
+ iseq.finalize
194
+ iseq.to_s
195
+ end
196
+
197
+ def generate_tree(tree)
198
+ top_iseq = iseq_stack_push ISEQ_TYPE_TOP
199
+ tree.each do |stmt|
200
+ generate_stmt stmt, :full_stmt => true, :last_stmt => tree.last == stmt
201
+ end
202
+ iseq_stack_pop
203
+ end
204
+
205
+ def generate_class(cls, context)
206
+ write "return " if context[:last_stmt] and context[:full_stmt]
207
+
208
+ current_iseq = @iseq_current
209
+ class_iseq = iseq_stack_push ISEQ_TYPE_CLASS
210
+ class_iseq.parent_iseq = current_iseq
211
+
212
+ # do each body stmt, but for now, assume nonoe
213
+ cls.bodystmt.each do |b|
214
+ generate_stmt b, :full_stmt => true, :last_stmt => b == cls.bodystmt.last
215
+ end
216
+
217
+ if cls.bodystmt.length == 0
218
+ write "return nil;"
219
+ end
220
+
221
+ iseq_stack_pop
222
+
223
+ write %{cr_defineclass(nil,nil,"#{cls.klass_name}",#{class_iseq},0)}
224
+
225
+ write ";" if context[:full_stmt]
226
+ end
227
+
228
+ def generate_def stmt, context
229
+ # work out if its an objj style method call..
230
+
231
+ write "return " if context[:last_stmt] and context[:full_stmt]
232
+
233
+ is_singleton = stmt[:singleton] ? 1 : 0
234
+
235
+ current_iseq = @iseq_current
236
+ def_iseq = iseq_stack_push(ISEQ_TYPE_METHOD)
237
+ def_iseq.parent_iseq = current_iseq
238
+
239
+ # arg names
240
+ if stmt[:arglist].arg
241
+ stmt[:arglist].arg.each { |a| @iseq_current.push_arg_name a[:value] }
242
+ end
243
+
244
+ # body stmts
245
+ stmt[:bodystmt].each do |b|
246
+ generate_stmt b, :full_stmt => true, :last_stmt => b == stmt[:bodystmt].last
247
+ end
248
+
249
+ iseq_stack_pop
250
+
251
+ # definemethod
252
+ write "cr_definemethod("
253
+
254
+ # base (singleton?)
255
+ if stmt[:singleton]
256
+ generate_stmt stmt[:singleton], :full_stmt => false, :last_stmt => false
257
+ else
258
+ # self
259
+ write "_a"
260
+ end
261
+
262
+ # method returns true if our normal method should add a colon onto the
263
+ # selector name (i.e. it takes either exactly 1 param, or it takes a
264
+ # single default param.. this might be the case, we just add a defailt
265
+ # value to the selector:)
266
+ sel_colon = gen_def_should_use_colon?(stmt[:arglist]) ? ":" : ""
267
+
268
+ write %{,"#{stmt[:fname]}#{sel_colon}",#{def_iseq},#{is_singleton})}
269
+
270
+ write ";" if context[:full_stmt]
271
+ end
272
+
273
+ # method returns true if our normal method should add a colon onto the
274
+ # selector name (i.e. it takes either exactly 1 param, or it takes a
275
+ # single default param.. this might be the case, we just add a defailt
276
+ # value to the selector:)
277
+ def gen_def_should_use_colon?(a)
278
+ # one normal arg, nothing else (block is irrelevant)
279
+ if a.arg_size==1 && a.opt_size== 0 && a.rest_size == 0 && a.post_size == 0
280
+ true
281
+ elsif a.arg_size==0 && a.opt_size==1 && a.rest_size==0 && a.post_size == 0
282
+ true
283
+ else
284
+ false
285
+ end
286
+ end
287
+
288
+ def generate_call call, context
289
+ # capture "function calls"
290
+ if call[:meth].match /^[A-Z](.*)$/
291
+ return generate_function_call call, context
292
+ end
293
+ # capture objj
294
+
295
+ write "return " if context[:last_stmt] and context[:full_stmt]
296
+
297
+ write %{cr_send(}
298
+ # receiver
299
+ if call[:recv]
300
+ call_bit = 0
301
+ generate_stmt call[:recv], :full_stmt => false, :last_stmt => false
302
+ else
303
+ call_bit = 8
304
+ # self as recv
305
+ write "_a"
306
+ end
307
+
308
+ write ","
309
+ # method id - we should look for adding a selector here..
310
+ sel_colon = gen_call_should_use_colon?(call) ? ":" : ""
311
+ write %{"#{call[:meth]}#{sel_colon}"}
312
+
313
+ write ","
314
+
315
+ # arguments
316
+ write "["
317
+ unless call[:call_args].nil? or call[:call_args][:args].nil?
318
+ call[:call_args][:args].each do |arg|
319
+ write "," unless call[:call_args][:args].last == arg
320
+ generate_stmt arg, :full_stmt => false
321
+ end
322
+ end
323
+
324
+ # assocs
325
+ if call[:call_args] and call[:call_args][:assocs]
326
+ write "," unless call[:call_args].nil? or call[:call_args][:args].nil?
327
+ write "cr_newhash("
328
+ call[:call_args][:assocs].each do |assoc|
329
+ write "," unless call[:call_args][:assocs].first == assoc
330
+ generate_stmt assoc[:key], :full_stmt => false, :last_stmt => false
331
+ write ","
332
+ generate_stmt assoc[:value], :full_stmt => false, :last_stmt => false
333
+ end
334
+ write ")"
335
+ end
336
+
337
+ write "]"
338
+ write ","
339
+
340
+ # block
341
+ if call[:brace_block]
342
+ current_iseq = @iseq_current
343
+ block_iseq = iseq_stack_push(ISEQ_TYPE_BLOCK)
344
+ block_iseq.parent_iseq = current_iseq
345
+
346
+ # block arg names
347
+ if call[:brace_block][:params]
348
+ call[:brace_block][:params].each do |p|
349
+ block_iseq.push_arg_name p[:value]
350
+ end
351
+ end
352
+
353
+ # block stmts
354
+ if call[:brace_block][:stmt]
355
+ call[:brace_block][:stmt].each do |a|
356
+ generate_stmt a, :full_stmt => true, :last_stmt => call[:brace_block][:stmt].last == a
357
+ end
358
+ end
359
+
360
+ iseq_stack_pop
361
+
362
+ write block_iseq.to_s
363
+ else
364
+ write "nil"
365
+ end
366
+ write ","
367
+
368
+ # op flag
369
+ write "#{call_bit})"
370
+
371
+ write ";" if context[:full_stmt]
372
+ end
373
+
374
+ def generate_function_call call, context
375
+ write "return " if context[:last_stmt] and context[:full_stmt]
376
+
377
+ write "cr_functioncall(\""
378
+ write call[:meth]
379
+ write "\",["
380
+
381
+ unless call[:call_args].nil? or call[:call_args][:args].nil?
382
+ call[:call_args][:args].each do |arg|
383
+ write "," unless call[:call_args][:args].first == arg
384
+ generate_stmt arg, :full_stmt => false
385
+ end
386
+ end
387
+
388
+ write "])"
389
+
390
+ write ";" if context[:full_stmt]
391
+ end
392
+
393
+ def generate_identifier id, context
394
+ write "return " if context[:last_stmt] and context[:full_stmt]
395
+
396
+ local = @iseq_current.lookup_local id[:name]
397
+ if local
398
+ write local
399
+ else
400
+ # cannot find local, so we assume it is a function call...
401
+ write %{cr_send(_a,"#{id[:name]}",[],nil,8)}
402
+ end
403
+
404
+ write ";" if context[:full_stmt]
405
+ end
406
+
407
+ # similar to def, but for calls (not objj style calls..)
408
+ def gen_call_should_use_colon?(c)
409
+ # basically, if a "special" method using ruby only things, then dont use
410
+ # a colon
411
+ return false if c[:meth].match /(\<|\!|\?\>\=\!)/
412
+
413
+ args_len = 0
414
+ if c[:call_args] and c[:call_args][:args]
415
+ args_len = args_len + c[:call_args][:args].length
416
+ end
417
+
418
+ if c[:call_args] and c[:call_args][:assocs]
419
+ args_len = args_len + 1
420
+ end
421
+
422
+ # essentially, true if only one arg..
423
+ (args_len == 1) ? true : false
424
+ end
425
+
426
+ def generate_self stmt, context
427
+ write "_a"
428
+ end
429
+
430
+ # Generate a yield stmt. This makes sure the current iseq is a method, as
431
+ # only methods can "yield".. also, sets the current iseq to "get block". We
432
+ # know the method uses a block, so we need to make sure we can get it, and
433
+ # put it into a local var.
434
+ def generate_yield stmt, context
435
+ write "\"block\""
436
+ end
437
+
438
+ def generate_string str, context
439
+ write %{"#{str[:value][0][:value]}"}
440
+ end
441
+
442
+ def generate_symbol sym, context
443
+ write %{ID2SYM("#{sym[:name]}")}
444
+ end
445
+
446
+ def generate_constant cnst, context
447
+ write %{cr_getconstant(_a,"#{cnst[:name]}")}
448
+ end
449
+
450
+ def generate_numeric num, context
451
+ write num[:value]
452
+ end
453
+
454
+ def generate_array ary, context
455
+ write "["
456
+ if ary[:args]
457
+ ary[:args].each do |a|
458
+ write "," unless ary[:args].first == a
459
+ generate_stmt a, :full_stmt => false, :last_stmt => false
460
+ end
461
+ end
462
+
463
+ write "]"
464
+ end
465
+
466
+ def generate_xstring stmt, context
467
+ write "return " if context[:last_stmt] and context[:full_stmt]
468
+ write stmt[:value][0][:value]
469
+ write ";" if context[:full_stmt]
470
+ end
471
+
472
+ def generate_assign stmt, context
473
+ write "return " if context[:last_stmt] and context[:full_stmt]
474
+
475
+ # LHS is an identifier (local)
476
+ if stmt[:lhs].node == :identifier
477
+ # check to see if it already exists, i.e. reusing old name
478
+ local = @iseq_current.lookup_local stmt[:lhs][:name]
479
+ unless local
480
+ # cannot find local, so we must make it
481
+ local = @iseq_current.push_local_name stmt[:lhs][:name]
482
+ end
483
+
484
+ write "#{local} = "
485
+ # RHS
486
+ generate_stmt stmt[:rhs], :full_stmt => false, :last_stmt => false
487
+ else
488
+ abort "unknown assign type: #{stmt[:lhs].node}"
489
+ end
490
+
491
+ write ";" if context[:full_stmt]
492
+ end
493
+ end
494
+ end
data/lib/cappruby.rb ADDED
@@ -0,0 +1,73 @@
1
+ #
2
+ # cappruby.rb
3
+ # cappruby
4
+ #
5
+ # Created by Adam Beynon.
6
+ # Copyright 2010 Adam Beynon.
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ # of this software and associated documentation files (the "Software"), to deal
10
+ # in the Software without restriction, including without limitation the rights
11
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ # copies of the Software, and to permit persons to whom the Software is
13
+ # furnished to do so, subject to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be included in
16
+ # all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ # THE SOFTWARE.
25
+ #
26
+
27
+ require 'yaml'
28
+ require 'fileutils'
29
+ require 'rubygems'
30
+ # require 'vienna'
31
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'vienna.rb')
32
+
33
+ module CappRuby
34
+
35
+ ROOTPATH = File.join(File.dirname(__FILE__), '..')
36
+
37
+ def self.tools(args)
38
+
39
+ cmd = args.shift
40
+ if cmd.nil? || cmd == "-h" || cmd == '--help'
41
+ print_usage
42
+ exit
43
+ end
44
+
45
+ case cmd
46
+ when "gen"
47
+ gen args
48
+ when "build"
49
+ require_libs
50
+ AppBuilder.new(args).build!
51
+ when "-f"
52
+ puts "update frameworks"
53
+ else
54
+ print_usage
55
+ exit
56
+ end
57
+
58
+ end
59
+
60
+ def self.print_usage
61
+ puts "Usage: cappruby gen <app name>"
62
+ end
63
+
64
+ def self.gen(args)
65
+ puts "gen.."
66
+ end
67
+
68
+ def self.require_libs
69
+ libs = File.join(File.dirname(__FILE__), 'cappruby', '**', '*.rb')
70
+ Dir.glob(libs).each { |f| require f }
71
+ end
72
+
73
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cappruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Beynon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-30 00:00:00 +00:00
13
+ default_executable: cappruby
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: vienna
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: cappruby
26
+ email: adam@adambeynon.com
27
+ executables:
28
+ - cappruby
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - Rakefile
35
+ - VERSION
36
+ - bin/cappruby
37
+ - build/CappRuby/CappRuby.j
38
+ - cappruby.gemspec
39
+ - demos/simple_app/config/build.yml
40
+ - demos/simple_app/lib/application.rb
41
+ - demos/simple_app/lib/menu.rb
42
+ - framework/array.js
43
+ - framework/cappruby.js
44
+ - framework/class.js
45
+ - framework/enumerator.js
46
+ - framework/file.js
47
+ - framework/geometry.js
48
+ - framework/hash.js
49
+ - framework/mapings.js
50
+ - framework/method.js
51
+ - framework/module.js
52
+ - framework/object.js
53
+ - framework/objj_additions.js
54
+ - framework/proc.js
55
+ - framework/string.js
56
+ - framework/variable.js
57
+ - framework/vm.js
58
+ - framework/window.js
59
+ - lib/cappruby.rb
60
+ - lib/cappruby/app_builder.rb
61
+ - lib/cappruby/framework_builder.rb
62
+ - lib/cappruby/ruby_builder.rb
63
+ has_rdoc: true
64
+ homepage: http://github.com/adambeynon/cappruby
65
+ licenses: []
66
+
67
+ post_install_message:
68
+ rdoc_options:
69
+ - --charset=UTF-8
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "0"
83
+ version:
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.3.5
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: cappruby
91
+ test_files: []
92
+