mirah 0.0.4-java

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.
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,33 @@
1
+ module Duby::JVM::Types
2
+ Boolean = BooleanType.new('boolean', java.lang.Boolean)
3
+ Byte = IntegerType.new('byte', java.lang.Byte)
4
+ Char = IntegerType.new('char', java.lang.Character)
5
+ Short = IntegerType.new('short', java.lang.Short)
6
+ Int = IntegerType.new('int', java.lang.Integer)
7
+ Long = LongType.new('long', java.lang.Long)
8
+ Float = FloatType.new('float', java.lang.Float)
9
+ Double = DoubleType.new('double', java.lang.Double)
10
+
11
+ # TODO these shouldn't be constants. They should be loaded from
12
+ # the compilation class path.
13
+ Object = Type.new(BiteScript::ASM::ClassMirror.load('java.lang.Object'))
14
+ ClassType = Type.new(BiteScript::ASM::ClassMirror.load('java.lang.Class'))
15
+ String = StringType.new(
16
+ BiteScript::ASM::ClassMirror.load('java.lang.String'))
17
+ Iterable = IterableType.new(
18
+ BiteScript::ASM::ClassMirror.load('java.lang.Iterable'))
19
+
20
+ Void = VoidType.new
21
+ Null = NullType.new
22
+
23
+ WIDENING_CONVERSIONS = {
24
+ Byte => [Byte, Short, Int, Long, Float, Double],
25
+ Short => [Short, Int, Long, Float, Double],
26
+ Char => [Char, Int, Long, Float, Double],
27
+ Int => [Int, Long, Float, Double],
28
+ Long => [Long, Float, Double],
29
+ Float => [Float, Double],
30
+ Double => [Double]
31
+ }
32
+ TYPE_ORDERING = [Byte, Short, Int, Long, Float, Double]
33
+ end
@@ -0,0 +1,17 @@
1
+ module Duby::JVM::Types
2
+ class BooleanType < PrimitiveType
3
+ def init_value(builder)
4
+ builder.iconst_0
5
+ end
6
+
7
+ def prefix
8
+ 'i'
9
+ end
10
+
11
+ def box(builder)
12
+ box_type = Duby::AST::type(nil, 'java.lang.Boolean')
13
+ builder.invokestatic box_type, "valueOf", [box_type, self]
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,65 @@
1
+ module Duby::JVM::Types
2
+ class Type
3
+ def expand_each(transformer, call)
4
+ arg_types = [Duby::AST.block_type]
5
+ code = intrinsics['each'][arg_types].return_type
6
+ code.inline(transformer, call)
7
+ end
8
+
9
+ def add_enumerable_macros
10
+ all_proc = proc do |transformer, call|
11
+ if !call.block
12
+ # We need to create a block that just returns the item passed to it
13
+ # First get a new temp for the block argument
14
+ var = transformer.tmp
15
+ # Parse a fake function call to create a block. Then pull of the
16
+ # block and attach it to the real call.
17
+ call.block = transformer.eval("foo {|#{var}| #{var}}").block
18
+ end
19
+
20
+ # Now that we've got a block we can transform it into a Loop.
21
+ forloop = expand_each(transformer, call)
22
+
23
+ # Start adding stuff to the loop.
24
+ # At the beginning of the loop we create a temp initialized to true
25
+ all = transformer.tmp
26
+ forloop.init << transformer.eval("#{all} = true")
27
+
28
+ # Now we want to wrap the body of the loop. Start off by using
29
+ # foo as a placeholder.
30
+ body = transformer.eval(
31
+ "unless foo;#{all} = false;break;end", '', forloop)
32
+ # Then replace foo with the real body.
33
+ body.condition.predicate = call.block.body
34
+ # And finally patch the new body back into the forloop.
35
+ forloop.body = call.block.body.parent = body
36
+
37
+ # Loops don't have a return value, so we need somewhere to
38
+ # put the result.
39
+ result = Duby::AST::Body.new(call.parent, call.position)
40
+ result << forloop << transformer.eval("#{all}", '', nil, all)
41
+ end
42
+ add_macro('all?', &all_proc)
43
+ add_macro('all?', Duby::AST.block_type, &all_proc)
44
+
45
+ any_proc = proc do |transformer, call|
46
+ if !call.block
47
+ var = transformer.tmp
48
+ call.block = transformer.eval("foo {|#{var}| #{var}}").block
49
+ end
50
+ forloop = expand_each(transformer, call)
51
+ any = transformer.tmp
52
+ forloop.init << transformer.eval("#{any} = false")
53
+ body = transformer.eval(
54
+ "if foo;#{any} = true;break;end", '', forloop)
55
+ body.condition.predicate = call.block.body
56
+ forloop.body = call.block.body.parent = body
57
+
58
+ result = Duby::AST::Body.new(call.parent, call.position)
59
+ result << forloop << transformer.eval("#{any}", '', nil, any)
60
+ end
61
+ add_macro('any?', &any_proc)
62
+ add_macro('any?', Duby::AST.block_type, &any_proc)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,86 @@
1
+ require 'delegate'
2
+
3
+ module Duby::JVM::Types
4
+ class ExtendedType < DelegateClass(Type)
5
+ def initialize(*args)
6
+ super
7
+ @static_includes = []
8
+ end
9
+
10
+ def include(type)
11
+ @static_includes << type
12
+ self
13
+ end
14
+
15
+ def meta
16
+ if meta?
17
+ self
18
+ else
19
+ __getobj__.meta
20
+ end
21
+ end
22
+
23
+ def unmeta
24
+ if meta?
25
+ __getobj__.unmeta
26
+ else
27
+ self
28
+ end
29
+ end
30
+
31
+ def get_method(name, args)
32
+ method = __getobj__.get_method(name, args)
33
+ return method if method
34
+ @static_includes.each do |type|
35
+ method = type.meta.get_method(name, args)
36
+ return method if method
37
+ end
38
+ nil
39
+ end
40
+
41
+ def java_method(name, *types)
42
+ __getobj__.java_method(name, *types) || __included_method(name, types)
43
+ end
44
+
45
+ def java_static_method(name, *types)
46
+ __getobj__.java_static_method(name, *types) || __included_method(name, types)
47
+ end
48
+
49
+ def declared_instance_methods(name=nil)
50
+ __combine_methods(__getobj__.declared_instance_methods)
51
+ end
52
+
53
+ def declared_class_methods(name=nil)
54
+ __combine_methods(__getobj__.declared_class_methods)
55
+ end
56
+
57
+ def __combine_methods(basic_methods)
58
+ methods = {}
59
+ basic_methods.each do |method|
60
+ key = [method.name, method.parameter_types, method.return_type]
61
+ methods[key] = method
62
+ end
63
+ @static_includes.each do |type|
64
+ type.declared_class_methods.each do |method|
65
+ key = [method.name, method.parameter_types, method.return_type]
66
+ methods[key] ||= method
67
+ end
68
+ end
69
+ methods.values
70
+ end
71
+
72
+ def __included_method(name, types)
73
+ @static_includes.each do |type|
74
+ method = type.meta.java_method(name, *types)
75
+ return method if method
76
+ end
77
+ nil
78
+ end
79
+ end
80
+
81
+ class Type
82
+ def include(type)
83
+ ExtendedType.new(self).include(type)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,186 @@
1
+ require 'jruby'
2
+ module Duby::JVM::Types
3
+ class TypeFactory
4
+ BASIC_TYPES = {
5
+ "boolean" => Boolean,
6
+ "byte" => Byte,
7
+ "char" => Char,
8
+ "short" => Short,
9
+ "int" => Int,
10
+ "long" => Long,
11
+ "float" => Float,
12
+ "double" => Double,
13
+ "fixnum" => Int,
14
+ "string" => String,
15
+ "java.lang.String" => String,
16
+ "String" => String,
17
+ "java.lang.Object" => Object,
18
+ "Object" => Object,
19
+ "java.lang.Class" => ClassType,
20
+ "java.lang.Iterable" => Iterable,
21
+ "Iterable" => Iterable,
22
+ "void" => Void,
23
+ "notype" => Void,
24
+ "null" => Null,
25
+ "dynamic" => DynamicType.new
26
+ }.freeze
27
+
28
+ attr_accessor :package
29
+ attr_reader :known_types
30
+
31
+ class ParanoidHash < Hash
32
+ def []=(k, v)
33
+ raise ArgumentError, "Can't store nil for key #{k.inspect}" if v.nil?
34
+ super(k, v)
35
+ end
36
+ end
37
+
38
+ def initialize
39
+ @known_types = ParanoidHash.new
40
+ @known_types.update(BASIC_TYPES)
41
+ @declarations = []
42
+ @mirrors = {}
43
+ end
44
+
45
+ def initialize_copy(other)
46
+ @known_types = other.known_types.dup
47
+ @known_types.delete_if do |key, value|
48
+ value.basic_type.kind_of?(Duby::JVM::Types::TypeDefinition)
49
+ end
50
+ @declarations = []
51
+ end
52
+
53
+ def define_types(builder)
54
+ @declarations.each do |declaration|
55
+ declaration.define(builder)
56
+ end
57
+ end
58
+
59
+ def type(scope, name, array=false, meta=false)
60
+ if name.kind_of?(BiteScript::ASM::Type)
61
+ if name.getDescriptor[0] == ?[
62
+ return type(scope, name.getElementType, true, meta)
63
+ else
64
+ name = name.getClassName
65
+ end
66
+ end
67
+ type = basic_type(scope, name)
68
+ type = type.array_type if array
69
+ type = type.meta if meta
70
+ return type
71
+ end
72
+
73
+ def basic_type(scope, name)
74
+ if name.kind_of?(Type) || name.kind_of?(NarrowingType)
75
+ return name.basic_type
76
+ end
77
+ orig = name
78
+ if name.kind_of? Java::JavaClass
79
+ if name.array?
80
+ return type(name.component_type, true)
81
+ else
82
+ name = name.name
83
+ end
84
+ elsif name.respond_to? :java_class
85
+ name = name.java_class.name
86
+ end
87
+ name = name.to_s unless name.kind_of?(::String)
88
+ raise ArgumentError, "Bad Type #{orig}" if name =~ /Java::/
89
+ raise ArgumentError, "Bad Type #{orig.inspect}" if name == '' || name.nil?
90
+ find_type(scope, name)
91
+ end
92
+
93
+ def find_type(scope, name)
94
+ begin
95
+ return get_type(name)
96
+ rescue NameError => ex
97
+ raise ex if scope.nil?
98
+ end
99
+
100
+ imports = scope.static_scope.imports
101
+ if imports.include?(name)
102
+ name = imports[name] while imports.include?(name)
103
+ return get_type(name)
104
+ end
105
+
106
+ # TODO support inner class names
107
+ if name !~ /\./
108
+ return package_search(name, scope)
109
+ end
110
+ end
111
+
112
+ def package_search(name, scope)
113
+ packages = []
114
+ packages << scope.static_scope.package unless scope.static_scope.package.empty?
115
+ packages.concat(scope.static_scope.search_packages)
116
+ packages << 'java.lang'
117
+ packages.each do |package|
118
+ begin
119
+ return get_type("#{package}.#{name}")
120
+ rescue
121
+ end
122
+ end
123
+ raise NameError, "Cannot find class #{name}"
124
+ end
125
+
126
+ def get_type(full_name)
127
+ type = @known_types[full_name]
128
+ return type.basic_type if type
129
+ type = Type.new(get_mirror(full_name)).load_extensions
130
+ @known_types[full_name] = type
131
+ end
132
+
133
+ def known_type(scope, name)
134
+ basic_type(scope, name) rescue nil
135
+ end
136
+
137
+ def declare_type(scope, name)
138
+ full_name = name
139
+ package = scope.static_scope.package
140
+ if !name.include?('.') && !package.empty?
141
+ full_name = "#{package}.#{name}"
142
+ end
143
+ if @known_types.include? full_name
144
+ @known_types[full_name]
145
+ else
146
+ scope.static_scope.import(full_name, name)
147
+ @known_types[full_name] = TypeDefinition.new(full_name, nil)
148
+ end
149
+ end
150
+
151
+ def define_type(node)
152
+ name = node.name
153
+ full_name = name
154
+ package = node.static_scope.package
155
+ if !name.include?('.') && !package.empty?
156
+ full_name = "#{package}.#{name}"
157
+ end
158
+ if @known_types.include? full_name
159
+ existing = @known_types[full_name]
160
+ existing.node ||= node
161
+ existing
162
+ else
163
+ if Duby::AST::InterfaceDeclaration === node
164
+ klass = InterfaceDefinition
165
+ else
166
+ klass = TypeDefinition
167
+ end
168
+ node.scope.static_scope.import(full_name, name)
169
+ @known_types[full_name] = klass.new(full_name, node)
170
+ end
171
+ end
172
+
173
+ def no_type
174
+ Void
175
+ end
176
+
177
+ def get_mirror(name)
178
+ @mirrors[name] ||= begin
179
+ classname = name.tr('.', '/') + ".class"
180
+ stream = JRuby.runtime.jruby_class_loader.getResourceAsStream(classname)
181
+ raise NameError, "Class '#{name}' not found." unless stream
182
+ BiteScript::ASM::ClassMirror.load(stream)
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,86 @@
1
+ module Duby::JVM::Types
2
+ class FloatType < Number
3
+ def prefix
4
+ 'f'
5
+ end
6
+
7
+ def math_type
8
+ Float
9
+ end
10
+
11
+ def box_type
12
+ java.lang.Float
13
+ end
14
+
15
+ def suffix
16
+ 'g'
17
+ end
18
+
19
+ def init_value(builder)
20
+ builder.fconst_0
21
+ end
22
+
23
+ def literal(builder, value)
24
+ case value
25
+ when 0.0
26
+ builder.fconst_0
27
+ when 1.0
28
+ builder.fconst_1
29
+ when 2.0
30
+ builder.fconst_2
31
+ else
32
+ builder.ldc_float(value)
33
+ end
34
+ end
35
+
36
+ def widen(builder, type)
37
+ case type
38
+ when Float
39
+ # Do nothing
40
+ when Double
41
+ builder.f2d
42
+ else
43
+ raise ArgumentError, "Invalid widening conversion from float to #{type}"
44
+ end
45
+ end
46
+ end
47
+
48
+ class DoubleType < FloatType
49
+ def prefix
50
+ 'd'
51
+ end
52
+
53
+ def math_type
54
+ Double
55
+ end
56
+
57
+ def box_type
58
+ java.lang.Double
59
+ end
60
+
61
+ def wide?
62
+ true
63
+ end
64
+
65
+ def init_value(builder)
66
+ builder.dconst_0
67
+ end
68
+
69
+ def literal(builder, value)
70
+ case value
71
+ when 0.0
72
+ builder.dconst_0
73
+ when 1.0
74
+ builder.dconst_1
75
+ else
76
+ builder.ldc_double(value)
77
+ end
78
+ end
79
+
80
+ def widen(builder, type)
81
+ if type != Double
82
+ raise ArgumentError, "Invalid widening conversion from double to #{type}"
83
+ end
84
+ end
85
+ end
86
+ end