mirah 0.0.4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/History.txt +15 -0
  2. data/README.txt +51 -0
  3. data/Rakefile +86 -0
  4. data/bin/duby +10 -0
  5. data/bin/dubyc +10 -0
  6. data/bin/dubyp +10 -0
  7. data/bin/jrubyp +36 -0
  8. data/bin/mirah +9 -0
  9. data/bin/mirah.cmd +1 -0
  10. data/bin/mirahc +9 -0
  11. data/bin/mirahc.cmd +1 -0
  12. data/bin/mirahp +9 -0
  13. data/bin/mirahp.cmd +1 -0
  14. data/examples/ant/example-build.xml +7 -0
  15. data/examples/appengine/Rakefile +19 -0
  16. data/examples/appengine/Readme +29 -0
  17. data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
  18. data/examples/appengine/src/org/mirah/list.dhtml +15 -0
  19. data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
  20. data/examples/bintrees.mirah +66 -0
  21. data/examples/construction.mirah +8 -0
  22. data/examples/dynamic.mirah +17 -0
  23. data/examples/edb.mirah +3 -0
  24. data/examples/fib.mirah +16 -0
  25. data/examples/fields.mirah +22 -0
  26. data/examples/fractal.mirah +55 -0
  27. data/examples/java_thing.mirah +13 -0
  28. data/examples/plugins/appengine/Rakefile +55 -0
  29. data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
  30. data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
  31. data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
  32. data/examples/simple_class.mirah +12 -0
  33. data/examples/sort_closure.mirah +7 -0
  34. data/examples/swing.mirah +20 -0
  35. data/examples/tak.mirah +15 -0
  36. data/examples/test.edb +9 -0
  37. data/examples/wiki/Rakefile +18 -0
  38. data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
  39. data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
  40. data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
  41. data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
  42. data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
  43. data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
  44. data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
  45. data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
  46. data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
  47. data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
  48. data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
  49. data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
  50. data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
  51. data/examples/wiki/war/app.yaml +21 -0
  52. data/examples/wiki/war/public/favicon.ico +0 -0
  53. data/examples/wiki/war/public/images/appengine_duby.png +0 -0
  54. data/examples/wiki/war/public/images/back.gif +0 -0
  55. data/examples/wiki/war/public/images/dir.gif +0 -0
  56. data/examples/wiki/war/public/images/file.gif +0 -0
  57. data/examples/wiki/war/public/javascripts/prettify.js +61 -0
  58. data/examples/wiki/war/public/robots.txt +0 -0
  59. data/examples/wiki/war/public/stylesheets/main.css +156 -0
  60. data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
  61. data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
  62. data/examples/wiki/war/public/stylesheets/source.css +21 -0
  63. data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
  64. data/examples/wiki/war/public/wmd/images/bg.png +0 -0
  65. data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
  66. data/examples/wiki/war/public/wmd/images/bold.png +0 -0
  67. data/examples/wiki/war/public/wmd/images/code.png +0 -0
  68. data/examples/wiki/war/public/wmd/images/h1.png +0 -0
  69. data/examples/wiki/war/public/wmd/images/hr.png +0 -0
  70. data/examples/wiki/war/public/wmd/images/img.png +0 -0
  71. data/examples/wiki/war/public/wmd/images/italic.png +0 -0
  72. data/examples/wiki/war/public/wmd/images/link.png +0 -0
  73. data/examples/wiki/war/public/wmd/images/ol.png +0 -0
  74. data/examples/wiki/war/public/wmd/images/redo.png +0 -0
  75. data/examples/wiki/war/public/wmd/images/separator.png +0 -0
  76. data/examples/wiki/war/public/wmd/images/ul.png +0 -0
  77. data/examples/wiki/war/public/wmd/images/undo.png +0 -0
  78. data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
  79. data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
  80. data/examples/wiki/war/public/wmd/showdown.js +421 -0
  81. data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
  82. data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
  83. data/examples/wiki/war/public/wmd/wmd.js +73 -0
  84. data/javalib/JRubyParser.jar +0 -0
  85. data/javalib/dynalang-invoke-0.1.jar +0 -0
  86. data/javalib/mirah-bootstrap.jar +0 -0
  87. data/javalib/mirah-parser.jar +0 -0
  88. data/lib/duby.rb +2 -0
  89. data/lib/mirah.rb +338 -0
  90. data/lib/mirah/appengine_tasks.rb +146 -0
  91. data/lib/mirah/ast.rb +615 -0
  92. data/lib/mirah/ast/call.rb +307 -0
  93. data/lib/mirah/ast/class.rb +311 -0
  94. data/lib/mirah/ast/flow.rb +364 -0
  95. data/lib/mirah/ast/intrinsics.rb +470 -0
  96. data/lib/mirah/ast/literal.rb +154 -0
  97. data/lib/mirah/ast/local.rb +89 -0
  98. data/lib/mirah/ast/method.rb +360 -0
  99. data/lib/mirah/ast/scope.rb +208 -0
  100. data/lib/mirah/ast/structure.rb +226 -0
  101. data/lib/mirah/ast/type.rb +130 -0
  102. data/lib/mirah/compiler.rb +341 -0
  103. data/lib/mirah/env.rb +33 -0
  104. data/lib/mirah/jvm/base.rb +258 -0
  105. data/lib/mirah/jvm/compiler.rb +885 -0
  106. data/lib/mirah/jvm/method_lookup.rb +203 -0
  107. data/lib/mirah/jvm/source_compiler.rb +737 -0
  108. data/lib/mirah/jvm/source_generator/builder.rb +444 -0
  109. data/lib/mirah/jvm/source_generator/loops.rb +110 -0
  110. data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
  111. data/lib/mirah/jvm/source_generator/typer.rb +11 -0
  112. data/lib/mirah/jvm/typer.rb +151 -0
  113. data/lib/mirah/jvm/types.rb +416 -0
  114. data/lib/mirah/jvm/types/basic_types.rb +33 -0
  115. data/lib/mirah/jvm/types/boolean.rb +17 -0
  116. data/lib/mirah/jvm/types/enumerable.rb +65 -0
  117. data/lib/mirah/jvm/types/extensions.rb +86 -0
  118. data/lib/mirah/jvm/types/factory.rb +186 -0
  119. data/lib/mirah/jvm/types/floats.rb +86 -0
  120. data/lib/mirah/jvm/types/integers.rb +171 -0
  121. data/lib/mirah/jvm/types/intrinsics.rb +376 -0
  122. data/lib/mirah/jvm/types/literals.rb +74 -0
  123. data/lib/mirah/jvm/types/methods.rb +614 -0
  124. data/lib/mirah/jvm/types/number.rb +143 -0
  125. data/lib/mirah/nbcompiler.rb +29 -0
  126. data/lib/mirah/plugin/edb.rb +29 -0
  127. data/lib/mirah/plugin/gwt.rb +173 -0
  128. data/lib/mirah/plugin/java.rb +55 -0
  129. data/lib/mirah/transform.rb +266 -0
  130. data/lib/mirah/transform2.rb +728 -0
  131. data/lib/mirah/typer.rb +407 -0
  132. data/lib/mirah_task.rb +107 -0
  133. data/test/test_ast.rb +359 -0
  134. data/test/test_compilation.rb +112 -0
  135. data/test/test_env.rb +42 -0
  136. data/test/test_gwt.rb +58 -0
  137. data/test/test_java_typer.rb +183 -0
  138. data/test/test_javac_compiler.rb +63 -0
  139. data/test/test_jvm_compiler.rb +2607 -0
  140. data/test/test_typer.rb +221 -0
  141. metadata +235 -0
@@ -0,0 +1,8 @@
1
+ import "java.lang.StringBuffer"
2
+ import "java.util.ArrayList"
3
+
4
+ list = ArrayList.new
5
+ sb = StringBuffer.new("Hello")
6
+ sb.append(", world")
7
+ list.add(sb)
8
+ puts list
@@ -0,0 +1,17 @@
1
+ # Example of using a dynamic type in a method definition
2
+ def foo(a:dynamic)
3
+ puts "I got a #{a.getClass.getName} of size #{a.size}"
4
+ end
5
+
6
+ class SizeThing
7
+ def initialize(size:int)
8
+ @size = size
9
+ end
10
+
11
+ def size
12
+ @size
13
+ end
14
+ end
15
+
16
+ foo([1,2,3])
17
+ foo(SizeThing.new(12))
@@ -0,0 +1,3 @@
1
+ def_edb :render, 'test.edb'
2
+ @message = "Hello"
3
+ puts render
@@ -0,0 +1,16 @@
1
+ def fib(a:int)
2
+ if a < 2
3
+ a
4
+ else
5
+ fib(a - 1) + fib(a - 2)
6
+ end
7
+ end
8
+
9
+ def bench(n:int)
10
+ n.times do
11
+ time_start = System.currentTimeMillis
12
+ puts "fib(45): #{fib(45)}\nTotal time: #{System.currentTimeMillis - time_start}"
13
+ end
14
+ end
15
+
16
+ bench 10
@@ -0,0 +1,22 @@
1
+ import 'java.util.ArrayList'
2
+
3
+ class Bar
4
+ def initialize
5
+ @a = ArrayList(nil)
6
+ end
7
+
8
+ def list(a:ArrayList)
9
+ @a = a
10
+ end
11
+
12
+ def foo
13
+ puts @a
14
+ end
15
+ end
16
+
17
+ b = Bar.new
18
+ list = ArrayList.new
19
+ list.add('hello')
20
+ list.add('world')
21
+ b.list(list)
22
+ b.foo
@@ -0,0 +1,55 @@
1
+ def run
2
+ puts "Rendering"
3
+ y = -39.0
4
+ while y <= 39.0
5
+ puts
6
+ x = -39.0
7
+ while x <= 39.0
8
+ i = iterate(x/40.0,y/40.0)
9
+ if (i == 0)
10
+ print "*"
11
+ else
12
+ print " "
13
+ end
14
+ x += 1
15
+ end
16
+ y += 1
17
+ end
18
+ puts
19
+ end
20
+
21
+ def iterate(x:double,y:double)
22
+ cr = y-0.5
23
+ ci = x
24
+ zi = 0.0
25
+ zr = 0.0
26
+ i = 0
27
+
28
+ result = 0
29
+ while true
30
+ i += 1
31
+ temp = zr * zi
32
+ zr2 = zr * zr
33
+ zi2 = zi * zi
34
+ zr = zr2 - zi2 + cr
35
+ zi = temp + temp + ci
36
+ if (zi2 + zr2 > 16)
37
+ result = i
38
+ break
39
+ end
40
+ if (i > 1000)
41
+ result = 0
42
+ break
43
+ end
44
+ end
45
+
46
+ result
47
+ end
48
+
49
+ i = 0
50
+ while i < 10
51
+ start = System.currentTimeMillis
52
+ run
53
+ puts "Time: #{(System.currentTimeMillis - start) / 1000.0}"
54
+ i += 1
55
+ end
@@ -0,0 +1,13 @@
1
+ import "java.lang.System"
2
+
3
+ def foo
4
+ home = System.getProperty "java.home"
5
+ System.setProperty "hello.world", "something"
6
+ hello = System.getProperty "hello.world"
7
+
8
+ puts home
9
+ puts hello
10
+ end
11
+
12
+ puts "Hello world!"
13
+ foo
@@ -0,0 +1,55 @@
1
+ require 'ant'
2
+ require 'appengine-sdk'
3
+
4
+ $: << '../../../lib'
5
+ require 'mirah_task'
6
+
7
+ JUNIT_JAR = '../../../javalib/junit.jar'
8
+ TESTING_JARS = [AppEngine::SDK::API_JAR, AppEngine::SDK::LABS_JAR, JUNIT_JAR] +
9
+ AppEngine::SDK::RUNTIME_JARS.reject {|j| j =~ /appengine-local-runtime/}
10
+ TESTING_JARS.each {|jar| $CLASSPATH << jar}
11
+
12
+ # Duby.compiler_options = ['-V']
13
+
14
+ task :default => :test
15
+
16
+ task :init do
17
+ mkdir_p 'dist'
18
+ mkdir_p 'build'
19
+ end
20
+
21
+ task :clean do
22
+ ant.delete :quiet => true, :dir => 'build'
23
+ ant.delete :quiet => true, :dir => 'dist'
24
+ end
25
+
26
+ task :compile => :init do
27
+ # build the Duby sources
28
+ puts "Compiling Duby sources"
29
+ mirahc 'com/google/appengine', :dir => 'src', :dest => 'build'
30
+ end
31
+
32
+ task :compile_test => :jar do
33
+ puts "Compiling Duby tests"
34
+ mirahc 'com/google/appengine', :dir => 'test', :dest => 'test',
35
+ :options => ['--classpath', Dir.pwd + "/dist/dubydatastore.jar"]
36
+ end
37
+
38
+ task :jar => :compile do
39
+ ant.jar :jarfile => 'dist/dubydatastore.jar' do
40
+ fileset :dir => 'lib'
41
+ fileset :dir => 'build'
42
+ end
43
+ end
44
+
45
+ task :test => :compile_test do
46
+ ant.junit :haltonfailure => 'true', :fork => 'true' do
47
+ classpath :path => (TESTING_JARS + ['build', 'test']).join(":")
48
+ batchtest do
49
+ fileset :dir => "test" do
50
+ include :name => '**/*Test.class'
51
+ end
52
+ formatter :type => 'plain', :usefile => 'false'
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,375 @@
1
+ module AppEngine
2
+ class DubyDatastorePlugin
3
+ @models = {}
4
+
5
+ TypeMap = {
6
+ 'Category' => 'String',
7
+ 'Email' => 'String',
8
+ 'Link' => 'String',
9
+ 'PhoneNumber' => 'String',
10
+ 'PostalAddress' => 'String',
11
+ 'Text' => 'String',
12
+ 'Blob' => 'byte[]',
13
+ 'ShortBlob' => 'byte[]',
14
+ 'Rating' => 'int',
15
+ 'Long' => 'long',
16
+ 'Double' => 'double',
17
+ 'Boolean' => 'boolean'
18
+ }
19
+
20
+ Primitives = ['Long', 'Double', 'Boolean', 'Rating']
21
+
22
+ Boxes = {
23
+ 'int' => 'Integer',
24
+ 'boolean' => 'Boolean',
25
+ 'long' => 'Long',
26
+ 'double' => 'Double',
27
+ }
28
+
29
+ Defaults = {
30
+ 'Rating' => '0',
31
+ 'Long' => 'long(0)',
32
+ 'Double' => '0.0',
33
+ 'Boolean' => 'false',
34
+ 'Blob' => 'byte[].cast(nil)',
35
+ 'ShortBlob' => 'byte[].cast(nil)',
36
+ }
37
+
38
+ Conversions = {
39
+ 'Category' => 'getCategory',
40
+ 'Email' => 'getEmail',
41
+ 'Link' => 'getValue',
42
+ 'PhoneNumber' => 'getNumber',
43
+ 'PostalAddress' => 'getAddress',
44
+ 'Text' => 'getValue',
45
+ 'Blob' => 'getBytes',
46
+ 'ShortBlob' => 'getBytes',
47
+ 'Long' => 'longValue',
48
+ 'Double' => 'doubleValue',
49
+ 'Boolean' => 'booleanValue',
50
+ 'Rating' => 'getRating',
51
+ }
52
+
53
+ class ModelState
54
+ include Duby::AST
55
+ attr_reader :kind, :query, :read, :save, :transformer
56
+
57
+ def initialize(transformer, klass, parent, position, ast)
58
+ @transformer = transformer
59
+ @kind = klass.name.split('.')[-1]
60
+ init_query(klass.name, parent, position, ast)
61
+ init_static(parent, ast)
62
+ init_read(parent, position, ast)
63
+ init_save(parent, position, ast)
64
+ end
65
+
66
+ def init_query(classname, parent, position, ast)
67
+ name = "#{classname}$Query"
68
+ @query = ClassDefinition.new(parent, position, name) do |classdef|
69
+ queryinit = <<-EOF
70
+ def initialize; end
71
+
72
+ def kind
73
+ "#{kind}"
74
+ end
75
+
76
+ def first
77
+ it = _prepare.asIterator
78
+ if it.hasNext
79
+ e = Entity(it.next)
80
+ m = #{kind}.new
81
+ m._read_from(e)
82
+ m
83
+ else
84
+ #{kind}(nil)
85
+ end
86
+ end
87
+
88
+ def run
89
+ entities = _prepare.asList(_options)
90
+ models = #{kind}[entities.size]
91
+ it = entities.iterator
92
+ i = 0
93
+ while (it.hasNext)
94
+ e = Entity(it.next)
95
+ m = #{kind}.new
96
+ m._read_from(e)
97
+ models[i] = m
98
+ i += 1
99
+ end
100
+ models
101
+ end
102
+
103
+ def sort(name:String)
104
+ sort(name, false)
105
+ end
106
+
107
+ def sort(name:String, descending:boolean)
108
+ _sort(name, descending)
109
+ self
110
+ end
111
+ EOF
112
+ [Duby::AST.type(nil, 'com.google.appengine.ext.duby.db.DQuery'),
113
+ eval(classdef, queryinit)]
114
+ end
115
+ ast << @query
116
+ end
117
+
118
+ def init_read(parent, position, ast)
119
+ @read = eval(parent, <<-EOF)
120
+ def _read_from(e:Entity)
121
+ self.entity = e
122
+ nil
123
+ end
124
+ EOF
125
+ ast << @read
126
+ get_properties = eval(parent, <<-EOF)
127
+ def properties
128
+ result = super()
129
+ nil
130
+ result
131
+ end
132
+ EOF
133
+ @get_properties = get_properties.body.children[1] =
134
+ Duby::AST::Body.new(get_properties.body, position)
135
+ ast << get_properties
136
+ update = eval(parent, <<-EOF)
137
+ def update(properties:Map)
138
+ nil
139
+ self
140
+ end
141
+ EOF
142
+ @update = update.body.children[0] = Body.new(update.body, position) {[]}
143
+ ast << update
144
+ end
145
+
146
+ def init_save(parent, position, ast)
147
+ @save = eval(parent, <<-EOF)
148
+ def _save_to(e:Entity)
149
+ end
150
+ EOF
151
+ @save.body = Body.new(@save, position) {[]}
152
+ ast << @save
153
+ end
154
+
155
+ def init_static(parent, ast)
156
+ # TODO These imports don't work any more. Figure out how to fix that.
157
+ scope = ast.static_scope
158
+ package = "#{scope.package}." unless scope.package.empty?
159
+ scope.import('java.util.Map', 'Map')
160
+ scope.import("#{package}#{kind}$Query", "#{kind}__Query__")
161
+ %w( Entity Blob Category Email GeoPt IMHandle Key
162
+ Link PhoneNumber PostalAddress Rating ShortBlob
163
+ Text KeyFactory EntityNotFoundException ).each do |name|
164
+ scope.import("com.google.appengine.api.datastore.#{name}", name)
165
+ end
166
+ ast << eval(parent, <<-EOF)
167
+ def initialize
168
+ super
169
+ end
170
+
171
+ def initialize(key_name:String)
172
+ super
173
+ end
174
+
175
+ def initialize(parent:Model)
176
+ super
177
+ end
178
+
179
+ def initialize(parent:Key)
180
+ super
181
+ end
182
+
183
+ def initialize(parent:Model, key_name:String)
184
+ super
185
+ end
186
+
187
+ def initialize(parent:Key, key_name:String)
188
+ super
189
+ end
190
+
191
+ def self.get(key:Key)
192
+ begin
193
+ m = #{kind}.new
194
+ m._read_from(Model._datastore.get(key))
195
+ m
196
+ rescue EntityNotFoundException
197
+ nil
198
+ end
199
+ end
200
+
201
+ def self.get(key_name:String)
202
+ get(KeyFactory.createKey("#{kind}", key_name))
203
+ end
204
+
205
+ def self.get(id:long)
206
+ get(KeyFactory.createKey("#{kind}", id))
207
+ end
208
+
209
+ def self.get(parent:Key, key_name:String)
210
+ get(KeyFactory.createKey(parent, "#{kind}", key_name))
211
+ end
212
+
213
+ def self.get(parent:Key, id:long)
214
+ get(KeyFactory.createKey(parent, "#{kind}", id))
215
+ end
216
+
217
+ def self.get(parent:Model, key_name:String)
218
+ get(KeyFactory.createKey(parent.key, "#{kind}", key_name))
219
+ end
220
+
221
+ def self.get(parent:Model, id:long)
222
+ get(KeyFactory.createKey(parent.key, "#{kind}", id))
223
+ end
224
+
225
+ def self.all
226
+ #{kind}__Query__.new
227
+ end
228
+ EOF
229
+ end
230
+
231
+ def eval(parent, src)
232
+ transformer.eval(src, __FILE__, parent)
233
+ end
234
+
235
+ def extend_query(code)
236
+ query.body << eval(query.body, code)
237
+ end
238
+
239
+ def extend_update(code)
240
+ @update << eval(@update, code)
241
+ end
242
+
243
+ def extend_get_properties(code)
244
+ @get_properties << eval(@get_properties, code)
245
+ end
246
+
247
+ def extend_read(code)
248
+ code = 'e=nil;' + code
249
+ eval(read.body, code).children[1..-1].each do |node|
250
+ read.body << node
251
+ end
252
+ end
253
+
254
+ def extend_save(code)
255
+ code = 'e=nil;' + code
256
+ eval(save.body, code).children[1..-1].each do |node|
257
+ save.body << node
258
+ end
259
+ end
260
+ end
261
+
262
+ def self.find_class(node)
263
+ node = node.parent until Duby::AST::ClassDefinition === node
264
+ node
265
+ end
266
+
267
+ def self.to_datastore(type, value)
268
+ if Primitives.include?(type)
269
+ "#{type}.new(#{value})"
270
+ elsif TypeMap.include?(type)
271
+ "(#{value} ? #{type}.new(#{value}) : nil)"
272
+ else
273
+ value
274
+ end
275
+ end
276
+
277
+ def self.from_datastore(type, value)
278
+ duby_type = TypeMap[type]
279
+ if duby_type
280
+ default = Defaults.fetch(type, "#{duby_type}(nil)")
281
+ conversion = Conversions[type]
282
+ "(#{value} ? #{type}(#{value}).#{conversion} : #{default})"
283
+ else
284
+ "#{type}(#{value})"
285
+ end
286
+ end
287
+
288
+
289
+ def self.add_property(name, type, transformer, fcall)
290
+ if transformer.state != @state
291
+ reset
292
+ @state = transformer.state
293
+ end
294
+ parent = fcall.parent
295
+ name = name.literal
296
+ type = type.name
297
+ type = 'Long' if type == 'Integer'
298
+
299
+ result = Duby::AST::ScopedBody.new(parent, fcall.position) {[]}
300
+ result.static_scope = fcall.scope.static_scope
301
+ klass = find_class(parent)
302
+ unless @models[klass]
303
+ @models[klass] = ModelState.new(
304
+ transformer, klass, parent, fcall.position, result)
305
+ end
306
+ model = @models[klass]
307
+
308
+ duby_type = TypeMap.fetch(type, type)
309
+ coercion = "coerce_" + duby_type.downcase.sub("[]", "s")
310
+
311
+ if duby_type == 'List'
312
+ model.extend_query(<<-EOF)
313
+ def #{name}(value:Object)
314
+ returns :void
315
+ _query.addFilter("#{name}", _eq_op, value)
316
+ end
317
+ EOF
318
+ else
319
+ model.extend_query(<<-EOF)
320
+ def #{name}(value:#{duby_type})
321
+ returns :void
322
+ _query.addFilter("#{name}", _eq_op, #{to_datastore(type, 'value')})
323
+ end
324
+ EOF
325
+ end
326
+ temp = transformer.tmp
327
+
328
+ model.extend_read(<<-EOF)
329
+ #{temp} = e.getProperty("#{name}")
330
+ @#{name} = #{from_datastore(type, temp)}
331
+ EOF
332
+
333
+ model.extend_save(<<-EOF)
334
+ e.setProperty("#{name}", #{to_datastore(type, '@' + name)})
335
+ EOF
336
+
337
+ model.extend_update(<<-EOF)
338
+ self.#{name} = properties.get("#{name}") if properties.containsKey("#{name}")
339
+ EOF
340
+
341
+ model.extend_get_properties(<<-EOF)
342
+ result.put("#{name}", #{maybe_box(duby_type, 'self.' + name)})
343
+ EOF
344
+
345
+ result << model.eval(parent, <<-EOF)
346
+ def #{name}
347
+ @#{name}
348
+ end
349
+
350
+ def #{name}=(value:#{duby_type})
351
+ @#{name} = value
352
+ end
353
+
354
+ def #{name}=(value:Object)
355
+ self.#{name} = #{coercion}(value)
356
+ end
357
+ EOF
358
+
359
+ result
360
+ end
361
+
362
+ def self.maybe_box(duby_type, value)
363
+ if Boxes.include?(duby_type)
364
+ "#{Boxes[duby_type]}.valueOf(#{value})"
365
+ else
366
+ value
367
+ end
368
+ end
369
+
370
+ def self.reset
371
+ @models = {}
372
+ end
373
+ end
374
+ ::Duby.plugins << DubyDatastorePlugin
375
+ end