1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.nashorn.api.tree; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.PrintWriter; 30 import java.io.Reader; 31 import java.net.URL; 32 import java.nio.file.Path; 33 import java.util.Arrays; 34 import java.util.Map; 35 import java.util.Objects; 36 import jdk.nashorn.api.scripting.NashornException; 37 import jdk.nashorn.api.scripting.ScriptObjectMirror; 38 import jdk.nashorn.internal.ir.FunctionNode; 39 import jdk.nashorn.internal.runtime.Context; 40 import jdk.nashorn.internal.runtime.ErrorManager; 41 import jdk.nashorn.internal.runtime.JSType; 42 import jdk.nashorn.internal.runtime.ParserException; 43 import jdk.nashorn.internal.runtime.ScriptEnvironment; 44 import jdk.nashorn.internal.runtime.Source; 45 import jdk.nashorn.internal.runtime.options.Options; 46 47 final class ParserImpl implements Parser { 48 49 private final ScriptEnvironment env; 50 private final boolean moduleMode; 51 52 ParserImpl(final String... args) throws IllegalArgumentException { 53 Objects.requireNonNull(args); 54 55 // handle the parser specific "--es6-module" option 56 boolean seenModuleOption = false; 57 for (int idx = 0; idx < args.length; idx++) { 58 final String opt = args[idx]; 59 if (opt.equals("--es6-module")) { 60 seenModuleOption = true; 61 /* 62 * Nashorn parser does not understand parser API specific 63 * option. This option implies --language=es6. So, we change 64 * the option to --language=es6. Note that if user specified 65 * --language=es6 explicitly, that is okay. Nashorn tolerates 66 * repeated options! 67 */ 68 args[idx] = "--language=es6"; 69 break; 70 } 71 } 72 this.moduleMode = seenModuleOption; 73 74 // append "--parse-only to signal to the Nashorn that it 75 // is being used in "parse only" mode. 76 final String[] newArgs = Arrays.copyOf(args, args.length + 1, String[].class); 77 newArgs[args.length] = "--parse-only"; 78 final Options options = new Options("nashorn"); 79 options.process(newArgs); 80 this.env = new ScriptEnvironment(options, 81 new PrintWriter(System.out), new PrintWriter(System.err)); 82 } 83 84 @Override 85 public CompilationUnitTree parse(final File file, final DiagnosticListener listener) throws IOException, NashornException { 86 if (moduleMode) { 87 return parseModule(file, listener); 88 } 89 final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file); 90 return translate(makeParser(src, listener).parse()); 91 } 92 93 @Override 94 public CompilationUnitTree parse(final Path path, final DiagnosticListener listener) throws IOException, NashornException { 95 if (moduleMode) { 96 return parseModule(path, listener); 97 } 98 final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path); 99 return translate(makeParser(src, listener).parse()); 100 } 101 102 @Override 103 public CompilationUnitTree parse(final URL url, final DiagnosticListener listener) throws IOException, NashornException { 104 if (moduleMode) { 105 return parseModule(url, listener); 106 } 107 final Source src = Source.sourceFor(url.toString(), url); 108 return translate(makeParser(src, listener).parse()); 109 } 110 111 @Override 112 public CompilationUnitTree parse(final String name, final Reader reader, final DiagnosticListener listener) throws IOException, NashornException { 113 if (moduleMode) { 114 return parseModule(name, reader, listener); 115 } 116 final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader)); 117 return translate(makeParser(src, listener).parse()); 118 } 119 120 @Override 121 public CompilationUnitTree parse(final String name, final String code, final DiagnosticListener listener) throws NashornException { 122 if (moduleMode) { 123 return parseModule(name, code, listener); 124 } 125 final Source src = Source.sourceFor(name, code); 126 return translate(makeParser(src, listener).parse()); 127 } 128 129 @Override 130 public CompilationUnitTree parse(final ScriptObjectMirror scriptObj, final DiagnosticListener listener) throws NashornException { 131 if (moduleMode) { 132 return parseModule(scriptObj, listener); 133 } 134 final Map<?, ?> map = Objects.requireNonNull(scriptObj); 135 if (map.containsKey("script") && map.containsKey("name")) { 136 final String script = JSType.toString(map.get("script")); 137 final String name = JSType.toString(map.get("name")); 138 final Source src = Source.sourceFor(name, script); 139 return translate(makeParser(src, listener).parse()); 140 } else { 141 throw new IllegalArgumentException("can't find 'script' and 'name' properties"); 142 } 143 } 144 145 private CompilationUnitTree parseModule(final File file, final DiagnosticListener listener) throws IOException, NashornException { 146 final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file); 147 return makeModule(src, listener); 148 } 149 150 private CompilationUnitTree parseModule(final Path path, final DiagnosticListener listener) throws IOException, NashornException { 151 final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path); 152 return makeModule(src, listener); 153 } 154 155 private CompilationUnitTree parseModule(final URL url, final DiagnosticListener listener) throws IOException, NashornException { 156 final Source src = Source.sourceFor(url.toString(), url); 157 return makeModule(src, listener); 158 } 159 160 private CompilationUnitTree parseModule(final String name, final Reader reader, final DiagnosticListener listener) throws IOException, NashornException { 161 final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader)); 162 return makeModule(src, listener); 163 } 164 165 private CompilationUnitTree parseModule(final String name, final String code, final DiagnosticListener listener) throws NashornException { 166 final Source src = Source.sourceFor(name, code); 167 return makeModule(src, listener); 168 } 169 170 private CompilationUnitTree parseModule(final ScriptObjectMirror scriptObj, final DiagnosticListener listener) throws NashornException { 171 final Map<?, ?> map = Objects.requireNonNull(scriptObj); 172 if (map.containsKey("script") && map.containsKey("name")) { 173 final String script = JSType.toString(map.get("script")); 174 final String name = JSType.toString(map.get("name")); 175 final Source src = Source.sourceFor(name, script); 176 return makeModule(src, listener); 177 } else { 178 throw new IllegalArgumentException("can't find 'script' and 'name' properties"); 179 } 180 } 181 182 private CompilationUnitTree makeModule(final Source src, final DiagnosticListener listener) { 183 final FunctionNode modFunc = makeParser(src, listener).parseModule(src.getName()); 184 return new IRTranslator().translate(modFunc); 185 } 186 187 private jdk.nashorn.internal.parser.Parser makeParser(final Source source, final DiagnosticListener listener) { 188 final ErrorManager errMgr = listener != null ? new ListenerErrorManager(listener) : new Context.ThrowErrorManager(); 189 return new jdk.nashorn.internal.parser.Parser(env, source, errMgr); 190 } 191 192 private static class ListenerErrorManager extends ErrorManager { 193 194 private final DiagnosticListener listener; 195 196 ListenerErrorManager(final DiagnosticListener listener) { 197 // null check 198 listener.getClass(); 199 this.listener = listener; 200 } 201 202 @Override 203 public void error(final String msg) { 204 error(new ParserException(msg)); 205 } 206 207 @Override 208 public void error(final ParserException e) { 209 listener.report(new DiagnosticImpl(e, Diagnostic.Kind.ERROR)); 210 } 211 212 @Override 213 public void warning(final String msg) { 214 warning(new ParserException(msg)); 215 } 216 217 @Override 218 public void warning(final ParserException e) { 219 listener.report(new DiagnosticImpl(e, Diagnostic.Kind.WARNING)); 220 } 221 } 222 223 private static CompilationUnitTree translate(final FunctionNode node) { 224 return new IRTranslator().translate(node); 225 } 226 }