File src/de/jandankert/jscriptbox/executor/ScriptInterpreter.java

Last commit: Sun May 31 00:20:40 2026 +0200	Jan Dankert	Fixing some javadoc errors.
1 2 3 package de.jandankert.jscriptbox.executor; 4 5 import de.jandankert.jscriptbox.standard.*; 6 import de.jandankert.jscriptbox.ast.DslStatement; 7 import de.jandankert.jscriptbox.context.Context; 8 import de.jandankert.jscriptbox.context.MapContext; 9 import de.jandankert.jscriptbox.context.Scriptable; 10 import de.jandankert.jscriptbox.formatter.ObjectDumper; 11 import de.jandankert.jscriptbox.standard.System; 12 import de.jandankert.jscriptbox.standard.*; 13 import de.jandankert.jscriptbox.exception.ScriptParserException; 14 import de.jandankert.jscriptbox.parser.AstParser; 15 import de.jandankert.jscriptbox.exception.ScriptException; 16 import de.jandankert.jscriptbox.parser.Lexer; 17 import de.jandankert.jscriptbox.exception.ScriptRuntimeException; 18 import de.jandankert.jscriptbox.parser.Token; 19 20 import java.io.PrintStream; 21 import java.util.Map; 22 import java.util.Queue; 23 24 public class ScriptInterpreter { 25 26 private PrintStream logWriter = java.lang.System.out; 27 28 /** 29 * Execution context. 30 * 31 * @var array 32 */ 33 private Context context; 34 35 /** 36 * Holds a reference to the write()-Function for getting the output buffer after execution. 37 * 38 * @var Writer 39 */ 40 private Writer writer = new Writer(); 41 private int flags; 42 43 /** 44 * Print Error Messages in the script output. 45 */ 46 public static int FLAG_SHOW_ERROR = 1; 47 /** 48 * Prints the stacktrace in script output, if an error occur. 49 */ 50 public static int FLAG_SHOW_TRACE = 2; 51 /** 52 * Throw @{@link ScriptRuntimeException} if an error occur. 53 */ 54 public static int FLAG_THROW_ERROR = 4; 55 /** 56 * Show debug messages on the standard output. 57 */ 58 public static int FLAG_DEBUG = 8; 59 /** 60 * Only allow access to objects which are marked as @{@link Scriptable}. 61 */ 62 public static int FLAG_ALLOW_UNSECURE = 16; 63 64 private static boolean secure = true; 65 private DslStatement rootStatement; 66 67 public ScriptInterpreter() { 68 this(FLAG_SHOW_ERROR + FLAG_THROW_ERROR ); 69 } 70 71 public ScriptInterpreter(int flags) { 72 this.flags = flags; 73 74 this.context = new MapContext( this.hasFlag(FLAG_ALLOW_UNSECURE) ); 75 this.addStandardContext(); 76 } 77 78 /** 79 * adds an external context to the interpreter environment. 80 * 81 * @param object 82 */ 83 public void addToContext(String name, Object object) { 84 this.context.put(name, object); 85 } 86 87 88 public void prepareCode(String code) throws ScriptParserException { 89 90 // Splitting the source code into tokens (the "Lexer") 91 Lexer lexer = new Lexer(); 92 lexer.tokenize(code); 93 Queue<Token> token = lexer.getToken(); 94 95 if ( this.hasFlag( FLAG_DEBUG )) { 96 97 if ( this.logWriter != null ) { 98 int line = 0; 99 logWriter.print("Tokenized source"); 100 logWriter.print("................"); 101 for( Token tok : token ) { 102 if ( line != tok.getLineNumber() ) { 103 line = tok.getLineNumber(); 104 logWriter.print( "\n" + String.format("%6s", line).replace(' ', '.') + " " ); 105 } 106 107 logWriter.print( tok.getValue() ); 108 } 109 logWriter.println(); 110 logWriter.println(); 111 } 112 } 113 // it has no security impact, so let's do it always. 114 this.addToContext("Script", new Script(token.toArray(new Token[]{}), this.rootStatement)); 115 116 // Creating a syntax tree (abstract syntax tree, AST). 117 AstParser parser = new AstParser(); 118 this.rootStatement = parser.parse(token); 119 120 if ( this.hasFlag( FLAG_DEBUG )) { 121 122 if ( this.logWriter != null ) { 123 logWriter.println("Syntax Tree"); 124 logWriter.println("..........."); 125 logWriter.println(ObjectDumper.getFormat(this.rootStatement," " )); 126 logWriter.println(); 127 } 128 } 129 } 130 131 132 public Object run(Map<String,Object> additionalContext ) throws ScriptRuntimeException { 133 this.context.putAll( additionalContext ); 134 return run(); 135 } 136 137 138 public Object run() throws ScriptRuntimeException { 139 140 this.writer.clear(); 141 if ( this.hasFlag( FLAG_DEBUG )) { 142 143 if ( this.logWriter != null ) { 144 logWriter.println( "Context: "+ this.context ); 145 } 146 } 147 148 if ( rootStatement == null ) { 149 throw new ScriptRuntimeException("No statement found."); 150 } 151 152 try { 153 // Executing the syntax tree. 154 return this.rootStatement.execute(this.context); 155 } catch (ScriptRuntimeException e) { 156 if (this.hasFlag(FLAG_SHOW_ERROR)) { 157 if (this.hasFlag(FLAG_SHOW_TRACE)) 158 this.writer.write(e.toString()); 159 else 160 this.writer.write(e.getMessage()); 161 } 162 if (this.hasFlag(FLAG_THROW_ERROR)) 163 throw e; 164 else 165 return null; // no return value 166 } 167 } 168 169 170 /** 171 * Parses and runs the DSL code. 172 * 173 * If you want to cache the code, use {@link #prepareCode(String)} and {@link #run()}. 174 * 175 * @param code String Script-Code 176 * @return mixed value of last return statement (if any) 177 * @throws ScriptException 178 */ 179 public Object runCode(String code) throws ScriptException { 180 181 this.prepareCode(code); 182 return this.run(); 183 } 184 185 186 /** 187 * Gets the output which was written by the code. 188 * 189 * @return mixed 190 */ 191 public String getOutput() { 192 193 return this.writer.getBuffer(); 194 } 195 196 /** 197 * @return bool 198 */ 199 public static boolean isSecure() { 200 return secure; 201 } 202 203 /** 204 * Adding the standard context. 205 */ 206 protected void addStandardContext() { 207 // Standard-Globals 208 209 // Standard JS objects 210 this.addToContext("Math", new MathWrapper()); 211 this.addToContext("Array", new ArrayWrapper()); 212 this.addToContext("String", new StringWrapper()); 213 this.addToContext("Number", new NumberWrapper()); 214 this.addToContext("Date", new DateWrapper()); 215 216 // Custom Scriptbox objects 217 this.addToContext("System", new System()); 218 this.addToContext("write", this.writer); 219 this.addToContext("writeln", new WriteWrapper(this.writer, "\n" )); 220 this.addToContext("print", new WriteWrapper(this.writer, "" )); 221 this.addToContext("println", new WriteWrapper(this.writer, "\n" )); 222 } 223 224 225 public void setLogWriter(PrintStream logWriter) { 226 this.logWriter = logWriter; 227 } 228 229 public boolean hasFlag( int flag) { 230 return (this.flags & flag) > 0; 231 } 232 233 public void addFlag( int flag ) { 234 this.flags += flag; 235 } 236 public void removeFlag( int flag ) { 237 this.flags -= flag; 238 } 239 240 @Override 241 public String toString() { 242 return "Interpreter{" + 243 "flags="+this.flags + 244 "}"; 245 } 246 }
Download src/de/jandankert/jscriptbox/executor/ScriptInterpreter.java
History Sun, 31 May 2026 00:20:40 +0200 Jan Dankert Fixing some javadoc errors. Sat, 30 May 2026 23:22:58 +0200 Jan Dankert Refactoring package openrat->jandankert because the maven artefact is in namespace de.jandankert