Wrap.java revision 3062:15bdc18525ff
1238384Sjkim/*
2238384Sjkim * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3238384Sjkim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4238384Sjkim *
5238384Sjkim * This code is free software; you can redistribute it and/or modify it
6238384Sjkim * under the terms of the GNU General Public License version 2 only, as
7238384Sjkim * published by the Free Software Foundation.  Oracle designates this
8238384Sjkim * particular file as subject to the "Classpath" exception as provided
9238384Sjkim * by Oracle in the LICENSE file that accompanied this code.
10238384Sjkim *
11238384Sjkim * This code is distributed in the hope that it will be useful, but WITHOUT
12238384Sjkim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13238384Sjkim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14238384Sjkim * version 2 for more details (a copy is included in the LICENSE file that
15238384Sjkim * accompanied this code).
16238384Sjkim *
17238384Sjkim * You should have received a copy of the GNU General Public License version
18238384Sjkim * 2 along with this work; if not, write to the Free Software Foundation,
19238384Sjkim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20238384Sjkim *
21238384Sjkim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22238384Sjkim * or visit www.oracle.com if you need additional information or have any
23238384Sjkim * questions.
24238384Sjkim */
25238384Sjkimpackage jdk.jshell;
26238384Sjkim
27238384Sjkimimport java.util.ArrayList;
28238384Sjkimimport java.util.List;
29238384Sjkimimport static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME;
30238384Sjkim
31238384Sjkim/**
32238384Sjkim * Wrapping of source into Java methods, fields, etc.  All but outer layer
33238384Sjkim * wrapping with imports and class.
34238384Sjkim *
35238384Sjkim * @author Robert Field
36238384Sjkim */
37238384Sjkimabstract class Wrap implements GeneralWrap {
38238384Sjkim
39238384Sjkim    private static Wrap methodWrap(String prefix, String source, String suffix) {
40238384Sjkim        Wrap wunit = new NoWrap(source);
41238384Sjkim        return new DoitMethodWrap(new CompoundWrap(prefix, wunit, suffix));
42238384Sjkim    }
43238384Sjkim
44238384Sjkim    public static Wrap methodWrap(String source) {
45238384Sjkim        return methodWrap("", source, semi(source) + "        return null;\n");
46238384Sjkim    }
47238384Sjkim
48238384Sjkim    public static Wrap methodReturnWrap(String source) {
49238384Sjkim        return methodWrap("return ", source, semi(source));
50238384Sjkim    }
51238384Sjkim
52238384Sjkim    public static Wrap methodUnreachableSemiWrap(String source) {
53238384Sjkim        return methodWrap("", source, semi(source));
54238384Sjkim    }
55238384Sjkim
56238384Sjkim    public static Wrap methodUnreachableWrap(String source) {
57238384Sjkim        return methodWrap("", source, "");
58238384Sjkim    }
59238384Sjkim
60238384Sjkim    public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) {
61238384Sjkim        List<Object> l = new ArrayList<>();
62238384Sjkim        l.add("    public static\n    ");
63238384Sjkim        if (!modRange.isEmpty()) {
64238384Sjkim            l.add(new RangeWrap(source, modRange));
65238384Sjkim            l.add(" ");
66238384Sjkim        }
67238384Sjkim        if (tpRange != null) {
68238384Sjkim            l.add("<");
69238384Sjkim            l.add(new RangeWrap(source, tpRange));
70238384Sjkim            l.add("> ");
71238384Sjkim        }
72238384Sjkim        l.add(new RangeWrap(source, typeRange));
73238384Sjkim        l.add(" " + name + "(\n        ");
74238384Sjkim        if (paramRange != null) {
75238384Sjkim            l.add(new RangeWrap(source, paramRange));
76238384Sjkim        }
77238384Sjkim        l.add(") ");
78238384Sjkim        if (throwsRange != null) {
79238384Sjkim            l.add("throws ");
80238384Sjkim            l.add(new RangeWrap(source, throwsRange));
81238384Sjkim        }
82238384Sjkim        l.add(" {\n        throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n");
83238384Sjkim        return new CompoundWrap(l.toArray());
84238384Sjkim    }
85238384Sjkim
86238384Sjkim    /**
87238384Sjkim     *
88238384Sjkim     * @param in
89238384Sjkim     * @param rname
90238384Sjkim     * @param rinit Initializer or null
91238384Sjkim     * @param rdecl Type name and name
92238384Sjkim     * @return
93238384Sjkim     */
94238384Sjkim    public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
95238384Sjkim        RangeWrap wname = new RangeWrap(source, rname);
96238384Sjkim        RangeWrap wtype = new RangeWrap(source, rtype);
97238384Sjkim        Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
98238384Sjkim        Wrap wmeth;
99238384Sjkim
100238384Sjkim        if (rinit == null) {
101238384Sjkim            wmeth = new CompoundWrap(new NoWrap(" "), "   return null;\n");
102238384Sjkim        } else {
103238384Sjkim            RangeWrap winit = new RangeWrap(source, rinit);
104238384Sjkim        // int x = y
105238384Sjkim            // int x_ = y; return x = x_;
106238384Sjkim            // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
107238384Sjkim            wmeth = new CompoundWrap(
108238384Sjkim                    wtype, brackets + " ", wname, "_ =\n        ", winit, semi(winit),
109238384Sjkim                    "        return ", wname, " = ", wname, "_;\n"
110238384Sjkim            );
111238384Sjkim        }
112238384Sjkim        Wrap wInitMeth = new DoitMethodWrap(wmeth);
113238384Sjkim        return new CompoundWrap(wVarDecl, wInitMeth);
114238384Sjkim    }
115238384Sjkim
116238384Sjkim    public static Wrap tempVarWrap(String source, String typename, String name) {
117238384Sjkim        RangeWrap winit = new NoWrap(source);
118238384Sjkim        // y
119238384Sjkim        // return $1 = y;
120238384Sjkim        // "return " + $1 + "=" + init ;
121238384Sjkim        Wrap wmeth = new CompoundWrap("return " + name + " =\n        ", winit, semi(winit));
122238384Sjkim        Wrap wInitMeth = new DoitMethodWrap(wmeth);
123238384Sjkim
124238384Sjkim        String varDecl = "    public static\n    " + typename + " " + name + ";\n";
125238384Sjkim        return new CompoundWrap(varDecl, wInitMeth);
126238384Sjkim    }
127238384Sjkim
128238384Sjkim    public static Wrap importWrap(String source) {
129238384Sjkim        return new NoWrap(source);
130238384Sjkim    }
131238384Sjkim
132238384Sjkim    public static Wrap classMemberWrap(String source) {
133238384Sjkim        Wrap w = new NoWrap(source);
134238384Sjkim        return new CompoundWrap("    public static\n    ", w);
135238384Sjkim    }
136238384Sjkim
137238384Sjkim    private static int countLines(String s) {
138238384Sjkim        return countLines(s, 0, s.length());
139238384Sjkim    }
140238384Sjkim
141238384Sjkim    private static int countLines(String s, int from, int toEx) {
142238384Sjkim        int cnt = 0;
143238384Sjkim        int idx = from;
144238384Sjkim        while ((idx = s.indexOf('\n', idx)) > 0) {
145238384Sjkim            if (idx >= toEx) break;
146238384Sjkim            ++cnt;
147238384Sjkim            ++idx;
148238384Sjkim        }
149238384Sjkim        return cnt;
150238384Sjkim    }
151238384Sjkim
152238384Sjkim    public static final class Range {
153238384Sjkim        final int begin;
154238384Sjkim        final int end;
155
156        Range(int begin, int end) {
157            this.begin = begin;
158            this.end = end;
159        }
160
161        Range(String s) {
162            this.begin = 0;
163            this.end = s.length();
164        }
165
166        String part(String s) {
167            return s.substring(begin, end);
168        }
169
170        int length() {
171            return end - begin;
172        }
173
174        boolean isEmpty() {
175            return end == begin;
176        }
177
178        void verify(String s) {
179            if (begin < 0 || end <= begin || end > s.length()) {
180                throw new InternalError("Bad Range: " + s + "[" + begin + "," + end + "]");
181            }
182        }
183
184        @Override
185        public String toString() {
186            return "Range[" + begin + "," + end + "]";
187        }
188    }
189
190    public static class CompoundWrap extends Wrap {
191
192        final Object[] os;
193        final String wrapped;
194        final int snidxFirst;
195        final int snidxLast;
196        final int snlineFirst;
197        final int snlineLast;
198
199        CompoundWrap(Object... os) {
200            this.os = os;
201            int sniFirst = Integer.MAX_VALUE;
202            int sniLast = Integer.MIN_VALUE;
203            int snlnFirst = Integer.MAX_VALUE;
204            int snlnLast = Integer.MIN_VALUE;
205            StringBuilder sb = new StringBuilder();
206            for (Object o : os) {
207                if (o instanceof String) {
208                    String s = (String) o;
209                    sb.append(s);
210                } else if (o instanceof Wrap) {
211                    Wrap w = (Wrap) o;
212                    if (w.firstSnippetIndex() < sniFirst) {
213                        sniFirst = w.firstSnippetIndex();
214                    }
215                    if (w.lastSnippetIndex() > sniLast) {
216                        sniLast = w.lastSnippetIndex();
217                    }
218                    if (w.firstSnippetLine() < snlnFirst) {
219                        snlnFirst = w.firstSnippetLine();
220                    }
221                    if (w.lastSnippetLine() > snlnLast) {
222                        snlnLast = w.lastSnippetLine();
223                    }
224                    sb.append(w.wrapped());
225                } else {
226                    throw new InternalError("Bad object in CommoundWrap: " + o);
227                }
228            }
229            this.wrapped = sb.toString();
230            this.snidxFirst = sniFirst;
231            this.snidxLast = sniLast;
232            this.snlineFirst = snlnFirst;
233            this.snlineLast = snlnLast;
234        }
235
236        @Override
237        public String wrapped() {
238            return wrapped;
239        }
240
241        @Override
242        public int snippetIndexToWrapIndex(int sni) {
243            int before = 0;
244            for (Object o : os) {
245                if (o instanceof String) {
246                    String s = (String) o;
247                    before += s.length();
248                } else if (o instanceof Wrap) {
249                    Wrap w = (Wrap) o;
250                    if (sni >= w.firstSnippetIndex() && sni <= w.lastSnippetIndex()) {
251                        return w.snippetIndexToWrapIndex(sni) + before;
252                    }
253                    before += w.wrapped().length();
254                }
255            }
256            return 0;
257        }
258
259        @Override
260        public int wrapIndexToSnippetIndex(int wi) {
261            int before = 0;
262            for (Object o : os) {
263                if (o instanceof String) {
264                    String s = (String) o;
265                    before += s.length();
266                } else if (o instanceof Wrap) {
267                    Wrap w = (Wrap) o;
268                    int len = w.wrapped().length();
269                    if ((wi - before) <= len) {
270                        //System.err.printf("Defer to wrap %s - wi: %d. before; %d   -- %s  >>> %s\n",
271                        //        w, wi, before, w.debugPos(wi - before), w.wrapped());
272                        return w.wrapIndexToSnippetIndex(wi - before);
273                    }
274                    before += len;
275                }
276            }
277            return lastSnippetIndex();
278        }
279
280        @Override
281        public int firstSnippetIndex() {
282            return snidxFirst;
283        }
284
285        @Override
286        public int lastSnippetIndex() {
287            return snidxLast;
288        }
289
290        @Override
291        public int snippetLineToWrapLine(int snline) {
292            int before = 0;
293            for (Object o : os) {
294                if (o instanceof String) {
295                    String s = (String) o;
296                    before += countLines(s);
297                } else if (o instanceof Wrap) {
298                    Wrap w = (Wrap) o;
299                    if (snline >= w.firstSnippetLine() && snline <= w.lastSnippetLine()) {
300                        return w.snippetLineToWrapLine(snline) + before;
301                    }
302                    before += countLines(w.wrapped());
303                }
304            }
305            return 0;
306        }
307
308        @Override
309        public int wrapLineToSnippetLine(int wline) {
310            int before = 0;
311            for (Object o : os) {
312                if (o instanceof String) {
313                    String s = (String) o;
314                    before += countLines(s);
315                } else if (o instanceof Wrap) {
316                    Wrap w = (Wrap) o;
317                    int lns = countLines(w.wrapped());
318                    if ((wline - before) < lns) {
319                        return w.wrapLineToSnippetLine(wline - before);
320                    }
321                    before += lns;
322                }
323            }
324            return 0;
325        }
326
327        @Override
328        public int firstSnippetLine() {
329            return snlineFirst;
330        }
331
332        @Override
333        public int lastSnippetLine() {
334            return snlineLast;
335        }
336
337
338    }
339
340    private static class RangeWrap extends Wrap {
341
342        final Range range;
343        final String wrapped;
344        final int firstSnline;
345        final int lastSnline;
346
347        RangeWrap(String snippetSource, Range usedWithinSnippet) {
348            this.range = usedWithinSnippet;
349            this.wrapped = usedWithinSnippet.part(snippetSource);
350            usedWithinSnippet.verify(snippetSource);
351            this.firstSnline = countLines(snippetSource, 0, range.begin);
352            this.lastSnline = firstSnline + countLines(snippetSource, range.begin, range.end);
353        }
354
355        @Override
356        public String wrapped() {
357            return wrapped;
358        }
359
360        @Override
361        public int snippetIndexToWrapIndex(int sni) {
362            if (sni < range.begin) {
363                return 0;
364            }
365            if (sni > range.end) {
366                return range.length();
367            }
368            return sni - range.begin;
369        }
370
371        @Override
372        public int wrapIndexToSnippetIndex(int wi) {
373            if (wi < 0) {
374                return 0; // bad index
375            }
376            int max = range.length();
377            if (wi > max) {
378                wi = max;
379            }
380            return wi + range.begin;
381        }
382
383        @Override
384        public int firstSnippetIndex() {
385            return range.begin;
386        }
387
388        @Override
389        public int lastSnippetIndex() {
390            return range.end;
391        }
392
393        @Override
394        public int snippetLineToWrapLine(int snline) {
395            if (snline < firstSnline) {
396                return 0;
397            }
398            if (snline >= lastSnline) {
399                return lastSnline - firstSnline;
400            }
401            return snline - firstSnline;
402        }
403
404        @Override
405        public int wrapLineToSnippetLine(int wline) {
406            if (wline < 0) {
407                return 0; // bad index
408            }
409            int max = lastSnline - firstSnline;
410            if (wline > max) {
411                wline = max;
412            }
413            return wline + firstSnline;
414        }
415
416        @Override
417        public int firstSnippetLine() {
418            return firstSnline;
419        }
420
421        @Override
422        public int lastSnippetLine() {
423            return lastSnline;
424        }
425
426    }
427
428    private static class NoWrap extends RangeWrap {
429
430        NoWrap(String unit) {
431            super(unit, new Range(unit));
432        }
433    }
434
435    private static String semi(Wrap w) {
436        return semi(w.wrapped());
437    }
438
439    private static String semi(String s) {
440        return ((s.endsWith(";")) ? "\n" : ((s.endsWith(";\n")) ? "" : ";\n"));
441    }
442
443    private static class DoitMethodWrap extends CompoundWrap {
444
445        DoitMethodWrap(Wrap w) {
446            super("    public static Object " + DOIT_METHOD_NAME + "() throws Throwable {\n"
447                    + "        ", w,
448                    "    }\n");
449        }
450    }
451
452    private static class VarDeclareWrap extends CompoundWrap {
453
454        VarDeclareWrap(Wrap wtype, String brackets, Wrap wname) {
455            super("    public static ", wtype, brackets + " ", wname, semi(wname));
456        }
457    }
458}
459