Skip to content

hetu-script/hetu-script-autobinding

Repository files navigation

Autobinding Codes Generator for Hetu Script Language

Introduction

A Dart binding code generator for Hetu script language. You can generate glue codes from Flutter/Dart library, your codes, or any packages. Then you can use them in the Hetu script:

The classes and enums that need to be used in the scripts:

@HTBinding()
enum Ingredients {
   Apple,
   Banana,
   Cinnamon,
}

@HTBinding()
class RootAssetBundle extends services.AssetBundle{
   @override
   Future<services.ByteData> load(String key) {
      return services.rootBundle.load(key);
   }

   @override
   Future<String> loadString(String key, {bool cache = true}) {
      return services.rootBundle.loadString(key, cache: cache);
   }

   @override
   Future<T> loadStructuredData<T>(String key, Future<T> Function(String value) parser) {
      return services.rootBundle.loadStructuredData(key, parser);
   }
}

@HTBinding()
class ScriptHelper {
   ScriptHelper._();

   static void futureHandler(HT_Function callback, Future future) {
      future.then((value) {
         try {
            callback.call(positionalArgs: [value]);
         }
         catch(err, stack) {
            print('$err\n$stack');
         }
      });
   }
}

The binding codes are generated by this tool:

class IngredientsClassBinding extends HT_ExternNamespace {
   @override
   dynamic fetch(String id) {
      switch (id) {
         case 'Apple':
            return Ingredients.Apple;
         case 'Banana':
            return Ingredients.Banana;
         case 'Cinnamon':
            return Ingredients.Cinnamon;
         default:
            throw HTErr_Undefined(id);
      }
   }
}

class RootAssetBundleClassBinding extends HT_ExternNamespace {
   @override
   dynamic fetch(String id) {
      switch (id) {
         case 'RootAssetBundle':
            return () => RootAssetBundleObjectBinding(RootAssetBundle());
         default:
            throw HTErr_Undefined(id);
      }
   }
}

class RootAssetBundleObjectBinding extends HT_ExternObject<RootAssetBundle> {
   RootAssetBundleObjectBinding(RootAssetBundle value) : super(value);

   @override
   final typeid = HT_TypeId('RootAssetBundle');

   @override
   dynamic fetch(String id) {
      switch (id) {
         case 'load':
            return externObject.load;
         case 'loadString':
            return externObject.loadString;
         case 'loadStructuredData':
            return externObject.loadStructuredData;
         default:
            throw HTErr_Undefined(id);
      }
   }

}

class ScriptHelperClassBinding extends HT_ExternNamespace {
   @override
   dynamic fetch(String id) {
      switch (id) {
         case 'futureHandler':
            return (callback, future) => ScriptHelper.futureHandler(callback, future);
         default:
            throw HTErr_Undefined(id);
      }
   }
}

And scripts are generated too:

external class Ingredients {
    static var Apple
    static var Banana
    static var Cinnamon
}
external class RootAssetBundle {
    construct
    fun load
    fun loadString
    fun loadStructuredData
}
external class ScriptHelper {
    static fun futureHandler (callback, future)
}

Then you can use the dart class from the script:

fun handleString(string) {
  print(string)
}

fun main() {
   print(Ingredients.Banana)
   var r = RootAssetBundle()   
   var strFuture = r.loadString('assets/data/test.txt')   
   ScriptHelper.futureHandler(handleString, strFuture)
}

Build

You can build the executable file by the script: build.sh

Generate the binding codes

  1. Flutter/Dart Framework (-f)

    Should only point to the root of the Flutter repository folder (containing 'packages' folder)

  2. Third-party packages (-p)

    Could point to any packages' lib folder or the root of the repository folder.

    You can find the packages from ~/.pub-cache/hosted/pub.dartlang.org/ or from a repository folder.

  3. Your own codes (-u)

    Point to the folder that containing your codes. You should also add a @HTBinding() annotation to your custom class/enum for binding:

@HTBinding()
class CustomClass {
  var m;
}

@HTBinding()
enum CustomEnum { 
  a,
  b,
}

More options could be found by flagging -h:

./bin/ht-binding-generator -h

-u, --user-lib-paths=<path1, path2, ...>                                        
  Will iterate over all the folders recursively.

-p, --package-lib-paths=<package1/lib, package2/lib, ...>                       
  Will iterate over all the package cache folders.

-f, --flutter-lib-path=<flutter-framework-path>                                 
  Will iterate the Flutter/Dart framework recursively. The path should point to the Flutter root folder.

-o, --output                                                                    
  The output path for .dart code generation and .json intermediate files.
  
-s, --script-output                                                             
  The output path for .ht code generation.
                                                                           
-j, --[no-]json-export                                                          
  Whether to export the intermediate JSON files for diagnostics.

-h, --[no-]help       
                                                        
-i, --ignores=<ignored-file-name, ignored-file-name:ignored-class-name, ...>    
  The files/classes from this list will be ignored during the code generation.
  
-w, --whitelist=<whitelist-file-name, whitelist-file-name2, ...>                
  Only the files from the list will be parsed, working with 'ignores' too.

Initialize the binding

call loadAutoBinding and loadAutoBindingScripts on a HetuScriptBinding() will initialize all definitions for Hetu script usage.

  void initBinding() async {
    var hetu = HTAstInterpreter(readFileMethod: (path) {
      return rootBundle.loadString(path);
    });
    var binding = HetuScriptBinding();
    binding.loadAutoBinding(hetu);
    binding.loadAutoBindingScripts(hetu, 'assets/path').then((value) {
      print('initialization done.');
    });
  }

Manual binding

You can also add manual-binding codes by subclassing HetuScriptBindingclass, and use ManualBinding instead of HetuScriptBinding.

The auto-binding codes will be loaded by calling the super.

class ManualBinding extends HetuScriptBinding {
  @override
  void loadAutoBinding(HTAstInterpreter interpreter) {
    super.loadAutoBinding(interpreter);
    var bindings = {
      'RootAssetBundle' : RootAssetBundleClassBinding(),
      'ScriptHelper' : ScriptHelperClassBinding(),
      'ExternalAssetBundle' : ExternalAssetBundleClassBinding(),
    };
    bindings.forEach((key, value) {
      interpreter.bindExternalNamespace(key, value);
    });
  }

  @override
  Future loadAutoBindingScripts(HTAstInterpreter interpreter, String path) {
    var future = super.loadAutoBindingScripts(interpreter, path);
    var futures = <Future>[];
    futures.add(future);
    futures.add(interpreter.evalf('$path/user/root_asset_bundle.ht'));
    futures.add(interpreter.evalf('$path/user/external_asset_bundle.ht'));
    return Future.wait(futures);
  }
}

About

Auto binding codes generator for Hetu script language. Generate from Flutter/Dart library, your codes, or any packages and use them in the scripts.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •