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,143 @@
1
+ module Duby::JVM::Types
2
+ class ComparisonIntrinsic < Intrinsic
3
+ attr_reader :name, :op
4
+ def initialize(type, name, op, args)
5
+ super(type, name, args, Boolean) do; end
6
+ @type = type
7
+ @op = op
8
+ end
9
+
10
+ def call(compiler, call, expression)
11
+ if expression
12
+ @type.compile_boolean_operator(compiler, op, false, call, nil)
13
+ end
14
+ end
15
+
16
+ def jump_if(compiler, call, label)
17
+ @type.compile_boolean_operator(compiler, @op, false, call, label)
18
+ end
19
+
20
+ def jump_if_not(compiler, call, label)
21
+ @type.compile_boolean_operator(compiler, @op, true, call, label)
22
+ end
23
+ end
24
+
25
+ class Number < PrimitiveType
26
+ # The type returned by arithmetic operations with this type.
27
+ def math_type
28
+ self
29
+ end
30
+
31
+ def suffix
32
+ ''
33
+ end
34
+
35
+ # Adds an intrinsic that delegates to an intrinsic in another primitive
36
+ # type. That type must support promoting the "this" argument.
37
+ def delegate_intrinsic(name, type, return_type)
38
+ args = [type]
39
+ delegate = type.intrinsics[name][args]
40
+ if delegate.kind_of?(ComparisonIntrinsic)
41
+ add_method(name, args, ComparisonIntrinsic.new(type, name, delegate.op, args))
42
+ else
43
+ add_method(name, args, return_type) do |compiler, call, expression|
44
+ if expression
45
+ delegate.call(compiler, call, expression)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def add_delegates(name, return_type = nil)
52
+ index = TYPE_ORDERING.index(math_type)
53
+ larger_types = TYPE_ORDERING[index + 1, TYPE_ORDERING.size]
54
+ larger_types.each do |type|
55
+ delegate_intrinsic(name, type, return_type || type)
56
+ end
57
+ end
58
+
59
+ # if_cmpxx for non-ints
60
+ def jump_if(builder, op, label)
61
+ builder.send "#{prefix}cmp#{suffix}"
62
+ builder.send "if#{op}", label
63
+ end
64
+
65
+ def boolean_operator(name, op)
66
+ args = [math_type]
67
+ add_method(name, args, ComparisonIntrinsic.new(self, name, op, args))
68
+ add_delegates(name, Boolean)
69
+ end
70
+
71
+ def invert_op(op)
72
+ inverted = {
73
+ :lt => :ge,
74
+ :le => :gt,
75
+ :eq => :ne,
76
+ :ne => :eq,
77
+ :gt => :le,
78
+ :ge => :lt
79
+ }[op]
80
+ raise "Can't invert #{op}." unless inverted
81
+ inverted
82
+ end
83
+
84
+ def compile_boolean_operator(compiler, op, negated, call, label)
85
+ # Promote the target or the argument if necessary
86
+ convert_args(compiler,
87
+ [call.target, *call.parameters],
88
+ [math_type, math_type])
89
+ if negated
90
+ op = invert_op(op)
91
+ end
92
+ if label
93
+ jump_if(compiler.method, op, label)
94
+ else
95
+ compiler.method.op_to_bool do |label|
96
+ jump_if(compiler.method, op, label)
97
+ end
98
+ end
99
+ end
100
+
101
+ def math_operator(name, op)
102
+ add_method(name, [math_type], math_type) do |compiler, call, expression|
103
+ if expression
104
+ # Promote the target or the argument if necessary
105
+ convert_args(compiler,
106
+ [call.target, *call.parameters],
107
+ [math_type, math_type])
108
+ compiler.method.send "#{prefix}#{op}"
109
+ end
110
+ end
111
+ add_delegates(name)
112
+ end
113
+
114
+ def unary_operator(name, op)
115
+ add_method(name, [], math_type) do |compiler, call, expression|
116
+ if expression
117
+ call.target.compile(compiler, true)
118
+ compiler.method.send("#{prefix}#{op}") if op
119
+ end
120
+ end
121
+ end
122
+
123
+ def add_intrinsics
124
+ boolean_operator('<', :lt)
125
+ boolean_operator('<=', :le)
126
+ boolean_operator('==', :eq)
127
+ boolean_operator('!=', :ne)
128
+ boolean_operator('>=', :ge)
129
+ boolean_operator('>', :gt)
130
+ math_operator('+', :add)
131
+ math_operator('-', :sub)
132
+ math_operator('*', :mul)
133
+ math_operator('/', :div)
134
+ math_operator('%', :rem)
135
+ unary_operator('-@', :neg)
136
+ unary_operator('+@', nil)
137
+ end
138
+
139
+ def box(builder)
140
+ builder.invokestatic box_type, "valueOf", [box_type, math_type]
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,29 @@
1
+ require 'mirah'
2
+ module Duby
3
+ class NbCompiler
4
+ include org.mirah.DubyCompiler
5
+
6
+ class ParseResult
7
+ ParseError = org.mirah.ParseError
8
+
9
+ include org.mirah.ParseResult
10
+
11
+ attr_reader :ast, :errors
12
+ def initialize(ast, errors)
13
+ @ast = ast
14
+ parse_errors = errors.map do |error|
15
+ ParseError.new(error.message, error.position)
16
+ end
17
+ @errors = parse_errors.to_java(ParseError)
18
+ end
19
+ end
20
+
21
+ def parse(text)
22
+ Duby::AST.type_factory = Duby::JVM::Types::TypeFactory.new
23
+ ast = Duby::AST.parse_ruby(text)
24
+ transformer = Duby::Transform::Transformer.new(Duby::CompilationState.new)
25
+ return ParseResult.new(
26
+ transformer.transform(ast, nil), transformer.errors)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ require 'erb'
2
+
3
+ Duby::AST.defmacro('def_edb') do |transformer, fcall, parent|
4
+ name = fcall.parameters[0].name
5
+ path = fcall.parameters[1].literal
6
+ compiler = ERB::Compiler.new(nil)
7
+ compiler.put_cmd = "_edbout.append"
8
+ compiler.insert_cmd = "__edb_insert__ _edbout.append"
9
+ compiler.pre_cmd = ["def #{name}", "_edbout = StringBuilder.new"]
10
+ compiler.post_cmd = ["_edbout.toString", "end"]
11
+ src = compiler.compile(IO.read(path))
12
+ ast = Duby::AST.parse_ruby(src, path)
13
+ transformer.filename = path
14
+ script = transformer.transform(ast, parent)
15
+ script.body.parent = parent
16
+ script.body
17
+ end
18
+
19
+ Duby::AST.defmacro('__edb_insert__') do |transformer, fcall, parent|
20
+ # ERB sticks in a .to_s that we don't want.
21
+ # the ast is __edb_insert__(_edbout.append(content.to_s))
22
+ append = fcall.parameters[0]
23
+ content = append.parameters[0].target
24
+ content.parent = append
25
+ append.parameters = [content]
26
+ append.parent = parent
27
+ append
28
+ end
29
+
@@ -0,0 +1,173 @@
1
+ require 'mirah/jvm/source_generator/builder'
2
+
3
+ module Duby::JavaSource
4
+ class ClassBuilder
5
+ def build_jsni_method(name, visibility, static, exceptions, type, *args)
6
+ finish_declaration
7
+ type ||= Duby::AST.type(nil, :void)
8
+ @methods << JsniMethodBuilder.new(self,
9
+ :name => name,
10
+ :visibility => visibility,
11
+ :static => static,
12
+ :return => type,
13
+ :args => args,
14
+ :exceptions => exceptions)
15
+ @methods[-1]
16
+ end
17
+ end
18
+
19
+ class JsniMethodBuilder < MethodBuilder
20
+ include Helper
21
+
22
+ attr_accessor :name, :type, :out
23
+
24
+ def initialize(cls, options)
25
+ super(cls, options)
26
+ end
27
+
28
+ # Based on superclass's method.
29
+ def start
30
+ print "public#{@static} native #{@typename} #{@name}("
31
+ @args.each_with_index do |(type, name), i|
32
+ print ', ' unless i == 0
33
+ print "#{type.to_source} #{name}"
34
+ end
35
+ print ')'
36
+ unless @exceptions.empty?
37
+ print ' throws '
38
+ @exceptions.each_with_index do |exception, i|
39
+ print ', ' unless i == 0
40
+ print exception.name
41
+ end
42
+ end
43
+ puts ' /*-{'
44
+ end
45
+
46
+ # Based on superclass's method.
47
+ def stop
48
+ puts '}-*/;'
49
+ end
50
+ end
51
+ end
52
+
53
+ module Duby::Compiler
54
+ class JVMCompilerBase
55
+ # arg_types must be an Array
56
+ def create_method_builder(name, node, static, exceptions, return_type, arg_types)
57
+ unless node.class == Duby::AST::JsniMethodDefinition
58
+ @class.build_method(name.to_s, node.visibility, static,
59
+ exceptions, return_type, *arg_types)
60
+ else
61
+ @class.build_jsni_method(name.to_s, node.visibility, static,
62
+ exceptions, return_type, *arg_types)
63
+ end
64
+ end
65
+ end
66
+
67
+ class JavaSource < JVMCompilerBase
68
+ def define_jsni_method(node)
69
+ base_define_method(node, false) do |method, arg_types|
70
+ with :method => method do
71
+ log "Starting new JSNI method #{node.name}"
72
+ @method.start
73
+
74
+ @method.puts node.body.literal.chomp
75
+
76
+ log "JSNI method #{node.name} complete!"
77
+ @method.stop
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ module Duby::AST
85
+ class JsniMethodDefinition < MethodDefinition
86
+ def initialize(static, parent, line_number, name, annotations=[], &block)
87
+ super(parent, line_number, name, annotations, &block)
88
+ @static = static
89
+ end
90
+
91
+ def compile(compiler, expression)
92
+ compiler.define_jsni_method(self)
93
+ end
94
+
95
+ def infer(typer)
96
+ @static ||= scope.static_scope.self_type.meta? unless scope.nil?
97
+ @defining_class ||= begin
98
+ static_scope.self_type = if static?
99
+ scope.static_scope.self_type.meta
100
+ else
101
+ scope.static_scope.self_type
102
+ end
103
+ end
104
+ resolve_if(typer) do
105
+ argument_types = typer.infer(arguments)
106
+ if argument_types.all?
107
+ typer.learn_method_type(defining_class, name, argument_types,
108
+ signature[:return], signature[:throws])
109
+ end
110
+ end
111
+ end
112
+
113
+ # JSNI can't be abstract.
114
+ def abstract?
115
+ false
116
+ end
117
+
118
+ def static?
119
+ @static
120
+ end
121
+ end
122
+
123
+ defmacro 'def_jsni' do |transformer, fcall, parent|
124
+ args = fcall.parameters
125
+
126
+ unless args.size == 3
127
+ raise "def_jsni must have 3 arguments."
128
+ end
129
+
130
+ call_node = args[1]
131
+ if Self === call_node.target
132
+ is_static = true
133
+ end
134
+
135
+ JsniMethodDefinition.new(is_static,
136
+ parent,
137
+ fcall.position,
138
+ call_node.name,
139
+ transformer.annotations) do |defn|
140
+
141
+ signature = {:return => Duby::AST.type(nil, args[0].name)}
142
+ method = call_node.parameters[0]
143
+
144
+ unless method.nil?
145
+ hash_node = method.parameters[0]
146
+
147
+ args = Arguments.new(defn, defn.position) do |args_new|
148
+ arg_list = []
149
+ hash_node.child_nodes.each_slice(2) do |name, type|
150
+ position = name.position + type.position
151
+ name = name.literal
152
+ type = Duby::AST.type(nil, type.name)
153
+ signature[name.intern] = type
154
+ arg_list.push(RequiredArgument.new(args_new, position, name))
155
+ end
156
+ [arg_list, nil, nil, nil]
157
+ end
158
+ else
159
+ args = Arguments.new(defn, defn.position) do |args_new|
160
+ [nil, nil, nil, nil]
161
+ end
162
+ end
163
+
164
+ body_node = fcall.parameters[-1]
165
+
166
+ [
167
+ signature,
168
+ args,
169
+ body_node
170
+ ]
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,55 @@
1
+ require 'mirah/typer'
2
+ require 'mirah/jvm/method_lookup'
3
+ require 'mirah/jvm/types'
4
+ require 'java'
5
+
6
+ module Duby
7
+ module Typer
8
+ class JavaTyper < BaseTyper
9
+ include Duby::JVM::MethodLookup
10
+ include Duby::JVM::Types
11
+
12
+ def initialize
13
+ end
14
+
15
+ def name
16
+ "Java"
17
+ end
18
+
19
+ def method_type(typer, target_type, name, parameter_types)
20
+ return if target_type.nil? or parameter_types.any? {|t| t.nil?}
21
+ if target_type.respond_to? :get_method
22
+ method = target_type.get_method(name, parameter_types)
23
+ unless method || target_type.basic_type.kind_of?(TypeDefinition)
24
+ raise NoMethodError, "Cannot find %s method %s(%s) on %s" %
25
+ [ target_type.meta? ? "static" : "instance",
26
+ name,
27
+ parameter_types.map{|t| t.full_name}.join(', '),
28
+ target_type.full_name
29
+ ]
30
+ end
31
+ if method
32
+ result = method.return_type
33
+ elsif typer.last_chance && target_type.meta? &&
34
+ name == 'new' && parameter_types == []
35
+ unmeta = target_type.unmeta
36
+ if unmeta.respond_to?(:default_constructor)
37
+ result = unmeta.default_constructor
38
+ typer.last_chance = false if result
39
+ end
40
+ end
41
+ end
42
+
43
+ if result
44
+ log "Method type for \"#{name}\" #{parameter_types} on #{target_type} = #{result}"
45
+ else
46
+ log "Method type for \"#{name}\" #{parameter_types} on #{target_type} not found"
47
+ end
48
+
49
+ result
50
+ end
51
+ end
52
+ end
53
+
54
+ typer_plugins << Typer::JavaTyper.new
55
+ end
@@ -0,0 +1,266 @@
1
+ require 'base64'
2
+ require 'jruby'
3
+
4
+ module Duby
5
+ module Transform
6
+ class Error < StandardError
7
+ attr_reader :position, :cause
8
+ def initialize(msg, position, cause=nil)
9
+ super(msg)
10
+ @position = position
11
+ @position = position.position if position.respond_to? :position
12
+ @cause = cause
13
+ end
14
+ end
15
+
16
+ class Transformer
17
+ begin
18
+ include Java::DubyLangCompiler.Compiler
19
+ rescue NameError
20
+ $CLASSPATH << File.dirname(__FILE__) + '/../../javalib/mirah-bootstrap.jar'
21
+ include Java::DubyLangCompiler.Compiler
22
+ end
23
+
24
+ attr_reader :errors, :state
25
+ attr_accessor :filename
26
+ def initialize(state)
27
+ @errors = []
28
+ @tmp_count = 0
29
+ @annotations = []
30
+ @scopes = []
31
+ @extra_body = nil
32
+ @state = state
33
+ @helper = Duby::AST::TransformHelper.new(self)
34
+ end
35
+
36
+ def destination
37
+ @state.destination
38
+ end
39
+
40
+ def verbose?
41
+ @state.verbose
42
+ end
43
+
44
+ def annotations
45
+ result, @annotations = @annotations, []
46
+ return result
47
+ end
48
+
49
+ def add_annotation(annotation)
50
+ @annotations << annotation
51
+ Duby::AST::Noop.new(annotation.parent, annotation.position)
52
+ end
53
+
54
+ def tmp(format="__xform_tmp_%d")
55
+ format % [@tmp_count += 1]
56
+ end
57
+
58
+ class JMetaPosition
59
+ attr_accessor :start_line, :end_line, :start_offset, :end_offset, :file
60
+ attr_accessor :startpos, :endpos, :start_col, :end_col
61
+
62
+ def initialize(startpos, endpos)
63
+ @startpos = startpos
64
+ @endpos = endpos
65
+ @file = startpos.filename
66
+ @start_line = startpos.line
67
+ @start_offset = startpos.pos
68
+ @start_col = startpos.col
69
+ @end_line = endpos.line
70
+ @end_offset = endpos.pos
71
+ @end_col = endpos.col
72
+ end
73
+
74
+ def +(other)
75
+ JMetaPosition.new(@startpos, other.endpos)
76
+ end
77
+ end
78
+
79
+ def position(node)
80
+ JMetaPosition.new(node.start_position, node.end_position)
81
+ end
82
+
83
+ def camelize(name)
84
+ name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
85
+ end
86
+
87
+ def transform(node, parent)
88
+ begin
89
+ top = @extra_body.nil?
90
+ if top
91
+ @extra_body = Duby::AST::Body.new(nil, position(node))
92
+ end
93
+ method = "transform_#{camelize(node[0])}"
94
+ result = @helper.send method, node, parent
95
+ if top
96
+ body = result.body
97
+ if body.kind_of?(Duby::AST::Body) && @extra_body.empty?
98
+ @extra_body = body
99
+ else
100
+ result.body = @extra_body
101
+ body.parent = @extra_body
102
+ @extra_body.children.insert(0, body)
103
+ end
104
+ end
105
+ return result
106
+ rescue Error => ex
107
+ @errors << ex
108
+ Duby::AST::ErrorNode.new(parent, ex)
109
+ rescue Exception => ex
110
+ error = Error.new(ex.message, position(node), ex)
111
+ @errors << error
112
+ Duby::AST::ErrorNode.new(parent, error)
113
+ end
114
+ end
115
+
116
+ def captured?(node)
117
+ depth = node.depth
118
+ scope = @scopes[-1]
119
+ while depth > 0
120
+ depth -= 1
121
+ scope = scope.enclosing_scope
122
+ end
123
+ scope.isCaptured(node.index)
124
+ end
125
+
126
+ def eval(src, filename='-', parent=nil, *vars)
127
+ node = Duby::AST.parse_ruby(src, filename)
128
+ duby_node = transform(node, nil).body
129
+ duby_node.parent = parent
130
+ duby_node
131
+ end
132
+
133
+ def dump_ast(node)
134
+ encoded = nil
135
+ values = Duby::AST::Unquote.extract_values do
136
+ encoded = Base64.encode64(Marshal.dump(node))
137
+ end
138
+ result = Duby::AST::Array.new(nil, node.position)
139
+ result << Duby::AST::String.new(result, node.position, encoded)
140
+ values.each {|value| result << value}
141
+ return result
142
+ end
143
+
144
+ def load_ast(args)
145
+ nodes = args.to_a
146
+ encoded = nodes.shift
147
+ Duby::AST::Unquote.inject_values(nodes) do
148
+ result = Marshal.load(Base64.decode64(encoded))
149
+ if Duby::AST::UnquotedValue === result
150
+ result.node
151
+ else
152
+ result
153
+ end
154
+ end
155
+ end
156
+
157
+ def __ruby_eval(code, arg)
158
+ Kernel.eval(code)
159
+ end
160
+
161
+ def fixnum(value)
162
+ node = eval("1")
163
+ node.literal = value
164
+ node
165
+ end
166
+
167
+ def constant(name)
168
+ node = eval("Foo")
169
+ node.name = name
170
+ node
171
+ end
172
+
173
+ def find_class(name)
174
+ AST.type(nil, name, false, false)
175
+ end
176
+
177
+ def expand(fvcall, parent)
178
+ result = yield self, fvcall, parent
179
+ unless AST::Node === result
180
+ raise Error.new('Invalid macro result', fvcall.position)
181
+ end
182
+ result
183
+ end
184
+
185
+ def append_node(node)
186
+ @extra_body << node
187
+ node
188
+ end
189
+
190
+ def define_class(position, name, &block)
191
+ append_node Duby::AST::ClassDefinition.new(@extra_body, position, name, &block)
192
+ end
193
+
194
+ def define_closure(position, name, enclosing_type)
195
+ target = self
196
+ parent = @extra_body
197
+ enclosing_type = enclosing_type.unmeta
198
+ if enclosing_type.respond_to?(:node) && enclosing_type.node
199
+ parent = target = enclosing_type.node
200
+ end
201
+ target.append_node(Duby::AST::ClosureDefinition.new(
202
+ parent, position, name, enclosing_type))
203
+ end
204
+ end
205
+ end
206
+ TransformError = Transform::Error
207
+
208
+ module AST
209
+ begin
210
+ java_import 'mirah.impl.MirahParser'
211
+ rescue NameError
212
+ $CLASSPATH << File.dirname(__FILE__) + '/../../javalib/mirah-parser.jar'
213
+ java_import 'mirah.impl.MirahParser'
214
+ end
215
+ java_import 'jmeta.ErrorHandler'
216
+
217
+ class MirahErrorHandler
218
+ include ErrorHandler
219
+ def warning(messages, positions)
220
+ print "Warning: "
221
+ messages.each_with_index do |message, i|
222
+ jpos = positions[i]
223
+ if jpos
224
+ dpos = Duby::Transform::Transformer::JMetaPosition.new(jpos, jpos)
225
+ print "#{message} at "
226
+ Duby.print_error("", dpos)
227
+ else
228
+ print message
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ def parse(src, filename='dash_e', raise_errors=false, transformer=nil)
235
+ ast = parse_ruby(src, filename)
236
+ transformer ||= Transform::Transformer.new(Duby::CompilationState.new)
237
+ transformer.filename = filename
238
+ ast = transformer.transform(ast, nil)
239
+ if raise_errors
240
+ transformer.errors.each do |e|
241
+ raise e.cause || e
242
+ end
243
+ end
244
+ ast
245
+ end
246
+ module_function :parse
247
+
248
+ def parse_ruby(src, filename='-')
249
+ raise ArgumentError if src.nil?
250
+ parser = MirahParser.new
251
+ parser.filename = filename
252
+ parser.errorHandler = MirahErrorHandler.new
253
+ begin
254
+ parser.parse(src)
255
+ rescue => ex
256
+ if ex.cause.respond_to? :position
257
+ position = ex.cause.position
258
+ Duby.print_error(ex.cause.message, position)
259
+ end
260
+ raise ex
261
+ end
262
+ end
263
+ module_function :parse_ruby
264
+ end
265
+ end
266
+ require 'mirah/transform2'