Skip to content

Commit

Permalink
Moves the standard library onto require("kolmafia") instead of a glob…
Browse files Browse the repository at this point in the history
…al. It also fixes some of the interrupt problems. Thanks @ikzann

git-svn-id: http://svn.code.sf.net/p/kolmafia/code@20529 b29ace70-8910-0410-8dcc-aa2fc6433167
  • Loading branch information
gausie committed Nov 29, 2020
1 parent 94d1bfa commit cb6c048
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 74 deletions.
4 changes: 3 additions & 1 deletion src/net/sourceforge/kolmafia/textui/ScriptException.java
Expand Up @@ -36,7 +36,9 @@
public class ScriptException
extends RuntimeException
{
public ScriptException( final String message )
private static final long serialVersionUID = 1L;

public ScriptException(final String message)
{
super( message );
}
Expand Down
8 changes: 3 additions & 5 deletions src/net/sourceforge/kolmafia/textui/javascript/AshStub.java
Expand Up @@ -41,7 +41,6 @@
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.Scriptable;

import net.sourceforge.kolmafia.KoLmafia;
import net.sourceforge.kolmafia.textui.DataTypes;
import net.sourceforge.kolmafia.textui.Parser;
import net.sourceforge.kolmafia.textui.ScriptRuntime;
Expand Down Expand Up @@ -105,10 +104,7 @@ private Function findMatchingFunction( List<Value> ashArgs )
@Override
public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] args )
{
if ( Thread.interrupted() || !KoLmafia.permitsContinue() )
{
throw new ScriptInterruptException();
}
JavascriptRuntime.checkInterrupted();

ValueConverter coercer = new ValueConverter( cx, scope );

Expand Down Expand Up @@ -156,6 +152,8 @@ public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] a
Value ashReturnValue = execute( function, ashArgs );
Object returnValue = coercer.asJava( ashReturnValue );

JavascriptRuntime.checkInterrupted();

if ( returnValue instanceof Value && ((Value) returnValue).asProxy() instanceof ProxyRecordValue )
{
returnValue = EnumeratedWrapper.wrap( returnValue.getClass(), (Value) returnValue );
Expand Down
Expand Up @@ -48,6 +48,7 @@
import net.sourceforge.kolmafia.textui.parsetree.Symbol;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.Function;
Expand All @@ -70,12 +71,16 @@
public class JavascriptRuntime
extends AbstractRuntime
{
public static final String DEFAULT_RUNTIME_LIBRARY_NAME = "__runtimeLibrary__";

static final Map<Thread, JavascriptRuntime> runningRuntimes = new ConcurrentHashMap<>();
static final ContextFactory contextFactory = new ObservingContextFactory();

private File scriptFile = null;
private String scriptString = null;

private Scriptable currentTopScope = null;
private Scriptable currentStdLib = null;

public static String toCamelCase( String name )
{
Expand Down Expand Up @@ -145,18 +150,26 @@ public static List<net.sourceforge.kolmafia.textui.parsetree.Function> getFuncti
return functions;
}

private void initRuntimeLibrary( Context cx, Scriptable scope )
private Scriptable initRuntimeLibrary( Context cx, Scriptable scope, boolean addToTopScope )
{
Set<String> uniqueFunctionNames = getFunctions().stream().map( Symbol::getName ).collect( Collectors.toCollection( TreeSet::new ) );

Scriptable stdLib = cx.newObject( scope );
int attributes = ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY;

for ( String libraryFunctionName : uniqueFunctionNames )
{
ScriptableObject.putProperty( stdLib, toCamelCase( libraryFunctionName ), new LibraryFunctionStub( this, libraryFunctionName ) );
ScriptableObject.defineProperty( stdLib, toCamelCase( libraryFunctionName ),
new LibraryFunctionStub( this, libraryFunctionName ), attributes );
if ( addToTopScope )
{
ScriptableObject.defineProperty( scope, toCamelCase( libraryFunctionName ),
new LibraryFunctionStub( this, libraryFunctionName ), attributes );
}
}

ScriptableObject.putProperty( scope, "Lib", stdLib );
ScriptableObject.defineProperty( scope, DEFAULT_RUNTIME_LIBRARY_NAME, stdLib, attributes );
return stdLib;
}

private static void initEnumeratedType( Context cx, Scriptable scope, Class<?> recordValueClass, Type valueType )
Expand Down Expand Up @@ -195,18 +208,20 @@ public Value execute( final String functionName, final Object[] arguments, final
}

// TODO: Support for requesting user arguments if missing.
Context cx = Context.enter();
Context cx = contextFactory.enterContext();

try
{
cx.setLanguageVersion( Context.VERSION_ES6 );
cx.setOptimizationLevel( 1 );
runningRuntimes.put( Thread.currentThread(), this );

// TODO: Use a shared parent scope and initialize this with that as a prototype.
Scriptable scope = cx.initSafeStandardObjects();
currentTopScope = scope;

initRuntimeLibrary( cx, scope );
// If executing from GCLI (and not file), add std lib to top scope.
currentStdLib = initRuntimeLibrary( cx, scope, scriptFile == null );
initEnumeratedTypes( cx, scope );

setState( State.NORMAL );
Expand Down Expand Up @@ -237,7 +252,7 @@ private Value executeRun( final String functionName, final Object[] arguments, f
{
if ( executeTopLevel )
{
Require require = new SafeRequire( cx, scope );
Require require = new SafeRequire( cx, scope, currentStdLib );
if ( scriptFile != null )
{
exports = require.requireMain( cx, scriptFile.toURI().toString() );
Expand All @@ -257,10 +272,6 @@ private Value executeRun( final String functionName, final Object[] arguments, f
}
}
}
catch ( ScriptInterruptException e )
{
// This only happens on world peace. Fall through and exit the interpreter.
}
catch ( WrappedException e )
{
Throwable unwrapped = e.getWrappedException();
Expand All @@ -272,7 +283,7 @@ private Value executeRun( final String functionName, final Object[] arguments, f
}
catch ( EcmaError e )
{
KoLmafia.updateDisplay( KoLConstants.MafiaState.ERROR, "JavaScript error: " + e.getErrorMessage() + "\n" + e.getScriptStackTrace() );
KoLmafia.updateDisplay( KoLConstants.MafiaState.ERROR, "JavaScript error: " + e.getErrorMessage() + "\n" + e.lineSource() + "\n" + e.getScriptStackTrace() );
}
catch ( JavaScriptException e )
{
Expand All @@ -298,6 +309,15 @@ public static void interruptAll()
}
}

public static void checkInterrupted()
{
if ( Thread.interrupted() || !KoLmafia.permitsContinue() )
{
KoLmafia.forceContinue();
throw new JavaScriptException( "Script interrupted.", null, 0 );
}
}

@Override
public ScriptException runtimeException( final String message )
{
Expand Down
Expand Up @@ -40,8 +40,6 @@
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

import net.sourceforge.kolmafia.KoLmafia;

public class ProxyRecordMethodWrapper
extends BaseFunction
{
Expand All @@ -57,11 +55,6 @@ public ProxyRecordMethodWrapper( Method method )
@Override
public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] args )
{
if ( Thread.interrupted() || !KoLmafia.permitsContinue() )
{
throw new ScriptInterruptException();
}

if ( !( thisObj instanceof EnumeratedWrapper ) )
{
return null;
Expand Down
14 changes: 11 additions & 3 deletions src/net/sourceforge/kolmafia/textui/javascript/SafeRequire.java
Expand Up @@ -28,9 +28,12 @@ public class SafeRequire
{
private static final long serialVersionUID = 1L;

public SafeRequire( Context cx, Scriptable nativeScope )
private Scriptable stdLib;

public SafeRequire( Context cx, Scriptable nativeScope, Scriptable stdLib )
{
super( cx, nativeScope, new SoftCachingModuleScriptProvider( new UrlModuleSourceProvider( Arrays.asList( KoLConstants.SCRIPT_LOCATION.toURI(), KoLConstants.RELAY_LOCATION.toURI() ), null ) ), null, new MainWarningScript(), true );
this.stdLib = stdLib;
}

@Override
Expand All @@ -42,7 +45,11 @@ public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] a
}

String path = (String) args[0];
if ( path.endsWith( ".ash" ) )
if ( path.equals( "kolmafia" ) )
{
return stdLib;
}
else if ( path.endsWith( ".ash" ) )
{
Scriptable exports = cx.newObject( scope );

Expand All @@ -69,7 +76,8 @@ public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] a
{
UserDefinedFunction userDefinedFunction = (UserDefinedFunction) f;
UserDefinedFunctionStub stub = new UserDefinedFunctionStub( interpreter, userDefinedFunction.getName() );
ScriptableObject.putProperty( exports, JavascriptRuntime.toCamelCase( userDefinedFunction.getName() ), stub );
int attributes = ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY;
ScriptableObject.defineProperty( exports, JavascriptRuntime.toCamelCase( userDefinedFunction.getName() ), stub, attributes );
}

interpreter.execute( null, null );
Expand Down

This file was deleted.

0 comments on commit cb6c048

Please sign in to comment.