Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.

Commit 48d5a80

Browse files
committed
22.3.0
1 parent 67034bb commit 48d5a80

11 files changed

Lines changed: 160 additions & 58 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# 22.3.0
2+
## Additions
3+
- Added Static Extensions, with some limitations
4+
5+
## Changes
6+
- `presetter` is replaced with `presetMode`
7+
8+
## Fixes
9+
- Some micro optimizations
10+
111
# 22.2.2
212
## Fixes
313
- You can now edit the properties of special objects in scripts

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,45 @@ class Main
113113
}
114114
```
115115

116+
#### Static Extensions
117+
SScript supports Static Extensions with the `using` keyword.
118+
119+
```haxe
120+
import hscript.SScript;
121+
122+
class Main
123+
{
124+
static function main()
125+
{
126+
var script:SScript = new SScript();
127+
script.setClass(IntExtender);
128+
script.doString("
129+
using IntExtender;
130+
using StringTools;
131+
132+
trace(1.triple()); // 3
133+
trace(.1.triple()); // 0.30000000000000004
134+
/*
135+
SScript doesn't check types in extension methods,
136+
so 'triple' returns a Float even though it should return an Int.
137+
Use it with caution.
138+
*/
139+
140+
var str = 'str-end';
141+
trace(str.startsWith('str'), str.endsWith('-end')); // true,true
142+
");
143+
}
144+
}
145+
146+
class IntExtender {
147+
static public function triple(i:Int):Int {
148+
return i * 3;
149+
}
150+
}
151+
```
152+
153+
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.
154+
116155
#### String Interpolation
117156
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.
118157

haxelib.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"script"
1010
],
1111
"description": "SScript (also known as SuperlativeScript), fork of HScript with fixes and improvements.",
12-
"version": "22.2.2",
12+
"version": "22.3.0",
1313
"classPath": "src/",
1414
"releasenote": "Check CHANGELOG.md",
1515
"contributors": [

src/hscript/SScript.hx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ class SScript
119119
120120
**MINI** contains only basic classes like `Math`.
121121
122-
123122
**REGULAR** contains most cross-target Haxe classes.
124123
125124
**FULL** contains all existing classes.
@@ -202,9 +201,11 @@ class SScript
202201
public var notAllowedClasses(default, null):Array<Class<Dynamic>> = [];
203202

204203
/**
205-
Preset tool for this script.
204+
Preset mode of this script.
205+
206+
@see SScript.defaultPreset
206207
**/
207-
public var presetter(default, null):Preset;
208+
public var presetMode(default, set):PresetMode;
208209

209210
/**
210211
Use this to access to interpreter's variables!
@@ -294,7 +295,7 @@ class SScript
294295

295296
parser = new Parser();
296297

297-
presetter = new Preset(this);
298+
presetMode = defaultPreset;
298299
if (preset)
299300
this.preset();
300301

@@ -419,9 +420,11 @@ class SScript
419420
This is a helper function for setting classes easily.
420421
For example, if `cl` is the `sys.io.File` class, it will be set as `File`.
421422
@param cl The class to set.
423+
@param setAsFinal Whether to set the object as final. If set as final,
424+
the object will act as a final variable and cannot be changed in the script.
422425
@return this instance for chaining.
423426
**/
424-
public function setClass(cl:Class<Dynamic>):SScript
427+
public function setClass(cl:Class<Dynamic>, ?setAsFinal:Bool = false):SScript
425428
{
426429
if (_destroyed)
427430
return null;
@@ -445,7 +448,7 @@ class SScript
445448
clName = splitCl[splitCl.length - 1];
446449
}
447450

448-
set(clName, cl);
451+
set(clName, cl, setAsFinal);
449452
}
450453
return this;
451454
}
@@ -454,9 +457,11 @@ class SScript
454457
Sets a class in this script from a string.
455458
`cl` will be formatted. For example: `sys.io.File` -> `File`.
456459
@param cl The class to set.
460+
@param setAsFinal Whether to set the object as final. If set as final,
461+
the object will act as a final variable and cannot be changed in the script.
457462
@return this instance for chaining.
458463
**/
459-
public function setClassString(cl:String):SScript
464+
public function setClassString(cl:String, ?setAsFinal:Bool = false):SScript
460465
{
461466
if (_destroyed)
462467
return null;
@@ -476,7 +481,7 @@ class SScript
476481
if (parts.length > 1)
477482
cl = parts[parts.length - 1];
478483

479-
set(cl, cls);
484+
set(cl, cls, setAsFinal);
480485
}
481486
return this;
482487
}
@@ -788,7 +793,7 @@ class SScript
788793
if (!active)
789794
return;
790795

791-
presetter.preset();
796+
Preset.preset(this);
792797
}
793798

794799
function resetInterp():Void
@@ -807,6 +812,7 @@ class SScript
807812
return;
808813

809814
interp.specialObject = null;
815+
interp.usingMethods = null;
810816
interp.script = null;
811817
interp.locals = null;
812818
interp.variables = null;
@@ -1032,8 +1038,6 @@ class SScript
10321038
if (ID != null && global.exists(Std.string(ID)))
10331039
global.remove(Std.string(ID));
10341040

1035-
presetter.destroy();
1036-
10371041
removeSpecialObject();
10381042
clear();
10391043
resetInterp();
@@ -1110,4 +1114,10 @@ class SScript
11101114

11111115
return defaultPreset = value;
11121116
}
1117+
1118+
function set_presetMode(value:PresetMode):PresetMode {
1119+
if (_destroyed)
1120+
return null;
1121+
return presetMode = value;
1122+
}
11131123
}

src/hscript/backend/MultiMap.hx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package hscript.backend;
2+
3+
import haxe.ds.Map;
4+
5+
class MultiMap<V:Dynamic> {
6+
private var data:Map<String, Array<V>>;
7+
8+
public function new() {
9+
data = new Map<String, Array<V>>();
10+
}
11+
12+
public function push(key:String, value:V):Void {
13+
if (!data.exists(key)) {
14+
data.set(key, [value]);
15+
} else {
16+
data.get(key).push(value);
17+
}
18+
}
19+
20+
public function get(key:String):Array<V> {
21+
return data.exists(key) ? data.get(key) : [];
22+
}
23+
24+
public function remove(key:String):Bool {
25+
return data.remove(key);
26+
}
27+
}

src/hscript/backend/Preset.hx

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,24 @@ enum PresetMode
1717
@:access(hscript.SScript)
1818
class Preset
1919
{
20-
public var presetMode:PresetMode;
21-
22-
var script:SScript;
23-
var _destroyed:Bool = false;
24-
public function new(script:SScript)
20+
static function preset(script:SScript)
2521
{
2622
if (script == null || script._destroyed)
2723
return;
2824

29-
this.script = script;
30-
presetMode = SScript.defaultPreset;
31-
}
32-
33-
function preset()
34-
{
35-
if (_destroyed || script == null || script._destroyed)
36-
return;
37-
38-
var hArray = switch presetMode {
25+
var hArray = switch script.presetMode {
3926
case MINI: PresetClasses.miniHaxe;
4027
case REGULAR: PresetClasses.regularHaxe;
4128
#if !DISABLED_MACRO_SUPERLATIVE
4229
case FULL: PresetClasses.fullHaxe;
4330
#end
44-
case _: [];
31+
default: [];
4532
}
4633

4734
for (i in hArray.copy()) {
4835
script.setClass(i);
4936
}
5037
}
51-
52-
function destroy()
53-
{
54-
if (_destroyed)
55-
return;
56-
57-
script = null;
58-
presetMode = null;
59-
60-
_destroyed = true;
61-
}
6238
}
6339

6440
class PresetClasses

src/hscriptBase/Expr.hx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ enum ExprDef {
6969
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
7070
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr , ifExpr : Expr }>, ?defaultExpr : Expr);
7171
EDoWhile( cond : Expr, e : Expr);
72-
EUsing( op : Dynamic , n : String );
72+
EUsing( c : String );
7373
EImport( i : Dynamic, c : String , ?asIdent : String , ?fullName : String );
7474
EImportStar( pkg : String );
7575
EPackage( ?p : String );
@@ -114,6 +114,7 @@ enum ErrorDef {
114114
ENullObjectReference;
115115
EInvalidChar( c : Int );
116116
EUnexpected( s : String );
117+
ETypeNotFound( s : String );
117118
EUnterminatedString;
118119
EUnterminatedComment;
119120
EInvalidPreprocessor( msg : String );

src/hscriptBase/Interp.hx

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222
package hscriptBase;
2323

24+
import hscript.backend.MultiMap;
2425
import haxe.ds.*;
2526
import haxe.PosInfos;
2627
import hscriptBase.Expr;
@@ -68,6 +69,8 @@ class Interp {
6869
var specialObject : {obj:Dynamic , ?includeFunctions:Bool , ?exclusions:Array<String>} = {obj : null , includeFunctions: null , exclusions: null };
6970
var specialObjectsFields : Array< String > = [];
7071

72+
var usingMethods : MultiMap< Function > = new MultiMap< Function >();
73+
7174
var hasPrivateAccess : Bool = false;
7275
var noPrivateAccess : Bool = false;
7376

@@ -732,9 +735,21 @@ class Interp {
732735
finalVariables.set(c,e);
733736

734737
return if( strictVar ) error(EUnexpected("import")) else null;
735-
case EUsing( e, c ):
736-
if( c != null && e != null )
737-
finalVariables.set( c , e );
738+
case EUsing( c ):
739+
var cl = Type.resolveClass(c);
740+
if( cl == null )
741+
cl = finalVariables.get(c);
742+
if( cl == null )
743+
cl = variables.get(c);
744+
if( cl == null )
745+
error(ETypeNotFound(c));
746+
747+
var fields = Reflect.fields(cl);
748+
for( i in fields ) {
749+
var f = Reflect.field(cl,i);
750+
if( f != null && Reflect.isFunction(f) )
751+
usingMethods.push(i,f);
752+
}
738753

739754
return if( strictVar ) error(EUnexpected("using")) else null;
740755
case EPackage(p):
@@ -1160,9 +1175,9 @@ class Interp {
11601175
restore(old);
11611176
}
11621177

1178+
static final mapClasses:Array<Dynamic> = ["Map", "StringMap", "IntMap", "ObjectMap", "HashMap", "EnumValueMap", "WeakMap"];
11631179
static inline function isMap(o:Dynamic):Bool {
1164-
var classes:Array<Dynamic> = ["Map", "StringMap", "IntMap", "ObjectMap", "HashMap", "EnumValueMap", "WeakMap"];
1165-
if(classes.contains(o))
1180+
if(mapClasses.contains(o))
11661181
return true;
11671182

11681183
return Std.isOfType(o, IMap);
@@ -1190,7 +1205,28 @@ class Interp {
11901205
}
11911206

11921207
function fcall( o : Dynamic, f : String, args : Array<Dynamic>) : Dynamic {
1193-
return call(o, get(o, f), args);
1208+
var exception = null;
1209+
try {
1210+
return call(o, get(o, f), args);
1211+
}
1212+
catch( e )
1213+
exception = e;
1214+
1215+
if( f != null ) {
1216+
var methods = usingMethods.get(f);
1217+
for( i in methods ) {
1218+
try {
1219+
var args = args.copy();
1220+
args.unshift(o);
1221+
return call(o, i, args);
1222+
}
1223+
catch( e ) {
1224+
exception = e;
1225+
continue;
1226+
}
1227+
}
1228+
}
1229+
return throw exception;
11941230
}
11951231

11961232
function call( o : Dynamic, f : Dynamic, args : Array<Dynamic>) : Dynamic {

0 commit comments

Comments
 (0)