/** * Construct a parser. * * @param env script environment * @param source source to parse * @param errors error manager * @param strict parser created with strict mode enabled. * @param lineOffset line offset to start counting lines from * @param log debug logger if one is needed */ public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { super(source, errors, strict, lineOffset); this.env = env; this.namespace = new Namespace(env.getNamespace()); this.scripting = env._scripting; if (this.scripting) { this.lineInfoReceiver = new Lexer.LineInfoReceiver() { @Override public void lineInfo(final int receiverLine, final int receiverLinePosition) { // update the parser maintained line information Parser.this.line = receiverLine; Parser.this.linePosition = receiverLinePosition; } }; } else { // non-scripting mode script can't have multi-line literals this.lineInfoReceiver = null; } this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; }
private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) { String baseName = new File(source.getName()).getName(); final int index = baseName.lastIndexOf(".js"); if (index != -1) { baseName = baseName.substring(0, index); } baseName = baseName.replace('.', '_').replace('-', '_'); if (!env._loader_per_compile) { baseName = baseName + installer.getUniqueScriptId(); } // ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char. // While ASM accepts such escapes for method names, field names, it enforces Java identifier // for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_' // rather than safe encoding using '\'. final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName); return mangled != null ? mangled : baseName; }
private boolean skipFunction(final FunctionNode functionNode) { final ScriptEnvironment env = compiler.getScriptEnvironment(); final boolean lazy = env._lazy_compilation; final boolean onDemand = compiler.isOnDemandCompilation(); // If this is on-demand or lazy compilation, don't compile a nested (not topmost) function. if((onDemand || lazy) && lc.getOutermostFunction() != functionNode) { return true; } // If lazy compiling with optimistic types, don't compile the program eagerly either. It will soon be // invalidated anyway. In presence of a class cache, this further means that an obsoleted program version // lingers around. Also, currently loading previously persisted optimistic types information only works if // we're on-demand compiling a function, so with this strategy the :program method can also have the warmup // benefit of using previously persisted types. // // NOTE that this means the first compiled class will effectively just have a :createProgramFunction method, and // the RecompilableScriptFunctionData (RSFD) object in its constants array. It won't even have the :program // method. This is by design. It does mean that we're wasting one compiler execution (and we could minimize this // by just running it up to scope depth calculation, which creates the RSFDs and then this limited codegen). // We could emit an initial separate compile unit with the initial version of :program in it to better utilize // the compilation pipeline, but that would need more invasive changes, as currently the assumption that // :program is emitted into the first compilation unit of the function lives in many places. return !onDemand && lazy && env._optimistic_types && functionNode.isProgram(); }
/** * Run method logic. * * @param in input stream for Shell * @param out output stream for Shell * @param err error stream for Shell * @param args arguments to Shell * * @return exit code * * @throws IOException if there's a problem setting up the streams */ protected final int run(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) throws IOException { final Context context = makeContext(in, out, err, args); if (context == null) { return COMMANDLINE_ERROR; } final Global global = context.createGlobal(); final ScriptEnvironment env = context.getEnv(); final List<String> files = env.getFiles(); if (files.isEmpty()) { return readEvalPrint(context, global); } if (env._compile_only) { return compileScripts(context, global, files); } if (env._fx) { return runFXScripts(context, global, files); } return runScripts(context, global, files); }
/** * Construct a parser. * * @param env script environment * @param source source to parse * @param errors error manager * @param strict parser created with strict mode enabled. * @param lineOffset line offset to start counting lines from * @param log debug logger if one is needed */ public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { super(source, errors, strict, lineOffset); this.lc = new ParserContext(); this.defaultNames = new ArrayDeque<>(); this.env = env; this.namespace = new Namespace(env.getNamespace()); this.scripting = env._scripting; if (this.scripting) { this.lineInfoReceiver = new Lexer.LineInfoReceiver() { @Override public void lineInfo(final int receiverLine, final int receiverLinePosition) { // update the parser maintained line information Parser.this.line = receiverLine; Parser.this.linePosition = receiverLinePosition; } }; } else { // non-scripting mode script can't have multi-line literals this.lineInfoReceiver = null; } this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler)); final ScriptEnvironment senv = compiler.getScriptEnvironment(); final PrintWriter err = senv.getErr(); //TODO separate phase for the debug printouts for abstraction and clarity if (senv._print_lower_ast || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_AST)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new ASTWriter(newFunctionNode)); } if (senv._print_lower_parse || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_PARSE)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new PrintVisitor(newFunctionNode)); } return newFunctionNode; }
private static Parser createParser(final ScriptEnvironment env) { final List<String> args = new ArrayList<>(); if (env._const_as_var) { args.add("--const-as-var"); } if (env._no_syntax_extensions) { args.add("-nse"); } if (env._scripting) { args.add("-scripting"); } if (env._strict) { args.add("-strict"); } if (env._es6) { args.add("--language=es6"); } return Parser.create(args.toArray(new String[0])); }
private static Parser createParser(final ScriptEnvironment env) { final List<String> args = new ArrayList<>(); if (env._const_as_var) { args.add("--const-as-var"); } if (env._no_syntax_extensions) { args.add("-nse"); } if (env._scripting) { args.add("-scripting"); } if (env._strict) { args.add("-strict"); } return Parser.create(args.toArray(new String[0])); }
@Override FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler)); final ScriptEnvironment senv = compiler.getScriptEnvironment(); final PrintWriter err = senv.getErr(); //TODO separate phase for the debug printouts for abstraction and clarity if (senv._print_lower_ast || fn.getFlag(FunctionNode.IS_PRINT_LOWER_AST)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new ASTWriter(newFunctionNode)); } if (senv._print_lower_parse || fn.getFlag(FunctionNode.IS_PRINT_LOWER_PARSE)) { err.println("Lower AST for: " + quote(newFunctionNode.getName())); err.println(new PrintVisitor(newFunctionNode)); } return newFunctionNode; }
/** * Construct a parser. * * @param env script environment * @param source source to parse * @param errors error manager * @param strict parser created with strict mode enabled. */ public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) { super(source, errors, strict); this.env = env; this.namespace = new Namespace(env.getNamespace()); this.scripting = env._scripting; if (this.scripting) { this.lineInfoReceiver = new Lexer.LineInfoReceiver() { @Override public void lineInfo(final int receiverLine, final int receiverLinePosition) { // update the parser maintained line information Parser.this.line = receiverLine; Parser.this.linePosition = receiverLinePosition; } }; } else { // non-scripting mode script can't have multi-line literals this.lineInfoReceiver = null; } }
/** * Collects the byte codes for a generated JavaScript class. * * @param classEmitter Open class emitter. * @return Byte codes for the class. */ private byte[] toByteArray(final ClassEmitter classEmitter) { classEmitter.end(); final byte[] code = classEmitter.toByteArray(); final ScriptEnvironment env = context.getEnv(); if (env._print_code) { env.getErr().println(ClassEmitter.disassemble(code)); } if (env._verify_code) { context.verify(code); } return code; }
/** * Run method logic. * * @param in input stream for Shell * @param out output stream for Shell * @param err error stream for Shell * @param args arguments to Shell * * @return exit code * * @throws IOException if there's a problem setting up the streams */ protected final int run(final InputStream in, final OutputStream out, final OutputStream err, final String[] args) throws IOException { final Context context = makeContext(in, out, err, args); if (context == null) { return COMMANDLINE_ERROR; } final ScriptObject global = context.createGlobal(); final ScriptEnvironment env = context.getEnv(); final List<String> files = env.getFiles(); if (files.isEmpty()) { return readEvalPrint(context, global); } if (env._compile_only) { return compileScripts(context, global, files); } if (env._fx) { return runFXScripts(context, global, files); } return runScripts(context, global, files); }
private void initScripting(final ScriptEnvironment scriptEnv) { Object value; value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE); addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value); value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY); addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value); final String execName = ScriptingFunctions.EXEC_NAME; value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.echo (scripting-mode-only) // alias for "print" value = get("print"); addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value); // Nashorn extension: global.$OPTIONS (scripting-mode-only) final ScriptObject options = newObject(); copyOptions(options, scriptEnv); addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options); // Nashorn extension: global.$ENV (scripting-mode-only) if (System.getSecurityManager() == null) { // do not fill $ENV if we have a security manager around // Retrieve current state of ENV variables. final ScriptObject env = newObject(); env.putAll(System.getenv(), scriptEnv._strict); addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); } else { addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); } // add other special properties for exec support addOwnProperty(ScriptingFunctions.OUT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); addOwnProperty(ScriptingFunctions.ERR_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); }