pygments.rb 0.2.4 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/lib/pygments/version.rb +1 -1
  2. data/vendor/pygments-main/AUTHORS +14 -0
  3. data/vendor/pygments-main/CHANGES +34 -3
  4. data/vendor/pygments-main/Makefile +1 -1
  5. data/vendor/pygments-main/docs/generate.py +1 -1
  6. data/vendor/pygments-main/external/markdown-processor.py +1 -1
  7. data/vendor/pygments-main/external/moin-parser.py +1 -1
  8. data/vendor/pygments-main/external/rst-directive-old.py +1 -1
  9. data/vendor/pygments-main/external/rst-directive.py +1 -1
  10. data/vendor/pygments-main/pygments/__init__.py +1 -1
  11. data/vendor/pygments-main/pygments/cmdline.py +4 -1
  12. data/vendor/pygments-main/pygments/console.py +1 -1
  13. data/vendor/pygments-main/pygments/filter.py +1 -1
  14. data/vendor/pygments-main/pygments/filters/__init__.py +1 -1
  15. data/vendor/pygments-main/pygments/formatter.py +1 -1
  16. data/vendor/pygments-main/pygments/formatters/__init__.py +1 -1
  17. data/vendor/pygments-main/pygments/formatters/_mapping.py +1 -1
  18. data/vendor/pygments-main/pygments/formatters/bbcode.py +1 -1
  19. data/vendor/pygments-main/pygments/formatters/html.py +2 -2
  20. data/vendor/pygments-main/pygments/formatters/img.py +1 -1
  21. data/vendor/pygments-main/pygments/formatters/latex.py +3 -2
  22. data/vendor/pygments-main/pygments/formatters/other.py +1 -1
  23. data/vendor/pygments-main/pygments/formatters/rtf.py +1 -1
  24. data/vendor/pygments-main/pygments/formatters/svg.py +1 -1
  25. data/vendor/pygments-main/pygments/formatters/terminal.py +5 -2
  26. data/vendor/pygments-main/pygments/formatters/terminal256.py +5 -2
  27. data/vendor/pygments-main/pygments/lexer.py +29 -10
  28. data/vendor/pygments-main/pygments/lexers/__init__.py +14 -11
  29. data/vendor/pygments-main/pygments/lexers/_asybuiltins.py +1 -1
  30. data/vendor/pygments-main/pygments/lexers/_clbuiltins.py +1 -1
  31. data/vendor/pygments-main/pygments/lexers/_luabuiltins.py +1 -1
  32. data/vendor/pygments-main/pygments/lexers/_mapping.py +41 -23
  33. data/vendor/pygments-main/pygments/lexers/_phpbuiltins.py +1 -1
  34. data/vendor/pygments-main/pygments/lexers/_postgres_builtins.py +1 -1
  35. data/vendor/pygments-main/pygments/lexers/_scilab_builtins.py +29 -0
  36. data/vendor/pygments-main/pygments/lexers/_vimbuiltins.py +3 -3
  37. data/vendor/pygments-main/pygments/lexers/agile.py +148 -443
  38. data/vendor/pygments-main/pygments/lexers/asm.py +5 -3
  39. data/vendor/pygments-main/pygments/lexers/compiled.py +298 -294
  40. data/vendor/pygments-main/pygments/lexers/dotnet.py +40 -34
  41. data/vendor/pygments-main/pygments/lexers/functional.py +723 -4
  42. data/vendor/pygments-main/pygments/lexers/hdl.py +228 -6
  43. data/vendor/pygments-main/pygments/lexers/jvm.py +678 -0
  44. data/vendor/pygments-main/pygments/lexers/math.py +65 -2
  45. data/vendor/pygments-main/pygments/lexers/other.py +875 -481
  46. data/vendor/pygments-main/pygments/lexers/parsers.py +1 -1
  47. data/vendor/pygments-main/pygments/lexers/shell.py +360 -0
  48. data/vendor/pygments-main/pygments/lexers/special.py +1 -1
  49. data/vendor/pygments-main/pygments/lexers/sql.py +565 -0
  50. data/vendor/pygments-main/pygments/lexers/templates.py +1 -1
  51. data/vendor/pygments-main/pygments/lexers/text.py +237 -100
  52. data/vendor/pygments-main/pygments/lexers/web.py +146 -10
  53. data/vendor/pygments-main/pygments/plugin.py +1 -1
  54. data/vendor/pygments-main/pygments/scanner.py +1 -1
  55. data/vendor/pygments-main/pygments/style.py +1 -1
  56. data/vendor/pygments-main/pygments/styles/__init__.py +2 -1
  57. data/vendor/pygments-main/pygments/styles/autumn.py +1 -1
  58. data/vendor/pygments-main/pygments/styles/borland.py +1 -1
  59. data/vendor/pygments-main/pygments/styles/bw.py +1 -1
  60. data/vendor/pygments-main/pygments/styles/colorful.py +1 -1
  61. data/vendor/pygments-main/pygments/styles/default.py +1 -1
  62. data/vendor/pygments-main/pygments/styles/emacs.py +1 -1
  63. data/vendor/pygments-main/pygments/styles/friendly.py +1 -1
  64. data/vendor/pygments-main/pygments/styles/fruity.py +1 -2
  65. data/vendor/pygments-main/pygments/styles/manni.py +1 -1
  66. data/vendor/pygments-main/pygments/styles/monokai.py +1 -1
  67. data/vendor/pygments-main/pygments/styles/murphy.py +1 -1
  68. data/vendor/pygments-main/pygments/styles/native.py +1 -1
  69. data/vendor/pygments-main/pygments/styles/pastie.py +1 -1
  70. data/vendor/pygments-main/pygments/styles/perldoc.py +1 -1
  71. data/vendor/pygments-main/pygments/styles/rrt.py +33 -0
  72. data/vendor/pygments-main/pygments/styles/tango.py +1 -1
  73. data/vendor/pygments-main/pygments/styles/trac.py +1 -1
  74. data/vendor/pygments-main/pygments/styles/vim.py +1 -1
  75. data/vendor/pygments-main/pygments/styles/vs.py +1 -1
  76. data/vendor/pygments-main/pygments/token.py +1 -1
  77. data/vendor/pygments-main/pygments/unistring.py +1 -1
  78. data/vendor/pygments-main/pygments/util.py +2 -2
  79. data/vendor/pygments-main/scripts/check_sources.py +2 -2
  80. data/vendor/pygments-main/scripts/find_codetags.py +1 -1
  81. data/vendor/pygments-main/scripts/find_error.py +5 -2
  82. data/vendor/pygments-main/scripts/get_vimkw.py +9 -4
  83. data/vendor/pygments-main/setup.py +1 -1
  84. data/vendor/pygments-main/tests/examplefiles/classes.dylan +16 -0
  85. data/vendor/pygments-main/tests/examplefiles/coq_RelationClasses +447 -0
  86. data/vendor/pygments-main/tests/examplefiles/example.cls +15 -0
  87. data/vendor/pygments-main/tests/examplefiles/example.moon +629 -0
  88. data/vendor/pygments-main/tests/examplefiles/example.p +34 -0
  89. data/vendor/pygments-main/tests/examplefiles/example.snobol +15 -0
  90. data/vendor/pygments-main/tests/examplefiles/example.u +548 -0
  91. data/vendor/pygments-main/tests/examplefiles/example_elixir.ex +363 -0
  92. data/vendor/pygments-main/tests/examplefiles/foo.sce +6 -0
  93. data/vendor/pygments-main/tests/examplefiles/http_request_example +14 -0
  94. data/vendor/pygments-main/tests/examplefiles/http_response_example +27 -0
  95. data/vendor/pygments-main/tests/examplefiles/irc.lsp +214 -0
  96. data/vendor/pygments-main/tests/examplefiles/markdown.lsp +679 -0
  97. data/vendor/pygments-main/tests/examplefiles/nemerle_sample.n +4 -2
  98. data/vendor/pygments-main/tests/examplefiles/reversi.lsp +427 -0
  99. data/vendor/pygments-main/tests/examplefiles/scilab.sci +30 -0
  100. data/vendor/pygments-main/tests/examplefiles/test.bro +250 -0
  101. data/vendor/pygments-main/tests/examplefiles/test.cs +23 -0
  102. data/vendor/pygments-main/tests/examplefiles/test.dart +23 -0
  103. data/vendor/pygments-main/tests/examplefiles/test.ecl +58 -0
  104. data/vendor/pygments-main/tests/examplefiles/test.fan +818 -0
  105. data/vendor/pygments-main/tests/examplefiles/test.ps1 +108 -0
  106. data/vendor/pygments-main/tests/examplefiles/test.vhdl +161 -0
  107. data/vendor/pygments-main/tests/old_run.py +1 -1
  108. data/vendor/pygments-main/tests/run.py +1 -1
  109. data/vendor/pygments-main/tests/test_basic_api.py +4 -3
  110. data/vendor/pygments-main/tests/test_clexer.py +1 -1
  111. data/vendor/pygments-main/tests/test_cmdline.py +1 -1
  112. data/vendor/pygments-main/tests/test_examplefiles.py +4 -3
  113. data/vendor/pygments-main/tests/test_html_formatter.py +33 -1
  114. data/vendor/pygments-main/tests/test_latex_formatter.py +1 -1
  115. data/vendor/pygments-main/tests/test_perllexer.py +137 -0
  116. data/vendor/pygments-main/tests/test_regexlexer.py +1 -1
  117. data/vendor/pygments-main/tests/test_token.py +1 -1
  118. data/vendor/pygments-main/tests/test_using_api.py +1 -1
  119. data/vendor/pygments-main/tests/test_util.py +35 -5
  120. metadata +30 -4
@@ -0,0 +1,30 @@
1
+ // Scilab ( http://www.scilab.org/ )
2
+ // Copyright (C) INRIA - Serge STEER
3
+ //
4
+
5
+ function I=sub2ind(dims,varargin)
6
+ //sub2ind is used to determine the equivalent single index
7
+ //corresponding to a given set of subscript values.
8
+
9
+ //I = sub2ind(dims,i1,i2,..) returns the linear index equivalent to the
10
+ //row, column, ... subscripts in the arrays i1,i2,.. for an matrix of
11
+ //size dims.
12
+
13
+ //I = sub2ind(dims,Mi) returns the linear index
14
+ //equivalent to the n subscripts in the columns of the matrix Mi for a matrix
15
+ //of size dims.
16
+
17
+ d=[1;cumprod(matrix(dims(1:$-1),-1,1))]
18
+ for i=1:size(varargin)
19
+ if varargin(i)==[] then I=[],return,end
20
+ end
21
+
22
+ if size(varargin)==1 then //subindices are the columns of the argument
23
+ I=(varargin(1)-1)*d+1
24
+ else //subindices are given as separated arguments
25
+ I=1
26
+ for i=1:size(varargin)
27
+ I=I+(varargin(i)-1)*d(i)
28
+ end
29
+ end
30
+ endfunction
@@ -0,0 +1,250 @@
1
+ @load notice
2
+ @load utils/thresholds
3
+
4
+ module SSH;
5
+
6
+ export {
7
+ redef enum Log::ID += { SSH };
8
+
9
+ redef enum Notice::Type += {
10
+ Login,
11
+ Password_Guessing,
12
+ Login_By_Password_Guesser,
13
+ Login_From_Interesting_Hostname,
14
+ Bytecount_Inconsistency,
15
+ };
16
+
17
+ type Info: record {
18
+ ts: time &log;
19
+ uid: string &log;
20
+ id: conn_id &log;
21
+ status: string &log &optional;
22
+ direction: string &log &optional;
23
+ remote_location: geo_location &log &optional;
24
+ client: string &log &optional;
25
+ server: string &log &optional;
26
+ resp_size: count &log &default=0;
27
+
28
+ ## Indicate if the SSH session is done being watched.
29
+ done: bool &default=F;
30
+ };
31
+
32
+ const password_guesses_limit = 30 &redef;
33
+
34
+ # The size in bytes at which the SSH connection is presumed to be
35
+ # successful.
36
+ const authentication_data_size = 5500 &redef;
37
+
38
+ # The amount of time to remember presumed non-successful logins to build
39
+ # model of a password guesser.
40
+ const guessing_timeout = 30 mins &redef;
41
+
42
+ # The set of countries for which you'd like to throw notices upon successful login
43
+ # requires Bro compiled with libGeoIP support
44
+ const watched_countries: set[string] = {"RO"} &redef;
45
+
46
+ # Strange/bad host names to originate successful SSH logins
47
+ const interesting_hostnames =
48
+ /^d?ns[0-9]*\./ |
49
+ /^smtp[0-9]*\./ |
50
+ /^mail[0-9]*\./ |
51
+ /^pop[0-9]*\./ |
52
+ /^imap[0-9]*\./ |
53
+ /^www[0-9]*\./ |
54
+ /^ftp[0-9]*\./ &redef;
55
+
56
+ # This is a table with orig subnet as the key, and subnet as the value.
57
+ const ignore_guessers: table[subnet] of subnet &redef;
58
+
59
+ # If true, we tell the event engine to not look at further data
60
+ # packets after the initial SSH handshake. Helps with performance
61
+ # (especially with large file transfers) but precludes some
62
+ # kinds of analyses (e.g., tracking connection size).
63
+ const skip_processing_after_detection = F &redef;
64
+
65
+ # Keeps count of how many rejections a host has had
66
+ global password_rejections: table[addr] of TrackCount
67
+ &write_expire=guessing_timeout
68
+ &synchronized;
69
+
70
+ # Keeps track of hosts identified as guessing passwords
71
+ # TODO: guessing_timeout doesn't work correctly here. If a user redefs
72
+ # the variable, it won't take effect.
73
+ global password_guessers: set[addr] &read_expire=guessing_timeout+1hr &synchronized;
74
+
75
+ global log_ssh: event(rec: Info);
76
+ }
77
+
78
+ # Configure DPD and the packet filter
79
+ redef capture_filters += { ["ssh"] = "tcp port 22" };
80
+ redef dpd_config += { [ANALYZER_SSH] = [$ports = set(22/tcp)] };
81
+
82
+ redef record connection += {
83
+ ssh: Info &optional;
84
+ };
85
+
86
+ event bro_init()
87
+ {
88
+ Log::create_stream(SSH, [$columns=Info, $ev=log_ssh]);
89
+ }
90
+
91
+ function set_session(c: connection)
92
+ {
93
+ if ( ! c?$ssh )
94
+ {
95
+ local info: Info;
96
+ info$ts=network_time();
97
+ info$uid=c$uid;
98
+ info$id=c$id;
99
+ c$ssh = info;
100
+ }
101
+ }
102
+
103
+ function check_ssh_connection(c: connection, done: bool)
104
+ {
105
+ # If done watching this connection, just return.
106
+ if ( c$ssh$done )
107
+ return;
108
+
109
+ # If this is still a live connection and the byte count has not
110
+ # crossed the threshold, just return and let the resheduled check happen later.
111
+ if ( !done && c$resp$size < authentication_data_size )
112
+ return;
113
+
114
+ # Make sure the server has sent back more than 50 bytes to filter out
115
+ # hosts that are just port scanning. Nothing is ever logged if the server
116
+ # doesn't send back at least 50 bytes.
117
+ if ( c$resp$size < 50 )
118
+ return;
119
+
120
+ local status = "failure";
121
+ local direction = Site::is_local_addr(c$id$orig_h) ? "to" : "from";
122
+ local location: geo_location;
123
+ location = (direction == "to") ? lookup_location(c$id$resp_h) : lookup_location(c$id$orig_h);
124
+
125
+ if ( done && c$resp$size < authentication_data_size )
126
+ {
127
+ # presumed failure
128
+ if ( c$id$orig_h !in password_rejections )
129
+ password_rejections[c$id$orig_h] = new_track_count();
130
+
131
+ # Track the number of rejections
132
+ if ( !(c$id$orig_h in ignore_guessers &&
133
+ c$id$resp_h in ignore_guessers[c$id$orig_h]) )
134
+ ++password_rejections[c$id$orig_h]$n;
135
+
136
+ if ( default_check_threshold(password_rejections[c$id$orig_h]) )
137
+ {
138
+ add password_guessers[c$id$orig_h];
139
+ NOTICE([$note=Password_Guessing,
140
+ $conn=c,
141
+ $msg=fmt("SSH password guessing by %s", c$id$orig_h),
142
+ $sub=fmt("%d failed logins", password_rejections[c$id$orig_h]$n),
143
+ $n=password_rejections[c$id$orig_h]$n]);
144
+ }
145
+ }
146
+ # TODO: This is to work around a quasi-bug in Bro which occasionally
147
+ # causes the byte count to be oversized.
148
+ # Watch for Gregors work that adds an actual counter of bytes transferred.
149
+ else if ( c$resp$size < 20000000 )
150
+ {
151
+ # presumed successful login
152
+ status = "success";
153
+ c$ssh$done = T;
154
+
155
+ if ( c$id$orig_h in password_rejections &&
156
+ password_rejections[c$id$orig_h]$n > password_guesses_limit &&
157
+ c$id$orig_h !in password_guessers )
158
+ {
159
+ add password_guessers[c$id$orig_h];
160
+ NOTICE([$note=Login_By_Password_Guesser,
161
+ $conn=c,
162
+ $n=password_rejections[c$id$orig_h]$n,
163
+ $msg=fmt("Successful SSH login by password guesser %s", c$id$orig_h),
164
+ $sub=fmt("%d failed logins", password_rejections[c$id$orig_h]$n)]);
165
+ }
166
+
167
+ local message = fmt("SSH login %s %s \"%s\" \"%s\" %f %f %s (triggered with %d bytes)",
168
+ direction, location$country_code, location$region, location$city,
169
+ location$latitude, location$longitude,
170
+ id_string(c$id), c$resp$size);
171
+ NOTICE([$note=Login,
172
+ $conn=c,
173
+ $msg=message,
174
+ $sub=location$country_code]);
175
+
176
+ # Check to see if this login came from an interesting hostname
177
+ when ( local hostname = lookup_addr(c$id$orig_h) )
178
+ {
179
+ if ( interesting_hostnames in hostname )
180
+ {
181
+ NOTICE([$note=Login_From_Interesting_Hostname,
182
+ $conn=c,
183
+ $msg=fmt("Strange login from %s", hostname),
184
+ $sub=hostname]);
185
+ }
186
+ }
187
+
188
+ if ( location$country_code in watched_countries )
189
+ {
190
+
191
+ }
192
+
193
+ }
194
+ else if ( c$resp$size >= 200000000 )
195
+ {
196
+ NOTICE([$note=Bytecount_Inconsistency,
197
+ $conn=c,
198
+ $msg="During byte counting in SSH analysis, an overly large value was seen.",
199
+ $sub=fmt("%d",c$resp$size)]);
200
+ }
201
+
202
+ c$ssh$remote_location = location;
203
+ c$ssh$status = status;
204
+ c$ssh$direction = direction;
205
+ c$ssh$resp_size = c$resp$size;
206
+
207
+ Log::write(SSH, c$ssh);
208
+
209
+ # Set the "done" flag to prevent the watching event from rescheduling
210
+ # after detection is done.
211
+ c$ssh$done;
212
+
213
+ # Stop watching this connection, we don't care about it anymore.
214
+ if ( skip_processing_after_detection )
215
+ {
216
+ skip_further_processing(c$id);
217
+ set_record_packets(c$id, F);
218
+ }
219
+ }
220
+
221
+ event connection_state_remove(c: connection) &priority=-5
222
+ {
223
+ if ( c?$ssh )
224
+ check_ssh_connection(c, T);
225
+ }
226
+
227
+ event ssh_watcher(c: connection)
228
+ {
229
+ local id = c$id;
230
+ # don't go any further if this connection is gone already!
231
+ if ( !connection_exists(id) )
232
+ return;
233
+
234
+ check_ssh_connection(c, F);
235
+ if ( ! c$ssh$done )
236
+ schedule +15secs { ssh_watcher(c) };
237
+ }
238
+
239
+ event ssh_server_version(c: connection, version: string) &priority=5
240
+ {
241
+ set_session(c);
242
+ c$ssh$server = version;
243
+ }
244
+
245
+ event ssh_client_version(c: connection, version: string) &priority=5
246
+ {
247
+ set_session(c);
248
+ c$ssh$client = version;
249
+ schedule +15secs { ssh_watcher(c) };
250
+ }
@@ -153,6 +153,29 @@ namespace Diva.Core {
153
153
  public OpenerTask (string fileName)
154
154
  {
155
155
  this.fileName = fileName;
156
+ var verbatimString = @"c:\test\";
157
+
158
+ var verbatimStringWithNewline = @"test \\ \n \t \r
159
+ a
160
+ b
161
+ c";
162
+ var verbatimStringWithEscapedQuotes = @"He said
163
+ ""she says \"" is not an escaped character in verbatimstrings""
164
+ ";
165
+
166
+ int[] numbers = { 5,6,4,2,4,6,8,9,7,0 };
167
+ var linqExample = from n in numbers
168
+ where n > 5
169
+ select n;
170
+
171
+ var anotherlinqExample = from n in numbers
172
+ orderby n descending
173
+ select n;
174
+
175
+ int[] someMoreNumbers = { 8,2,17,34,8,9,9,5,3,4,2,1,5 };
176
+ var moreLinq = from n in numbers
177
+ join mn in moreNumbers on n equals mn + 2
178
+ select new {n, mn};
156
179
  }
157
180
 
158
181
  public override void Reset ()
@@ -0,0 +1,23 @@
1
+ // Greeter example from
2
+ // <http://www.dartlang.org/docs/getting-started/interface.html>
3
+ class Greeter implements Comparable {
4
+ String prefix = 'Hello,';
5
+ Greeter() {}
6
+ Greeter.withPrefix(this.prefix);
7
+ greet(String name) => print('$prefix $name');
8
+
9
+ int compareTo(Greeter other) => prefix.compareTo(other.prefix);
10
+ }
11
+
12
+ void main() {
13
+ Greeter greeter = new Greeter();
14
+ Greeter greeter2 = new Greeter.withPrefix('Hi,');
15
+
16
+ num result = greeter2.compareTo(greeter);
17
+ if (result == 0) {
18
+ greeter2.greet('you are the same.');
19
+ } else {
20
+ greeter2.greet('you are different.');
21
+ }
22
+ }
23
+
@@ -0,0 +1,58 @@
1
+ /*##############################################################################
2
+
3
+ Copyright (C) 2011 HPCC Systems.
4
+
5
+ All rights reserved. This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Affero General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Affero General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Affero General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ ############################################################################## */
18
+
19
+ #option ('slidingJoins', true);
20
+
21
+ namesRecord :=
22
+ RECORD
23
+ string20 surname;
24
+ string10 forename;
25
+ integer2 age;
26
+ integer2 dadAge;
27
+ integer2 mumAge;
28
+ END;
29
+
30
+ namesRecord2 :=
31
+ record
32
+ string10 extra;
33
+ namesRecord;
34
+ end;
35
+
36
+ namesTable := dataset('x',namesRecord,FLAT);
37
+ namesTable2 := dataset('y',namesRecord2,FLAT);
38
+
39
+ integer2 aveAgeL(namesRecord l) := (l.dadAge+l.mumAge)/2;
40
+ integer2 aveAgeR(namesRecord2 r) := (r.dadAge+r.mumAge)/2;
41
+
42
+ // Standard join on a function of left and right
43
+ output(join(namesTable, namesTable2, aveAgeL(left) = aveAgeR(right)));
44
+
45
+ //Several simple examples of sliding join syntax
46
+ output(join(namesTable, namesTable2, left.age >= right.age - 10 and left.age <= right.age +10));
47
+ output(join(namesTable, namesTable2, left.age between right.age - 10 and right.age +10));
48
+ output(join(namesTable, namesTable2, left.age between right.age + 10 and right.age +30));
49
+ output(join(namesTable, namesTable2, left.age between (right.age + 20) - 10 and (right.age +20) + 10));
50
+ output(join(namesTable, namesTable2, aveAgeL(left) between aveAgeR(right)+10 and aveAgeR(right)+40));
51
+
52
+ //Same, but on strings. Also includes age to ensure sort is done by non-sliding before sliding.
53
+ output(join(namesTable, namesTable2, left.surname between right.surname[1..10]+'AAAAAAAAAA' and right.surname[1..10]+'ZZZZZZZZZZ' and left.age=right.age));
54
+ output(join(namesTable, namesTable2, left.surname between right.surname[1..10]+'AAAAAAAAAA' and right.surname[1..10]+'ZZZZZZZZZZ' and left.age=right.age,all));
55
+
56
+ //This should not generate a self join
57
+ output(join(namesTable, namesTable, left.age between right.age - 10 and right.age +10));
58
+
@@ -0,0 +1,818 @@
1
+ //
2
+ // Copyright (c) 2008, Brian Frank and Andy Frank
3
+ // Licensed under the Academic Free License version 3.0
4
+ //
5
+ // History:
6
+ // 17 Nov 08 Brian Frank Creation
7
+ //
8
+
9
+ using compiler
10
+
11
+ **
12
+ ** JavaBridge is the compiler plugin for bringing Java
13
+ ** classes into the Fantom type system.
14
+ **
15
+ class JavaBridge : CBridge
16
+ {
17
+
18
+ //////////////////////////////////////////////////////////////////////////
19
+ // Constructor
20
+ //////////////////////////////////////////////////////////////////////////
21
+
22
+ **
23
+ ** Construct a JavaBridge for current environment
24
+ **
25
+ new make(Compiler c, ClassPath cp := ClassPath.makeForCurrent)
26
+ : super(c)
27
+ {
28
+ this.cp = cp
29
+ }
30
+
31
+ //////////////////////////////////////////////////////////////////////////
32
+ // Namespace
33
+ //////////////////////////////////////////////////////////////////////////
34
+
35
+ **
36
+ ** Map a FFI "podName" to a Java package.
37
+ **
38
+ override CPod resolvePod(Str name, Loc? loc)
39
+ {
40
+ // the empty package is used to represent primitives
41
+ if (name == "") return primitives
42
+
43
+ // look for package name in classpatch
44
+ classes := cp.classes[name]
45
+ if (classes == null)
46
+ throw CompilerErr("Java package '$name' not found", loc)
47
+
48
+ // map package to JavaPod
49
+ return JavaPod(this, name, classes)
50
+ }
51
+
52
+ **
53
+ ** Map class meta-data and Java members to Fantom slots
54
+ ** for the specified JavaType.
55
+ **
56
+ virtual Void loadType(JavaType type, Str:CSlot slots)
57
+ {
58
+ JavaReflect.loadType(type, slots)
59
+ }
60
+
61
+ //////////////////////////////////////////////////////////////////////////
62
+ // Call Resolution
63
+ //////////////////////////////////////////////////////////////////////////
64
+
65
+ **
66
+ ** Resolve a construction call to a Java constructor.
67
+ **
68
+ override Expr resolveConstruction(CallExpr call)
69
+ {
70
+ // if the last argument is an it-block, then we know
71
+ // right away that we will not be passing it thru to Java,
72
+ // so strip it off to be appended as call to Obj.with
73
+ itBlock := call.args.last as ClosureExpr
74
+ if (itBlock != null && itBlock.isItBlock)
75
+ call.args.removeAt(-1)
76
+ else
77
+ itBlock = null
78
+
79
+ // if this is an interop array like IntArray/int[] use make
80
+ // factory otherwise look for Java constructor called <init>
81
+ JavaType base := call.target.ctype
82
+ if (base.isInteropArray)
83
+ call.method = base.method("make")
84
+ else
85
+ call.method = base.method("<init>")
86
+
87
+ // call resolution to deal with overloading
88
+ call = resolveCall(call)
89
+
90
+ // we need to create an implicit target for the Java runtime
91
+ // to perform the new opcode to ensure it is on the stack
92
+ // before the args (we don't do this for interop Array classes)
93
+ if (!base.isInteropArray)
94
+ {
95
+ loc := call.loc
96
+ call.target = CallExpr.makeWithMethod(loc, null, base.newMethod) { synthetic=true }
97
+ }
98
+
99
+ // if we stripped an it-block argument,
100
+ // add it as trailing call to Obj.with
101
+ if (itBlock != null) return itBlock.toWith(call)
102
+ return call
103
+ }
104
+
105
+ **
106
+ ** Resolve a construction chain call where a Fantom constructor
107
+ ** calls the super-class constructor. Type check the arguments
108
+ ** and insert any conversions needed.
109
+ **
110
+ override Expr resolveConstructorChain(CallExpr call)
111
+ {
112
+ // we don't allow chaining to a this ctor for Java FFI
113
+ if (call.target.id !== ExprId.superExpr)
114
+ throw err("Must use super constructor call in Java FFI", call.loc)
115
+
116
+ // route to a superclass constructor
117
+ JavaType base := call.target.ctype.deref
118
+ call.method = base.method("<init>")
119
+
120
+ // call resolution to deal with overloading
121
+ return resolveCall(call)
122
+ }
123
+
124
+ **
125
+ ** Given a dot operator slot access on the given foreign
126
+ ** base type, determine the appopriate slot to use based on
127
+ ** whether parens were used
128
+ ** base.name => noParens = true
129
+ ** base.name() => noParens = false
130
+ **
131
+ ** In Java a given name could be bound to both a field and
132
+ ** a method. In this case we only resolve the field if
133
+ ** no parens are used. We also handle the special case of
134
+ ** Java annotations here because their element methods are
135
+ ** also mapped as Fantom fields (instance based mixin field).
136
+ **
137
+ override CSlot? resolveSlotAccess(CType base, Str name, Bool noParens)
138
+ {
139
+ // first try to resolve as a field
140
+ field := base.field(name)
141
+ if (field != null)
142
+ {
143
+ // if no () we used and this isn't an annotation field
144
+ if (noParens && (field.isStatic || !base.isMixin))
145
+ return field
146
+
147
+ // if we did find a field, then make sure we use that
148
+ // field's parent type to resolve a method (becuase the
149
+ // base type might be a sub-class of a Java type in which
150
+ // case it is unware of field/method overloads)
151
+ return field.parent.method(name)
152
+ }
153
+
154
+ // lookup method
155
+ return base.method(name)
156
+ }
157
+
158
+ **
159
+ ** Resolve a method call: try to find the best match
160
+ ** and apply any coercions needed.
161
+ **
162
+ override CallExpr resolveCall(CallExpr call)
163
+ {
164
+ // try to match against all the overloaded methods
165
+ matches := CallMatch[,]
166
+ CMethod? m := call.method
167
+ while (m != null)
168
+ {
169
+ match := matchCall(call, m)
170
+ if (match != null) matches.add(match)
171
+ m = m is JavaMethod ? ((JavaMethod)m).next : null
172
+ }
173
+
174
+ // if we have exactly one match use then use that one
175
+ if (matches.size == 1) return matches[0].apply(call)
176
+
177
+ // if we have multiple matches; resolve to
178
+ // most specific match according to JLS rules
179
+ // TODO: this does not correct resolve when using Fantom implicit casting
180
+ if (matches.size > 1)
181
+ {
182
+ best := resolveMostSpecific(matches)
183
+ if (best != null) return best.apply(call)
184
+ }
185
+
186
+ // zero or multiple ambiguous matches is a compiler error
187
+ s := StrBuf()
188
+ s.add(matches.isEmpty ? "Invalid args " : "Ambiguous call ")
189
+ s.add(call.name).add("(")
190
+ s.add(call.args.join(", ") |Expr arg->Str| { return arg.toTypeStr })
191
+ s.add(")")
192
+ throw err(s.toStr, call.loc)
193
+ }
194
+
195
+ **
196
+ ** Check if the call matches the specified overload method.
197
+ ** If so return method and coerced args otherwise return null.
198
+ **
199
+ internal CallMatch? matchCall(CallExpr call, CMethod m)
200
+ {
201
+ // first check if have matching numbers of args and params
202
+ args := call.args
203
+ if (m.params.size < args.size) return null
204
+
205
+ // check if each argument is ok or can be coerced
206
+ isErr := false
207
+ newArgs := args.dup
208
+ m.params.each |CParam p, Int i|
209
+ {
210
+ if (i >= args.size)
211
+ {
212
+ // param has a default value, then that is ok
213
+ if (!p.hasDefault) isErr = true
214
+ }
215
+ else
216
+ {
217
+ // ensure arg fits parameter type (or auto-cast)
218
+ newArgs[i] = coerce(args[i], p.paramType) |->| { isErr = true }
219
+ }
220
+ }
221
+ if (isErr) return null
222
+ return CallMatch { it.method = m; it.args = newArgs }
223
+ }
224
+
225
+ **
226
+ ** Given a list of overloaed methods find the most specific method
227
+ ** according to Java Language Specification 15.11.2.2. The "informal
228
+ ** intuition" rule is that a method is more specific than another
229
+ ** if the first could be could be passed onto the second one.
230
+ **
231
+ internal static CallMatch? resolveMostSpecific(CallMatch[] matches)
232
+ {
233
+ CallMatch? best := matches[0]
234
+ for (i:=1; i<matches.size; ++i)
235
+ {
236
+ x := matches[i]
237
+ if (isMoreSpecific(best, x)) { continue }
238
+ if (isMoreSpecific(x, best)) { best = x; continue }
239
+ return null
240
+ }
241
+ return best
242
+ }
243
+
244
+ **
245
+ ** Is 'a' more specific than 'b' such that 'a' could be used
246
+ ** passed to 'b' without a compile time error.
247
+ **
248
+ internal static Bool isMoreSpecific(CallMatch a, CallMatch b)
249
+ {
250
+ return a.method.params.all |CParam ap, Int i->Bool|
251
+ {
252
+ bp := b.method.params[i]
253
+ return ap.paramType.fits(bp.paramType)
254
+ }
255
+ }
256
+
257
+ //////////////////////////////////////////////////////////////////////////
258
+ // Overrides
259
+ //////////////////////////////////////////////////////////////////////////
260
+
261
+ **
262
+ ** Called during Inherit step when a Fantom slot overrides a FFI slot.
263
+ ** Log and throw compiler error if there is a problem.
264
+ **
265
+ override Void checkOverride(TypeDef t, CSlot base, SlotDef def)
266
+ {
267
+ // we don't allow Fantom to override Java methods with multiple
268
+ // overloaded versions since the Fantom type system can't actually
269
+ // override all the overloaded versions
270
+ jslot := base as JavaSlot
271
+ if (jslot?.next != null)
272
+ throw err("Cannot override Java overloaded method: '$jslot.name'", def.loc)
273
+
274
+ // route to method override checking
275
+ if (base is JavaMethod && def is MethodDef)
276
+ checkMethodOverride(t, base, def)
277
+ }
278
+
279
+ **
280
+ ** Called on method/method overrides in the checkOverride callback.
281
+ **
282
+ private Void checkMethodOverride(TypeDef t, JavaMethod base, MethodDef def)
283
+ {
284
+ // bail early if we know things aren't going to work out
285
+ if (base.params.size != def.params.size) return
286
+
287
+ // if the return type is primitive or Java array and the
288
+ // Fantom declaration matches how it is inferred into the Fan
289
+ // type system, then just change the return type - the compiler
290
+ // will impliclty do all the return coercions
291
+ if (isOverrideInferredType(base.returnType, def.returnType))
292
+ {
293
+ def.ret = def.inheritedRet = base.returnType
294
+ }
295
+
296
+ // if any of the parameters is a primitive or Java array
297
+ // and the Fantom declaration matches how it is inferred into
298
+ // the Fantom type type, then change the parameter type to
299
+ // the Java override type and make the Fantom type a local
300
+ // variable:
301
+ // Java: void foo(int a) { ... }
302
+ // Fantom: Void foo(Int a) { ... }
303
+ // Result: Void foo(int a_$J) { Int a := a_$J; ... }
304
+ //
305
+ base.params.eachr |CParam bp, Int i|
306
+ {
307
+ dp := def.paramDefs[i]
308
+ if (!isOverrideInferredType(bp.paramType, dp.paramType)) return
309
+
310
+ // add local variable: Int bar := bar_$J
311
+ local := LocalDefStmt(def.loc)
312
+ local.ctype = dp.paramType
313
+ local.name = dp.name
314
+ local.init = UnknownVarExpr(def.loc, null, dp.name + "_\$J")
315
+ def.code.stmts.insert(0, local)
316
+
317
+ // rename parameter Int bar -> int bar_$J
318
+ dp.name = dp.name + "_\$J"
319
+ dp.paramType = bp.paramType
320
+ }
321
+ }
322
+
323
+ **
324
+ ** When overriding a Java method check if the base type is
325
+ ** is a Java primitive or array and the override definition is
326
+ ** matches how the Java type is inferred in the Fantom type system.
327
+ ** If we have a match return true and we'll swizzle things in
328
+ ** checkMethodOverride.
329
+ **
330
+ static private Bool isOverrideInferredType(CType base, CType def)
331
+ {
332
+ // check if base class slot is a JavaType
333
+ java := base.toNonNullable as JavaType
334
+ if (java != null)
335
+ {
336
+ // allow primitives is it matches the inferred type
337
+ if (java.isPrimitive) return java.inferredAs == def
338
+
339
+ // allow arrays if mapped as Foo[] -> Foo?[]?
340
+ if (java.isArray) return java.inferredAs == def.toNonNullable && def.isNullable
341
+ }
342
+ return false
343
+ }
344
+
345
+ //////////////////////////////////////////////////////////////////////////
346
+ // CheckErrors
347
+ //////////////////////////////////////////////////////////////////////////
348
+
349
+ **
350
+ ** Called during CheckErrors step for a type which extends
351
+ ** a FFI class or implements any FFI mixins.
352
+ **
353
+ override Void checkType(TypeDef def)
354
+ {
355
+ // can't subclass a primitive array like ByteArray/byte[]
356
+ if (def.base.deref is JavaType && def.base.deref->isInteropArray)
357
+ {
358
+ err("Cannot subclass from Java interop array: $def.base", def.loc)
359
+ return
360
+ }
361
+
362
+ // we don't allow deep inheritance of Java classes because
363
+ // the Fantom constructor and Java constructor model don't match
364
+ // up past one level of inheritance
365
+ // NOTE: that that when we remove this restriction we need to
366
+ // test how field initialization works because instance$init
367
+ // is almost certain to break with the current emit design
368
+ javaBase := def.base
369
+ while (javaBase != null && !javaBase.isForeign) javaBase = javaBase.base
370
+ if (javaBase != null && javaBase !== def.base)
371
+ {
372
+ err("Cannot subclass Java class more than one level: $javaBase", def.loc)
373
+ return
374
+ }
375
+
376
+ // ensure that when we map Fantom constructors to Java
377
+ // constructors that we don't have duplicate signatures
378
+ ctors := def.ctorDefs
379
+ ctors.each |MethodDef a, Int i|
380
+ {
381
+ ctors.each |MethodDef b, Int j|
382
+ {
383
+ if (i > j && areParamsSame(a, b))
384
+ err("Duplicate Java FFI constructor signatures: '$b.name' and '$a.name'", a.loc)
385
+ }
386
+ }
387
+ }
388
+
389
+ **
390
+ ** Do the two methods have the exact same parameter types.
391
+ **
392
+ static Bool areParamsSame(CMethod a, CMethod b)
393
+ {
394
+ if (a.params.size != b.params.size) return false
395
+ for (i:=0; i<a.params.size; ++i)
396
+ {
397
+ if (a.params[i].paramType != b.params[i].paramType)
398
+ return false
399
+ }
400
+ return true
401
+ }
402
+
403
+ //////////////////////////////////////////////////////////////////////////
404
+ // Coercion
405
+ //////////////////////////////////////////////////////////////////////////
406
+
407
+ **
408
+ ** Return if we can make the actual type fit the expected
409
+ ** type, potentially using a coercion.
410
+ **
411
+ Bool fits(CType actual, CType expected)
412
+ {
413
+ // use dummy expression and route to coerce code
414
+ dummy := UnknownVarExpr(Loc("dummy"), null, "dummy") { ctype = actual }
415
+ fits := true
416
+ coerce(dummy, expected) |->| { fits=false }
417
+ return fits
418
+ }
419
+
420
+ **
421
+ ** Coerce expression to expected type. If not a type match
422
+ ** then run the onErr function.
423
+ **
424
+ override Expr coerce(Expr expr, CType expected, |->| onErr)
425
+ {
426
+ // handle easy case
427
+ actual := expr.ctype
428
+ expected = expected.deref
429
+ if (actual == expected) return expr
430
+
431
+ // handle null literal
432
+ if (expr.id === ExprId.nullLiteral && expected.isNullable)
433
+ return expr
434
+
435
+ // handle Fantom to Java primitives
436
+ if (expected.pod == primitives)
437
+ return coerceToPrimitive(expr, expected, onErr)
438
+
439
+ // handle Java primitives to Fan
440
+ if (actual.pod == primitives)
441
+ return coerceFromPrimitive(expr, expected, onErr)
442
+
443
+ // handle Java array to Fantom list
444
+ if (actual.name[0] == '[')
445
+ return coerceFromArray(expr, expected, onErr)
446
+
447
+ // handle Fantom list to Java array
448
+ if (expected.name[0] == '[')
449
+ return coerceToArray(expr, expected, onErr)
450
+
451
+ // handle sys::Func -> Java interface
452
+ if (actual is FuncType && expected.isMixin && expected.toNonNullable is JavaType)
453
+ return coerceFuncToInterface(expr, expected.toNonNullable, onErr)
454
+
455
+ // handle special classes and interfaces for built-in Fantom
456
+ // classes which actually map directly to Java built-in types
457
+ if (actual.isBool && boolTypes.contains(expected.toNonNullable.signature)) return box(expr)
458
+ if (actual.isInt && intTypes.contains(expected.toNonNullable.signature)) return box(expr)
459
+ if (actual.isFloat && floatTypes.contains(expected.toNonNullable.signature)) return box(expr)
460
+ if (actual.isDecimal && decimalTypes.contains(expected.toNonNullable.signature)) return expr
461
+ if (actual.isStr && strTypes.contains(expected.toNonNullable.signature)) return expr
462
+
463
+ // use normal Fantom coercion behavior
464
+ return super.coerce(expr, expected, onErr)
465
+ }
466
+
467
+ **
468
+ ** Ensure value type is boxed.
469
+ **
470
+ private Expr box(Expr expr)
471
+ {
472
+ if (expr.ctype.isVal)
473
+ return TypeCheckExpr.coerce(expr, expr.ctype.toNullable)
474
+ else
475
+ return expr
476
+ }
477
+
478
+ **
479
+ ** Coerce a fan expression to a Java primitive (other
480
+ ** than the ones we support natively)
481
+ **
482
+ Expr coerceToPrimitive(Expr expr, JavaType expected, |->| onErr)
483
+ {
484
+ actual := expr.ctype
485
+
486
+ // sys::Int (long) -> int, short, byte
487
+ if (actual.isInt && expected.isPrimitiveIntLike)
488
+ return TypeCheckExpr.coerce(expr, expected)
489
+
490
+ // sys::Float (double) -> float
491
+ if (actual.isFloat && expected.isPrimitiveFloat)
492
+ return TypeCheckExpr.coerce(expr, expected)
493
+
494
+ // no coercion - type error
495
+ onErr()
496
+ return expr
497
+ }
498
+
499
+ **
500
+ ** Coerce a Java primitive to a Fantom type.
501
+ **
502
+ Expr coerceFromPrimitive(Expr expr, CType expected, |->| onErr)
503
+ {
504
+ actual := (JavaType)expr.ctype
505
+
506
+ // int, short, byte -> sys::Int (long)
507
+ if (actual.isPrimitiveIntLike)
508
+ {
509
+ if (expected.isInt || expected.isObj)
510
+ return TypeCheckExpr.coerce(expr, expected)
511
+ }
512
+
513
+ // float -> sys::Float (float)
514
+ if (actual.isPrimitiveFloat)
515
+ {
516
+ if (expected.isFloat || expected.isObj)
517
+ return TypeCheckExpr.coerce(expr, expected)
518
+ }
519
+
520
+ // no coercion - type error
521
+ onErr()
522
+ return expr
523
+ }
524
+
525
+ **
526
+ ** Coerce a Java array to a Fantom list.
527
+ **
528
+ Expr coerceFromArray(Expr expr, CType expected, |->| onErr)
529
+ {
530
+ actual := (JavaType)expr.ctype.toNonNullable
531
+
532
+ // if expected is array type
533
+ if (expected is JavaType && ((JavaType)expected).isArray)
534
+ if (actual.arrayOf.fits(((JavaType)expected).arrayOf)) return expr
535
+
536
+ // if expected is Obj
537
+ if (expected.isObj) return arrayToList(expr, actual.inferredArrayOf)
538
+
539
+ // if expected is list type
540
+ if (expected.toNonNullable is ListType)
541
+ {
542
+ expectedOf := ((ListType)expected.toNonNullable).v
543
+ if (actual.inferredArrayOf.fits(expectedOf)) return arrayToList(expr, expectedOf)
544
+ }
545
+
546
+ // no coercion available
547
+ onErr()
548
+ return expr
549
+ }
550
+
551
+ **
552
+ ** Generate List.make(of, expr) where expr is Object[]
553
+ **
554
+ private Expr arrayToList(Expr expr, CType of)
555
+ {
556
+ loc := expr.loc
557
+ ofExpr := LiteralExpr(loc, ExprId.typeLiteral, ns.typeType, of)
558
+ call := CallExpr.makeWithMethod(loc, null, listMakeFromArray, [ofExpr, expr])
559
+ call.synthetic = true
560
+ return call
561
+ }
562
+
563
+ **
564
+ ** Coerce a Fantom list to Java array.
565
+ **
566
+ Expr coerceToArray(Expr expr, CType expected, |->| onErr)
567
+ {
568
+ loc := expr.loc
569
+ expectedOf := ((JavaType)expected.toNonNullable).inferredArrayOf
570
+ actual := expr.ctype
571
+
572
+ // if actual is list type
573
+ if (actual.toNonNullable is ListType)
574
+ {
575
+ actualOf := ((ListType)actual.toNonNullable).v
576
+ if (actualOf.fits(expectedOf))
577
+ {
578
+ // (Foo[])list.asArray(cls)
579
+ clsLiteral := CallExpr.makeWithMethod(loc, null, JavaType.classLiteral(this, expectedOf))
580
+ asArray := CallExpr.makeWithMethod(loc, expr, listAsArray, [clsLiteral])
581
+ return TypeCheckExpr.coerce(asArray, expected)
582
+ }
583
+ }
584
+
585
+ // no coercion available
586
+ onErr()
587
+ return expr
588
+ }
589
+
590
+ **
591
+ ** Attempt to coerce a parameterized sys::Func expr to a Java
592
+ ** interface if the interface supports exactly one matching method.
593
+ **
594
+ Expr coerceFuncToInterface(Expr expr, JavaType expected, |->| onErr)
595
+ {
596
+ // check if we have exactly one abstract method in the expected type
597
+ loc := expr.loc
598
+ abstracts := expected.methods.findAll |CMethod m->Bool| { return m.isAbstract }
599
+ if (abstracts.size != 1) { onErr(); return expr }
600
+ method := abstracts.first
601
+
602
+ // check if we have a match
603
+ FuncType funcType := (FuncType)expr.ctype
604
+ if (!isFuncToInterfaceMatch(funcType, method)) { onErr(); return expr }
605
+
606
+ // check if we've already generated a wrapper for this combo
607
+ key := "${funcType.signature}+${method.qname}"
608
+ ctor := funcWrappers[key]
609
+ if (ctor == null)
610
+ {
611
+ ctor = generateFuncToInterfaceWrapper(expr.loc, funcType, expected, method)
612
+ funcWrappers[key] = ctor
613
+ }
614
+
615
+ // replace expr with FuncWrapperX(expr)
616
+ call := CallExpr.makeWithMethod(loc, null, ctor, [expr])
617
+ call.synthetic = true
618
+ return call
619
+ }
620
+
621
+ **
622
+ ** Return if the specified function type can be used to implement
623
+ ** the specified interface method.
624
+ **
625
+ Bool isFuncToInterfaceMatch(FuncType funcType, CMethod method)
626
+ {
627
+ // sanity check to map to callX method - can't handle more than 8 args
628
+ if (method.params.size > 8) return false
629
+
630
+ // check if method is match for function; first check is that
631
+ // method must supply all the arguments required by the function
632
+ if (funcType.params.size > method.params.size) return false
633
+
634
+ // check that func return type fits method return
635
+ retOk := method.returnType.isVoid || fits(funcType.ret, method.returnType)
636
+ if (!retOk) return false
637
+
638
+ // check all the method parameters fit the function parameters
639
+ paramsOk := funcType.params.all |CType f, Int i->Bool| { return fits(f, method.params[i].paramType) }
640
+ if (!paramsOk) return false
641
+
642
+ return true
643
+ }
644
+
645
+ **
646
+ ** Generate the wrapper which implements the specified expected interface
647
+ ** and overrides the specified method which calls the function.
648
+ **
649
+ CMethod generateFuncToInterfaceWrapper(Loc loc, FuncType funcType, CType expected, CMethod method)
650
+ {
651
+ // Fantom: func typed as |Str|
652
+ // Java: interface Foo { void bar(String) }
653
+ // Result: FuncWrapperX(func)
654
+ //
655
+ // class FuncWrapperX : Foo
656
+ // {
657
+ // new make(Func f) { _func = f }
658
+ // override Void bar(Str a) { _func.call(a) }
659
+ // Func _func
660
+ // }
661
+
662
+ // generate FuncWrapper class
663
+ name := "FuncWrapper" + funcWrappers.size
664
+ cls := TypeDef(ns, loc, compiler.types[0].unit, name, FConst.Internal + FConst.Synthetic)
665
+ cls.base = ns.objType
666
+ cls.mixins = [expected]
667
+ addTypeDef(cls)
668
+
669
+ // generate FuncWrapper._func field
670
+ field := FieldDef(loc, cls)
671
+ ((SlotDef)field).name = "_func"
672
+ ((DefNode)field).flags = FConst.Private + FConst.Storage + FConst.Synthetic
673
+ field.fieldType = funcType
674
+ cls.addSlot(field)
675
+
676
+ // generate FuncWrapper.make constructor
677
+ ctor := MethodDef(loc, cls, "make", FConst.Internal + FConst.Ctor + FConst.Synthetic)
678
+ ctor.ret = ns.voidType
679
+ ctor.paramDefs = [ParamDef(loc, funcType, "f")]
680
+ ctor.code = Block.make(loc)
681
+ ctor.code.stmts.add(BinaryExpr.makeAssign(
682
+ FieldExpr(loc, ThisExpr(loc), field),
683
+ UnknownVarExpr(loc, null, "f")).toStmt)
684
+ ctor.code.stmts.add(ReturnStmt.make(loc))
685
+ cls.addSlot(ctor)
686
+
687
+ // generate FuncWrapper override of abstract method
688
+ over := MethodDef(loc, cls, method.name, FConst.Public + FConst.Override + FConst.Synthetic)
689
+ over.ret = method.returnType
690
+ over.paramDefs = ParamDef[,]
691
+ over.code = Block.make(loc)
692
+ callArity := "call"
693
+ call := CallExpr.makeWithMethod(loc, FieldExpr(loc, ThisExpr(loc), field), funcType.method(callArity))
694
+ method.params.each |CParam param, Int i|
695
+ {
696
+ paramName := "p$i"
697
+ over.params.add(ParamDef(loc, param.paramType, paramName))
698
+ if (i < funcType.params.size)
699
+ call.args.add(UnknownVarExpr(loc, null, paramName))
700
+ }
701
+ if (method.returnType.isVoid)
702
+ over.code.stmts.add(call.toStmt).add(ReturnStmt(loc))
703
+ else
704
+ over.code.stmts.add(ReturnStmt(loc, call))
705
+ cls.addSlot(over)
706
+
707
+ // return the ctor which we use for coercion
708
+ return ctor
709
+ }
710
+
711
+ //////////////////////////////////////////////////////////////////////////
712
+ // Reflection
713
+ //////////////////////////////////////////////////////////////////////////
714
+
715
+ **
716
+ ** Get a CMethod representation for 'List.make(Type, Object[])'
717
+ **
718
+ once CMethod listMakeFromArray()
719
+ {
720
+ return JavaMethod(
721
+ this.ns.listType,
722
+ "make",
723
+ FConst.Public + FConst.Static,
724
+ this.ns.listType.toNullable,
725
+ [
726
+ JavaParam("of", this.ns.typeType),
727
+ JavaParam("array", objectArrayType)
728
+ ])
729
+ }
730
+
731
+ **
732
+ ** Get a CMethod representation for 'Object[] List.asArray()'
733
+ **
734
+ once CMethod listAsArray()
735
+ {
736
+ return JavaMethod(
737
+ this.ns.listType,
738
+ "asArray",
739
+ FConst.Public,
740
+ objectArrayType,
741
+ [JavaParam("cls", classType)])
742
+ }
743
+
744
+ **
745
+ ** Get a CType representation for 'java.lang.Class'
746
+ **
747
+ once JavaType classType()
748
+ {
749
+ return ns.resolveType("[java]java.lang::Class")
750
+ }
751
+
752
+ **
753
+ ** Get a CType representation for 'java.lang.Object[]'
754
+ **
755
+ once JavaType objectArrayType()
756
+ {
757
+ return ns.resolveType("[java]java.lang::[Object")
758
+ }
759
+
760
+ //////////////////////////////////////////////////////////////////////////
761
+ // Fields
762
+ //////////////////////////////////////////////////////////////////////////
763
+
764
+ const static Str[] boolTypes := Str[
765
+ "[java]java.io::Serializable",
766
+ "[java]java.lang::Comparable",
767
+ ]
768
+
769
+ const static Str[] intTypes := Str[
770
+ "[java]java.lang::Number",
771
+ "[java]java.io::Serializable",
772
+ "[java]java.lang::Comparable",
773
+ ]
774
+
775
+ const static Str[] floatTypes := Str[
776
+ "[java]java.lang::Number",
777
+ "[java]java.io::Serializable",
778
+ "[java]java.lang::Comparable",
779
+ ]
780
+
781
+ const static Str[] decimalTypes := Str[
782
+ "[java]java.lang::Number",
783
+ "[java]java.io::Serializable",
784
+ "[java]java.lang::Comparable",
785
+ ]
786
+
787
+ const static Str[] strTypes := Str[
788
+ "[java]java.io::Serializable",
789
+ "[java]java.lang::CharSequence",
790
+ "[java]java.lang::Comparable",
791
+ ]
792
+
793
+ JavaPrimitives primitives := JavaPrimitives(this)
794
+ ClassPath cp
795
+
796
+ private Str:CMethod funcWrappers := Str:CMethod[:] // funcType+method:ctor
797
+
798
+ }
799
+
800
+ **************************************************************************
801
+ ** CallMatch
802
+ **************************************************************************
803
+
804
+ internal class CallMatch
805
+ {
806
+ CallExpr apply(CallExpr call)
807
+ {
808
+ call.args = args
809
+ call.method = method
810
+ call.ctype = method.isCtor ? method.parent : method.returnType
811
+ return call
812
+ }
813
+
814
+ override Str toStr() { return method.signature }
815
+
816
+ CMethod? method // matched method
817
+ Expr[]? args // coerced arguments
818
+ }