Compare commits

...
Author SHA1 Message Date
Jaime Humberto Macias Bustamante 24abfa436e Update CustomClassHandler.hx
forgot to change this too...
2026-06-20 23:29:32 -07:00
Jaime Humberto Macias Bustamante 92e458876e remove direct function call handling
after testing, it turns out that trying to handle the direct getter/setter function will be so complex than I thought.
2026-06-20 23:23:10 -07:00
Jaime Humberto Macias Bustamante 44d8b1e0e1 better static field filtering 2026-06-20 19:39:17 -07:00
Jaime Humberto Macias Bustamante ff649efadf better accessor bypass handling 2026-06-20 18:50:03 -07:00
Crimson-is-stupidandJaime Humberto Macias Bustamante 4625529be7 Reimplement Trigraph Fix (#18)
* replace all "??=" with "??" + "="

* Update Expr.hx
2026-06-03 23:37:56 -07:00
Jaime Humberto Macias Bustamante b9da833bb5 better callAccessor + optimize "__allowGetSet" 2026-06-03 17:14:08 -07:00
Jaime Humberto Macias Bustamante 0c08f64274 Update Property.hx 2026-06-03 16:57:58 -07:00
Jaime Humberto Macias Bustamante 3add08e0ee some docs + small optimizations 2026-05-29 10:23:56 -07:00
Jaime Humberto Macias Bustamante 77fae88890 oversight again... 2026-04-30 11:32:13 -07:00
Jaime Humberto Macias Bustamante 2a301ea591 fixed small oversight 2026-04-30 11:27:07 -07:00
Jaime Humberto Macias Bustamante 634d819cc2 Refactor property fields
Now you can call directly the getter/setter functions without triggering them again.
2026-04-30 11:02:47 -07:00
Jaime Humberto Macias Bustamante 7f3de28e02 Update Interp.hx 2026-04-30 09:30:10 -07:00
Jaime Humberto Macias Bustamante 0322624729 New Ops fixes 2026-04-21 11:01:22 -07:00
HEIHUAaandGitHub 68358bb084 cache+optimize+fix (#17)
* 更新 Interp.hx

* exprReturn

* Binop

* exprReturn repair

* exprReturn repair

* Revert "Merge branch 'cache' of https://github.com/HEIHUAa/hscript-improved into cache"

This reverts commit 2bc31b672c, reversing
changes made to 188031c416.

* Unop

* Fix override not applying across multiple inheritance levels.

* 更新 Interp.hx

* 更新 README.md

* ++
2026-04-21 10:48:42 -07:00
Jaime Humberto Macias Bustamante 65ab73d93f fix enum abstract field declaration + implicit string
now enum abstract are parsed correctly.
2026-03-18 01:05:20 -07:00
Jaime Humberto Macias Bustamante fff4f68d66 small optimization + docs check 2026-03-16 21:41:56 -07:00
HEIHUAaandGitHub 65fe06feba Implement enum abstract + fully qualified path functionality. (#15)
* enum

* path functionality

* allowTypes
2026-03-16 21:05:53 -07:00
Jaime Humberto Macias Bustamante b980b73f9e small optimizations 2026-03-08 21:07:41 -07:00
Yoshman29 5d2ab05fc9 (IMPORTANT) added new define for abstracthandler 2026-01-29 20:46:54 +01:00
Jaime Humberto Macias Bustamante b82aad097a Property resolve optimization 2026-01-10 20:35:20 -07:00
Jaime Humberto Macias Bustamante df1bc5c68b Multiple implements support 2026-01-08 15:13:59 -07:00
HEIHUAaandGitHub 1033e2fd10 Parser optimization (#12) 2026-01-08 14:08:37 -07:00
Jaime Humberto Macias Bustamante f9b5ce71b4 Class Path fix + more optimizations 2025-12-27 13:34:56 -07:00
Jaime Humberto Macias Bustamante 951a0898ce more optimizations
- some functions are inlined now to improve performance.
- "hasScriptObject" and "inCustomClass" has been turned to a real variable to reduce the amount of null checks.
- some condition has been reordered to improve performance.
2025-12-15 15:54:28 -07:00
Jaime Humberto Macias Bustamante 22b4b25f5a small static extension fix + small optimization 2025-12-07 14:29:50 -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
Jaime Humberto Macias Bustamante d344ede669 Regular Expression support (regex) 2025-09-03 20:13:39 -07:00
Jaime Humberto Macias Bustamante 85f51df7eb fixed accessing class fields from objects
this shouldn't happen, unless "useRedirects" is on.
2025-08-19 19:24:00 -07:00
FrakitsandGitHub 5dce82eaf6 Update haxelib.json 2025-08-15 15:07:28 +03:00
Jaime Humberto Macias Bustamante 0b4675b4ad static property accessor call 2025-08-14 03:07:44 -07:00
Jaime Humberto Macias Bustamante e4861a606a Features Documentation 2025-08-04 13:40:48 -07:00
Jaime Humberto Macias Bustamante bbe9fd255d fixed package parsing issue 2025-08-03 21:46:04 -07:00
Jaime Humberto Macias Bustamante 6bd3f26746 package syntax support
For now it's just sugar syntax.
2025-08-03 21:28:59 -07:00
Jaime Humberto Macias Bustamante 83aa0f3856 fixed variable set bug 2025-08-03 01:08:06 -07:00
Jaime Humberto Macias Bustamante f97a7b8a55 Merge branch 'codename-dev' of github.com:CodenameCrew/hscript-improved into codename-dev 2025-08-03 00:08:46 -07:00
Jaime Humberto Macias Bustamante f936877339 MyCustomClass.new + Optimization
You can now pass the custom class constructor as a field.
2025-08-03 00:08:43 -07:00
Jamextreme140andGitHub 9fbe8a6316 Update README.md 2025-08-02 02:45:30 -07:00
Jaime Humberto Macias Bustamante 7f087eab03 fixed getting property fields on superclass
Basically "Type.getInstanceFields" doesn't take into account property fields, so it uses "Reflect.fields" to fetch the rest of fields.
2025-08-01 16:55:13 -07:00
Jaime Humberto Macias Bustamante 056a2bd791 fixed calling superclass functions 2025-07-29 13:23:13 -07:00
Jaime Humberto Macias Bustamante 902133a8ba goodbye legacy custom class, you will never be missed :3 2025-07-26 21:22:16 -07:00
Jaime Humberto Macias Bustamante 1791187808 Update ClassExtendMacro.hx 2025-07-26 16:09:02 -07:00
Jaime Humberto Macias Bustamante cacb0cdbd6 Cleanup + loopRun
- added loopRun to define custom loops (https://github.com/HaxeFoundation/hscript/commit/20c8bc3f3c72a4dedabf9a647940b9c4f43eedf8)
2025-07-26 15:34:35 -07:00
Jaime Humberto Macias Bustamante 0b1fbf66dc "cast" syntax support
- Now it parses unsafe/safe cast. For now it's just sugar syntax.
2025-07-26 01:59:57 -07:00
Jaime Humberto Macias Bustamante 2c6f48b1bc Update Parser.hx
now enum parses correctly
2025-07-24 14:18:45 -07:00
Jaime Humberto Macias Bustamante ed78ed79d9 Scripted Enums 2025-07-23 19:50:36 -07:00
Jaime Humberto Macias Bustamante 98b97bef66 Scripted Enums WIP 2025-07-21 22:39:08 -07:00
Jaime Humberto Macias Bustamante 003d22286c super call fixes 2025-07-21 16:47:01 -07:00
Jaime Humberto Macias Bustamante 5232f069fb final classes + improved custom class aliases 2025-07-17 14:46:12 -07:00
Jaime Humberto Macias Bustamante 4f13f07071 better custom class import alias 2025-07-17 13:20:03 -07:00
Jaime Humberto Macias Bustamante 70efab47d1 Documentation + custom classes import alias 2025-07-14 12:59:54 -07:00
Jaime Humberto Macias Bustamante c00c0c3257 Create IHScriptAbstractBehaviour.hx 2025-07-12 16:49:04 -07:00
Jaime Humberto Macias Bustamante f8a930cd48 upcasting 2025-07-12 16:13:59 -07:00
Jaime Humberto Macias Bustamante 1d753731e0 better default static extension fetch 2025-07-12 13:44:06 -07:00
Jaime Humberto Macias Bustamante b239ad2790 Update Interp.hx
oops :3
2025-07-11 09:03:29 -07:00
Jaime Humberto Macias Bustamante 97c3f8bb01 small optimization
since Reflect.hasField(cls, name) is quite expensive, we cache the fields, so it gets the field directly without issues.
2025-07-11 08:45:33 -07:00
Jaime Humberto Macias Bustamante 6b54479211 Static Extension support + small fixes
Static extension for real/custom classes. aka. the `using` keyword

Warning: UNTESTED
2025-07-11 04:35:03 -07:00
Jaime Humberto Macias Bustamante fd88d78544 Custom Class Type Check + Getting custom fields
- Now it checks for the custom class type (partial).

- Custom class fields get for generated classes.
2025-07-08 17:06:33 -07:00
Jaime Humberto Macias Bustamante 434ded6503 "null" value fix
CLOSES #9
2025-07-06 21:50:24 -07:00
Jaime Humberto Macias Bustamante a2cdefb369 static fixes :3 2025-07-03 02:44:53 -07:00
Jaime Humberto Macias Bustamante 46285a800e Update CustomClass.hx 2025-07-01 14:34:41 -07:00
Jaime Humberto Macias Bustamante 305ede38cc Update Parser.hx 2025-06-26 16:56:10 -07:00
Jaime Humberto Macias Bustamante f773589a37 Improved "is" operator
Official implementation of "is" operator.
2025-06-26 16:37:04 -07:00
Jaime Humberto Macias Bustamante b9a0706d6d performance fix for js + cleanup 2025-06-26 14:42:53 -07:00
Jaime Humberto Macias Bustamante 85f3830d71 bruh :'3 2025-06-23 18:23:51 -07:00
Jaime Humberto Macias Bustamante 2c6db18d06 Type Parameters parsing for "ENew"
it now parses type parameters on "ENew", ignored by the interpreter.

Example: "var a = new Object<Float>();
2025-06-23 15:12:15 -07:00
Jaime Humberto Macias Bustamante c165cdfc0a another bit of documentation 2025-06-20 15:59:31 -07:00
Jaime Humberto Macias Bustamante b48a3ee9ed Allow for setting fields before super
also improved fetching superclass fields
2025-06-20 14:45:06 -07:00
Jaime Humberto Macias Bustamante 1af4a64b10 Update CustomClassHandler.hx
i forgot to delete this
2025-06-20 01:28:15 -07:00
Jaime Humberto Macias Bustamante 64f287fd6d Better "EVar" pretty print + fix 2025-06-19 20:20:01 -07:00
Jaime Humberto Macias Bustamante c927d324dc Allow accessing other custom classes 2025-06-19 18:45:51 -07:00
Jaime Humberto Macias Bustamante bcd212a450 "null" fix 2025-06-19 15:55:00 -07:00
Jaime Humberto Macias Bustamante d05270d413 extending typed classes (WIP) 2025-06-19 13:14:02 -07:00
Jaime Humberto Macias Bustamante e40d18b8c4 Update AbstractHandler.hx
oops
2025-06-19 12:50:40 -07:00
Jaime Humberto Macias Bustamante 0e977b071c cleanup + optimization 2025-06-19 01:07:48 -07:00
Jaime Humberto Macias Bustamante c79882b75e Implemented Override
untested, still in progress tho
2025-06-18 10:08:59 -07:00
Jaime Humberto Macias Bustamante 251306a3d3 A bit if documentation + cleanup 2025-06-17 23:50:00 -07:00
Jaime Humberto Macias Bustamante 0bd95d402a Update CustomClass.hx
bruh
2025-06-17 22:49:54 -07:00
Jaime Humberto Macias Bustamante 6441acc93d fixes :3 2025-06-17 15:27:21 -07:00
Jaime Humberto Macias Bustamante 04a50580c6 Disallow static fields access from outside instances 2025-06-17 12:33:32 -07:00
Jaime Humberto Macias Bustamante a4d2d4c788 Custom Classes rework progress - 2 2025-06-16 22:24:22 -07:00
Jaime Humberto Macias Bustamante 54ab2fc509 Custom Classes rework progress 2025-06-16 12:44:40 -07:00
Jaime Humberto Macias Bustamante c16a5e99d5 Custom Classes rework (WIP) 2025-06-16 02:56:10 -07:00
Jaime Humberto Macias Bustamante e28b5a6de5 Property Variables
Now property variables fully works.
2025-06-15 23:03:46 -07:00
Jaime Humberto Macias Bustamante 6ac8fc7fe5 Fixed property access check 2025-06-12 14:50:31 -07:00
Jaime Humberto Macias Bustamante 43bd1001d2 "@:isVar" parses correctly now 2025-06-12 14:41:14 -07:00
Jaime Humberto Macias Bustamante 8bdc07c91b oops :3 2025-06-12 14:27:30 -07:00
Jaime Humberto Macias Bustamante a3a8f602ea Mandatory "allowTypes" for Property + "isVar" parsing 2025-06-12 14:24:51 -07:00
Jaime Humberto Macias Bustamante 1a9c0c68ac Update Parser.hx 2025-06-12 13:35:20 -07:00
Jaime Humberto Macias Bustamante 27b26eb2a0 Property Parsing + Simplified Interfaces - Part 2
- Now it parses "(get, set)". For now it's just sugar syntax.
2025-06-12 00:33:20 -07:00
Jaime Humberto Macias Bustamante 1bfe81cfac Simplified Interfaces - Part 1
here we go again...
2025-05-30 22:05:54 -07:00
Ne_Eo fe673c21b2 Forgot to change this back to false 2025-01-19 21:08:40 +01:00
Ne_Eo 77420e9873 Bug fix with locals + Compatibility improvement 2025-01-19 21:00:20 +01:00
Ne_Eo e4789d9c40 Fix typo 2024-12-16 03:54:00 +01:00
Ne_Eo 9f0937b5c3 Merge branch 'master' into codename-dev 2024-11-15 15:25:22 +01:00
Ne_Eo bb46d45d56 Import Redirects 2024-11-15 15:25:04 +01:00
Ne_Eo ad18c12326 Small change to support more platforms 2024-11-15 14:51:04 +01:00
Redar13andGitHub 3a5c4f2164 Fix ending in with #end in the file (#5)
* Update Parser.hx

* Update Parser.hx
2024-11-06 16:39:09 +01:00
Ne_Eo b683c981b0 no more safe casts 2024-10-18 02:16:50 +02:00
Ne_Eo 9b614421b6 Remove haxe2 support 2024-10-18 01:57:19 +02:00
Ne_Eo 26659db833 Small fix to allow StringMap and such (testing required) 2024-10-04 23:15:50 +02:00
Ne_Eo 6b5a47b017 Fix isBypassAccessor on get resolve 2024-09-04 00:11:19 +02:00
Ne_Eo 3ec4fc9f0b Fixed bug with assign 2024-09-04 00:06:57 +02:00
Ne_Eo 5d2a99d40e More Optimizations 2024-09-03 15:28:33 +02:00
Ne_Eo 1d06905fc5 Optimizations 2024-09-03 14:12:11 +02:00
Ne_Eo 3f98441918 Fixed bugs and ram improvements 2024-09-03 13:42:25 +02:00
Ne_Eo f8e00859cd Inline parses correctly now 2024-09-03 13:10:13 +02:00
Ne_Eo 933c9cb5e3 final function parsing 2024-09-03 05:05:21 +02:00
Ne_Eo 11b3a52287 pain and suffering 2024-09-03 04:58:14 +02:00
Ne_Eo 07f7a75759 small todo 2024-09-03 02:04:40 +02:00
Ne_Eo 644c75094e Added private syntax sugar, custom class fix 2024-09-03 02:03:31 +02:00
Ne_Eo a565cb7b2a I think i fixed classes 2024-09-03 01:21:39 +02:00
Ne_Eo 6db0f7c60b Fix bug 2024-08-31 20:11:48 +02:00
Ne_Eo bfe0b0e99e Simplified code 2024-08-24 21:59:22 +02:00
Ne_Eo 13bdf30055 Classes work more reliably + Optimizations 2024-08-20 04:50:20 +02:00
Ne_Eo f18c7a2210 Small optimization 2024-08-02 23:50:16 +02:00
Ne_Eo 123a7de64a Fix Trigraph bug 2024-07-26 04:24:37 +02:00
Ne_Eo e0e1436930 Fix bug oops :3 2024-06-03 19:00:40 +02:00
b96e6c8149 Fix import extend class (#4)
* Fix import extend class

yea

* Update Interp.hx

* Fix issues with compiling

* Improved extend Errors

---------

Co-authored-by: NeeEoo <NeeEoo@users.noreply.github.com>
2024-04-23 00:01:43 +02:00
NeeEoo f6402ac638 Improve Auto Complete Performance 2024-04-13 18:32:13 +02:00
Ne_EoandGitHub 1e55d0200b Update README.md 2024-02-15 19:43:11 +01:00
NeeEoo 1725dfd1ea Merge branch 'master' into custom-classes 2024-02-15 19:35:31 +01:00
NeeEoo a8cc0ccc86 Restructuring + KeyValueItherators + is + fixes 2023-09-23 21:23:31 +02:00
LeerandGitHub 7dd868aac7 fix compilation errors and make setVar public (#1)
* fix 1

* fix 2

* make setVar public
2023-09-23 20:32:31 +02:00
NeeEoo 220e5ce007 Merge branch 'custom-classes' 2023-08-17 09:55:12 +02:00
NeeEoo 80f6ea4502 Oops 2023-08-17 09:54:56 +02:00
NeeEoo eb820aaf6a Improved ?. 2023-08-17 09:51:43 +02:00
NeeEoo a754c162d9 Fix private class bug 2023-08-13 19:29:08 +02:00
NeeEoo de18ceb887 Fixed Type not found error 2023-08-13 19:24:08 +02:00
31 changed files with 6450 additions and 2222 deletions
+2
View File
@@ -1,2 +1,4 @@
/hscript.swf
/release.zip
dump/*
tests/bin/*
+26 -4
View File
@@ -1,8 +1,30 @@
hscript
hscript-improved
=======
[![TravisCI Build Status](https://travis-ci.org/HaxeFoundation/hscript.svg?branch=master)](https://travis-ci.org/HaxeFoundation/hscript)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HaxeFoundation/hscript?branch=master&svg=true)](https://ci.appveyor.com/project/HaxeFoundation/hscript)
- [Features](docs/FEATURES.md)
How to install
```
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
```
To enable custom classes support you have to do this in project.xml
```xml
<define name="CUSTOM_CLASSES" />
```
or set this in build.hxml
```hxml
-D CUSTOM_CLASSES
```
Current Custom Class Limitations :
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
-----------
Parse and evalutate Haxe expressions.
@@ -100,4 +122,4 @@ Some other optional files :
- `hscript.Macro` : convert Haxe macro into hscript Expr
- `hscript.Printer` : convert hscript Expr to String
- `hscript.Tools` : utility functions (map/iter)
-9
View File
@@ -26,13 +26,8 @@ class TestHScript extends TestCase {
assertScript("0",0);
assertScript("0xFF", 255);
#if !(php || python)
#if haxe3
assertScript("0xBFFFFFFF", 0xBFFFFFFF);
assertScript("0x7FFFFFFF", 0x7FFFFFFF);
#elseif !neko
assertScript("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
assertScript("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
#end
#end
assertScript("-123",-123);
assertScript("- 123",-123);
@@ -81,11 +76,7 @@ class TestHScript extends TestCase {
assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
assertScript("var a = false; do { a = true; } while (!a); a;",true);
assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45);
#if haxe3
assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
#else
assertScript("var t = 0; for( x in new IntIter(1,10) ) t +=x; t", 45);
#end
assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790);
assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56);
assertScript("var i=2; if( true ) --i; i",1);
+83
View File
@@ -0,0 +1,83 @@
# FEATURES
- Custom Classes
- Final Classes
- Static Classes
- Allow for type check (`is`)
- Allow extending other custom classes
- Enums
```haxe
enum TypeValue {
NUMBER(n:Int);
DECIMAL(d:Float, ?p:Int);
CHARACTER(s:String);
BOOLEAN(b:Bool);
}
var type = TypeValue.DECIMAL(10.1234, 2);
// You need to type the full enum field for each case
// i.e. you can't type the enum field directly (limitation for now)
switch(type) {
case TypeValue.NUMBER(number):
trace("number: " + number);
case TypeValue.DECIMAL(decimal, precision):
if(precision != null)
trace("decimal: " + decimal + " | rounded decimal: " + roundDecimal(decimal, precision));
else
trace("decimal: " + decimal);
case TypeValue.CHARACTER(char):
trace("character: " + char);
default:
trace("unknown type");
}
function roundDecimal(Value:Float, Precision:Int) {
var mult:Float = Math.pow(10, Precision);
return Math.fround(Value * mult) / mult;
}
```
- Enum matching with arguments for switch statements (for real and scripted enums)
- Property Fields (`(get, set)` variables)
```haxe
public var myvar(get, set):Int;
var _myvar:Int = 10;
function get_myvar():Int {
return _myvar;
}
function set_myvar(val:Int):Int {
if(val > 10) return _myvar = val;
return val;
}
```
- `@:isVar` metadata support
- Static extension (`using`)
```haxe
using StringTools;
class IntExtender {
static public function triple(i:Int) {
return i * 3;
}
}
// need to create/import the custom class
// before setting the extension (limitation for now)
using IntExtender;
var str = " Hello World! ";
trace(str.trim()); // "Hello World!"
trace(12.triple()); // 36
```
- Support for real and custom classes
- Misc.
- Allow using type parameters for creating objects (i.e. `var a = new TypedObject<Int>();`)
- Allow `package` declaration. Ignored by the interpreter.
+2 -1
View File
@@ -1,2 +1,3 @@
--macro keep('IntIterator')
--macro hscript.UsingHandler.init()
--macro hscript.macros.AbstractHandler.init()
--macro hscript.macros.ClassExtendMacro.init()
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "hscript",
"name": "hscript-improved",
"url": "https://github.com/HaxeFoundation/hscript",
"license": "MIT",
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
+536 -536
View File
File diff suppressed because it is too large Load Diff
+22 -30
View File
@@ -27,7 +27,7 @@ class Bytes {
var bin : haxe.io.Bytes;
var bout : haxe.io.BytesBuffer;
var pin : Int;
var hstrings : #if haxe3 Map<String,Int> #else Hash<Int> #end;
var hstrings : Map<String,Int>;
var strings : Array<String>;
var nstrings : Int;
@@ -35,7 +35,7 @@ class Bytes {
this.bin = bin;
pin = 0;
bout = new haxe.io.BytesBuffer();
hstrings = #if haxe3 new Map() #else new Hash() #end;
hstrings = new Map();
strings = [null];
nstrings = 1;
}
@@ -44,7 +44,7 @@ class Bytes {
var vid = hstrings.get(v);
if( vid == null ) {
if( nstrings == 256 ) {
hstrings = #if haxe3 new Map() #else new Hash() #end;
hstrings = new Map();
nstrings = 1;
}
hstrings.set(v,nstrings);
@@ -85,15 +85,6 @@ class Bytes {
bout.addByte(1);
doEncodeInt(v);
}
#if !haxe3
case CInt32(v):
bout.addByte(4);
var mid = haxe.Int32.toInt(haxe.Int32.and(v,haxe.Int32.ofInt(0xFFFFFF)));
bout.addByte(mid & 0xFF);
bout.addByte((mid >> 8) & 0xFF);
bout.addByte(mid >> 16);
bout.addByte(haxe.Int32.toInt(haxe.Int32.ushr(v, 24)));
#end
case CFloat(f):
bout.addByte(2);
doEncodeString(Std.string(f));
@@ -120,13 +111,6 @@ class Bytes {
CFloat( Std.parseFloat(doDecodeString()) );
case 3:
CString( doDecodeString() );
#if !haxe3
case 4:
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16);
var j = bin.get(pin+3);
pin += 4;
CInt32(haxe.Int32.or(haxe.Int32.ofInt(i), haxe.Int32.shl(haxe.Int32.ofInt(j), 24)));
#end
default:
throw "Invalid code "+bin.get(pin-1);
}
@@ -140,10 +124,18 @@ class Bytes {
#end
bout.addByte(Type.enumIndex(e));
switch( e ) {
case EPackage(n):
// TODO
case EImport(c):
// TODO
case EClass(_, _, _, _):
// TODO
case EEnum(en):
// TODO
case ECast(e, _):
// TODO
case ERegex(e, f):
// TODO
case EConst(c):
doEncodeConst(c);
case EIdent(v):
@@ -164,11 +156,11 @@ class Bytes {
doEncode(e);
doEncodeString(f);
case EBinop(op,e1,e2):
doEncodeString(op);
doEncodeString(op.toString());
doEncode(e1);
doEncode(e2);
case EUnop(op,prefix,e):
doEncodeString(op);
doEncodeString(op.toString()); // maybe doEncodeInt
bout.addByte(prefix?1:0);
doEncode(e);
case ECall(e,el):
@@ -278,7 +270,7 @@ class Bytes {
case 3:
EParent(doDecode());
case 4:
var a = new Array();
var a = [];
for( i in 0...bin.get(pin++) )
a.push(doDecode());
EBlock(a);
@@ -286,16 +278,16 @@ class Bytes {
var e = doDecode();
EField(e,doDecodeString());
case 6:
var op = doDecodeString();
var op = Binop.fromString(doDecodeString());
var e1 = doDecode();
EBinop(op,e1,doDecode());
case 7:
var op = doDecodeString();
var op = Unop.fromString(doDecodeString());
var prefix = bin.get(pin++) != 0;
EUnop(op,prefix,doDecode());
case 8:
var e = doDecode();
var params = new Array();
var params = [];
for( i in 0...bin.get(pin++) )
params.push(doDecode());
ECall(e,params);
@@ -317,7 +309,7 @@ class Bytes {
case 14:
var params = new Array<Argument>();
for( i in 0...bin.get(pin++) )
params.push({ name : doDecodeString() });
params.push({ name : doDecodeString(), opt: false, value: null, t: null });
var e = doDecode();
var name = doDecodeString();
EFunction(params,e,(name == "") ? null: name);
@@ -327,13 +319,13 @@ class Bytes {
var e = doDecode();
EArray(e,doDecode());
case 17:
var el = new Array();
var el = [];
for( i in 0...bin.get(pin++) )
el.push(doDecode());
EArrayDecl(el);
case 18:
var cl = doDecodeString();
var el = new Array();
var el = [];
for( i in 0...bin.get(pin++) )
el.push(doDecode());
ENew(cl,el);
@@ -344,7 +336,7 @@ class Bytes {
var v = doDecodeString();
ETry(e,v,null,doDecode());
case 21:
var fl = new Array();
var fl:Array<ObjectField> = [];
for( i in 0...bin.get(pin++) ) {
var name = doDecodeString();
var e = doDecode();
@@ -358,7 +350,7 @@ class Bytes {
ETernary(cond, e1, e2);
case 23:
var e = doDecode();
var cases = [];
var cases:Array<SwitchCase> = [];
while( true ) {
var v = doDecode();
if( v == null ) break;
+35 -17
View File
@@ -422,6 +422,9 @@ class Checker {
return makeType(t,e);
case CTOpt(t):
return makeType(t,e);
case CTExpr(_):
error("Unsupported expr type parameter", e);
return null;
}
}
@@ -1070,10 +1073,10 @@ class Checker {
case EUnop(op, _, e):
var et = typeExpr(e, Value);
switch( op ) {
case "++", "--", "-":
case OpIncrement | OpDecrement | OpNeg:
unify(et,TInt,e);
return et;
case "!":
case OpNot:
unify(et,TBool,e);
return et;
default:
@@ -1110,11 +1113,11 @@ class Checker {
return TVoid;
case EBinop(op, e1, e2):
switch( op ) {
case "&", "|", "^", ">>", ">>>", "<<":
case OpAnd, OpOr, OpXor, OpShr, OpUshr, OpShl:
typeExprWith(e1,TInt);
typeExprWith(e2,TInt);
return TInt;
case "=":
case OpAssign:
if( allowDefine ) {
switch( edef(e1) ) {
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
@@ -1130,7 +1133,7 @@ class Checker {
}
typeExprWith(e2,vt);
return vt;
case "+":
case OpAdd:
var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1));
tryUnify(t1,t2);
@@ -1147,14 +1150,14 @@ class Checker {
unify(t1, TFloat, e1);
unify(t2, TFloat, e2);
}
case "-", "*", "/", "%":
case OpSub, OpMult, OpDiv, OpMod:
var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
unify(t2,t1,e2);
switch( [follow(t1), follow(t2)]) {
case [TInt, TInt]:
if( op == "/" ) return TFloat;
if( op == OpDiv ) return TFloat;
return TInt;
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
return TFloat;
@@ -1162,21 +1165,21 @@ class Checker {
unify(t1, TFloat, e1);
unify(t2, TFloat, e2);
}
case "&&", "||":
case OpBoolAnd, OpBoolOr:
typeExprWith(e1,TBool);
typeExprWith(e2,TBool);
return TBool;
case "...":
case OpInterval:
typeExprWith(e1,TInt);
typeExprWith(e2,TInt);
return makeIterator(TInt);
case "==", "!=":
case OpEq, OpNeq:
var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
unify(t2,t1,e2);
return TBool;
case ">", "<", ">=", "<=":
case OpGt, OpLt, OpGte, OpLte:
var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
@@ -1187,12 +1190,26 @@ class Checker {
error("Cannot compare "+typeStr(t1), expr);
}
return TBool;
case OpAddAssign, OpSubAssign, OpMultAssign, OpDivAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign, OpShlAssign, OpShrAssign, OpUshrAssign, OpNcoalAssign:
var baseOp = switch(op) {
case OpAddAssign: OpAdd;
case OpSubAssign: OpSub;
case OpMultAssign: OpMult;
case OpDivAssign: OpDiv;
case OpModAssign: OpMod;
case OpAndAssign: OpAnd;
case OpOrAssign: OpOr;
case OpXorAssign: OpXor;
case OpShlAssign: OpShl;
case OpShrAssign: OpShr;
case OpUshrAssign: OpUshr;
case OpNcoalAssign: OpNcoal;
default: op;
};
var t = typeExpr(mk(EBinop(baseOp,e1,e2),expr),withType);
return typeExpr(mk(EBinop(OpAssign,e1,e2),expr), withType);
default:
if( op.charCodeAt(op.length-1) == "=".code ) {
var t = typeExpr(mk(EBinop(op.substr(0,op.length-1),e1,e2),expr),withType);
return typeExpr(mk(EBinop("=",e1,e2),expr), withType);
}
error("Unsupported operation "+op, expr);
error("Unsupported operation "+op.toString(), expr);
}
case ETry(etry, v, et, ecatch):
var vt = typeExpr(etry, withType);
@@ -1233,9 +1250,10 @@ class Checker {
mergeType( typeExpr(defaultExpr, withType), defaultExpr);
return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin;
case ENew(cl, params):
default:
}
error("Don't know how to type "+edef(expr).getName(), expr);
return TDynamic;
}
}
}
+24
View File
@@ -0,0 +1,24 @@
package hscript;
class Config {
// Runs support for custom classes in these
public static final ALLOWED_CUSTOM_CLASSES = [
"flixel",
];
// Runs support for abstract support in these
public static final ALLOWED_ABSTRACT_AND_ENUM = [
"flixel",
"openfl.display.BlendMode",
];
// Incase any of your files fail
// These are the module names
public static final DISALLOW_CUSTOM_CLASSES = [
];
public static final DISALLOW_ABSTRACT_AND_ENUM = [
];
}
+359
View File
@@ -0,0 +1,359 @@
package hscript;
import hscript.utils.UnsafeReflect;
import haxe.Constraints.Function;
using Lambda;
/**
* The Custom Class core.
*
* Provides handlers for custom classes.
*
* @author Jamextreme140
*/
@:access(hscript.CustomClassHandler)
class CustomClass implements IHScriptCustomClassBehaviour {
public var className(get, never):String;
private function get_className():String
return __class.name;
public var __interp:Interp;
public var __real_fields:Array<String> = []; // UNUSED
public var __class__fields:Array<String> = []; // Declared fields
public var __allowSetGet:Bool = true;
var __class:CustomClassHandler;
var __superClass:IHScriptCustomClassBehaviour;
var __upperClass:IHScriptCustomClassBehaviour;
var __constructor:Function;
var __overrideFields:Array<String> = [];
var __cachedFieldSet:Map<String, Dynamic> = null;
var initializing:Bool = false;
public function new(__class:CustomClassHandler, ?args:Array<Dynamic>, ?cachedFieldSet:Map<String, Dynamic>) {
this.__class = __class;
__interp = new Interp();
__interp.errorHandler = __class.__interp.errorHandler;
__interp.importFailedCallback = __class.__interp.importFailedCallback;
// __interp.variables = __class.staticInterp.variables;
@:privateAccess __interp.usingHandler.usingEntries = __class.ogInterp.usingHandler.usingEntries;
__interp.publicVariables = __class.ogInterp.publicVariables;
__interp.staticVariables = __class.ogInterp.staticVariables;
__interp.customClasses = __class.ogInterp.customClasses;
for(f => v in __class.__interp.variables) {
if(f == 'new') continue;
if (!__interp.variables.exists(f))
__interp.variables.set(f, v);
}
for (f in __class.fields) {
switch (Tools.expr(f)) {
case EVar(n): __class__fields.push(n);
case EFunction(_, _, n, _, _, _, isOverride):
if(isOverride) __overrideFields.push(n);
__class__fields.push(n);
default: continue;
}
@:privateAccess __interp.exprReturn(f);
}
__interp.scriptObject = this;
initializing = true;
if(cachedFieldSet != null)
for(f => v in cachedFieldSet)
this.hset(f, v);
if (hasField('new')) {
buildConstructor();
call('new', args);
if(__cachedFieldSet != null) {
__cachedFieldSet.clear();
__cachedFieldSet = null;
}
if (this.__superClass == null && __class.extend != null)
__interp.error(ECustom("super() not called"));
} else if (__class.extend != null) {
buildSuperClass(args);
}
initializing = false;
}
function cacheFieldSet(name:String, val:Dynamic) {
if(!initializing) return;
if(__cachedFieldSet == null) __cachedFieldSet = [];
__cachedFieldSet.set(name, val);
}
function buildConstructor() {
__constructor = Reflect.makeVarArgs(buildSuperClass);
}
function buildSuperClass(?args:Array<Dynamic>) {
if (args == null)
args = [];
if (__class.cl == null) {
__interp.error(ECustom('Current class does not have a super'));
return;
}
if (__class.cl is CustomClassHandler) {
var customClass = new CustomClass(__class.cl, args, __cachedFieldSet);
if(__overrideFields.length > 0) {
for (field in __overrideFields) {
var func = __interp.variables.get(field);
customClass.overrideField(field, func);
}
}
customClass.__upperClass = this;
__superClass = customClass;
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields());
} else {
if(__cachedFieldSet != null)
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
__superClass = Type.createInstance(__class.cl, args);
var disallowCopy:Array<String> = {
var fieldMap:Map<String, String> = []; // Prevent duplicate values
for(f in Reflect.fields(__superClass).concat(Type.getInstanceFields(Type.getClass(__superClass))))
fieldMap.set(f, f);
fieldMap.array();
}
this.__real_fields = disallowCopy;
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(disallowCopy);
__superClass.__real_fields = this.__real_fields;
__superClass.__class__fields = this.__class__fields;
__superClass.__interp = this.__interp;
}
}
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
var fn:Dynamic = {
if(toSuper && __interp.variables.exists(superFnName)) {
__interp.variables.get(superFnName);
}
else
__interp.variables.get(name);
};
if (fn != null && Reflect.isFunction(fn))
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
// If not found in current class, try parent class recursively
if (__superClass != null && __superClass is CustomClass)
return cast(__superClass, CustomClass).call(name, args, toSuper);
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
return null;
}
function hasField(name:String) {
return __class__fields.contains(name);
}
function hasStaticField(name:String):Bool {
return __class.hasField(name);
}
function getField(name:String, allowProperty:Bool = true):Dynamic {
var f = __interp.variables.get(name);
if (f != null && allowProperty && f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.get(!__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
return f;
}
function setField(name:String, val:Dynamic):Dynamic {
var f = getField(name, false);
if (f != null && f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.set(val, !__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
__interp.variables.set(name, val);
return val;
}
/**
* Overrides (replaces) the declared function.
* @param name
* @param func
*/
function overrideField(name:String, func:Function) {
var f = getField(name, false);
if(f != null && Reflect.isFunction(f)) {
__interp.variables.set(name, func);
__interp.variables.set('_HX_SUPER__$name', f);
}
else if(__superClass != null && __superClass is CustomClass) {
cast(__superClass, CustomClass).overrideField(name, func);
}
}
function superHasField(name:String) {
if (__superClass == null)
return false;
var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name);
var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name);
if(!realFieldExists && !classFieldExists && __superClass is CustomClass)
return cast(__superClass, CustomClass).superHasField(name);
return realFieldExists || classFieldExists;
}
function getSuperFields():Array<String> {
if(__superClass == null) return [];
var classFields:Map<String, String> = []; // Prevents duplicated values
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
while (cls != null) {
for(fieldSet in [cls.__class__fields, cls.__real_fields])
for(f in fieldSet)
classFields.set(f, f);
var next:IHScriptCustomClassBehaviour = null;
if(cls is CustomClass)
next = cast(cls, CustomClass).__superClass;
if (next == null)
break;
cls = next;
}
return [for(f in classFields) f];
}
public function hget(name:String):Dynamic {
switch (name) {
case 'superClass': return __superClass;
case 'superConstructor': return __constructor;
default:
if (hasField(name))
return getField(name);
if (hasStaticField(name)) {
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
return null;
}
if (__superClass != null) {
if (superHasField(name)) {
__superClass.__allowSetGet = this.__allowSetGet;
return __superClass.hget(name);
}
}
throw "field '"
+ name
+ "' does not exist in custom class '"
+ this.className
+ "'"
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
}
return null;
}
public function hset(name:String, val:Dynamic):Dynamic {
if (hasField(name))
return setField(name, val);
if (hasStaticField(name)) {
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
return null;
}
if (__superClass != null) {
if (superHasField(name)) {
__superClass.__allowSetGet = this.__allowSetGet;
return __superClass.hset(name, val);
}
}
else if(__class.extend != null && initializing) {
cacheFieldSet(name, val);
return val;
}
throw "field '"
+ name
+ "' does not exist in custom class '"
+ this.className
+ "'"
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
return null;
}
// UNUSED
public function __callGetter(name:String):Dynamic {
return null;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
return null;
}
/**
* Returns the real superClass if the Custom Class
* extends another Custom Class, and so on until
* it reaches a real class, otherwise it will
* return the last fetched Custom Class
* @return Null<Dynamic>
*/
public function getSuperclass():IHScriptCustomClassBehaviour {
if(__superClass == null) return null;
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
// Check if the superClass is another custom class,
// so it will find for a real class, otherwise
// returns the last super CustomClass parent.
while (cls != null && cls is CustomClass) {
var next = cast(cls, CustomClass).__superClass;
if (next == null)
break; // Return the Custom Class itself
cls = next;
}
return cls is CustomClass ? this : cls;
}
// TODO: scripted safe cast for custom classes
public function getUpperclass():IHScriptCustomClassBehaviour {
if(__upperClass == null) return this;
var cls:CustomClass = cast __upperClass;
while (cls != null) {
var prev:CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
return cls;
}
// TODO: scriptable "toString" function
public function toString():String
return className;
}
+150 -66
View File
@@ -1,75 +1,147 @@
package hscript;
using StringTools;
class CustomClassHandler implements IHScriptCustomConstructor {
public static var staticHandler = new StaticHandler();
/**
* Provides handlers for static custom class fields and instantiation.
*/
@:access(hscript.Property)
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
public var ogInterp:Interp;
public var name:String;
public var fields:Array<Expr>;
public var extend:String;
public var extend:Null<String>;
public var interfaces:Array<String>;
public final isFinal:Bool;
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
public var cl:Dynamic;
private var __interp:Interp;
private var __staticFields:Array<String> = [];
public var __allowSetGet:Bool = true;
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>, ?isFinal:Bool) {
this.ogInterp = ogInterp;
this.name = name;
this.fields = fields;
this.extend = extend;
this.interfaces = interfaces;
this.isFinal = isFinal != null ? isFinal : false;
if(extend != null) {
if(ogInterp.customClasses.exists(extend)) {
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
if(customCls.isFinal)
ogInterp.error(ECustom('Cannot extend a final class'));
this.cl = customCls;
}
else
this.cl = Type.resolveClass('${extend}_HSX');
if(cl == null)
ogInterp.error(EInvalidClass(extend));
}
initStatic();
}
public function hnew(args:Array<Dynamic>):Dynamic {
var interp = new Interp();
@:access(hscript.Interp)
function initStatic() {
__interp = new Interp();
__interp.errorHandler = ogInterp.errorHandler;
__interp.importFailedCallback = ogInterp.importFailedCallback;
interp.errorHandler = ogInterp.errorHandler;
//__interp.variables = ogInterp.variables;
__interp.usingHandler.usingEntries = ogInterp.usingHandler.usingEntries;
__interp.publicVariables = ogInterp.publicVariables;
__interp.staticVariables = ogInterp.staticVariables;
__interp.customClasses = ogInterp.customClasses;
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
var _class = Type.createInstance(cl, args);
for(f => v in ogInterp.variables)
if(!__interp.variables.exists(f))
__interp.variables.set(f, v);
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
for(k=>e in __capturedLocals)
if (e != null && e.depth <= 0)
capturedLocals.set(k, e);
for(i => e in fields.copy()) {
var isValid:Bool = false;
var staticField:Bool = false;
var fieldName:String = null;
switch (Tools.expr(e)) {
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
isValid = true;
staticField = isStatic;
fieldName = n;
default:
}
var disallowCopy = Type.getInstanceFields(cl);
//trace("Locals");
for (key => value in capturedLocals) {
if(!disallowCopy.contains(key)) {
interp.locals.set(key, {r: value, depth: -1});
//trace(key, value);
if(staticField && isValid) {
__interp.exprReturn(e);
__staticFields.push(fieldName);
fields.remove(e);
}
}
//trace("Variables");
for (key => value in ogInterp.variables) {
if(!disallowCopy.contains(key)) {
interp.variables.set(key, value);
//trace(key, value);
}
}
public function hnew(args:Array<Dynamic>):Dynamic
return new CustomClass(this, args);
@:allow(hscript.Interp)
inline function hasField(name:String) {
return __staticFields.contains(name);
}
function getField(name:String, allowProperty:Bool = true):Dynamic {
var f = __interp.variables.get(name);
if(f is Property && allowProperty) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.get(!__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
return f;
}
function setField(name:String, val:Dynamic):Dynamic {
var f = getField(name, false);
if(f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.set(val, !__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
__interp.variables.set(name, val);
return val;
}
public function hget(name:String):Dynamic {
if(name == 'new') {
return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
return inline this.hnew(args);
});
}
if(hasField(name)) {
return getField(name);
}
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
return null;
}
for(expr in fields) {
@:privateAccess
interp.exprReturn(expr);
}
public function hset(name:String, val:Dynamic):Dynamic {
if(hasField(name))
return setField(name, val);
interp.variables.set("super", staticHandler);
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
return null;
}
_class.__interp = interp;
interp.scriptObject = _class;
// UNUSED
public function __callGetter(name:String):Dynamic {
return null;
}
var newFunc = interp.variables.get("new");
if(newFunc != null) {
Reflect.callMethod(null, newFunc, args);
}
for(variable => value in interp.variables) {
if(variable == "this") continue;
}
return _class;
public function __callSetter(name:String, val:Dynamic):Dynamic {
return null;
}
public function toString():String {
@@ -77,29 +149,41 @@ class CustomClassHandler implements IHScriptCustomConstructor {
}
}
class TemplateClass implements IHScriptCustomBehaviour {
/**
* This is for backwards compatibility with old hscript-improved, since some scripts use it
**/
@:dox(hide)
@:keep
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
public var __interp:Interp;
public var __allowSetGet:Bool = true;
public function hset(name:String, val:Dynamic):Dynamic {
if(this.__interp.variables.exists("set_" + name)) {
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
}
if (this.__interp.variables.exists(name)) {
this.__interp.variables.set(name, val);
return val;
}
Reflect.setProperty(this, name, val);
return Reflect.field(this, name);
var variables = __interp.variables;
if(__allowSetGet && variables.exists("set_" + name))
return __callSetter(name, val);
variables.set(name, val);
return val;
}
public function hget(name:String):Dynamic {
if(this.__interp.variables.exists("get_" + name))
return this.__interp.variables.get("get_" + name)();
if (this.__interp.variables.exists(name))
return this.__interp.variables.get(name);
return Reflect.getProperty(this, name);
var variables = __interp.variables;
if(__allowSetGet && variables.exists("get_" + name))
return __callGetter(name);
return variables.get(name);
}
public function __callGetter(name:String):Dynamic {
__allowSetGet = false;
var v = __interp.variables.get("get_" + name)();
__allowSetGet = true;
return v;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
__allowSetGet = false;
var v = __interp.variables.get("set_" + name)(val);
__allowSetGet = true;
return v;
}
}
class StaticHandler {
public function new() {}
}
+403 -185
View File
@@ -1,185 +1,403 @@
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
enum Const {
CInt( v : Int );
CFloat( f : Float );
CString( s : String );
#if !haxe3
CInt32( v : haxe.Int32 );
#end
}
#if hscriptPos
typedef Expr = {
var e : ExprDef;
var pmin : Int;
var pmax : Int;
var origin : String;
var line : Int;
}
enum ExprDef {
#else
typedef ExprDef = Expr;
enum Expr {
#end
EConst( c : Const );
EIdent( v : String );
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
EParent( e : Expr );
EBlock( e : Array<Expr> );
EField( e : Expr, f : String , ?safe : Bool );
EBinop( op : String, e1 : Expr, e2 : Expr );
EUnop( op : String, prefix : Bool, e : Expr );
ECall( e : Expr, params : Array<Expr> );
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
EWhile( cond : Expr, e : Expr );
EFor( v : String, it : Expr, e : Expr );
EBreak;
EContinue;
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
EReturn( ?e : Expr );
EArray( e : Expr, index : Expr );
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
ENew( cl : String, params : Array<Expr> );
EThrow( e : Expr );
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
EObject( fl : Array<{ name : String, e : Expr }> );
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr );
EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
ECheckType( e : Expr, t : CType );
EImport( c : String, ?asname:String );
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
}
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
enum CType {
CTPath( path : Array<String>, ?params : Array<CType> );
CTFun( args : Array<CType>, ret : CType );
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
CTParent( t : CType );
CTOpt( t : CType );
CTNamed( n : String, t : CType );
}
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef {
#else
enum Error {
#end
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
}
enum ModuleDecl {
DPackage( path : Array<String> );
DImport( path : Array<String>, ?everything : Bool );
DClass( c : ClassDecl );
DTypedef( c : TypeDecl );
}
typedef ModuleType = {
var name : String;
var params : {}; // TODO : not yet parsed
var meta : Metadata;
var isPrivate : Bool;
}
typedef ClassDecl = {> ModuleType,
var extend : Null<CType>;
var implement : Array<CType>;
var fields : Array<FieldDecl>;
var isExtern : Bool;
}
typedef TypeDecl = {> ModuleType,
var t : CType;
}
typedef FieldDecl = {
var name : String;
var meta : Metadata;
var kind : FieldKind;
var access : Array<FieldAccess>;
}
enum FieldAccess {
APublic;
APrivate;
AInline;
AOverride;
AStatic;
AMacro;
}
enum FieldKind {
KFunction( f : FunctionDecl );
KVar( v : VarDecl );
}
typedef FunctionDecl = {
var args : Array<Argument>;
var expr : Expr;
var ret : Null<CType>;
}
typedef VarDecl = {
var get : Null<String>;
var set : Null<String>;
var expr : Null<Expr>;
var type : Null<CType>;
}
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
enum abstract Binop(Int) from Int to Int {
var OpAdd = 0;
var OpSub = 1;
var OpMult = 2;
var OpDiv = 3;
var OpMod = 4;
var OpAnd = 5;
var OpOr = 6;
var OpXor = 7;
var OpShl = 8;
var OpShr = 9;
var OpUshr = 10;
var OpEq = 11;
var OpNeq = 12;
var OpGte = 13;
var OpLte = 14;
var OpGt = 15;
var OpLt = 16;
var OpBoolOr = 17;
var OpBoolAnd = 18;
var OpIs = 19;
var OpAssign = 20;
var OpNcoal = 21;
var OpInterval = 22;
var OpArrow = 23;
var OpAddAssign = 24;
var OpSubAssign = 25;
var OpMultAssign = 26;
var OpDivAssign = 27;
var OpModAssign = 28;
var OpAndAssign = 29;
var OpOrAssign = 30;
var OpXorAssign = 31;
var OpShlAssign = 32;
var OpShrAssign = 33;
var OpUshrAssign = 34;
var OpNcoalAssign = 35;
var OpArrowFn = 36;
public static inline function fromString(s:String):Binop {
return switch(s) {
case "+": OpAdd;
case "-": OpSub;
case "*": OpMult;
case "/": OpDiv;
case "%": OpMod;
case "&": OpAnd;
case "|": OpOr;
case "^": OpXor;
case "<<": OpShl;
case ">>": OpShr;
case ">>>": OpUshr;
case "==": OpEq;
case "!=": OpNeq;
case ">=": OpGte;
case "<=": OpLte;
case ">": OpGt;
case "<": OpLt;
case "||": OpBoolOr;
case "&&": OpBoolAnd;
case "is": OpIs;
case "=": OpAssign;
case "??": OpNcoal;
case "...": OpInterval;
case "->": OpArrow;
case "=>": OpArrowFn;
case "+=": OpAddAssign;
case "-=": OpSubAssign;
case "*=": OpMultAssign;
case "/=": OpDivAssign;
case "%=": OpModAssign;
case "&=": OpAndAssign;
case "|=": OpOrAssign;
case "^=": OpXorAssign;
case "<<=": OpShlAssign;
case ">>=": OpShrAssign;
case ">>>=": OpUshrAssign;
case _ if (s == "??" + "="): OpNcoalAssign;
default: -1;
}
}
public inline function toString():String {
return switch(this) {
case OpAdd: "+";
case OpSub: "-";
case OpMult: "*";
case OpDiv: "/";
case OpMod: "%";
case OpAnd: "&";
case OpOr: "|";
case OpXor: "^";
case OpShl: "<<";
case OpShr: ">>";
case OpUshr: ">>>";
case OpEq: "==";
case OpNeq: "!=";
case OpGte: ">=";
case OpLte: "<=";
case OpGt: ">";
case OpLt: "<";
case OpBoolOr: "||";
case OpBoolAnd: "&&";
case OpIs: "is";
case OpAssign: "=";
case OpNcoal: "??";
case OpInterval: "...";
case OpArrow: "->";
case OpArrowFn: "=>";
case OpAddAssign: "+=";
case OpSubAssign: "-=";
case OpMultAssign: "*=";
case OpDivAssign: "/=";
case OpModAssign: "%=";
case OpAndAssign: "&=";
case OpOrAssign: "|=";
case OpXorAssign: "^=";
case OpShlAssign: "<<=";
case OpShrAssign: ">>=";
case OpUshrAssign: ">>>=";
case OpNcoalAssign: "??" + "=";
default: "?";
}
}
}
enum abstract Unop(Int) from Int to Int {
var OpNot = 0;
var OpNeg = 1;
var OpIncrement = 2;
var OpDecrement = 3;
var OpNegBits = 4;
public static inline function fromString(s:String):Unop {
return switch(s) {
case "!": OpNot;
case "-": OpNeg;
case "++": OpIncrement;
case "--": OpDecrement;
case "~": OpNegBits;
default: -1;
}
}
public inline function toString():String {
return switch(this) {
case OpNot: "!";
case OpNeg: "-";
case OpIncrement: "++";
case OpDecrement: "--";
case OpNegBits: "~";
default: "?";
}
}
}
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
enum Const {
CInt( v : Int );
CFloat( f : Float );
CString( s : String, ?i : Bool );
}
#if hscriptPos
@:structInit
final class Expr {
public var e : ExprDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
}
enum ExprDef {
#else
typedef ExprDef = Expr;
enum Expr {
#end
EConst( c : Const );
EIdent( v : String );
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
EParent( e : Expr );
EBlock( e : Array<Expr> );
EField( e : Expr, f : String , ?safe : Bool );
EBinop( op : Binop, e1 : Expr, e2 : Expr );
EUnop( op : Unop, prefix : Bool, e : Expr );
ECall( e : Expr, params : Array<Expr> );
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
EWhile( cond : Expr, e : Expr );
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
EBreak;
EContinue;
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
EReturn( ?e : Expr );
EArray( e : Expr, index : Expr );
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
EThrow( e : Expr );
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
EObject( fl : Array<ObjectField> );
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
ECheckType( e : Expr, t : CType );
EPackage( ?n:String );
EImport( c : String, ?asname:String, ?isUsing:Bool );
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
EEnum( en:EnumDecl, ?isAbstract:Bool );
ECast(e:Expr, ?t:CType);
ERegex(e:String, flags:String);
}
@:structInit
final class ObjectField {
public var name : String;
public var e : Expr;
}
@:structInit
final class SwitchCase {
public var values : Array<Expr>;
public var expr : Expr;
}
@:structInit
final class Argument {
public var name : String;
public var t : CType;
public var opt : Bool;
public var value : Expr;
}
@:structInit
final class MetadataEntry {
public var name : String;
public var params : Array<Expr>;
}
typedef Metadata = Array<MetadataEntry>;
@:structInit
final class EnumDecl {
public var name : String;
public var fields : Array<EnumField>;
public var underlyingType : Null<CType>;
}
@:structInit
final class EnumField {
public var name : String;
public var args : Array<Argument>;
public var value : Null<Expr>;
}
enum CType {
CTPath( path : Array<String>, ?params : Array<CType> );
CTFun( args : Array<CType>, ret : CType );
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
CTParent( t : CType );
CTOpt( t : CType );
CTNamed( n : String, t : CType );
CTExpr( e : Expr ); // for type parameters only
}
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef {
#else
enum Error {
#end
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
}
enum ModuleDecl {
DPackage( path : Array<String> );
DImport( path : Array<String>, ?everything : Bool );
DClass( c : ClassDecl );
DTypedef( c : TypeDecl );
}
typedef ModuleType = {
var name : String;
var params : {}; // TODO : not yet parsed
var meta : Metadata;
var isPrivate : Bool;
}
typedef ClassDecl = {> ModuleType,
var extend : Null<CType>;
var implement : Array<CType>;
var fields : Array<FieldDecl>;
var isExtern : Bool;
}
typedef TypeDecl = {> ModuleType,
var t : CType;
}
typedef FieldDecl = {
var name : String;
var meta : Metadata;
var kind : FieldKind;
var access : Array<FieldAccess>;
}
enum abstract FieldAccess(UInt8) {
var APublic;
var APrivate;
var AInline;
var AOverride;
var AStatic;
var AMacro;
}
enum abstract FieldPropertyAccess(UInt8) {
var ADefault;
var ANull;
var AGet;
var ASet;
var ADynamic;
var ANever;
}
enum FieldKind {
KFunction( f : FunctionDecl );
KVar( v : VarDecl );
}
@:structInit
final class FunctionDecl {
public var args : Array<Argument>;
public var body : Expr;
public var ret : Null<CType>;
}
typedef VarDecl = {
var get : Null<String>;
var set : Null<String>;
var expr : Null<Expr>;
var type : Null<CType>;
}
+182
View File
@@ -0,0 +1,182 @@
package hscript;
import hscript.utils.UnsafeReflect;
/**
* Wrapper class for enums, both for real and scripted.
* Use EnumTools and EnumValueTools for enum operations.
*/
@:structInit
class HEnum implements IHScriptCustomBehaviour {
var enumValues(default, null) = {};
public function setEnum(name:String, enumValue:Dynamic):Void {
UnsafeReflect.setField(enumValues, name, enumValue);
}
public function getEnum(name:String):Null<Dynamic> {
if (UnsafeReflect.hasField(enumValues, name))
return UnsafeReflect.field(enumValues, name);
return null;
}
public function getEnumValues():Dynamic {
return enumValues;
}
public function hget(name:String):Dynamic {
return getEnum(name);
}
public function hset(name:String, val:Dynamic):Dynamic {
return null;
}
}
@:nullSafety
@:structInit
class HEnumValue {
public var enumName:String;
public var fieldName:String;
public var index:Int;
public var args:Array<Dynamic>;
public function toString():String {
return '$enumName.$fieldName${args.length > 0 ? '(${[for (a in args) a].join(", ")})' : ''}';
}
public inline function getEnumName():String
return this.enumName;
public inline function getConstructorArgs():Array<Dynamic>
return this.args;
public function compare(other:HEnumValue):Bool {
if (enumName != other.enumName || fieldName != other.fieldName)
return false;
if (args.length == 0 && other.args.length == 0)
return true;
if (args.length == 0 || other.args.length == 0)
return false;
if (args.length != other.args.length)
return false;
for (i in 0...args.length)
if (args[i] != other.args[i])
return false;
return true;
}
}
@:nullSafety
class EnumTools {
public static function getConstructors(e:Dynamic):Array<String> {
if(Std.isOfType(e, HEnum)) {
var henum:HEnum = cast e;
return UnsafeReflect.fields(henum.getEnumValues());
}
return Type.getEnumConstructs(cast e);
}
public static function createByName(e:Dynamic, constr:String, ?params:Array<Dynamic>):Dynamic {
if(Std.isOfType(e, HEnum)) {
var henum:HEnum = cast e;
var constructor = henum.getEnum(constr);
if(constructor == null)
throw 'Constructor $constr not found in enum';
if(Std.isOfType(constructor, HEnumValue))
return constructor;
if(Reflect.isFunction(constructor))
return constructor(params == null ? [] : params);
throw 'Invalid constructor type';
}
return Type.createEnum(cast e, constr, params);
}
public static function createByIndex(e:Dynamic, index:Int, ?params:Array<Dynamic>):Dynamic {
if(Std.isOfType(e, HEnum)) {
var constructors = getConstructors(e);
if(index < 0 || index >= constructors.length)
throw 'Index $index out of bounds for enum';
return createByName(e, constructors[index], params);
}
return Type.createEnumIndex(cast e, index, params);
}
}
@:nullSafety
class EnumValueTools {
public static function getType(e:Dynamic):Null<String> {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.enumName;
}
var en = Type.getEnum(e);
if(en != null)
return Type.getEnumName(en);
return null;
}
public static function getName(e:Dynamic):String {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.fieldName;
}
return Type.enumConstructor(e);
}
public static function getParameters(e:Dynamic):Array<Dynamic> {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.args.copy();
}
return Type.enumParameters(e);
}
public static function getIndex(e:Dynamic):Int {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.index;
}
return Type.enumIndex(e);
}
public static function equals(a:Dynamic, b:Dynamic):Bool {
if(Std.isOfType(a, HEnumValue) && Std.isOfType(b, HEnumValue)) {
var hva:HEnumValue = cast a;
var hvb:HEnumValue = cast b;
return hva.compare(hvb);
}
return Type.enumEq(a, b);
}
public static function match(e:Dynamic, pattern:Dynamic):Bool {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
if(Std.isOfType(pattern, HEnumValue)) {
var hp:HEnumValue = cast pattern;
if(hv.enumName != hp.enumName || hv.fieldName != hp.fieldName)
return false;
if(hp.args.length == 0)
return true;
if(hv.args.length != hp.args.length)
return false;
for(i in 0...hp.args.length) {
var pa = hp.args[i];
if(pa != null && hv.args[i] != pa)
return false;
}
return true;
}
if(Reflect.isObject(pattern)) {
var patternName = UnsafeReflect.hasField(pattern, "name") ? UnsafeReflect.field(pattern, "name") : null;
if(patternName != null && patternName != hv.fieldName)
return false;
return true;
}
return false;
}
return Type.enumEq(e, pattern);
}
}
+12
View File
@@ -0,0 +1,12 @@
package hscript;
// Soon...
interface IHScriptAbstractBehaviour extends IHScriptCustomBehaviour {
public var hasOp:Bool;
public var hasArr:Bool;
// @:op(A * B), @:op(A++), etc...
public function hop(kind:String, a:Dynamic, ?b:Dynamic):Dynamic;
public function harrayget(key:Dynamic):Dynamic;
public function harrayset(key:Dynamic, val:Dynamic):Dynamic;
}
+11
View File
@@ -0,0 +1,11 @@
package hscript;
/**
* Same Interface as IHScriptCustomBehaviour but for Property.
*/
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
var __allowSetGet:Bool;
public function __callGetter(name:String):Dynamic;
public function __callSetter(name:String, val:Dynamic):Dynamic;
}
+17
View File
@@ -1,6 +1,23 @@
package hscript;
/**
* Special Interface for handling field access behaviour.
* Basically works like the operator overload `@:op(a.b)`
* for an abstract.
*/
interface IHScriptCustomBehaviour {
/**
* Field Write Access
* @param name - Field Name
* @param val - Value to assign
* @return Dynamic - The assigned value
*/
public function hset(name:String, val:Dynamic):Dynamic;
/**
* Field Read Access
* @param name - Field Name
* @return Dynamic - The returned field
*/
public function hget(name:String):Dynamic;
}
+11
View File
@@ -0,0 +1,11 @@
package hscript;
/**
* Special Interface to make a class usable for Custom Classes.
*/
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
public var __interp:Interp;
public var __real_fields:Array<String>;
public var __class__fields:Array<String>;
}
+3
View File
@@ -1,5 +1,8 @@
package hscript;
/**
* Special Interface for handling new instances of an object.
*/
interface IHScriptCustomConstructor {
public function hnew(args:Array<Dynamic>):Dynamic;
}
+1245 -426
View File
File diff suppressed because it is too large Load Diff
+13 -42
View File
@@ -29,23 +29,13 @@ import haxe.macro.Expr;
class Macro {
var p : Position;
#if haxe3
var binops : Map<String,Binop>;
var unops : Map<String,Unop>;
#else
var binops : Hash<Binop>;
var unops : Hash<Unop>;
#end
public function new(pos) {
p = pos;
#if haxe3
binops = new Map();
unops = new Map();
#else
binops = new Hash();
unops = new Hash();
#end
for( c in Type.getEnumConstructs(Binop) ) {
if( c == "OpAssignOp" ) continue;
var op = Type.createEnum(Binop, c);
@@ -73,9 +63,7 @@ class Macro {
case OpMod: assign = true; "%";
case OpAssignOp(_): "";
case OpInterval: "...";
#if haxe3
case OpArrow: "=>";
#end
#if (haxe_ver >= 4)
case OpIn: "in";
#end
@@ -102,15 +90,8 @@ class Macro {
}
}
#if !haxe3
function isType(v:String) {
var c0 = v.charCodeAt(0);
return c0 >= 'A'.code && c0 <= 'Z'.code;
}
#end
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
var b = new Array();
var b = [];
for( x in a )
b.push(f(x));
return b;
@@ -146,6 +127,8 @@ class Macro {
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
}
TAnonymous(tf);
case CTExpr(_):
throw "assert";
};
}
@@ -156,17 +139,9 @@ class Macro {
case CInt(v): CInt(Std.string(v));
case CFloat(f): CFloat(Std.string(f));
case CString(s): CString(s);
#if !haxe3
case CInt32(v): CInt(Std.string(v));
#end
});
case EIdent(v):
#if !haxe3
if( isType(v) )
EConst(CType(v));
else
#end
EConst(CIdent(v));
EConst(CIdent(v));
case EVar(n, t, e):
EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]);
case EParent(e):
@@ -174,19 +149,15 @@ class Macro {
case EBlock(el):
EBlock(map(el,convert));
case EField(e, f):
#if !haxe3
if( isType(f) )
EType(convert(e), f);
else
#end
EField(convert(e), f);
EField(convert(e), f);
case EBinop(op, e1, e2):
var b = binops.get(op);
if( b == null ) throw EInvalidOp(op);
var b = binops.get(op.toString());
if( b == null ) throw EInvalidOp(op.toString());
EBinop(b, convert(e1), convert(e2));
case EUnop(op, prefix, e):
var u = unops.get(op);
if( u == null ) throw EInvalidOp(op);
var opStr = op.toString();
var u = unops.get(opStr);
if( u == null ) throw EInvalidOp(opStr);
EUnop(u, !prefix, convert(e));
case ECall(e, params):
ECall(convert(e), map(params, convert));
@@ -200,11 +171,9 @@ class Macro {
#if (haxe_ver >= 4)
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
#elseif (haxe_211 || haxe3)
#else
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
#else
EFor(v, convert(it), convert(efor));
#end
case EBreak:
EBreak;
@@ -252,6 +221,8 @@ class Macro {
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
case ECheckType(e, t):
ECheckType(convert(e), convertType(t));
default:
null;
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
}
+817 -305
View File
File diff suppressed because it is too large Load Diff
+494 -374
View File
@@ -1,374 +1,494 @@
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
import hscript.Expr;
class Printer {
var buf : StringBuf;
var tabs : String;
public function new() {
}
public function exprToString( e : Expr ) {
buf = new StringBuf();
tabs = "";
expr(e);
return buf.toString();
}
public function typeToString( t : CType ) {
buf = new StringBuf();
tabs = "";
type(t);
return buf.toString();
}
inline function add<T>(s:T) buf.add(s);
function type( t : CType ) {
switch( t ) {
case CTOpt(t):
add('?');
type(t);
case CTPath(path, params):
add(path.join("."));
if( params != null ) {
add("<");
var first = true;
for( p in params ) {
if( first ) first = false else add(", ");
type(p);
}
add(">");
}
case CTNamed(name, t):
add(name);
add(':');
type(t);
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
add('(');
for (a in args)
switch a {
case CTNamed(_, _): type(a);
default: type(CTNamed('_', a));
}
add(')->');
type(ret);
case CTFun(args, ret):
if( args.length == 0 )
add("Void -> ");
else {
for( a in args ) {
type(a);
add(" -> ");
}
}
type(ret);
case CTAnon(fields):
add("{");
var first = true;
for( f in fields ) {
if( first ) { first = false; add(" "); } else add(", ");
add(f.name + " : ");
type(f.t);
}
add(first ? "}" : " }");
case CTParent(t):
add("(");
type(t);
add(")");
}
}
function addType( t : CType ) {
if( t != null ) {
add(" : ");
type(t);
}
}
function expr( e : Expr ) {
if( e == null ) {
add("??NULL??");
return;
}
switch( #if hscriptPos e.e #else e #end ) {
case EImport(c, n):
add("import " + c);
if(n != null)
add(' as $n');
case EClass(name, fields, extend, interfaces):
add('class $name');
if (extend != null)
add(' extends $extend');
for(_interface in interfaces) {
add(' implements $_interface');
}
add(' {\n');
tabs += "\t";
//for(field in fields) {
// expr(field);
//}
tabs = tabs.substr(1);
add("}");
case EConst(c):
switch( c ) {
case CInt(i): add(i);
case CFloat(f): add(f);
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
}
case EIdent(v):
add(v);
case EVar(n, t, e): // TODO: static, public, override
add("var " + n);
addType(t);
if( e != null ) {
add(" = ");
expr(e);
}
case EParent(e):
add("("); expr(e); add(")");
case EBlock(el):
if( el.length == 0 ) {
add("{}");
} else {
tabs += "\t";
add("{\n");
for( e in el ) {
add(tabs);
expr(e);
add(";\n");
}
tabs = tabs.substr(1);
add("}");
}
case EField(e, f, s):
expr(e);
add((s == true ? "?." : ".") + f);
case EBinop(op, e1, e2):
expr(e1);
add(" " + op + " ");
expr(e2);
case EUnop(op, pre, e):
if( pre ) {
add(op);
expr(e);
} else {
expr(e);
add(op);
}
case ECall(e, args):
if( e == null )
expr(e);
else switch( #if hscriptPos e.e #else e #end ) {
case EField(_), EIdent(_), EConst(_):
expr(e);
default:
add("(");
expr(e);
add(")");
}
add("(");
var first = true;
for( a in args ) {
if( first ) first = false else add(", ");
expr(a);
}
add(")");
case EIf(cond,e1,e2):
add("if( ");
expr(cond);
add(" ) ");
expr(e1);
if( e2 != null ) {
add(" else ");
expr(e2);
}
case EWhile(cond,e):
add("while( ");
expr(cond);
add(" ) ");
expr(e);
case EDoWhile(cond,e):
add("do ");
expr(e);
add(" while ( ");
expr(cond);
add(" )");
case EFor(v, it, e):
add("for( "+v+" in ");
expr(it);
add(" ) ");
expr(e);
case EBreak:
add("break");
case EContinue:
add("continue");
case EFunction(params, e, name, ret): // TODO: static, public, override
add("function");
if( name != null )
add(" " + name);
add("(");
var first = true;
for( a in params ) {
if( first ) first = false else add(", ");
if( a.opt ) add("?");
add(a.name);
addType(a.t);
}
add(")");
addType(ret);
add(" ");
expr(e);
case EReturn(e):
add("return");
if( e != null ) {
add(" ");
expr(e);
}
case EArray(e,index):
expr(e);
add("[");
expr(index);
add("]");
case EArrayDecl(el, _):
add("[");
var first = true;
for( e in el ) {
if( first ) first = false else add(", ");
expr(e);
}
add("]");
case ENew(cl, args):
add("new " + cl + "(");
var first = true;
for( e in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
case EThrow(e):
add("throw ");
expr(e);
case ETry(e, v, t, ecatch):
add("try ");
expr(e);
add(" catch( " + v);
addType(t);
add(") ");
expr(ecatch);
case EObject(fl):
if( fl.length == 0 ) {
add("{}");
} else {
tabs += "\t";
add("{\n");
for( f in fl ) {
add(tabs);
add(f.name+" : ");
expr(f.e);
add(",\n");
}
tabs = tabs.substr(1);
add("}");
}
case ETernary(c,e1,e2):
expr(c);
add(" ? ");
expr(e1);
add(" : ");
expr(e2);
case ESwitch(e, cases, def):
add("switch( ");
expr(e);
add(") {");
for( c in cases ) {
add("case ");
var first = true;
for( v in c.values ) {
if( first ) first = false else add(", ");
expr(v);
}
add(": ");
expr(c.expr);
add(";\n");
}
if( def != null ) {
add("default: ");
expr(def);
add(";\n");
}
add("}");
case EMeta(name, args, e):
add("@");
add(name);
if( args != null && args.length > 0 ) {
add("(");
var first = true;
for( a in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
}
add(" ");
expr(e);
case ECheckType(e, t):
add("(");
expr(e);
add(" : ");
addType(t);
add(")");
}
}
public static function toString( e : Expr ) {
return new Printer().exprToString(e);
}
public static function errorToString( e : Expr.Error ) {
var message = switch( #if hscriptPos e.e #else e #end ) {
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
case EUnexpected(s): "Unexpected token: \""+s+"\"";
case EUnterminatedString: "Unterminated string";
case EUnterminatedComment: "Unterminated comment";
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
case EUnknownVariable(v): "Unknown variable: "+v;
case EInvalidIterator(v): "Invalid iterator: "+v;
case EInvalidOp(op): "Invalid operator: "+op;
case EInvalidAccess(f): "Invalid access to field " + f;
case ECustom(msg): msg;
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
};
#if hscriptPos
return e.origin + ":" + e.line + ": " + message;
#else
return message;
#end
}
}
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
import hscript.Expr;
class Printer {
var buf : StringBuf;
var tabs : String;
public function new() {
}
public function exprToString( e : Expr ):String {
buf = new StringBuf();
tabs = "";
expr(e);
return buf.toString();
}
public function typeToString( t : CType ):String {
buf = new StringBuf();
tabs = "";
type(t);
return buf.toString();
}
inline function add<T>(s:T):Void buf.add(s);
function type( t : CType ):Void {
switch( t ) {
case CTOpt(t):
add('?');
type(t);
case CTPath(path, params):
add(path.join("."));
if( params != null ) {
add("<");
var first = true;
for( p in params ) {
if( first ) first = false else add(", ");
type(p);
}
add(">");
}
case CTNamed(name, t):
add(name);
add(':');
type(t);
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
add('(');
for (a in args)
switch a {
case CTNamed(_, _): type(a);
default: type(CTNamed('_', a));
}
add(')->');
type(ret);
case CTFun(args, ret):
if( args.length == 0 )
add("Void -> ");
else {
for( a in args ) {
type(a);
add(" -> ");
}
}
type(ret);
case CTAnon(fields):
add("{");
var first = true;
for( f in fields ) {
if( first ) { first = false; add(" "); } else add(", ");
add(f.name + " : ");
type(f.t);
}
add(first ? "}" : " }");
case CTParent(t):
add("(");
type(t);
add(")");
case CTExpr(e):
expr(e);
}
}
function addType( t : CType ):Void {
if( t != null ) {
add(" : ");
type(t);
}
}
function expr( e : Expr ):Void {
if( e == null ) {
add("??NULL??");
return;
}
switch(Tools.expr(e)) {
case EPackage(n):
add('package');
if(n != null)
add(' $n');
add(';\n');
case EImport(c, n, u):
add('${u ? 'using' : 'import'} $c');
if(n != null)
add(' as $n');
case EClass(name, fields, extend, interfaces, fnal):
var isFinal = fnal != null && fnal;
if(isFinal)
add('final ');
add('class $name');
if (extend != null)
add(' extends $extend');
for(_interface in interfaces) {
add(' implements $_interface');
}
tabs += "\t";
add(" {\n");
for( e in fields ) {
add(tabs);
expr(e);
//add(";\n");
}
//for(field in fields) {
// expr(field);
//}
tabs = tabs.substr(1);
add("}");
case EEnum(en, isAbstract):
if(isAbstract) {
add('enum abstract ${en.name}(');
if(en.underlyingType != null)
type(en.underlyingType);
else
add('Int');
add(')');
if(en.fields.length == 0) {
add(' {}');
return;
}
tabs += "\t";
add(" {\n");
for(e in en.fields) {
add(tabs);
add(e.name);
if(e.value != null) {
add(" = ");
expr(e.value);
}
add(";\n");
}
tabs = tabs.substr(1);
add("}");
} else {
add('enum ${en.name}');
if(en.fields.length == 0) {
add(' {}');
return;
}
tabs += "\t";
add(" {\n");
for(e in en.fields) {
add(tabs);
add(e.name);
if(e.args.length > 0) {
add("(");
var first = true;
for( a in e.args ) {
if( first ) first = false else add(", ");
if( a.opt ) add("?");
add(a.name);
addType(a.t);
}
add(')');
}
add(";\n");
}
tabs = tabs.substr(1);
add("}");
}
case ECast(e, t):
var safe = t != null;
add("cast ");
if(safe) add("(");
expr(e);
if(safe) {
add(", ");
addType(t);
add(")");
}
case ERegex(e, f):
add('~/$e/$f');
add(';\n');
case EConst(c):
switch( c ) {
case CInt(i): add(i);
case CFloat(f): add(f);
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
}
case EIdent(v):
add(v);
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
if(p) add("public ");
else if(pr) add("private ");
if(s) add("static ");
if(isInline) add("inline ");
if(isFinal) add("final " + n);
else add("var " + n);
if(get != null || set != null) {
add("(");
switch(get) {
case ADefault: add("default, ");
case ANull: add("null, ");
case AGet: add("get, ");
case ADynamic: add("dynamic, ");
case ANever: add("never, ");
default:
}
switch(set) {
case ADefault: add("default");
case ANull: add("null");
case ASet: add("set");
case ADynamic: add("dynamic");
case ANever: add("never");
default:
}
add(")");
}
addType(t);
if( e != null ) {
add(" = ");
expr(e);
}
case EParent(e):
add("("); expr(e); add(")");
case EBlock(el):
if( el.length == 0 ) {
add("{}");
} else {
tabs += "\t";
add("{\n");
for( e in el ) {
add(tabs);
expr(e);
add(";\n");
}
tabs = tabs.substr(1);
add("}");
}
case EField(e, f, s):
expr(e);
add((s == true ? "?." : ".") + f);
case EBinop(op, e1, e2):
expr(e1);
add(" " + op.toString() + " ");
expr(e2);
case EUnop(op, pre, e):
if( pre ) {
add(op);
expr(e);
} else {
expr(e);
add(op);
}
case ECall(e, args):
if( e == null )
expr(e);
else switch( Tools.expr(e)) {
case EField(_), EIdent(_), EConst(_):
expr(e);
default:
add("(");
expr(e);
add(")");
}
add("(");
var first = true;
for( a in args ) {
if( first ) first = false else add(", ");
expr(a);
}
add(")");
case EIf(cond,e1,e2):
add("if( ");
expr(cond);
add(" ) ");
expr(e1);
if( e2 != null ) {
add(" else ");
expr(e2);
}
case EWhile(cond,e):
add("while( ");
expr(cond);
add(" ) ");
expr(e);
case EDoWhile(cond,e):
add("do ");
expr(e);
add(" while ( ");
expr(cond);
add(" )");
case EFor(v, it, e, ithv):
if(ithv != null)
add("for( "+ithv+" => "+v+" in ");
else
add("for( "+v+" in ");
expr(it);
add(" ) ");
expr(e);
case EBreak:
add("break");
case EContinue:
add("continue");
case EFunction(params, e, name, ret): // TODO: static, public, override
add("function");
if( name != null )
add(" " + name);
add("(");
var first = true;
for( a in params ) {
if( first ) first = false else add(", ");
if( a.opt ) add("?");
add(a.name);
addType(a.t);
}
add(")");
addType(ret);
add(" ");
expr(e);
case EReturn(e):
add("return");
if( e != null ) {
add(" ");
expr(e);
}
case EArray(e,index):
expr(e);
add("[");
expr(index);
add("]");
case EArrayDecl(el, _):
add("[");
var first = true;
for( e in el ) {
if( first ) first = false else add(", ");
expr(e);
}
add("]");
case ENew(cl, args, params):
add("new " + cl);
if(params != null) {
add("<");
var first = true;
for( p in params ) {
if( first ) first = false else add(", ");
type(p);
}
add(">");
}
add("(");
var first = true;
for( e in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
case EThrow(e):
add("throw ");
expr(e);
case ETry(e, v, t, ecatch):
add("try ");
expr(e);
add(" catch( " + v);
addType(t);
add(") ");
expr(ecatch);
case EObject(fl):
if( fl.length == 0 ) {
add("{}");
} else {
tabs += "\t";
add("{\n");
for( f in fl ) {
add(tabs);
add(f.name+" : ");
expr(f.e);
add(",\n");
}
tabs = tabs.substr(1);
add("}");
}
case ETernary(c,e1,e2):
expr(c);
add(" ? ");
expr(e1);
add(" : ");
expr(e2);
case ESwitch(e, cases, def):
add("switch( ");
expr(e);
add(") {");
for( c in cases ) {
add("case ");
var first = true;
for( v in c.values ) {
if( first ) first = false else add(", ");
expr(v);
}
add(": ");
expr(c.expr);
add(";\n");
}
if( def != null ) {
add("default: ");
expr(def);
add(";\n");
}
add("}");
case EMeta(name, args, e):
add("@");
add(name);
if( args != null && args.length > 0 ) {
add("(");
var first = true;
for( a in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
}
add(" ");
expr(e);
case ECheckType(e, t):
add("(");
expr(e);
add(" : ");
addType(t);
add(")");
}
}
public static function toString( e : Expr ):String {
return new Printer().exprToString(e);
}
public static function errorToString( e : Expr.Error ):String {
var message = switch( #if hscriptPos e.e #else e #end ) {
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
case EUnexpected(s): "Unexpected token: \""+s+"\"";
case EUnterminatedString: "Unterminated string";
case EUnterminatedComment: "Unterminated comment";
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
case EUnknownVariable(v): "Unknown variable: "+v;
case EInvalidIterator(v): "Invalid iterator: "+v;
case EInvalidOp(op): "Invalid operator: "+op;
case EInvalidAccess(f): "Invalid access to field " + f;
case ECustom(msg): msg;
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
};
#if hscriptPos
return e.origin + ":" + e.line + ": " + message;
#else
return message;
#end
}
}
+179
View File
@@ -0,0 +1,179 @@
package hscript;
import hscript.utils.UnsafeReflect;
import hscript.Interp;
import hscript.Expr.FieldPropertyAccess;
/**
* Special variable that handles 'getter/setter' function calls
* depending of the read/write access combination.
*
* Example:
* ```haxe
* public var myvar(get, set):Int;
* var _myvar:Int = 10;
*
* function get_myvar():Int {
* return _myvar;
* }
*
* function set_myvar(val:Int):Int {
* if(val > 10) return _myvar = val;
* return val;
* }
* ```
*
* @see https://haxe.org/manual/class-field-property.html
*/
@:access(hscript.Interp)
class Property {
private static inline var GET = 'get_';
private static inline var SET = 'set_';
/**
* Name of the attached field.
*/
public final name:String;
/**
* The current value. If isn't initialized, it's always `null`.
*/
public var r:Dynamic;
/**
* The getter property kind
*/
public final getter:FieldPropertyAccess;
/**
* The setter property kind
*/
public final setter:FieldPropertyAccess;
/**
* If the field is declared as static.
*/
public var isStatic(get, never):Bool;
function get_isStatic() {
return __isStatic && interp.allowStaticVariables;
}
var isVar:Bool;
var interp:Interp;
@:allow(hscript.Interp)
private var getterFunc(get, never):String;
private inline function get_getterFunc():String {
return '$GET$name';
}
@:allow(hscript.Interp)
private var setterFunc(get, never):String;
private inline function get_setterFunc():String {
return '$SET$name';
}
public function new(name:String, r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) {
this.name = name;
this.r = r;
this.getter = getter;
this.setter = setter;
this.isVar = isVar;
this.__isStatic = isStatic;
this.interp = interp;
}
// Internal flags to gain access to the current field value (if isn't a property field)
var __allowReadAccess:Bool = false;
var __allowWriteAccess:Bool = false;
// Internal flag to gain access if the field is accessed with @:bypassAccessor
var __allowSetGet:Bool = true;
final __isStatic:Bool = false;
public function get(isBypassAccessor:Bool) {
if(isBypassAccessor) __allowSetGet = false;
var r:Dynamic = callGetter();
if(isBypassAccessor) __allowSetGet = true;
return r;
}
public function set(value:Dynamic, isBypassAccessor:Bool) {
if(isBypassAccessor) __allowSetGet = false;
var r:Dynamic = callSetter(value);
if(isBypassAccessor) __allowSetGet = true;
return r;
}
private function callGetter():Dynamic {
switch (getter) {
case AGet | ADynamic:
var fName:String = getterFunc;
if (!__allowReadAccess && __allowSetGet) {
if (varExists(fName)) {
return callAccessor(fName);
} else
interp.error(ECustom('Method $fName required by property $name is missing'));
} else {
if ((setter == ADefault || setter == ANull) || isVar) {
return r;
}
else
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
}
case ANever:
interp.error(ECustom('This expression cannot be accessed for reading'));
default:
}
return r;
}
private function callSetter(val:Dynamic):Dynamic {
switch (setter) {
case ASet | ADynamic:
var fName:String = setterFunc;
if (!__allowWriteAccess && __allowSetGet) {
if (varExists(fName))
return callAccessor(fName, val);
else
interp.error(ECustom('Method $fName required by property $name is missing'));
} else {
if ((getter == ADefault || getter == ANull) || isVar) {
return r = val;
}
else
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
}
case ANever:
interp.error(ECustom('This expression cannot be accessed for writing'));
default:
}
return r = val;
}
private function callAccessor(f:String, ?value:Dynamic):Dynamic {
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
var rt:Dynamic = null;
var isWrite:Bool = value != null;
if (fn != null && Reflect.isFunction(fn)) {
if (isWrite) __allowWriteAccess = true;
else __allowReadAccess = true;
rt = UnsafeReflect.callMethodUnsafe(null, fn, isWrite ? [value] : []);
if (isWrite) __allowWriteAccess = false;
else __allowReadAccess = false;
return rt;
} else
interp.error(ECustom('Method $f required by property ${f.substr(3)} is missing'));
return rt;
}
private inline function varExists(n:String) {
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
}
}
+143 -113
View File
@@ -1,114 +1,144 @@
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
import hscript.Expr;
class Tools {
public static function iter( e : Expr, f : Expr -> Void ) {
switch( expr(e) ) {
case EConst(_), EIdent(_):
case EImport(c): f(e);
case EClass(_, e, _, _): for( a in e ) f(a);
case EVar(_, _, e): if( e != null ) f(e);
case EParent(e): f(e);
case EBlock(el): for( e in el ) f(e);
case EField(e, _): f(e);
case EBinop(_, e1, e2): f(e1); f(e2);
case EUnop(_, _, e): f(e);
case ECall(e, args): f(e); for( a in args ) f(a);
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
case EWhile(c, e): f(c); f(e);
case EDoWhile(c, e): f(c); f(e);
case EFor(_, it, e): f(it); f(e);
case EBreak,EContinue:
case EFunction(_, e, _, _): f(e);
case EReturn(e): if( e != null ) f(e);
case EArray(e, i): f(e); f(i);
case EArrayDecl(el): for( e in el ) f(e);
case ENew(_,el): for( e in el ) f(e);
case EThrow(e): f(e);
case ETry(e, _, _, c): f(e); f(c);
case EObject(fl): for( fi in fl ) f(fi.e);
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
case ESwitch(e, cases, def):
f(e);
for( c in cases ) {
for( v in c.values ) f(v);
f(c.expr);
}
if( def != null ) f(def);
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
case ECheckType(e,_): f(e);
}
}
public static function map( e : Expr, f : Expr -> Expr ) {
var edef = switch( expr(e) ) {
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
case EVar(n, t, e): EVar(n, t, if( e != null ) f(e) else null);
case EParent(e): EParent(f(e));
case EBlock(el): EBlock([for( e in el ) f(e)]);
case EField(e, fi): EField(f(e),fi);
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EUnop(op, pre, e): EUnop(op, pre, f(e));
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
case EWhile(c, e): EWhile(f(c),f(e));
case EDoWhile(c, e): EDoWhile(f(c),f(e));
case EFor(v, it, e): EFor(v, f(it), f(e));
case EFunction(args, e, name, t): EFunction(args, f(e), name, t);
case EReturn(e): EReturn(if( e != null ) f(e) else null);
case EArray(e, i): EArray(f(e),f(i));
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
case EThrow(e): EThrow(f(e));
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
case ECheckType(e,t): ECheckType(f(e), t);
case EImport(c): EImport(c);
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
}
return mk(edef, e);
}
public static inline function expr( e : Expr ) : ExprDef {
#if hscriptPos
return e.e;
#else
return e;
#end
}
public static inline function mk( e : ExprDef, p : Expr ) {
#if hscriptPos
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
#else
return e;
#end
}
/*
* Copyright (C)2008-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package hscript;
import hscript.Expr;
class Tools {
public static function iter( e : Expr, f : Expr -> Void ):Void {
switch( expr(e) ) {
case EConst(_), EIdent(_):
case EImport(c): f(e);
case EClass(_, e, _, _): for( a in e ) f(a);
case EVar(_, _, e): if( e != null ) f(e);
case EParent(e): f(e);
case EBlock(el): for( e in el ) f(e);
case EField(e, _): f(e);
case EBinop(_, e1, e2): f(e1); f(e2);
case EUnop(_, _, e): f(e);
case ECall(e, args): f(e); for( a in args ) f(a);
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
case EWhile(c, e): f(c); f(e);
case EDoWhile(c, e): f(c); f(e);
case EFor(_, it, e): f(it); f(e);
case EBreak,EContinue:
case EFunction(_, e, _, _): f(e);
case EReturn(e): if( e != null ) f(e);
case EArray(e, i): f(e); f(i);
case EArrayDecl(el): for( e in el ) f(e);
case ENew(_,el): for( e in el ) f(e);
case EThrow(e): f(e);
case ETry(e, _, _, c): f(e); f(c);
case EObject(fl): for( fi in fl ) f(fi.e);
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
case ESwitch(e, cases, def):
f(e);
for( c in cases ) {
for( v in c.values ) f(v);
f(c.expr);
}
if( def != null ) f(def);
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
case ECheckType(e,_): f(e);
default:
}
}
public static function map( e : Expr, f : Expr -> Expr ):Expr {
var edef = switch( expr(e) ) {
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
case EParent(e): EParent(f(e));
case EBlock(el): EBlock([for( e in el ) f(e)]);
case EField(e, fi): EField(f(e),fi);
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EUnop(op, pre, e): EUnop(op, pre, f(e));
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
case EWhile(c, e): EWhile(f(c),f(e));
case EDoWhile(c, e): EDoWhile(f(c),f(e));
case EFor(v, it, e): EFor(v, f(it), f(e));
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
case EReturn(e): EReturn(if( e != null ) f(e) else null);
case EArray(e, i): EArray(f(e),f(i));
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
case EThrow(e): EThrow(f(e));
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
case ECheckType(e,t): ECheckType(f(e), t);
case EImport(c): EImport(c);
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
default: expr(e);
}
return mk(edef, e);
}
public static inline function expr( e : Expr ) : ExprDef {
#if hscriptPos
return e.e;
#else
return e;
#end
}
public static inline function mk( e : ExprDef, p : Expr ):Expr {
#if hscriptPos
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
#else
return e;
#end
}
/**
* DO NOT USE INLINE ON THIS FUNCTION
**/
public static function argCount(func: haxe.Constraints.Function): Int {
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
#if cpp
return untyped __cpp__("{0}->__ArgCount()", func);
#elseif js
return untyped js.Syntax.code("{0}.length", func);
#elseif hl
var ft = hl.Type.getDynamic(func);
if (ft.kind != HFun)
return -1;
return ft.getArgsCount();
#else
return -1;
#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;
}
+162
View File
@@ -0,0 +1,162 @@
package hscript.macros;
#if macro
import Type.ValueType;
import haxe.macro.ComplexTypeTools;
import haxe.macro.Expr;
import haxe.macro.Context;
import haxe.macro.Printer;
import haxe.macro.Compiler;
using StringTools;
class AbstractHandler {
public static function init() {
#if HSCRIPT_ABSTRACT_SUPPORT
#if !display
if(Context.defined("display")) return;
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
}
#end
#end
}
public static function build():Array<Field> {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
var cl = clRef.get();
if (/* cl.name.startsWith("Flx") && */ cl.name.endsWith("_Impl_") && cl.params.length <= 0 && !cl.meta.has(":multiType") && !cl.name.contains("_HSC")) {
var metas = cl.meta.get();
var trimEnum = cl.name.substr(0, cl.name.length - 6);
var key = cl.module;
var fkey = cl.module + "." + trimEnum;
if(key == "lime.system.Locale") return fields; // Error: Unknown identifier : currentLocale, Due to Func
if(key == "cpp.Function") return fields; // Error: Unknown identifier : nativeGetProcAddress, Due to Func
if(key == "haxe.ds.Vector") return fields; // Error: haxe.ds._Vector.VectorData<blit.T> has no field blit, Due to Func
if(key == "haxe.display.Display") return fields; // Error: haxe.display.DisplayItemKind<haxe.display.DisplayLiteral<Dynamic>> has no field Null, Due to Func
if(key == "cpp.Callable") return fields; // Error: cpp.Function.fromStaticFunction must be called on static function, Due to Func
if(key == "haxe.display.JsonAnonStatusKind") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
if(key == "cpp.CharStar") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
if(Config.DISALLOW_ABSTRACT_AND_ENUM.contains(cl.module) || Config.DISALLOW_ABSTRACT_AND_ENUM.contains(fkey)) return fields;
if(cl.module.contains("_")) return fields; // Weird issue, sorry
var shadowClass = macro class {
};
shadowClass.kind = TDClass();
shadowClass.params = switch(cl.params.length) {
case 0:
null;
case 1:
[{
name: "T",
}];
default:
[for(k=>e in cl.params) {
name: "T" + Std.int(k+1)
}];
};
shadowClass.name = '${cl.name.substr(0, cl.name.length - 6)}_HSC';
var imports = Context.getLocalImports().copy();
Utils.setupMetas(shadowClass, imports);
//trace(cl.module);
for(f in fields)
switch(f.kind) {
case FFun(fun):
if (f.access.contains(AStatic)) {
if (fun.expr != null) {
fun.expr = macro @:privateAccess $e{fun.expr};
shadowClass.fields.push(f);
/*var trimEnum = cl.name.substr(0, cl.name.length - 6);
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
var name = f.name;
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
var expr:Expr = Context.parse('${returns?"return " : ""} $trimEnum.$name(${[for(a in fun.args) a.name].join(", ")})', f.pos);
var func:Function = {
ret: fun.ret,
params: fun.params.copy(),
expr: expr,
args: fun.args.copy()
};
var field:Field = {
pos: f.pos,
name: f.name,
meta: f.meta,
kind: FFun(func),
doc: null,//f.doc,
access: [APublic, AStatic]
}
shadowClass.fields.push(field);*/
}
}
case FProp(get, set, t, e):
if (get == "default" && (set == "never" || set == "null")) {
shadowClass.fields.push(f);
}
case FVar(t, e):
if (f.access.contains(AStatic) || cl.meta.has(":enum") || f.name.toUpperCase() == f.name) {
var name:String = f.name;
var enumType:String = cl.name;
var pack = cl.module.split(".");
//trace(pack, cl.name, name, cl.module);
if(pack[pack.length - 1] == trimEnum)
pack.pop();
var complexType:ComplexType = t;
if(complexType == null && e != null) {
complexType = switch(e.expr) {
case EConst(CRegexp(_)): TPath({ name: "EReg", pack: [] });
default: null;
}
}
if(complexType == null) {
complexType = TPath({
name: trimEnum,
pack: [],//pack
});
}
var code = Context.parse('@:privateAccess ($trimEnum.$name)', f.pos); // '${pack.join(".")}.${trimEnum}.$name'
var field:Field = {
pos: f.pos,
name: f.name,
meta: f.meta,
kind: FVar(null, code),
doc: f.doc,
access: [APublic, AStatic]
}
shadowClass.fields.push(field);
}
default:
}
//var printer = new Printer();
//for(field in shadowClass.fields)
// trace(printer.printField(field));
Context.defineModule(cl.module, [shadowClass], imports);
}
return fields;
}
}
#end
+709
View File
@@ -0,0 +1,709 @@
package hscript.macros;
#if macro
import haxe.macro.Type.ClassType;
import Type.ValueType;
import haxe.macro.Expr.Function;
import haxe.macro.Expr;
import haxe.macro.Type.MetaAccess;
import haxe.macro.Type.FieldKind;
import haxe.macro.Type.ClassField;
import haxe.macro.Type.VarAccess;
import haxe.macro.*;
using StringTools;
// BIG TODO: make typed classes scriptable
class ClassExtendMacro {
public static inline final FUNC_PREFIX = "_HX_SUPER__";
public static inline final CLASS_SUFFIX = "_HSX";
public static var unallowedMetas:Array<String> = [":bitmap", ":noCustomClass", ":generic"];
public static var modifiedClasses:Array<String> = [];
public static function init() {
#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
}
public static function build():Array<Field> {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
var cl = clRef.get();
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface) return fields;
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC")) {
var metas = cl.meta.get();
for(m in metas)
if (unallowedMetas.contains(m.name))
return fields;
if(cl.params.length > 0)
return fields;
var key = cl.module;
var fkey = cl.module + "." + cl.name;
if(key == "sys.thread.FixedThreadPool") return fields; // Error: Type name sys.thread.Worker_HSX is redefined from module sys.thread.FixedThreadPool
if(key == "StdTypes") return fields; // Error: Cant extend basic class
if(key == "Xml") return fields; // Error: Cant extend basic class
if(key == "Date") return fields; // Error: Cant extend basic class
if(key == "away3d.tools.commands.Mirror") return fields; // Error: Unknown identifier
if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined
if(fkey == "hscript.CustomClass") return fields; // Error: Redefined
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
if(cl.module.contains("_")) return fields; // Weird issue, sorry
var superFields = [];
if(false && cl.superClass != null) {
var _superFields = cl.superClass.t.get().fields.get();
_superFields = []; // Comment to enable super support, (broken)
function convertField(field:ClassField) {
try {
var nfield = FixedTypeTools.toSimpleField(field);
switch ([field.kind, field.type]) {
case [FMethod(kind), TFun(args, ret)]:
if(kind == MethInline)
nfield.access.push(AInline);
if(kind == MethDynamic)
nfield.access.push(ADynamic);
default:
}
switch(nfield.kind) {
case FFun(fun):
if (fun.params != null && fun.params.length > 0)
return null;
//sfun.ret = Utils.fixStdTypes(fun.ret);
var metas = nfield.meta;
var defaultValues:Map<String, Dynamic> = [];
var defaultEntry = null;
var isGeneric = false;
for(m in metas) {
if(m.name == ":value") {
defaultEntry = m;
switch(m.params[0].expr) {
case EObjectDecl(fields):
for(fil in fields)
defaultValues[fil.field] = fil.expr;
default:
}
}
if(m.name == ":generic")
isGeneric = true;
}
if(isGeneric) return null;
if(defaultEntry != null)
metas.remove(defaultEntry);
for(arg in fun.args) {
var opt = false;
if(defaultValues.exists(arg.name)) {
arg.value = defaultValues[arg.name];
arg.opt = false;
}
arg.type = null;//Utils.fixStdTypes(arg.type);
//if(arg.opt) {
// if(arg.type.getParameters()[0].name != "Null")
// arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
//}
}
trace(nfield.name);
default:
}
return nfield;
} catch(e) {
trace(field.name, e);
return null;
}
}
var didPrint = false;
var fieldNames = [for(f in fields) f.name];
/*for(field in _superFields) {
if(fieldNames.contains(field.name))
continue;
if(!field.kind.match(FMethod(_))) // only catch methods
continue;
if(field.name.startsWith("get_")) {
var access = FixedTypeTools.getAccess(field);
if(access.contains(AInline) || access.contains(AFinal) || field.isFinal)
continue;
var name = field.name;
superFields.push({
name: field.name,
pos: field.pos,
kind: FFun({
ret: null,
params: [],
expr: macro {
return super.$name();
},
args: []
}),
access: access,
meta: field.meta.get(),
});
//var f = convertField(field);
//if(f != null)
// superFields.push(f);
if(field.name == "get_bgColor") {
if(!didPrint) {
trace(cl.name);
didPrint = true;
}
trace("> " + field.name + " : " + access, field);
}
}
}*/
// want to get this working
/*for(field in _superFields) {
if(fieldNames.contains(field.name))
continue;
if(!field.kind.match(FMethod(_))) // only catch methods
continue;
var f = convertField(field);
if(f != null)
superFields.push(f);
}*/
//superFields = [];
}
var shadowClass = macro class {
};
var definedFields:Array<String> = [];
//trace(getModuleName(cl));
var hasNew = false;
for(_field in [fields.copy(), superFields.copy()])
for(f in _field) {
if (f == null)
continue;
if (f.name == "new") {
hasNew = true;
switch (f.kind) {
case FFun(fn):
var constructor:Field = buildConstructor(fn.args);
shadowClass.fields.push(constructor);
definedFields.push(f.name);
default:
continue;
}
continue;
}
if (f.name.startsWith(FUNC_PREFIX))
continue;
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline) || f.access.contains(AFinal))
continue;
if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet
if(definedFields.contains(f.name)) continue; // no duplicate fields
for(m in f.meta)
if (unallowedMetas.contains(m.name))
continue;
switch(f.kind) {
case FFun(fun):
if (fun == null)
continue;
if (fun.params != null && fun.params.length > 0) // TODO: Support for this maybe?
continue;
if(fun.params == null)
fun.params = [];
var overrideExpr:Expr;
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
var name = f.name;
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
if (returns) {
overrideExpr = macro {
var name:String = $v{name};
if (__interp != null && __class__fields.contains(name)) {
var v:Dynamic = null;
if (Reflect.isFunction(v = __interp.variables.get(name))) {
return v($a{arguments});
}
}
return super.$name($a{arguments});
};
} else {
overrideExpr = macro {
var name:String = $v{name};
if (__interp != null && __class__fields.contains(name)) {
var v:Dynamic = null;
if (Reflect.isFunction(v = __interp.variables.get(name))) {
v($a{arguments});
return;
}
}
super.$name($a{arguments});
};
}
var superFuncExpr:Expr = returns ? {
macro return super.$name($a{arguments});
} : {
macro super.$name($a{arguments});
};
var func:Function = {
ret: fun.ret,
params: fun.params.copy(),
expr: overrideExpr,
args: fun.args.copy()
};
var overrideField:Field = {
name: f.name,
access: f.access.copy(),
kind: FFun(func),
pos: Context.currentPos(),
doc: f.doc,
meta: f.meta.copy()
};
if (!overrideField.access.contains(AOverride))
overrideField.access.push(AOverride);
var superField:Field = {
name: '$FUNC_PREFIX${f.name}',
pos: Context.currentPos(),
kind: FFun({
ret: fun.ret,
params: fun.params.copy(),
expr: superFuncExpr,
args: fun.args.copy()
}),
access: f.access.copy()
};
if (superField.access.contains(AOverride))
superField.access.remove(AOverride);
shadowClass.fields.push(overrideField);
shadowClass.fields.push(superField);
definedFields.push(f.name);
default:
// fuck off >:(
}
}
var totalFields = definedFields.length;
if(totalFields == 0 && !hasNew) {
//Sys.println(cl.pack.join(".") + "." + cl.name + ", " + totalFields);
return fields;
}
shadowClass.kind = TDClass({
pack: cl.pack.copy(),
name: cl.name
}, [
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
], false, true, false);
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
var imports = Context.getLocalImports().copy();
Utils.setupMetas(shadowClass, imports);
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
// Adding hscript getters and setters
shadowClass.fields.push({
name: "__cachedFieldSet",
pos: Context.currentPos(),
kind: FVar(macro: Map<String, Dynamic>),
access: [APublic, AStatic]
});
shadowClass.fields.push({
name: "__interp",
pos: Context.currentPos(),
kind: FVar(macro: hscript.Interp),
access: [APublic]
});
/*
shadowClass.fields.push({
name: "__custom__variables",
pos: Context.currentPos(),
kind: FVar(macro: Map<String, Dynamic>),
access: [APublic]
});
*/
shadowClass.fields.push({
name: "__allowSetGet",
pos: Context.currentPos(),
kind: FVar(macro: Bool, macro true),
access: [APublic]
});
shadowClass.fields.push({
name: "__real_fields",
pos: Context.currentPos(),
kind: FVar(macro: Array<String>),
access: [APublic]
});
shadowClass.fields.push({
name: "__class__fields",
pos: Context.currentPos(),
kind: FVar(macro: Array<String>),
access: [APublic]
});
shadowClass.fields.push({
name: "__callGetter",
pos: Context.currentPos(),
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: macro {
return null;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
}
]
}),
access: [APublic]
});
shadowClass.fields.push({
name: "__callSetter",
pos: Context.currentPos(),
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: macro {
return null;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
},
{
name: "val",
opt: false,
meta: [],
type: macro: Dynamic
}
]
}),
access: [APublic]
});
// Todo: make it possible to override
if(cl.name == "FunkinShader" || cl.name == "CustomShader" || cl.name == "MultiThreadedScript") {
Context.defineModule(cl.module, [shadowClass], imports);
return fields;
}
var hasHgetInSuper = false;
var hasHsetInSuper = false;
if(cl.name == "CustomShader") {
hasHgetInSuper = hasHsetInSuper = true;
}
// TODO: somehow check the super super class
for(_field in [fields.copy(), superFields.copy()])
for(f in _field) {
if (f.name == "new")
continue;
if (f.name.startsWith(FUNC_PREFIX))
continue;
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern))
continue;
switch(f.kind) {
case FFun(fun):
if (fun.params != null && fun.params.length > 0)
continue;
if(!hasHgetInSuper)
hasHgetInSuper = f.name == "hget";
if(!hasHsetInSuper)
hasHsetInSuper = f.name == "hset";
if(hasHgetInSuper && hasHsetInSuper)
break;
default:
}
}
var hgetField = if(hasHgetInSuper) {
macro {
if (__interp != null) {
if(__class__fields.contains(name)) {
var v:Dynamic = __interp.variables.get(name);
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).callGetter(name);
return v;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.getField(name);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
return super.hget(name);
}
} else {
macro {
if (__interp != null) {
if(__class__fields.contains(name)) {
var v:Dynamic = __interp.variables.get(name);
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).get(ba);
return v;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.getField(name);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
return UnsafeReflect.getProperty(this, name);
}
}
var hsetField = if(hasHsetInSuper) {
macro {
if (__interp != null) {
if(__class__fields.contains(name)) {
var v:Dynamic = __interp.variables.get(name);
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).callSetter(name, val);
__interp.variables.set(name, val);
return val;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.setField(name, val);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
if(__real_fields.contains(name)) {
UnsafeReflect.setProperty(this, name, val);
return UnsafeReflect.field(this, name);
}
return super.hset(name, val);
}
} else {
macro {
if (__interp != null) {
if(__class__fields.contains(name)) {
var v:Dynamic = __interp.variables.get(name);
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).set(val, ba);
__interp.variables.set(name, val);
return val;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.setField(name, val);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
if(__real_fields.contains(name)) {
UnsafeReflect.setProperty(this, name, val);
return UnsafeReflect.field(this, name);
}
//__custom__variables.set(name, val);
return val;
}
}
//if(hasHsetInSuper || hasHgetInSuper) return fields;
//trace(cl.name);
shadowClass.fields.push({
name: "hset",
pos: Context.currentPos(),
access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: hsetField,
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
},
{
name: "val",
opt: false,
meta: [],
type: macro: Dynamic
}
]
})
});
shadowClass.fields.push({
name: "hget",
pos: Context.currentPos(),
access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: hgetField,
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
}
]
})
});
/*var p = new Printer();
var aa = p.printTypeDefinition(shadowClass);
if(aa.length < 5024)
trace(aa);
if(aa.indexOf("pack") >= 0)
if(cl.name == "FunkinShader")*/
Context.defineModule(cl.module, [shadowClass], imports);
}
return fields;
}
static function buildConstructor(constArgs:Array<FunctionArg>):Field {
var superCallArgs:Array<Expr> = [for (arg in constArgs) macro $i{arg.name}];
return {
name: 'new',
access: [APublic],
pos: Context.currentPos(),
kind: FFun({
args: constArgs,
expr: macro {
// Call the super constructor with appropriate args
super($a{superCallArgs});
if(__cachedFieldSet != null) {
for(k => v in __cachedFieldSet) {
Reflect.setProperty(this, k, v);
}
__cachedFieldSet.clear();
__cachedFieldSet = null;
}
}
}),
};
}
static function buildTyped(modules:Array<haxe.macro.Type.ModuleType>) {
for(m in modules) {
switch(m) {
case TClassDecl(c):
var cl = c.get();
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface)
continue;
if (cl.params.length == 0)
continue;
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC"))
buildTypedClass(cl);
default:
}
}
}
static function buildTypedClass(cl:ClassType) {}
static function buildShadowClass(cl:ClassType) {}
}
#else
class ClassExtendMacro {
public var usedClass:Class<Dynamic>;
public var className:String;
}
#end
+529
View File
@@ -0,0 +1,529 @@
package hscript.macros;
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import Type as StdType;
using Lambda;
/**
This class provides some utility methods to work with types. It is
best used through 'using haxe.macro.TypeTools' syntax and then provides
additional methods on haxe.macro.Type instances.
**/
#if hl
@:hlNative("macro")
#end
class FixedTypeTools {
static function nullable(complexType:ComplexType):ComplexType
return macro:Null<$complexType>;
public static function toField(cf:ClassField):Field {
function varAccessToString(va:VarAccess, getOrSet:String):String {
return {
switch (va) {
case AccNormal | AccCtor: "default";
case AccNo: "null";
case AccNever: "never";
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
case AccCall: getOrSet;
case AccInline: "default";
case AccRequire(_, _): "default";
}
}
}
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final")) {
access.push(AFinal);
}
if (cf.params.length != 0)
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
return {
name: cf.name,
doc: cf.doc,
access: access,
kind: switch ([cf.kind, cf.type]) {
case [FVar(read, write), ret]:
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
case [FMethod(_), TFun(args, ret)]:
Sys.println("Converting " + cf.name);
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: toComplexType(a.t),
}
],
ret: toComplexType(ret),
expr: null,
});
case [FMethod(_), TLazy(f)]:
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
switch(f()) {
case TFun(args, ret):
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: toComplexType(a.t),
}
],
ret: toComplexType(ret),
expr: null,
});
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
}
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
},
pos: cf.pos,
meta: cf.meta.get(),
}
}
public static function getAccess(cf:ClassField):Array<Access> {
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final") || cf.isFinal) {
access.push(AFinal);
}
switch ([cf.kind, cf.type]) {
case [FMethod(kind), TFun(_, _)] | [FMethod(kind), TLazy(_)]:
if(kind == MethInline)
access.push(AInline);
if(kind == MethDynamic)
access.push(ADynamic);
default:
}
return access;
}
public static function toSimpleField(cf:ClassField):Field {
function varAccessToString(va:VarAccess, getOrSet:String):String {
return {
switch (va) {
case AccNormal | AccCtor: "default";
case AccNo: "null";
case AccNever: "never";
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
case AccCall: getOrSet;
case AccInline: "default";
case AccRequire(_, _): "default";
}
}
}
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final")) {
access.push(AFinal);
}
if (cf.params.length != 0)
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
return {
name: cf.name,
doc: cf.doc,
access: access,
kind: switch ([cf.kind, cf.type]) {
case [FVar(read, write), ret]:
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
case [FMethod(_), TFun(args, ret)]:
Sys.println("Converting " + cf.name);
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: null,//toComplexType(a.t),
}
],
ret: null,//toComplexType(ret),
expr: null,
});
case [FMethod(_), TLazy(f)]:
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
switch(f()) {
case TFun(args, ret):
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: null,//toComplexType(a.t),
}
],
ret: null,//toComplexType(ret),
expr: null,
});
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
}
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
},
pos: cf.pos,
meta: cf.meta.get(),
}
}
/**
Returns a syntax-level type corresponding to Type `t`.
This function is mostly inverse to `ComplexTypeTools.toType`, but may
lose some information on types that do not have a corresponding syntax
version, such as monomorphs. In these cases, the result is null.
If `t` is null, an internal exception is thrown.
**/
public static function toComplexType(type:Null<Type>):Null<ComplexType>
return {
#if macro
Context.toComplexType(type);
#else
switch (type) {
case null:
null;
case TMono(_.get() => t):
t == null ? null : toComplexType(t);
case TEnum(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
case TInst(_.get() => classType, params):
switch (classType.kind) {
case KTypeParameter(_):
TPath({
name: classType.name,
pack: [],
});
default:
TPath(toTypePath(classType, params));
}
case TType(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
case TFun(args, ret):
TFunction([for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t)], toComplexType(ret));
case TAnonymous(_.get() => {fields: fields}):
TAnonymous([for (cf in fields) toField(cf)]);
case TDynamic(t):
if (t == null) {
macro:Dynamic;
} else {
var ct = toComplexType(t);
macro:Dynamic<$ct>;
}
case TLazy(f):
toComplexType(f());
case TAbstract(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
default:
throw "Invalid type";
}
#end
}
static function toTypeParam(type:Type):TypeParam
return {
switch (type) {
case TInst(_.get() => {kind: KExpr(e)}, _): TPExpr(e);
case _: TPType(toComplexType(type));
}
}
static function toTypePath(baseType:BaseType, params:Array<Type>):TypePath
return {
var module = baseType.module;
{
pack: baseType.pack,
name: module.substring(module.lastIndexOf(".") + 1),
sub: baseType.name,
params: [for (t in params) toTypeParam(t)],
}
}
#if macro
/**
Follows all typedefs of `t` to reach the actual type.
If `once` is true, this function does not call itself recursively,
otherwise it does. This can be useful in cases where intermediate
typedefs might be of interest.
Affected types are monomorphs `TMono` and typedefs `TType(t,pl)`.
If `t` is null, an internal exception is thrown.
Usage example with monomorphs:
var t = Context.typeof(macro null); // TMono(<mono>)
var ts = Context.typeof(macro "foo"); //TInst(String,[])
Context.unify(t, ts);
trace(t); // TMono(<mono>)
trace(t.follow()); //TInst(String,[])
Usage example with typedefs:
var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
trace(t); // TType(MyString,[])
trace(t.follow()); //TInst(String,[])
**/
static public inline function follow(t:Type, ?once:Bool):Type
return Context.follow(t, once);
/**
Like `follow`, follows all typedefs of `t` to reach the actual type.
Will however follow also abstracts to their underlying implementation,
if they are not a @:coreType abstract
If `t` is null, an internal exception is thrown.
Usage example:
var t = Context.typeof(macro new Map<String, String>());
trace(t); // TAbstract(Map,[TInst(String,[]),TInst(String,[])])
trace(t.followWithAbstracts()); // TInst(haxe.ds.StringMap, [TInst(String,[])])
**/
static public inline function followWithAbstracts(t:Type, once:Bool = false):Type
return Context.followWithAbstracts(t, once);
/**
Returns true if `t1` and `t2` unify, false otherwise.
**/
static public inline function unify(t1:Type, t2:Type):Bool
return Context.unify(t1, t2);
/**
Tries to extract the class instance stored inside `t`.
If `t` is a class instance `TInst(c,pl)`, c is returned.
If `t` is of a different type, an exception of type String is thrown.
If `t` is null, the result is null.
**/
static public function getClass(t:Type)
return t == null ? null : switch (follow(t)) {
case TInst(c, _): c.get();
case _: throw "Class instance expected";
}
/**
Tries to extract the enum instance stored inside `t`.
If `t` is an enum instance `TEnum(e,pl)`, e is returned.
If `t` is of a different type, an exception of type String is thrown.
If `t` is null, the result is null.
**/
static public function getEnum(t:Type)
return t == null ? null : switch (follow(t)) {
case TEnum(e, _): e.get();
case _: throw "Enum instance expected";
}
/**
Applies the type parameters `typeParameters` to type `t` with the given
types `concreteTypes`.
This function replaces occurrences of type parameters in `t` if they are
part of `typeParameters`. The array index of such a type parameter is
then used to lookup the concrete type in `concreteTypes`.
If `typeParameters.length` is not equal to `concreteTypes.length`, an
exception of type `String` is thrown.
If `typeParameters.length` is 0, `t` is returned unchanged.
If either argument is `null`, the result is unspecified.
**/
static public function applyTypeParameters(t:Type, typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>):Type {
if (typeParameters.length != concreteTypes.length)
throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types';
else if (typeParameters.length == 0)
return t;
#if (neko || eval)
return @:privateAccess Context.load("apply_params", 3)(typeParameters, concreteTypes, t);
#else
return applyParams(typeParameters, concreteTypes, t);
#end
}
#if !neko
private static function applyParams(typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>, t:Type):Type {
return null;
}
#end
/**
Transforms `t` by calling `f` on each of its subtypes.
If `t` is a compound type, `f` is called on each of its components.
Otherwise `t` is returned unchanged.
The following types are considered compound:
- TInst, TEnum, TType and TAbstract with type parameters
- TFun
- TAnonymous
If `t` or `f` are null, the result is unspecified.
**/
static public function map(t:Type, f:Type->Type):Type {
return switch (t) {
case TMono(tm):
switch (tm.get()) {
case null: t;
case var t: f(t);
}
case TEnum(_, []) | TInst(_, []) | TType(_, []):
t;
case TEnum(en, tl):
TEnum(en, tl.map(f));
case TInst(cl, tl):
TInst(cl, tl.map(f));
case TType(t2, tl):
TType(t2, tl.map(f));
case TAbstract(a, tl):
TAbstract(a, tl.map(f));
case TFun(args, ret):
TFun(args.map(function(arg) return {
name: arg.name,
opt: arg.opt,
t: f(arg.t)
}), f(ret));
case TAnonymous(an):
TAnonymous(@:privateAccess Context.load("map_anon_ref", 2)(an, f));
case TDynamic(t2):
t == t2 ? t : TDynamic(f(t2));
case TLazy(ft):
var ft = ft();
var ft2 = f(ft);
ft == ft2 ? t : ft2;
}
}
/**
Calls function `f` on each component of type `t`.
If `t` is not a compound type, this operation has no effect.
The following types are considered compound:
- TInst, TEnum, TType and TAbstract with type parameters
- TFun
- TAnonymous
If `t` or `f` are null, the result is unspecified.
**/
static public function iter(t:Type, f:Type->Void):Void {
switch (t) {
case TMono(tm):
var t = tm.get();
if (t != null)
f(t);
case TEnum(_, tl) | TInst(_, tl) | TType(_, tl) | TAbstract(_, tl):
for (t in tl)
f(t);
case TDynamic(t2):
if (t != t2)
f(t2);
case TLazy(ft):
f(ft());
case TAnonymous(an):
for (field in an.get().fields)
f(field.type);
case TFun(args, ret):
for (arg in args)
f(arg.t);
f(ret);
}
}
/**
Converts type `t` to a human-readable String representation.
**/
static public function toString(t:Type):String {
#if (neko || eval)
return @:privateAccess Context.load("s_type", 1)(t);
#else
return null;
#end
}
/**
Changes the name of the variable in the typed expression.
**/
static public function setVarName(t:TVar, name:String) {
@:privateAccess Context.load("set_var_name", 2)(t, name);
}
/**
Converts type `t` to `ModuleType`.
**/
static public function toModuleType(t:Type):ModuleType {
#if (neko || eval)
return @:privateAccess Context.load("type_to_module_type", 1)(t);
#else
return null;
#end
}
/**
Creates a type from the `ModuleType` argument.
**/
static public function fromModuleType(mt:ModuleType):Type {
#if (neko || eval)
return @:privateAccess Context.load("module_type_to_type", 1)(mt);
#else
return null;
#end
}
#end
/**
Resolves the field named `name` on class `c`.
If `isStatic` is true, the classes' static fields are checked. Otherwise
the classes' member fields are checked.
If the field is found, it is returned. Otherwise if `c` has a super
class, `findField` recursively checks that super class. Otherwise null
is returned.
If any argument is null, the result is unspecified.
**/
static public function findField(c:ClassType, name:String, isStatic:Bool = false):Null<ClassField> {
var field = (isStatic ? c.statics : c.fields).get().find(function(field) return field.name == name);
return if (field != null) field; else if (c.superClass != null) findField(c.superClass.t.get(), name, isStatic); else null;
}
}
@@ -1,107 +1,20 @@
package hscript;
package hscript.macros;
import Type.ValueType;
import haxe.macro.ComplexTypeTools;
#if macro
import haxe.macro.Type.ClassType;
import Type.ValueType;
import haxe.macro.Expr.Function;
import haxe.macro.Expr;
import haxe.macro.Context;
import haxe.macro.Printer;
import haxe.macro.Compiler;
import haxe.macro.Type.MetaAccess;
import haxe.macro.Type.FieldKind;
import haxe.macro.Type.ClassField;
import haxe.macro.Type.VarAccess;
import haxe.macro.*;
using StringTools;
class UsingHandler {
public var usedClass:Class<Dynamic>;
public var className:String;
public function new(className:String, usedClass:Class<Dynamic>) {
this.className = className;
this.usedClass = usedClass;
}
public static function init() {
Compiler.addGlobalMetadata('flixel', '@:build(hscript.UsingHandler.build())');
Compiler.addGlobalMetadata('openfl.display.BlendMode', '@:build(hscript.UsingHandler.build())');
}
public static function build():Array<Field> {
var fields = Context.getBuildFields();
var clRef = Context.getLocalClass();
if (clRef == null) return fields;
var cl = clRef.get();
if (/* cl.name.startsWith("Flx") && */ cl.name.endsWith("_Impl_") && cl.params.length <= 0 && !cl.meta.has(":multiType")) {
var metas = cl.meta.get();
var shadowClass = macro class {
};
shadowClass.kind = TDClass();
shadowClass.params = switch(cl.params.length) {
case 0:
null;
case 1:
[
{
name: "T",
}
];
default:
[for(k=>e in cl.params) {
name: "T" + Std.int(k+1)
}];
};
shadowClass.name = '${cl.name.substr(0, cl.name.length - 6)}_HSC';
var imports = Context.getLocalImports().copy();
setupMetas(shadowClass, imports);
for(f in fields)
switch(f.kind) {
case FFun(fun):
if (f.access.contains(AStatic)) {
if (fun.expr != null)
shadowClass.fields.push(f);
}
case FProp(get, set, t, e):
if (get == "default" && (set == "never" || set == "null"))
shadowClass.fields.push(f);
case FVar(t, e):
if (f.access.contains(AStatic) || cl.meta.has(":enum") || f.name.toUpperCase() == f.name) {
var name:String = f.name;
var enumType:String = cl.name;
var pack = cl.module.split(".");
pack.pop();
var complexType:ComplexType = t != null ? t : (name.contains("REGEX") ? TPath({
name: "EReg",
pack: []
}) : TPath({
name: cl.name.substr(0, cl.name.length - 6),
pack: pack}));
var field:Field = {
pos: f.pos,
name: f.name,
meta: f.meta,
kind: FVar(complexType, {
pos: Context.currentPos(),
expr: ECast(e, complexType)
}),
doc: f.doc,
access: [APublic, AStatic]
}
shadowClass.fields.push(field);
}
default:
}
Context.defineModule(cl.module + "_HSC", [shadowClass], imports);
}
return fields;
}
static function fixStdTypes(type:ComplexType) {
class Utils {
public static function fixStdTypes(type:ComplexType) {
switch(type) {
case TPath({name: "StdTypes"}):
var a:TypePath = type.getParameters()[0];
@@ -113,16 +26,9 @@ class UsingHandler {
}
public static function setupMetas(shadowClass:TypeDefinition, imports) {
shadowClass.meta = [{
name: ':dox',
pos: Context.currentPos(),
params: [
{
expr: EConst(CIdent("hide")),
pos: Context.currentPos()
}
]
}];
shadowClass.meta = [];
shadowClass.meta.push({name: ":dox", params: [macro hide], pos: Context.currentPos()});
shadowClass.meta.push({name: ":noCompletion", params: [], pos: Context.currentPos()});
var module = Context.getModule(Context.getLocalModule());
for(t in module) {
switch(t) {
@@ -300,9 +206,4 @@ class UsingHandler {
}
}
}
#else
class UsingHandler {
public var usedClass:Class<Dynamic>;
public var className:String;
}
#end
+184
View File
@@ -0,0 +1,184 @@
package hscript.utils;
#if cpp
import cpp.ObjectType;
#end
@:analyzer(ignore)
class UnsafeReflect {
public #if !cpp inline #end static function hasField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return o.__HasField(field);
}
#else
return Reflect.hasField(o, field);
#end
}
public #if !cpp inline #end static function field(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.field(o, field);
#end
}
public #if !cpp inline #end static function setField(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.setField(o, field, value);
#end
}
public #if !cpp inline #end static function getProperty(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccAlways"));
}
#else
return Reflect.getProperty(o, field);
#end
}
public #if !cpp inline #end static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccAlways"));
}
#else
Reflect.setProperty(o, field, value);
#end
}
public #if !cpp inline #end static function callFieldUnsafe(o:Dynamic, field:String, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
var func:Dynamic = o.__Field(field, untyped __cpp__("::hx::paccDynamic"));
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, Reflect.field(o, field), args);
#end
}
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
return Reflect.callMethod(o, func, args);
}
public #if !cpp inline #end static function callMethodSafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
if (func == null)
throw cpp.ErrorConstants.nullFunctionPointer;
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public #if !cpp inline #end static function callMethodUnsafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public inline static function fields(o:Dynamic):Array<String>
return Reflect.fields(o);
/*untyped {
if (o == null)
return new Array();
var a:Array<String> = [];
o.__GetFields(a);
return a;
}*/
public #if !cpp inline #end static function isFunction(f:Dynamic):Bool
#if cpp
untyped {
return f.__GetType() == ObjectType.vtFunction;
}
#else
return Reflect.isFunction(f);
#end
public inline static function compare<T>(a:T, b:T):Int {
return Reflect.compare(a, b);
//return (a == b) ? 0 : (((a : Dynamic) > (b : Dynamic)) ? 1 : -1);
}
public inline static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
return Reflect.compareMethods(f1, f2);
}
public #if !cpp inline #end static function isObject(v:Dynamic):Bool {
#if cpp
untyped {
var t:Int = v.__GetType();
return t == ObjectType.vtObject || t == ObjectType.vtClass || t == ObjectType.vtString || t == ObjectType.vtArray;
}
#else
return Reflect.isObject(v);
#end
}
public #if !cpp inline #end static function isEnumValue(v:Dynamic):Bool {
#if cpp
untyped {
return v.__GetType() == ObjectType.vtEnum;
}
#else
return Reflect.isEnumValue(v);
#end
}
public #if !cpp inline #end static function deleteField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return untyped __global__.__hxcpp_anon_remove(o, field);
}
#else
return Reflect.deleteField(o, field);
#end
}
public #if !cpp inline #end static function copy<T>(o:Null<T>):Null<T> {
#if cpp
if (o == null)
return null;
var t:Int = untyped o.__GetType();
if (t == ObjectType.vtString)
return o;
if (t == ObjectType.vtArray)
return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))();
var o2:Dynamic = {};
for (f in UnsafeReflect.fields(o))
UnsafeReflect.setField(o2, f, UnsafeReflect.field(o, f));
return o2;
#else
return Reflect.copy(o);
#end
}
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
#if cpp
return untyped __global__.__hxcpp_create_var_args(f);
#else
return inline Reflect.makeVarArgs(f);
#end
}
}
+82
View File
@@ -0,0 +1,82 @@
package hscript.utils;
@:structInit
class UsingEntry {
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
public var fields:Array<String>;
public function hasField(name:String) {
return fields.contains(name);
}
}
/**
* Special class that handles static extension function calls.
*
* A static extension allows pseudo-extending
* existing types without modifying their source.
* In Haxe this is achieved by declaring a static method with a first argument
* of the extending type and then bringing the defining class into context through `using`.
*
* Example:
* ```haxe
* class IntExtender {
* static public function triple(i:Int) {
* return i * 3;
* }
* }
*
* using IntExtender;
*
* trace(12.triple()); // 36
* ```
*
* @see https://haxe.org/manual/lf-static-extension.html
*/
class UsingHandler {
// Predefined static extension classes
public static final defaultExtension:Map<String, UsingEntry> = [
"StringTools" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L45
fields: Type.getClassFields(StringTools),
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if (f == "isEof") // has @:noUsing
return null;
return switch (Type.typeof(o)) {
case TInt if (f == 'hex'):
StringTools.hex(o, args[0]);
case TClass(String):
var field = UnsafeReflect.field(StringTools, f);
if (UnsafeReflect.isFunction(field)) UnsafeReflect.callMethodUnsafe(StringTools, field, [o].concat(args)); else null;
default:
null;
}
}
},
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
fields: Type.getClassFields(Lambda),
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if (o != null && o.iterator != null) {
var field = UnsafeReflect.field(Lambda, f);
if (UnsafeReflect.isFunction(field)) {
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
}
}
return null;
}
}
];
@:allow(hscript.CustomClass)
@:allow(hscript.CustomClassHandler)
public var usingEntries(default, null):Map<String, UsingEntry> = [];
public function new() {}
public function registerEntry(name:String, entry:Dynamic->String->Array<Dynamic>->Dynamic, fields:Array<String>) {
usingEntries.set(name, {call: entry, fields: fields});
}
public inline function entryExists(name:String):Bool {
return usingEntries.exists(name);
}
}