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,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'