mirah 0.0.4-java
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -0
- data/README.txt +51 -0
- data/Rakefile +86 -0
- data/bin/duby +10 -0
- data/bin/dubyc +10 -0
- data/bin/dubyp +10 -0
- data/bin/jrubyp +36 -0
- data/bin/mirah +9 -0
- data/bin/mirah.cmd +1 -0
- data/bin/mirahc +9 -0
- data/bin/mirahc.cmd +1 -0
- data/bin/mirahp +9 -0
- data/bin/mirahp.cmd +1 -0
- data/examples/ant/example-build.xml +7 -0
- data/examples/appengine/Rakefile +19 -0
- data/examples/appengine/Readme +29 -0
- data/examples/appengine/src/org/mirah/MirahApp.mirah +57 -0
- data/examples/appengine/src/org/mirah/list.dhtml +15 -0
- data/examples/appengine/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/bintrees.mirah +66 -0
- data/examples/construction.mirah +8 -0
- data/examples/dynamic.mirah +17 -0
- data/examples/edb.mirah +3 -0
- data/examples/fib.mirah +16 -0
- data/examples/fields.mirah +22 -0
- data/examples/fractal.mirah +55 -0
- data/examples/java_thing.mirah +13 -0
- data/examples/plugins/appengine/Rakefile +55 -0
- data/examples/plugins/appengine/lib/com/google/appengine/ext/duby/db/datastore.rb +375 -0
- data/examples/plugins/appengine/src/com/google/appengine/ext/duby/db/Model.duby +336 -0
- data/examples/plugins/appengine/test/com/google/appengine/ext/duby/db/ModelTest.duby +113 -0
- data/examples/simple_class.mirah +12 -0
- data/examples/sort_closure.mirah +7 -0
- data/examples/swing.mirah +20 -0
- data/examples/tak.mirah +15 -0
- data/examples/test.edb +9 -0
- data/examples/wiki/Rakefile +18 -0
- data/examples/wiki/src/org/mirah/wiki/MirahWiki.duby +324 -0
- data/examples/wiki/src/org/mirah/wiki/edit.eduby.html +42 -0
- data/examples/wiki/src/org/mirah/wiki/error.eduby.html +2 -0
- data/examples/wiki/src/org/mirah/wiki/layout.eduby.html +69 -0
- data/examples/wiki/src/org/mirah/wiki/parser.eduby.html +7 -0
- data/examples/wiki/src/org/mirah/wiki/view.eduby.html +15 -0
- data/examples/wiki/war/WEB-INF/classes/test/HeredocContext.class +0 -0
- data/examples/wiki/war/WEB-INF/classes/test/MirahParser.class +0 -0
- data/examples/wiki/war/WEB-INF/lib/appengine-api.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/dubydatastore.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/jmeta-runtime.jar +0 -0
- data/examples/wiki/war/WEB-INF/lib/pegdown-stubs.jar +0 -0
- data/examples/wiki/war/WEB-INF/pegdown.jar +0 -0
- data/examples/wiki/war/app.yaml +21 -0
- data/examples/wiki/war/public/favicon.ico +0 -0
- data/examples/wiki/war/public/images/appengine_duby.png +0 -0
- data/examples/wiki/war/public/images/back.gif +0 -0
- data/examples/wiki/war/public/images/dir.gif +0 -0
- data/examples/wiki/war/public/images/file.gif +0 -0
- data/examples/wiki/war/public/javascripts/prettify.js +61 -0
- data/examples/wiki/war/public/robots.txt +0 -0
- data/examples/wiki/war/public/stylesheets/main.css +156 -0
- data/examples/wiki/war/public/stylesheets/prettify.css +1 -0
- data/examples/wiki/war/public/stylesheets/sh_style.css +66 -0
- data/examples/wiki/war/public/stylesheets/source.css +21 -0
- data/examples/wiki/war/public/wmd/images/bg-fill.png +0 -0
- data/examples/wiki/war/public/wmd/images/bg.png +0 -0
- data/examples/wiki/war/public/wmd/images/blockquote.png +0 -0
- data/examples/wiki/war/public/wmd/images/bold.png +0 -0
- data/examples/wiki/war/public/wmd/images/code.png +0 -0
- data/examples/wiki/war/public/wmd/images/h1.png +0 -0
- data/examples/wiki/war/public/wmd/images/hr.png +0 -0
- data/examples/wiki/war/public/wmd/images/img.png +0 -0
- data/examples/wiki/war/public/wmd/images/italic.png +0 -0
- data/examples/wiki/war/public/wmd/images/link.png +0 -0
- data/examples/wiki/war/public/wmd/images/ol.png +0 -0
- data/examples/wiki/war/public/wmd/images/redo.png +0 -0
- data/examples/wiki/war/public/wmd/images/separator.png +0 -0
- data/examples/wiki/war/public/wmd/images/ul.png +0 -0
- data/examples/wiki/war/public/wmd/images/undo.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd-on.png +0 -0
- data/examples/wiki/war/public/wmd/images/wmd.png +0 -0
- data/examples/wiki/war/public/wmd/showdown.js +421 -0
- data/examples/wiki/war/public/wmd/wmd-base.js +1799 -0
- data/examples/wiki/war/public/wmd/wmd-plus.js +311 -0
- data/examples/wiki/war/public/wmd/wmd.js +73 -0
- data/javalib/JRubyParser.jar +0 -0
- data/javalib/dynalang-invoke-0.1.jar +0 -0
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/lib/duby.rb +2 -0
- data/lib/mirah.rb +338 -0
- data/lib/mirah/appengine_tasks.rb +146 -0
- data/lib/mirah/ast.rb +615 -0
- data/lib/mirah/ast/call.rb +307 -0
- data/lib/mirah/ast/class.rb +311 -0
- data/lib/mirah/ast/flow.rb +364 -0
- data/lib/mirah/ast/intrinsics.rb +470 -0
- data/lib/mirah/ast/literal.rb +154 -0
- data/lib/mirah/ast/local.rb +89 -0
- data/lib/mirah/ast/method.rb +360 -0
- data/lib/mirah/ast/scope.rb +208 -0
- data/lib/mirah/ast/structure.rb +226 -0
- data/lib/mirah/ast/type.rb +130 -0
- data/lib/mirah/compiler.rb +341 -0
- data/lib/mirah/env.rb +33 -0
- data/lib/mirah/jvm/base.rb +258 -0
- data/lib/mirah/jvm/compiler.rb +885 -0
- data/lib/mirah/jvm/method_lookup.rb +203 -0
- data/lib/mirah/jvm/source_compiler.rb +737 -0
- data/lib/mirah/jvm/source_generator/builder.rb +444 -0
- data/lib/mirah/jvm/source_generator/loops.rb +110 -0
- data/lib/mirah/jvm/source_generator/precompile.rb +188 -0
- data/lib/mirah/jvm/source_generator/typer.rb +11 -0
- data/lib/mirah/jvm/typer.rb +151 -0
- data/lib/mirah/jvm/types.rb +416 -0
- data/lib/mirah/jvm/types/basic_types.rb +33 -0
- data/lib/mirah/jvm/types/boolean.rb +17 -0
- data/lib/mirah/jvm/types/enumerable.rb +65 -0
- data/lib/mirah/jvm/types/extensions.rb +86 -0
- data/lib/mirah/jvm/types/factory.rb +186 -0
- data/lib/mirah/jvm/types/floats.rb +86 -0
- data/lib/mirah/jvm/types/integers.rb +171 -0
- data/lib/mirah/jvm/types/intrinsics.rb +376 -0
- data/lib/mirah/jvm/types/literals.rb +74 -0
- data/lib/mirah/jvm/types/methods.rb +614 -0
- data/lib/mirah/jvm/types/number.rb +143 -0
- data/lib/mirah/nbcompiler.rb +29 -0
- data/lib/mirah/plugin/edb.rb +29 -0
- data/lib/mirah/plugin/gwt.rb +173 -0
- data/lib/mirah/plugin/java.rb +55 -0
- data/lib/mirah/transform.rb +266 -0
- data/lib/mirah/transform2.rb +728 -0
- data/lib/mirah/typer.rb +407 -0
- data/lib/mirah_task.rb +107 -0
- data/test/test_ast.rb +359 -0
- data/test/test_compilation.rb +112 -0
- data/test/test_env.rb +42 -0
- data/test/test_gwt.rb +58 -0
- data/test/test_java_typer.rb +183 -0
- data/test/test_javac_compiler.rb +63 -0
- data/test/test_jvm_compiler.rb +2607 -0
- data/test/test_typer.rb +221 -0
- 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'
|