SuperlativeScript is a fork of HScript with fixes and improvements.
haxelib install SScript
Enter this command in the command prompt to get the latest release from the Haxe library.
After installing SScript, don't forget to add it to your Haxe project.
Add this to Project.xml to add SScript to your OpenFL project:
<haxelibname="SScript"/>Add this to build.hxml to add SScript to your Haxe build.
-lib SScriptHaxe definition hscriptPos is deprecated and shouldn't be used unless you also want to use vanilla HScript.
To use SScript, you will need either a file or a script. Using a file is recommended.
importhscript.SScript;
classMain {
staticfunctionmain() {
varscript:SScript=newSScript(); // Create a new SScript classscript.doString(" function returnRandom():Float return Math.random() * 100;"); // Implement the scriptvarcall=script.call('returnRandom');
varrandomNumber:Float=call.returnValue; // Access the returned value with returnValue
}
}importhscript.SScript;
classMain {
staticfunctionmain() {
varscript:SScript=newSScript("script.hx"); // Contains the same code as the script abovevarrandomNumber:Float=script.call('returnRandom').returnValue;
}
}SScript supports normal imports, wildcard imports and imports with aliases.
importhscript.SScript;
classMain {
staticfunctionmain() {
varscript:SScript=newSScript();
script.doString(" import Date; trace(Date.now());");
}
}importhscript.SScript;
classMain {
staticfunctionmain() {
varscript:SScript=newSScript();
script.doString(" import sys.*; trace(FileSystem); // Class<sys.FileSystem>");
}
}SScript uses a macro for wildcard imports. In most cases, it works fine. However, if you want to disable this feature, you can define DISABLED_MACRO_SUPERLATIVE in your project. This is not recommended, however, as doing so will also make the FULL preset mode unavailable.
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript:SScript=newSScript();
script.doString(" import sys.FileSystem in L; import sys.io.File as G; trace(L, G); // Class<sys.FileSystem>,Class<sys.io.File>");
}
}SScript supports Static Extensions with the using keyword.
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript:SScript=newSScript();
script.setClass(IntExtender);
script.doString(" using IntExtender; using StringTools; trace(1.triple()); // 3 trace(.1.triple()); // 0.30000000000000004 /* SScript doesn't check types in extension methods, so 'triple' returns a Float even though it should return an Int. Use it with caution. */ var str = 'str-end'; trace(str.startsWith('str'), str.endsWith('-end')); // true,true");
}
}
classIntExtender {
staticpublicfunctiontriple(i:Int):Int {
returni*3;
}
}As explained above, SScript doesn’t check types. It also doesn’t verify if the correct number of arguments is used; therefore, if an incorrect number of arguments is provided (such as passing two arguments to endsWith like str.endsWith(str, "-end")), Haxe will throw a vague Something went wrong error.
SScript supports string interpolation. Just like in Haxe, special identifiers denoted by the dollar sign $ within a string (enclosed by single quotes ') are evaluated as expressions.
importhscript.SScript;
varscript:SScript=newSScript(); // Create a new SScript classscript.doString(" var x = 12; trace('The value of x is $x'); // The value of x is 12 trace('The value of x is ${x + 2}'); // The value of x is 14"); SScript has support for regular expressions.
Example:
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript=newSScript();
script.doString(' function getMatches(ereg:EReg, input:String, index:Int = 0):Array<String> { var matches = []; while (ereg.match(input)) { matches.push(ereg.matched(index)); input = ereg.matchedRight(); } return matches; } var message = "row row row your boat"; var matches = getMatches(~/(row)/, message); trace(matches); // [row,row,row] trace(matches.length); // 3 // Email addresses regular expression // (In files, use one back slash instead) var emailReg = ~/[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z][A-Z][A-Z]*/i; trace(emailReg.match("superlative@email.com")); // true');
}
}You can still create regular expressions using the standard syntax:
varr=newEReg("haxe", "i");With faulty EReg instances, Haxe may produce corrupted error messages. These errors cannot be caught and may crash the session.
Sometimes, Haxe may not display error messages. If this happens, the session may enter a loop and become unresponsive.
Platform limitations also apply here, the flag u is only available in C++ and Neko.
Flag s is not available in C# and JavaScript.
With SScript, you can access (excluding unused) classes or enums with their full name like Haxe. Example:
importhscript.SScript;
classMain {
staticfunctionmain()
{
SScript.defaultImprovedField=true;
varscript=newSScript();
script.doString(" trace(haxe.Timer.stamp());");
}
}This makes import optional and it is useful for one-time use of a class or enum.
This feature may be exhausting for weak machines and is disabled by default, so if you wish to enable it set hscript.SScript.defaultImprovedField to true.
Function arguments have been reworked, so optional arguments will work like native Haxe.
Example:
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript=newSScript();
script.doString(" function add(a:Int, ?b:Int = 1) { return a + b; } trace(add()); // Exception: Not enough arguments, expected a:Int trace(add(0)); // 1 trace(add(0, 2)); // 2");
}
}Presets are the variables that get set before the script gets executed.
SScript has a presetting system that allows you to configure multiple preset modes.
Currently, it includes 4 modes: NONE, MINI, REGULAR, and FULL.
MINIcontains only basic classes and is extremely lightweight.REGULARincludes more commonly used classes.FULLincludes all available classes and can be expensive when handling many scripts. (Available only ifDISABLED_MACRO_SUPERLATIVEis not defined)
Example:
importhscript.backend.Preset;
importhscript.SScript;
classMain {
staticfunctionmain() {
SScript.defaultPreset=PresetMode.FULL;
varscript=newSScript("trace(Json); // haxe.Json class is included with REGULAR and FULL");
}
}You can also set variables manually with set, setClass, setClassString and setByPackage (not available if DISABLED_MACRO_SUPERLATIVE is defined).
Example:
importhscript.backend.Preset;
importhscript.SScript;
classMain {
staticfunctionmain() {
varscript=newSScript();
script.set("Json", haxe.Json);
script.setClass(haxe.Serializer);
script.setClassString("haxe.ds.ArraySort");
script.setByPackage("haxe.sys", false); // Do NOT include sub-packagesscript.doString(" trace(Json); // Class<haxe.Json> trace(Serializer); // Class<haxe.Serializer> trace(ArraySort); // Class<haxe.ds.ArraySort> trace(FileSystem); // Class<sys.FileSystem>");
}
}SuperlativeScript supports both ?. and ?? syntaxes including ??=.
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript:SScript=newSScript();
script.doString(" var string:String = null; trace(string.length); // Throws an error trace(string?.length); // Doesn't throw an error and returns null trace(string ?? 'ss'); // Returns 'ss'; trace(string ??= 'ss'); // Returns 'ss' and assigns it to `string` variable");
}
}You can create a class extending SScript to customize it better.
classSScriptExextendshscript.SScript
{ overridefunctionpreset():Void
{
super.preset();
// Only use 'set', 'setClass' or 'setClassString' in preset// Macro classes are not allowed to be setsetClass(StringTools);
set('NaN', Math.NaN);
setClassString('sys.io.File');
}
}Extend other functions only if you know what you're doing.
You can call methods and receive their return value from scripts using call function.
It needs one obligatory argument (function name) and one optional argument (function arguments array).
Using call will return a structure that contains the return value, if calling has been successful, exceptions if it did not, called function name and script file name of the script.
Example:
importhscript.SScript;
classMain {
staticfunctionmain() {
varscript:SScript=newSScript();
script.doString(' function method() { return 2 + 2; }');
varcall=script.call('method');
trace(call.returnValue); // 4script.doString(' function method() { var num = null; return num + 1; }');
varcall=script.call('method');
trace(call.returnValue, call.exceptions[0]); // null, Invalid operation: null + 1
}
}With SScript, you can set variables to all existing scripts. Example:
importhscript.SScript;
classMain {
staticfunctionmain() {
SScript.globalVariables.set('variable2', 2);
varscript:SScript=newSScript();
script.set('variable', 1);
script.doString(' function returnVar() { return variable + variable2; }');
trace(script.call('returnVar').returnValue); // 3
}
}Variables from globalVariables can be changed in script but the value in SScript.globalVariables won't be affected.
If you do not want this, add -final at the end of the variable name. They will act as a final and cannot be changed in script.
importhscript.SScript;
classMain {
staticfunctionmain() {
SScript.globalVariables.set('variable2-final', 2);
varscript:SScript=newSScript();
script.doString(' variable2 = 0;');
trace(script.parsingException); // This expression cannot be accessed for writing
}
}Special object is an object that'll get checked if a variable is not found in a script. A special object cannot be a basic type like Int, Float, String, Array and Bool.
Special objects are especially useful for OpenFL and Flixel states.
Example:
importflixel.FlxG;
importhscript.SScript;
classPlayStateextendsflixel.FlxState {
varsprite:flixel.FlxSprite;
overridefunctioncreate()
{
sprite=newflixel.FlxSprite();
sprite.makeGraphic(FlxG.width, FlxG.height, FlxColor.WHITE);
add(sprite);
varnewScript:SScript=newSScript();
newScript.setSpecialObject(this);
newScript.doString("sprite.visible = false;");
super.create();
}
}Special objects can also be Classes and Enums.
importhscript.SScript;
classMain {
staticfunctionmain()
{
varscript:SScript=newSScript();
script.setSpecialObject(SpecialObject);
script.doString(" call(); //You called me!");
varscript:SScript=newSScript();
script.setSpecialObject(Special);
script.doString(" trace(AA(1)); //SScript:2: AA(1) trace(BB); //SScript:3: BB");
}
}
classSpecialObject {
staticfunctioncall() {
trace("You called me!");
}
}
enumSpecial {
AA(r:Int);
BB;
}
