Compare commits

..
Author SHA1 Message Date
Jaime Humberto Macias Bustamante 1002bfc969 Just found out i have to rewrite the entire thing due to compilation errors :'3 2025-11-05 18:45:32 -07:00
Jaime Humberto Macias Bustamante 8d99717f39 I forgot 2025-10-25 16:42:55 -07:00
Jaime Humberto Macias Bustamante 97a0aa4e37 It works! >:3 2025-10-25 16:42:05 -07:00
Jaime Humberto Macias Bustamante 54333cdb3a Update CustomClassMacro.hx 2025-10-24 12:29:14 -07:00
Jaime Humberto Macias Bustamante 99d542215f Update CustomClassMacro.hx 2025-10-23 11:10:14 -07:00
Jaime Humberto Macias Bustamante ec01692883 Update CustomClassMacro.hx 2025-10-23 11:07:32 -07:00
Jaime Humberto Macias Bustamante 9ddc7eee5c New Custom Class Macro (NOT READY TO USE) 2025-10-17 12:38:27 -07:00
Jaime Humberto Macias Bustamante a69d51f474 Update Interp.hx 2025-09-21 12:14:32 -07:00
Jaime Humberto Macias Bustamante 9c3069d62e forgot this 2025-09-19 16:53:03 -07:00
Jaime Humberto Macias Bustamante c91ca46eb4 Warning message handling + optimization
Now Duplicated Custom Class declaration will be ignored and prints a warning message.
2025-09-19 16:37:11 -07:00
TBar09andGitHub 115bd453b9 Added static imports (#10)
* Added static imports

* Update Interp.hx
2025-09-08 08:53:37 -07:00
Jaime Humberto Macias Bustamante 826282aa72 Merge branch 'feature/string-interpolation' into codename-dev 2025-09-06 19:42:39 -07:00
Jaime Humberto Macias Bustamante 9fa4a548e5 String Interpolation Support
implementation from hscript-iris (by inky03)

Note: it needs optimization
2025-09-06 19:39:57 -07:00
Jaime Humberto Macias Bustamante 18f4ebccd9 Fix small bug with slash literal ("\/") 2025-09-06 19:31:48 -07:00
Jaime Humberto Macias Bustamante 8dcebe3930 Regular Expression support (regex) 2025-09-06 19:31:48 -07:00
Jaime Humberto Macias Bustamante 3b8b017d4d Fix small bug with slash literal ("\/") 2025-09-03 22:00:32 -07:00
7 changed files with 1238 additions and 48 deletions
+1
View File
@@ -1,3 +1,4 @@
--macro keep('IntIterator')
--macro hscript.macros.AbstractHandler.init()
--macro hscript.macros.ClassExtendMacro.init()
--macro hscript.macros.CustomClassMacro.init()
+1 -1
View File
@@ -34,7 +34,7 @@ typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
enum Const {
CInt( v : Int );
CFloat( f : Float );
CString( s : String );
CString( s : String, ?i : Bool );
}
#if hscriptPos
+69 -40
View File
@@ -122,7 +122,8 @@ class Interp {
return inCustomClass ? cast scriptObject : null;
public var errorHandler:Error->Void;
public var importFailedCallback:Array<String>->Bool;
public var warnHandler:Error->Void;
public var importFailedCallback:Array<String>->Null<String>->Bool;
public var customClasses:Map<String, CustomClassHandler>;
public var variables:Map<String, Dynamic>;
@@ -143,6 +144,7 @@ class Interp {
var beforeAlias:Null<String> = null;
public var importEnabled:Bool = true;
public var allowStaticImports:Bool = true;
public var allowStaticVariables:Bool = false;
public var allowPublicVariables:Bool = false;
@@ -602,6 +604,15 @@ class Interp {
return null;
}
public inline function warn(e:#if hscriptPos ErrorDef #else Error #end) {
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
if(warnHandler != null)
warnHandler(e);
else
trace('[ Warning ] ${Printer.errorToString(e)}');
}
inline function rethrow(e:Dynamic):Void {
#if hl
hl.Api.rethrow(e);
@@ -705,12 +716,15 @@ class Interp {
switch (e) {
case EPackage(_):
case EClass(name, fields, extend, interfaces, isFinal):
// TODO: module isolation
var oldName:String = name;
var hasAlias:Bool = (setAlias != null && beforeAlias == oldName);
var toSetName:String = hasAlias ? setAlias : oldName;
if (customClasses.exists(toSetName))
error(EAlreadyExistingClass(toSetName));
if (customClasses.exists(toSetName)) {
warn(EAlreadyExistingClass(toSetName));
return null;// ignore it
}
inline function importVar(thing:String):String {
if (thing == null)
@@ -725,20 +739,20 @@ class Interp {
beforeAlias = null;
setAlias = null;
}
case EImport(c, n, isUsing):
if (!importEnabled)
return null;
var splitClassName = [for (e in c.split(".")) e.trim()];
case EImport(clsName, aliasAs, isUsing):
if(!importEnabled) return null;
var splitClassName = [for (e in clsName.split(".")) e.trim()];
var realClassName = splitClassName.join(".");
var claVarName = splitClassName[splitClassName.length - 1];
var toSetName = n != null ? n : claVarName;
var toSetName = aliasAs != null ? aliasAs : claVarName;
var oldClassName = realClassName;
var oldSplitName = splitClassName.copy();
if (variables.exists(toSetName)) { // class is already imported
if(variables.exists(toSetName)) { // class is already imported
if(isUsing && !usingHandler.entryExists(toSetName))
setUsing(toSetName, variables.get(toSetName));
return null;
}
@@ -748,56 +762,70 @@ class Interp {
// setting the extension
if(isUsing && !usingHandler.entryExists(toSetName))
setCustomClassUsing(toSetName, customClasses.get(toSetName));
return null;
}
function importResolve(__clsName:String):Null<Dynamic> {
var _realClassName = getLocalImportRedirect(__clsName);
if(importBlocklist.contains(_realClassName)) return null;
var realClassName = getLocalImportRedirect(realClassName);
if (importBlocklist.contains(realClassName))
return null;
var cl = Type.resolveClass(realClassName);
if (cl == null)
cl = Type.resolveClass('${realClassName}_HSC');
var _cl = Type.resolveClass(_realClassName);
if(_cl == null) _cl = Type.resolveClass('${_realClassName}_HSC');
return _cl;
}
var cl = importResolve(realClassName);
var en = Type.resolveEnum(realClassName);
//trace(realClassName, cl, en, splitClassName);
// Allow for flixel.ui.FlxBar.FlxBarFillDirection;
if (cl == null && en == null) {
if(cl == null && en == null) {
if(splitClassName.length > 1) {
splitClassName.splice(-2, 1); // Remove the last last item
realClassName = splitClassName.join(".");
var realClassName = getLocalImportRedirect(realClassName);
if (importBlocklist.contains(realClassName))
return null;
cl = Type.resolveClass(realClassName);
if (cl == null)
cl = Type.resolveClass('${realClassName}_HSC');
cl = importResolve(realClassName);
en = Type.resolveEnum(realClassName);
//trace(realClassName, cl, en, splitClassName);
}
}
if (cl == null && en == null) {
if(cl == null && en == null) {
if(allowStaticImports) { //allows for static imports like "haxe.io.Path.normalize"
var clPth = oldSplitName.copy();
var funcName = clPth.pop();
var statField = Reflect.getProperty(Type.resolveClass(StringTools.trim(clPth.join("."))), funcName);
if(statField != null) {
variables.set((toSetName != null && toSetName.length > 0 ? toSetName : funcName), statField);
return null;
}
}
beforeAlias = claVarName;
setAlias = n;
if (importFailedCallback == null || !importFailedCallback(oldSplitName)){
setAlias = aliasAs;
if(importFailedCallback == null || !importFailedCallback(oldSplitName, toSetName)){
beforeAlias = null;
setAlias = null;
error(EInvalidClass(oldClassName));
}
}
} else {
if (en != null) {
if(isUsing) error(EInvalidClass(oldClassName));
// ENUM!!!!
//If the first letter of the alias is not an uppercase letter, then throw an error.
//We don't need to worry about this for static imports.
if(toSetName != claVarName && !Tools.isUppercase(toSetName)) {
error(ECustom("Type aliases must start with an uppercase letter"));
return null;
}
if(en != null) { // ENUM!!!!
if(isUsing) {
error(EInvalidClass(oldClassName));
return null;
}
var enumThingy:HEnum = {};
for (c in en.getConstructors()) {
for(c in en.getConstructors()) {
try {
//UnsafeReflect.setField(enumThingy, c, en.createByName(c));
enumThingy.setEnum(c, en.createByName(c));
@@ -811,12 +839,11 @@ class Interp {
}
}
variables.set(toSetName, enumThingy);
} else {
} else { //Standard class
if(isUsing) setUsing(toSetName, cl);
variables.set(toSetName, cl);
}
}
return null;
case EEnum(en, _): // TODO: enum abstracts
@@ -1222,7 +1249,7 @@ class Interp {
var match = false;
for (c in cases) {
for (v in c.values) {
// https://github.com/FunkinCrew/hscript/blob/funkin-dev/hscript/Interp.hx#L531
// https://github.com/FunkinCrew/hscript/blob/funkin-dev/hscript/Interp.hx#L611
switch (Tools.expr(v)) {
case ECall(e, params):
switch (Tools.expr(e)) {
@@ -1626,3 +1653,5 @@ class Interp {
return Type.createInstance(c, args);
}
}
+146 -7
View File
@@ -340,7 +340,7 @@ class Parser {
if( !allowJSON )
unexpected(tk);
switch( c ) {
case CString(s): id = s;
case CString(s, _): id = s;
default: unexpected(tk);
}
case TBrClose:
@@ -377,6 +377,11 @@ class Parser {
e = mk(EIdent(id));
return parseExprNext(e);
case TConst(c):
switch(c) {
case CString(s, i):
if(i) return parseExprNext(interpolateString(s));
default:
}
return parseExprNext(mk(EConst(c)));
case TPOpen:
tk = token();
@@ -1638,6 +1643,94 @@ class Parser {
}
return args;
}
// From hscript-iris: https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Parser.hx#L409
// by inky03
function interpolateString(s:String):Expr {
var exprs:Array<Expr> = [];
var dollarPos:Int = s.indexOf('$');
if(dollarPos == -1)
return mk(EConst(CString(s)));
final singleFirst:EReg = ~/[a-zA-Z_]/i;
final singleExpr:EReg = ~/[a-zA-Z0-9_]/i;
// TODO: optimize this using regex
while(dollarPos > -1) {
var pos:Int = dollarPos;
var pre:String = s.substr(0, pos);
var next:String = s.charAt(++pos);
if(next == '{') {
if (pre != '')
exprs.push(mk(EConst(CString(pre))));
var exprStr:String = '';
var depth:Int = 1;
while (true) {
next = s.charAt(++pos);
if (next == '{') {
depth++;
} else if (next == '}') {
depth--;
}
if (depth < 1)
break;
if (pos >= s.length) {
error(EUnterminatedString, pos, pos);
}
exprStr += next;
}
if (exprStr.trim() == '') {
error(ECustom("Expression cannot be empty"), pos, pos);
}
var prevChar = char;
var prevInput = input;
var prevReadPos = readPos; // a bit stupid innit???
#if hscriptPos
var prevOrigin = origin;
#end
var expr = parseString('($exprStr)' #if hscriptPos, origin #end);
readPos = prevReadPos; // rolling back parser state because otherwise we get problems...
input = prevInput;
char = prevChar;
#if hscriptPos
origin = prevOrigin;
#end
exprs.push(expr);
pos++;
}
else if(singleFirst.match(next)) {
if (pre != '')
exprs.push(mk(EConst(CString(pre))));
var ident: String = '';
while(singleExpr.match(next)) {
ident += next;
next = s.charAt(++pos);
}
exprs.push(mk(EIdent(ident)));
}
else if (next == '$') {
var secondToNext: String = s.charAt(pos);
if (secondToNext == "$") { // if its another dollar, skip...
s = pre + s.substr(pos, pos + 1); // remove $ ahead of the current one
break;
}
exprs.push(mk(EConst(CString(pre + '$'))));
}
s = s.substr(pos++);
dollarPos = s.indexOf('$');
}
if (exprs.length == 0) {
return mk(EConst(CString(s)));
} else {
exprs.push(mk(EConst(CString(s))));
var expr:Null<Expr> = exprs.shift();
while(true) {
if(exprs.length == 0) break;
expr = mk(EBinop('+', expr, exprs.shift()));
}
return expr;
}
}
function checkAccess(get:FieldPropertyAccess, set:FieldPropertyAccess, ?expr:Expr, ?type:CType) {
#if hscriptPos
@@ -1873,8 +1966,9 @@ class Parser {
return StringTools.fastCodeAt(input, readPos++);
}
function readString( until:Int, regex:Bool = false ):String {
function readString( until:Int, regex:Bool = false, interpolate:Bool = false ):String {
var c = 0;
var prev = 0;
var b = new StringBuf();
var esc = false;
var old = line;
@@ -1923,11 +2017,53 @@ class Parser {
}
} else if( c == 92 && !regex)
esc = true;
else if( c == until )
break;
else if( c == until ) {
if(regex && prev == 92) {
b.addChar(c);
prev = c;
}
else
break;
}
else if (c == 36 && interpolate) { // brace for impact !!
// From hscript-iris: https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Parser.hx#L1665
// by inky03
// TODO: optimize this
b.addChar(c);
var next = readChar();
if (next == 123) {
b.addChar(next);
var depth:Int = 0;
while (true) {
next = readChar();
if (StringTools.isEof(next)) {
error(EUnterminatedString, p1, p1);
}
b.addChar(next);
if (next == "'".code) {
var nextStr:String = readString("'".code, false, true);
for (char in nextStr) {
b.addChar(char);
}
b.addChar("'".code);
next = readChar();
b.addChar(next);
}
if (next == 125) {
depth--;
if (depth < 0)
break;
}
}
} else {
readPos--;
}
}
else {
if( c == 10 ) line++;
b.addChar(c);
if(regex)
prev = c;
}
}
return b.toString();
@@ -2133,7 +2269,10 @@ class Parser {
case "}".code: return TBrClose;
case "[".code: return TBkOpen;
case "]".code: return TBkClose;
case "'".code, '"'.code: return TConst( CString(readString(char)) );
case "'".code:
return TConst( CString(readString(char, false, true), true) );
case '"'.code:
return TConst( CString(readString(char), false) );
case "?".code:
char = readChar();
switch (char) {
@@ -2394,7 +2533,7 @@ class Parser {
return switch(c) {
case CInt(v): Std.string(v);
case CFloat(f): Std.string(f);
case CString(s): s; // TODO : escape + quote
case CString(s, _): s; // TODO : escape + quote
}
}
@@ -2418,7 +2557,7 @@ class Parser {
case TDoubleDot: ":";
case TMeta(id): "@" + id;
case TPrepro(id): "#" + id;
case TRegex(e, f): '~/$e/${f == null ? '' : f}';
case TRegex(e, f): '~/$e/$f';
}
}
+7
View File
@@ -131,6 +131,13 @@ class Tools {
#end
}
public static function isUppercase(s:String) {
if(s.length == 0) return false;
var c:Int = StringTools.fastCodeAt(s, 0);
if(StringTools.isEof(c)) return false; // Just in case :3
return c >= 65 && c <= 90; // A-Z
}
public static inline function isCustomAbstract(obj:Dynamic):Bool
return obj != null && obj is IHScriptAbstractBehaviour;
+2
View File
@@ -26,9 +26,11 @@ class ClassExtendMacro {
#if !display
#if CUSTOM_CLASSES
if(Context.defined("display")) return;
/*
for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
}
*/
//Context.onAfterTyping(buildTyped);
#end
#end
File diff suppressed because it is too large Load Diff