This commit is contained in:
Dante
2026-05-21 23:40:20 -07:00
parent 3e2915dff7
commit 877a69d844
5737 changed files with 29796 additions and 1589684 deletions

View File

@ -52,6 +52,10 @@ enum abstract ModuleCheckPolicy(Int) {
of the current module file.
**/
var NoCheckShadowing = 3;
/**
Retype the module's contents if its file is invalidated. This is currently experimental.
**/
var Retype = 4;
}
enum abstract ContextOptions(Int) {
@ -97,7 +101,9 @@ class CompilationServer {
**/
static public function setModuleCheckPolicy(pathFilters:Array<String>, policy:Array<ModuleCheckPolicy>, ?recursive = true,
?contextOptions:ContextOptions = NormalContext) {
@:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions);
Context.onAfterInitMacros(() -> {
@:privateAccess Compiler.load("server_add_module_check_policy", 4)(pathFilters, policy, recursive, contextOptions);
});
}
/**

View File

@ -22,6 +22,7 @@
package haxe.macro;
import haxe.display.Display;
import haxe.macro.Expr;
/**
@ -69,13 +70,16 @@ class Compiler {
**/
public static function define(flag:String, ?value:String) {
#if (neko || eval)
Context.assertInitMacro();
load("define", 2)(flag, value);
#end
}
#if (!neko && !eval)
@:deprecated("Will be removed in Haxe 5.0")
private static function typePatch(cl:String, f:String, stat:Bool, t:String) {}
@:deprecated("Will be removed in Haxe 5.0")
private static function metaPatch(meta:String, cl:String, f:String, stat:Bool) {}
private static function addGlobalMetadataImpl(pathFilter:String, meta:String, recursive:Bool, toTypes:Bool, toFields:Bool) {}
@ -85,13 +89,18 @@ class Compiler {
Removes a (static) field from a given class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function removeField(className:String, field:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (!ident.match(field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("type_patch", 4)(className, field, isStatic == true, null));
#else
load("type_patch", 4)(className, field, isStatic == true, null);
#end
#else
typePatch(className, field, isStatic == true, null);
#end
@ -101,13 +110,18 @@ class Compiler {
Set the type of a (static) field at a given class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function setFieldType(className:String, field:String, type:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (!ident.match((field.charAt(0) == "$") ? field.substr(1) : field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("type_patch", 4)(className, field, isStatic == true, type));
#else
load("type_patch", 4)(className, field, isStatic == true, type);
#end
#else
typePatch(className, field, isStatic == true, type);
#end
@ -117,13 +131,18 @@ class Compiler {
Add metadata to a (static) field or class by name.
An error is thrown when `className` or `field` is invalid.
**/
@:deprecated
public static function addMetadata(meta:String, className:String, ?field:String, ?isStatic:Bool) {
if (!path.match(className))
throw "Invalid " + className;
if (field != null && !ident.match(field))
throw "Invalid " + field;
#if (neko || eval)
#if haxe_next
Context.onAfterInitMacros(() -> load("meta_patch", 4)(meta, className, field, isStatic == true));
#else
load("meta_patch", 4)(meta, className, field, isStatic == true);
#end
#else
metaPatch(meta, className, field, isStatic == true);
#end
@ -136,6 +155,7 @@ class Compiler {
**/
public static function addClassPath(path:String) {
#if (neko || eval)
Context.assertInitMacro();
load("add_class_path", 1)(path);
#end
}
@ -162,6 +182,19 @@ class Compiler {
#end
}
/**
Returns all the configuration settings applied to the compiler.
Usage of this function outside a macro context returns `null`.
**/
public static function getConfiguration():Null<CompilerConfiguration> {
#if (neko || eval)
return load("get_configuration", 0)();
#else
return null;
#end
}
/**
Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
@ -169,6 +202,7 @@ class Compiler {
**/
public static function addNativeLib(name:String) {
#if (neko || eval)
Context.assertInitMacro();
load("add_native_lib", 1)(name);
#end
}
@ -192,6 +226,8 @@ class Compiler {
If you want to specify a different set of paths to search for modules, you can use the optional
argument `classPath`.
Usage of this function outside of initialization macros is deprecated and may cause compilation server issues.
@param pack The package dot-path as String. Use `''` to include the root package.
@param rec If true, recursively adds all sub-packages.
@param ignore Array of module names to ignore for inclusion.
@ -201,69 +237,74 @@ class Compiler {
@param strict If true and given package wasn't found in any of class paths, fail with an error.
**/
public static function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
var ignoreWildcard:Array<String> = [];
var ignoreString:Array<String> = [];
if (ignore != null) {
for (ignoreRule in ignore) {
if (StringTools.endsWith(ignoreRule, "*")) {
ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
} else {
ignoreString.push(ignoreRule);
function include(pack:String, ?rec = true, ?ignore:Array<String>, ?classPaths:Array<String>, strict = false) {
var ignoreWildcard:Array<String> = [];
var ignoreString:Array<String> = [];
if (ignore != null) {
for (ignoreRule in ignore) {
if (StringTools.endsWith(ignoreRule, "*")) {
ignoreWildcard.push(ignoreRule.substr(0, ignoreRule.length - 1));
} else {
ignoreString.push(ignoreRule);
}
}
}
}
var skip = if (ignore == null) {
function(c) return false;
} else {
function(c:String) {
if (Lambda.has(ignoreString, c))
return true;
for (ignoreRule in ignoreWildcard)
if (StringTools.startsWith(c, ignoreRule))
var skip = if (ignore == null) {
function(c) return false;
} else {
function(c:String) {
if (Lambda.has(ignoreString, c))
return true;
return false;
for (ignoreRule in ignoreWildcard)
if (StringTools.startsWith(c, ignoreRule))
return true;
return false;
}
}
var displayValue = Context.definedValue("display");
if (classPaths == null) {
classPaths = Context.getClassPath();
// do not force inclusion when using completion
switch (displayValue) {
case null:
case "usage":
case _:
return;
}
// normalize class path
for (i in 0...classPaths.length) {
var cp = StringTools.replace(classPaths[i], "\\", "/");
if (StringTools.endsWith(cp, "/"))
cp = cp.substr(0, -1);
if (cp == "")
cp = ".";
classPaths[i] = cp;
}
}
var prefix = pack == '' ? '' : pack + '.';
var found = false;
for (cp in classPaths) {
var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
continue;
found = true;
for (file in sys.FileSystem.readDirectory(path)) {
if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
if( file == "import.hx" ) continue;
var cl = prefix + file.substr(0, file.length - 3);
if (skip(cl))
continue;
Context.getModule(cl);
} else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
include(prefix + file, true, ignore, classPaths);
}
}
if (strict && !found)
Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
}
var displayValue = Context.definedValue("display");
if (classPaths == null) {
classPaths = Context.getClassPath();
// do not force inclusion when using completion
switch (displayValue) {
case null:
case "usage":
case _:
return;
}
// normalize class path
for (i in 0...classPaths.length) {
var cp = StringTools.replace(classPaths[i], "\\", "/");
if (StringTools.endsWith(cp, "/"))
cp = cp.substr(0, -1);
if (cp == "")
cp = ".";
classPaths[i] = cp;
}
}
var prefix = pack == '' ? '' : pack + '.';
var found = false;
for (cp in classPaths) {
var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/");
if (!sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path))
continue;
found = true;
for (file in sys.FileSystem.readDirectory(path)) {
if (StringTools.endsWith(file, ".hx") && file.substr(0, file.length - 3).indexOf(".") < 0) {
if( file == "import.hx" ) continue;
var cl = prefix + file.substr(0, file.length - 3);
if (skip(cl))
continue;
Context.getModule(cl);
} else if (rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file))
include(prefix + file, true, ignore, classPaths);
}
}
if (strict && !found)
Context.error('Package "$pack" was not found in any of class paths', Context.currentPos());
Context.assertInitMacro();
Context.onAfterInitMacros(() -> include(pack, rec, ignore, classPaths, strict));
}
/**
@ -340,6 +381,7 @@ class Compiler {
/**
Load a type patch file that can modify the field types within declared classes and enums.
**/
@:deprecated("Will be removed in Haxe 5.0")
public static function patchTypes(file:String):Void {
var file = Context.resolvePath(file);
var f = sys.io.File.read(file, true);
@ -450,6 +492,44 @@ class Compiler {
#end
}
/**
Reference a json file describing user-defined metadata
See https://github.com/HaxeFoundation/haxe/blob/development/src-json/meta.json
**/
public static function registerMetadataDescriptionFile(path:String, ?source:String):Void {
var f = sys.io.File.getContent(path);
var content:Array<MetadataDescription> = haxe.Json.parse(f);
for (m in content) registerCustomMetadata(m, source);
}
/**
Reference a json file describing user-defined defines
See https://github.com/HaxeFoundation/haxe/blob/development/src-json/define.json
**/
public static function registerDefinesDescriptionFile(path:String, ?source:String):Void {
var f = sys.io.File.getContent(path);
var content:Array<DefineDescription> = haxe.Json.parse(f);
for (d in content) registerCustomDefine(d, source);
}
/**
Register a custom medatada for documentation and completion purposes
**/
public static function registerCustomMetadata(meta:MetadataDescription, ?source:String):Void {
#if (neko || eval)
load("register_metadata_impl", 2)(meta, source);
#end
}
/**
Register a custom define for documentation purposes
**/
public static function registerCustomDefine(define:DefineDescription, ?source:String):Void {
#if (neko || eval)
load("register_define_impl", 2)(define, source);
#end
}
/**
Change the default JS output by using a custom generator callback
**/
@ -577,3 +657,108 @@ enum abstract NullSafetyMode(String) to String {
**/
var StrictThreaded;
}
typedef MetadataDescription = {
final metadata:String;
final doc:String;
/**
External resources for more information about this metadata.
**/
@:optional final links:Array<String>;
/**
List (small description) of parameters that this metadata accepts.
**/
@:optional final params:Array<String>;
/**
Haxe target(s) for which this metadata is used.
**/
@:optional final platforms:Array<Platform>;
/**
Places where this metadata can be applied.
**/
@:optional final targets:Array<MetadataTarget>;
}
typedef DefineDescription = {
final define:String;
final doc:String;
/**
External resources for more information about this define.
**/
@:optional final links:Array<String>;
/**
List (small description) of parameters that this define accepts.
**/
@:optional final params:Array<String>;
/**
Haxe target(s) for which this define is used.
**/
@:optional final platforms:Array<Platform>;
}
typedef CompilerConfiguration = {
/**
The version integer of the current Haxe compiler build.
**/
final version:Int;
/**
Returns an array of the arguments passed to the compiler from either the `.hxml` file or the command line.
**/
final args:Array<String>;
/**
If `--debug` mode is enabled, this is `true`.
**/
final debug:Bool;
/**
If `--verbose` mode is enabled, this is `true`.
**/
final verbose:Bool;
/**
If `--no-opt` is enabled, this is `false`.
**/
final foptimize:Bool;
/**
The target platform.
**/
final platform:haxe.display.Display.Platform;
/**
The compilation configuration for the target platform.
**/
final platformConfig:PlatformConfig;
/**
A list of paths being used for the standard library.
**/
final stdPath:Array<String>;
/**
The path of the class passed using the `-main` argument.
**/
final mainClass:TypePath;
/**
Special access rules for packages depending on the compiler configuration.
For example, the "java" package is "Forbidden" when the target platform is Python.
**/
final packageRules:Map<String,PackageRule>;
}
enum PackageRule {
Forbidden;
Directory(path:String);
Remap(path:String);
}

View File

@ -39,7 +39,7 @@ class ComplexTypeTools {
static public function toString(c:ComplexType):String
return new Printer().printComplexType(c);
#if (macro || display)
#if macro
/**
Returns a type corresponding to `c`.

View File

@ -47,45 +47,61 @@ class Context {
Displays a compilation error `msg` at the given `Position` `pos`
and aborts the current macro call.
**/
public static function error(msg:String, pos:Position):Dynamic {
return load("error", 2)(msg, pos);
public static function error(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
return load("error", 2)(msg, pos, depth);
}
/**
Displays a compilation error `msg` at the given `Position` `pos`
and aborts the compilation.
**/
public static function fatalError(msg:String, pos:Position):Dynamic {
return load("fatal_error", 2)(msg, pos);
public static function fatalError(msg:String, pos:Position, ?depth:Int = 0):Dynamic {
return load("fatal_error", 2)(msg, pos, depth);
}
/**
Displays a compilation error `msg` at the given `Position` `pos`
without aborting the current macro call.
**/
public static function reportError(msg:String, pos:Position, ?depth:Int = 0):Void {
load("report_error", 2)(msg, pos, depth);
}
/**
Displays a compilation warning `msg` at the given `Position` `pos`.
**/
public static function warning(msg:String, pos:Position) {
load("warning", 2)(msg, pos);
public static function warning(msg:String, pos:Position, ?depth:Int = 0) {
load("warning", 2)(msg, pos, depth);
}
/**
Displays a compilation info `msg` at the given `Position` `pos`.
**/
public static function info(msg:String, pos:Position) {
load("info", 2)(msg, pos);
public static function info(msg:String, pos:Position, ?depth:Int = 0) {
load("info", 2)(msg, pos, depth);
}
/**
Gets a list of all current compilation info/warning messages.
**/
public static function getMessages() : Array<Message> {
return load("get_messages",0)();
public static function getMessages():Array<Message> {
return load("get_messages", 0)();
}
/**
Filters all current info/warning messages. Filtered out messages will
not be displayed by the compiler.
**/
public static function filterMessages( predicate : Message -> Bool ) {
load("filter_messages",1)(predicate);
public static function filterMessages(predicate:Message->Bool) {
load("filter_messages", 1)(predicate);
}
/**
Check if compiler is past initializations macros or not.
When it is, configuration phase is over and parsing/typing can start.
**/
public static function initMacrosDone():Bool {
return load("init_macros_done", 0)();
}
/**
@ -119,6 +135,10 @@ class Context {
return load("contains_display_position", 1)(pos);
}
public static function getDisplayMode():DisplayMode {
return load("get_display_mode", 0)();
}
/**
Returns the position at which the macro was called.
**/
@ -126,6 +146,14 @@ class Context {
return load("current_pos", 0)();
}
/**
Get the call stack (excluding the call to `Context.getMacroStack()`
that led to current macro.
**/
public static function getMacroStack():Array<Position> {
return load("get_macro_stack", 0)();
}
/**
Returns the type which is expected at the place the macro is called.
@ -136,6 +164,7 @@ class Context {
macro is not an expression-macro.
**/
public static function getExpectedType():Null<Type> {
assertInitMacrosDone(false);
return load("get_expected_type", 0)();
}
@ -146,6 +175,7 @@ class Context {
Returns `null` if the current macro is not a `@:genericBuild` macro.
**/
public static function getCallArguments():Null<Array<Expr>> {
assertInitMacrosDone(false);
return load("get_call_arguments", 0)();
}
@ -155,6 +185,7 @@ class Context {
If no such class exists, `null` is returned.
**/
public static function getLocalClass():Null<Type.Ref<Type.ClassType>> {
assertInitMacrosDone(false);
var l:Type = load("get_local_type", 0)();
if (l == null)
return null;
@ -168,6 +199,7 @@ class Context {
Returns the current module path in/on which the macro was called.
**/
public static function getLocalModule():String {
assertInitMacrosDone(false);
return load("get_local_module", 0)();
}
@ -177,6 +209,7 @@ class Context {
If no such type exists, `null` is returned.
**/
public static function getLocalType():Null<Type> {
assertInitMacrosDone(false);
return load("get_local_type", 0)();
}
@ -186,6 +219,7 @@ class Context {
If no such method exists, `null` is returned.
**/
public static function getLocalMethod():Null<String> {
assertInitMacrosDone(false);
return load("get_local_method", 0)();
}
@ -196,6 +230,7 @@ class Context {
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalUsing():Array<Type.Ref<Type.ClassType>> {
assertInitMacrosDone(false);
return load("get_local_using", 0)();
}
@ -205,6 +240,7 @@ class Context {
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalImports():Array<ImportExpr> {
assertInitMacrosDone(false);
return load("get_local_imports", 0)();
}
@ -219,6 +255,7 @@ class Context {
**/
@:deprecated("Use Context.getLocalTVars() instead")
public static function getLocalVars():Map<String, Type> {
assertInitMacrosDone(false);
return load("local_vars", 1)(false);
}
@ -227,6 +264,7 @@ class Context {
of `Type`.
**/
public static function getLocalTVars():Map<String, Type.TVar> {
assertInitMacrosDone(false);
return load("local_vars", 1)(true);
}
@ -279,8 +317,13 @@ class Context {
declared class path has priority.
If no type can be found, an exception of type `String` is thrown.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getType(name:String):Type {
assertInitMacrosDone();
return load("get_type", 1)(name);
}
@ -292,11 +335,44 @@ class Context {
declared class path has priority.
If no module can be found, an exception of type `String` is thrown.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getModule(name:String):Array<Type> {
assertInitMacrosDone();
return load("get_module", 1)(name);
}
/**
Returns the typed expression of the call to the main function.
This function will only work in the generation phase. Any calls
made outside a function passed to `haxe.macro.Context.onGenerate`
or `haxe.macro.Context.onAfterGenerate` will return `null`.
**/
public static function getMainExpr():Null<TypedExpr> {
return load("get_main_expr", 0)();
}
/**
Returns an array of module types to be generated in the output.
This list may change depending on the phase of compilation and
should not be treated as conclusive until the generation phase.
Modifying the returned array has no effect on the compilation.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getAllModuleTypes():Array<haxe.macro.Type.ModuleType> {
assertInitMacrosDone();
return load("get_module_types", 0)();
}
/**
Parses `expr` as Haxe code, returning the corresponding AST.
@ -334,6 +410,7 @@ class Context {
Returns a hashed MD5 signature of value `v`.
**/
public static function signature(v:Dynamic):String {
assertInitMacrosDone(false);
return load("signature", 1)(v);
}
@ -382,6 +459,22 @@ class Context {
load("on_after_typing", 1)(callback);
}
/**
Adds a callback function `callback` which is invoked after the compiler
is done running initialization macros, when typing begins.
`onAfterInitMacros` should be used to delay typer-dependant code from
your initalization macros, to properly separate configuration phase and
actual typing.
**/
public static function onAfterInitMacros(callback:Void->Void):Void {
if (Context.initMacrosDone()) {
callback();
} else {
load("on_after_init_macros", 1)(callback);
}
}
/**
Adds a callback function `callback` which is invoked when a type name
cannot be resolved.
@ -399,8 +492,13 @@ class Context {
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeof(e:Expr):Type {
assertInitMacrosDone();
return load("typeof", 1)(e);
}
@ -408,9 +506,17 @@ class Context {
Types expression `e` and returns the corresponding `TypedExpr`.
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
caught using `try ... catch`. Note that not all compiler errors can
be caught this way because the compiler might delay various checks
to a later stage, at which point the exception handler is no longer
active.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeExpr(e:Expr):TypedExpr {
assertInitMacrosDone();
return load("type_expr", 1)(e);
}
@ -420,8 +526,13 @@ class Context {
Resolving the type may result in a compiler error which can be
caught using `try ... catch`.
Resolution is performed based on the current context in which the macro is called.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function resolveType(t:ComplexType, p:Position):Type {
assertInitMacrosDone();
return load("resolve_type", 2)(t, p);
}
@ -436,8 +547,13 @@ class Context {
/**
Tries to unify `t1` and `t2` and returns `true` if successful.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function unify(t1:Type, t2:Type):Bool {
assertInitMacrosDone();
return load("unify", 2)(t1, t2);
}
@ -445,8 +561,13 @@ class Context {
Follows a type.
See `haxe.macro.TypeTools.follow` for details.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function follow(t:Type, ?once:Bool):Type {
assertInitMacrosDone();
return load("follow", 2)(t, once);
}
@ -454,8 +575,13 @@ class Context {
Follows a type, including abstracts' underlying implementation
See `haxe.macro.TypeTools.followWithAbstracts` for details.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function followWithAbstracts(t:Type, once:Bool = false):Type {
assertInitMacrosDone();
return load("follow_with_abstracts", 2)(t, once);
}
@ -505,6 +631,7 @@ class Context {
This is only defined for `@:build/@:autoBuild` macros.
**/
public static function getBuildFields():Array<Field> {
assertInitMacrosDone(false);
return load("get_build_fields", 0)();
}
@ -514,11 +641,31 @@ class Context {
If `moduleDependency` is given and is not `null`, it should contain
a module path that will be used as a dependency for the newly defined module
instead of the current module.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function defineType(t:TypeDefinition, ?moduleDependency:String):Void {
assertInitMacrosDone();
load("define_type", 2)(t, moduleDependency);
}
/**
Creates and returns a new instance of monomorph (`TMono`) type.
Returned monomorph can be used with e.g. `Context.unify` to make the compiler
bind the monomorph to an actual type and let macro further process the resulting type.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function makeMonomorph():Type {
assertInitMacrosDone();
return load("make_monomorph", 0)();
}
/**
Defines a new module as `modulePath` with several `TypeDefinition`
`types`. This is analogous to defining a .hx file.
@ -526,12 +673,17 @@ class Context {
The individual `types` can reference each other and any identifier
respects the `imports` and `usings` as usual, expect that imports are
not allowed to have `.*` wildcards or `as s` shorthands.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function defineModule(modulePath:String, types:Array<TypeDefinition>, ?imports:Array<ImportExpr>, ?usings:Array<TypePath>):Void {
if (imports == null)
imports = [];
if (usings == null)
usings = [];
assertInitMacrosDone();
load("define_module", 4)(modulePath, types, imports, usings);
}
@ -539,8 +691,13 @@ class Context {
Returns a syntax-level expression corresponding to typed expression `t`.
This process may lose some information.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function getTypedExpr(t:Type.TypedExpr):Expr {
assertInitMacrosDone();
return load("get_typed_expr", 1)(t);
}
@ -555,8 +712,13 @@ class Context {
that is reset between compilations, so care should be taken when storing
the expression returned by this method in a static variable and using the
compilation server.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function storeTypedExpr(t:Type.TypedExpr):Expr {
assertInitMacrosDone();
return load("store_typed_expr", 1)(t);
}
@ -574,11 +736,29 @@ class Context {
that is reset between compilations, so care should be taken when storing
the expression returned by this method in a static variable and using the
compilation server.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function storeExpr(e:Expr):Expr {
assertInitMacrosDone();
return load("store_expr", 1)(e);
}
/**
This function works like `storeExpr`, but also returns access to the expression's
type through the `type` field of the return value.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function typeAndStoreExpr(e:Expr):{final type:Type.Ref<Type>; final expr:Expr;} {
assertInitMacrosDone();
return load("type_and_store_expr", 1)(e);
}
/**
Manually adds a dependency between module `modulePath` and an external
file `externFile`.
@ -587,9 +767,13 @@ class Context {
`externFile` has changed.
Has no effect if the compilation cache is not used.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function registerModuleDependency(modulePath:String, externFile:String) {
load("register_module_dependency", 2)(modulePath, externFile);
onAfterInitMacros(() -> load("register_module_dependency", 2)(modulePath, externFile));
}
/**
@ -606,10 +790,47 @@ class Context {
stopTimer();
```
**/
public static function timer(id:String):()->Void {
public static function timer(id:String):() -> Void {
return load("timer", 1)(id);
}
/**
Executes `code` in a context that has `imports` and `usings` added.
This is equivalent to temporarily having `import` and `using` statements in a file. These
are only active during the execution of `code` and do not affect anything afterwards. This
is true even if `code` throws an exception.
If any argument is `null`, the result is unspecified.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function withImports<X>(imports:Array<String>, usings:Array<String>, code:() -> X):X {
assertInitMacrosDone();
return load("with_imports", 3)(imports, usings, code);
}
/**
Executes `code` in a context that has some compiler options set, restore the compiler to its
default behavior afterwards.
`allowInlining`: enable or disable inlining during typing with `typeExpr`.
`allowTransform`: when disabled, the code typed with `typeExpr` will be almost exactly the same
as the input code. This will disable some abstract types transformations.
Usage of this function from initialization macros is deprecated and may
cause compilation server issues. Use `Context.onAfterInitMacros` to
run your code once typer is ready to be used.
**/
public static function withOptions<X>(options:{?allowInlining:Bool,?allowTransform:Bool}, code : () -> X) : X {
assertInitMacrosDone();
return load("with_options", 2)(options, code);
}
@:deprecated
public static function registerModuleReuseCall(modulePath:String, macroCall:String) {
throw "This method is no longer supported. See https://github.com/HaxeFoundation/haxe/issues/5746";
@ -639,7 +860,36 @@ class Context {
}
private static function sExpr(e:TypedExpr, pretty:Bool):String {
return haxe.macro.Context.load("s_expr", 2)(e, pretty);
return load("s_expr", 2)(e, pretty);
}
@:allow(haxe.macro.Compiler)
private static function assertInitMacro():Void {
if (initMacrosDone()) {
var stack = getMacroStack();
warning(
"This API should only be used from initialization macros.",
if (stack.length > 2) stack[2] else currentPos()
);
}
}
@:allow(haxe.macro.Compiler)
private static function assertInitMacrosDone(includeSuggestion = true):Void {
#if haxe_next
if (!initMacrosDone()) {
var stack = getMacroStack();
var suggestion = includeSuggestion
? "\nUse `Context.onAfterInitMacros` to register a callback to run when context is ready."
: "";
warning(
"Cannot use this API from initialization macros." + suggestion,
if (stack.length > 2) stack[2] else currentPos()
);
}
#end
}
#end
}

View File

@ -0,0 +1,15 @@
package haxe.macro;
enum DisplayMode {
None;
Default;
Definition;
TypeDefinition;
Implementation;
Package;
Hover;
References(withDefinition:Bool, findDescendants:Bool, findBase:Bool);
ModuleSymbols;
WorkspaceSymbols(filter:String);
Signature;
}

View File

@ -231,7 +231,13 @@ class ExampleJSGenerator {
public function generate() {
print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }");
newline();
print("function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; };");
print(
#if (js_es < 5)
"function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }"
#else
"function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = m.bind(o); o.hx__closures__[m.__id__] = f; } return f; }"
#end
);
newline();
for (t in api.types)
genType(t);

View File

@ -60,12 +60,12 @@ enum Constant {
/**
Represents an integer literal.
**/
CInt(v:String);
CInt(v:String, ?s:String);
/**
Represents a float literal.
**/
CFloat(f:String);
CFloat(f:String, ?s:String);
/**
Represents a string literal.
@ -214,6 +214,11 @@ enum Binop {
`in`
**/
OpIn;
/**
`??`
**/
OpNullCoal;
}
/**
@ -252,6 +257,11 @@ enum Unop {
OpSpread;
}
enum EFieldKind {
Normal;
Safe;
}
/**
Represents a node in the AST.
@see https://haxe.org/manual/macro-reification-expression.html
@ -306,6 +316,11 @@ typedef Var = {
**/
var name:String;
/**
The position of the variable name.
**/
var ?namePos:Position;
/**
The type-hint of the variable, if available.
**/
@ -321,6 +336,11 @@ typedef Var = {
**/
var ?isFinal:Bool;
/**
Whether or not the variable is static.
**/
var ?isStatic:Bool;
/**
Metadata associatied with the variable, if available.
**/
@ -424,8 +444,10 @@ enum ExprDef {
/**
Field access on `e.field`.
If `kind` is null, it is equal to Normal.
**/
EField(e:Expr, field:String);
EField(e:Expr, field:String, ?kind:EFieldKind);
/**
Parentheses `(e)`.
@ -545,11 +567,6 @@ enum ExprDef {
**/
EDisplay(e:Expr, displayKind:DisplayKind);
/**
Used internally to provide completion.
**/
EDisplayNew(t:TypePath);
/**
A `(econd) ? eif : eelse` expression.
**/
@ -681,6 +698,11 @@ typedef TypeParamDecl = {
**/
var ?constraints:Array<ComplexType>;
/**
The optional default type of the type parameter.
**/
var ?defaultType:Null<ComplexType>;
/**
The optional parameters of the type parameter.
**/
@ -977,7 +999,7 @@ enum TypeDefKind {
/**
Represents an abstract kind.
**/
TDAbstract(tthis:Null<ComplexType>, ?from:Array<ComplexType>, ?to:Array<ComplexType>);
TDAbstract(tthis:Null<ComplexType>, ?flags:Array<AbstractFlag>, ?from:Array<ComplexType>, ?to:Array<ComplexType>);
/**
Represents a module-level field.
@ -985,6 +1007,28 @@ enum TypeDefKind {
TDField(kind:FieldType, ?access:Array<Access>); // ignore TypeDefinition.fields
}
/**
Represents an abstract flag.
**/
enum AbstractFlag {
/**
Indicates that this abstract is an `enum abstract`
**/
AbEnum;
/**
Indicates that this abstract can be assigned from `ct`.
This flag can be added several times to add multiple "from" types.
**/
AbFrom(ct:ComplexType);
/**
Indicates that this abstract can be assigned to `ct`.
This flag can be added several times to add multiple "to" types.
**/
AbTo(ct:ComplexType);
}
/**
This error can be used to handle or produce compilation errors in macros.
**/
@ -994,6 +1038,11 @@ class Error extends Exception {
**/
public var pos:Position;
/**
Child error messages, if any.
**/
private var childErrors:Array<Error>;
/**
Instantiates an error with given message and position.
**/

View File

@ -70,7 +70,7 @@ class ExprTools {
**/
static public function iter(e:Expr, f:Expr->Void):Void {
switch (e.expr) {
case EConst(_), EContinue, EBreak, EDisplayNew(_):
case EConst(_), EContinue, EBreak:
case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EIs(e, _) | EMeta(_, e):
f(e);
case EArray(e1, e2), EWhile(e1, e2, _), EBinop(_, e1, e2), EFor(e1, e2):
@ -144,7 +144,7 @@ class ExprTools {
case EConst(_): e.expr;
case EArray(e1, e2): EArray(f(e1), f(e2));
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EField(e, field): EField(f(e), field);
case EField(e, field, kind): EField(f(e), field, kind);
case EParenthesis(e): EParenthesis(f(e));
case EObjectDecl(fields):
var ret = [];
@ -161,6 +161,8 @@ class ExprTools {
var v2:Var = {name: v.name, type: v.type, expr: opt(v.expr, f)};
if (v.isFinal != null)
v2.isFinal = v.isFinal;
if (v.isStatic != null)
v2.isStatic = v.isStatic;
ret.push(v2);
}
EVars(ret);
@ -176,7 +178,7 @@ class ExprTools {
case EDisplay(e, dk): EDisplay(f(e), dk);
case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse));
case ECheckType(e, t): ECheckType(f(e), t);
case EDisplayNew(_), EContinue, EBreak:
case EContinue, EBreak:
e.expr;
case ETry(e, catches):
var ret = [];

View File

@ -32,7 +32,7 @@ import haxe.macro.Expr;
@:hlNative("macro")
#end
class MacroStringTools {
#if (macro || display)
#if macro
/**
Formats `String` `s` using the usual interpolation rules.

View File

@ -0,0 +1,206 @@
package haxe.macro;
import haxe.macro.Expr;
/**
Represents the internal structure generated with options assigned based on
the target platform.
Warning: `PlatformConfig` and the typedefs unique to its fields correspond to
compiler-internal data structures and might change in minor Haxe releases in
order to adapt to internal changes.
**/
typedef PlatformConfig = {
/**
Has a static type system, with not-nullable basic types (Int/Float/Bool)
**/
final staticTypeSystem:Bool;
/**
Has access to the "sys" package
**/
final sys:Bool;
/**
Captured variables handling (see before)
**/
final capturePolicy:CapturePolicy;
/**
When calling a method with optional args, do we replace the missing args with "null" constants
**/
final padNulls:Bool;
/**
Add a final return to methods not having one already - prevent some compiler warnings
**/
final addFinalReturn:Bool;
/**
Does the platform natively support overloaded functions
**/
final overloadFunctions:Bool;
/**
Can the platform use default values for non-nullable arguments
**/
final canSkipNonNullableArgument:Bool;
/**
Type paths that are reserved on the platform
**/
final reservedTypePaths:Array<TypePath>;
/**
Supports function == function
**/
final supportsFunctionEquality:Bool;
/**
Uses utf16 encoding with ucs2 api
**/
final usesUtf16:Bool;
/**
Target supports accessing `this` before calling `super(...)`
**/
final thisBeforeSuper:Bool;
/**
Target supports threads
**/
final supportsThreads:Bool;
/**
Target supports Unicode
**/
final supportsUnicode:Bool;
/**
Target supports rest arguments
**/
final supportsRestArgs:Bool;
/**
Exceptions handling config
**/
final exceptions:ExceptionsConfig;
/**
The scoping of local variables
**/
final scoping:VarScopingConfig;
/**
Target supports atomic operations via haxe.Atomic
**/
final supportsAtomics:Bool;
}
enum CapturePolicy {
/**
Do nothing, let the platform handle it
**/
None;
/**
Wrap all captured variables into a single-element array to allow modifications
**/
WrapRef;
/**
Similar to wrap ref, but will only apply to the locals that are declared in loops
**/
LoopVars;
}
typedef VarScopingConfig = {
final scope:VarScope;
final flags:Array<VarScopingFlags>;
}
enum VarScope {
FunctionScope;
BlockScope;
}
enum VarScopingFlags {
/**
Variables are hoisted in their scope
**/
VarHoisting;
/**
It's not allowed to shadow existing variables in a scope.
**/
NoShadowing;
/**
It's not allowed to shadow a `catch` variable.
**/
NoCatchVarShadowing;
/**
Local vars cannot have the same name as the current top-level package or
(if in the root package) current class name
**/
ReserveCurrentTopLevelSymbol;
/**
Local vars cannot have a name used for any top-level symbol
(packages and classes in the root package)
**/
ReserveAllTopLevelSymbols;
/**
Reserve all type-paths converted to "flat path" with `Path.flat_path`
**/
ReserveAllTypesFlat;
/**
List of names cannot be taken by local vars
**/
ReserveNames(names:Array<String>);
/**
Cases in a `switch` won't have blocks, but will share the same outer scope.
**/
SwitchCasesNoBlocks;
}
typedef ExceptionsConfig = {
/**
Base types which may be thrown from Haxe code without wrapping.
**/
final nativeThrows:Array<TypePath>;
/**
Base types which may be caught from Haxe code without wrapping.
**/
final nativeCatches:Array<TypePath>;
/**
Hint exceptions filter to avoid wrapping for targets, which can throw/catch any type
Ignored on targets with a specific native base type for exceptions.
**/
final avoidWrapping:Bool;
/**
Path of a native class or interface, which can be used for wildcard catches.
**/
final wildcardCatch:TypePath;
/**
Path of a native base class or interface, which can be thrown.
This type is used to cast `haxe.Exception.thrown(v)` calls to.
For example `throw 123` is compiled to `throw (cast Exception.thrown(123):ec_base_throw)`
**/
final baseThrow:TypePath;
/**
Checks if throwing this expression is a special case for current target
and should not be modified.
**/
// final specialThrow:(TypedExpr)->Bool;
}

View File

@ -60,7 +60,7 @@ class PositionTools {
#end
}
#if (macro || display)
#if macro
/**
Converts a `haxe.macro.Position` to a `haxe.display.Position.Location`.

View File

@ -75,13 +75,15 @@ class Printer {
case OpInterval: "...";
case OpArrow: "=>";
case OpIn: "in";
case OpNullCoal: "??";
case OpAssignOp(op):
printBinop(op) + "=";
}
function escapeString(s:String, delim:String) {
return delim
+ s.replace("\n", "\\n")
+ s.replace('\\', '\\\\')
.replace("\n", "\\n")
.replace("\t", "\\t")
.replace("\r", "\\r")
.replace("'", "\\'")
@ -100,8 +102,10 @@ class Printer {
return switch (c) {
case CString(s, SingleQuotes): printFormatString(s);
case CString(s, _): printString(s);
case CIdent(s), CInt(s), CFloat(s):
case CIdent(s), CInt(s, null), CFloat(s, null):
s;
case CInt(s, suffix), CFloat(s, suffix):
s + suffix;
case CRegexp(s, opt): '~/$s/$opt';
}
@ -192,7 +196,8 @@ class Printer {
return (tpd.meta != null && tpd.meta.length > 0 ? tpd.meta.map(printMetadata).join(" ") + " " : "")
+ tpd.name
+ (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "")
+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "");
+ (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : "")
+ (tpd.defaultType != null ? "=" + printComplexType(tpd.defaultType) : "");
public function printFunctionArg(arg:FunctionArg)
return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = ");
@ -235,7 +240,7 @@ class Printer {
case EConst(c): printConstant(c);
case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]';
case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
case EField(e1, n): '${printExpr(e1)}.$n';
case EField(e1, n, kind): kind == Safe ? '${printExpr(e1)}?.$n' : '${printExpr(e1)}.$n';
case EParenthesis(e1): '(${printExpr(e1)})';
case EObjectDecl(fl):
"{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
@ -246,7 +251,8 @@ class Printer {
case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind);
case EVars(vl): "var " + vl.map(printVar).join(", ");
case EVars([]): "var ";
case EVars(vl): ((vl[0].isStatic) ? "static " : "") + ((vl[0].isFinal) ? "final " : "var ") + vl.map(printVar).join(", ");
case EBlock([]): '{ }';
case EBlock(el):
var old = tabs;
@ -281,7 +287,6 @@ class Printer {
case ECast(e1, _): "cast " + printExpr(e1);
case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})';
case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})';
case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1);
@ -377,13 +382,28 @@ class Printer {
case _: printComplexType(ct);
})
+ ";";
case TDAbstract(tthis, from, to):
"abstract "
case TDAbstract(tthis, tflags, from, to):
var from = from == null ? [] : from.copy();
var to = to == null ? [] : to.copy();
var isEnum = false;
if (tflags != null) {
for (flag in tflags) {
switch (flag) {
case AbEnum: isEnum = true;
case AbFrom(ct): from.push(ct);
case AbTo(ct): to.push(ct);
}
}
}
(isEnum ? "enum " : "")
+ "abstract "
+ t.name
+ ((t.params != null && t.params.length > 0) ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "")
+ (tthis == null ? "" : "(" + printComplexType(tthis) + ")")
+ (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join(""))
+ (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join(""))
+ [for (f in from) " from " + printComplexType(f)].join("")
+ [for (f in to) " to " + printComplexType(f)].join("")
+ " {\n"
+ [
for (f in t.fields) {
@ -443,8 +463,9 @@ class Printer {
add("EBinop " + printBinop(op));
loopI(e1);
loopI(e2);
case EField(e, field):
add("EField " + field);
case EField(e, field, kind):
if (kind == null) kind = Normal;
add('EField $field (${kind.getName()})');
loopI(e);
case EParenthesis(e):
add("EParenthesis");
@ -543,8 +564,6 @@ class Printer {
case EDisplay(e, displayKind):
add("EDisplay");
loopI(e);
case EDisplayNew(t):
add("EDisplayNew");
case ETernary(econd, eif, eelse):
add("ETernary");
loopI(econd);

View File

@ -180,6 +180,11 @@ typedef TypeParameter = {
`KTypeParameter` kind.
**/
var t:Type;
/**
The default type for this type parameter.
**/
var ?defaultType:Null<Type>;
}
/**
@ -765,6 +770,11 @@ typedef TVar = {
The metadata of the variable.
**/
public var meta(default, never):Null<MetaAccess>;
/**
Whether the variable is a local static variable
**/
public var isStatic(default, never):Bool;
}
/**

View File

@ -85,7 +85,7 @@ class TypeTools {
pos: cf.pos,
meta: cf.meta.get(),
} else {
throw "Invalid TAnonymous";
throw "Invalid TAnonymous";
}
}
@ -162,7 +162,7 @@ class TypeTools {
}
}
#if (macro || display)
#if macro
/**
Follows all typedefs of `t` to reach the actual type.
@ -174,12 +174,17 @@ class TypeTools {
If `t` is null, an internal exception is thrown.
Usage example:
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);
@ -363,6 +368,35 @@ class TypeTools {
return null;
#end
}
/**
Changes the name of the variable in the typed expression.
**/
static public function setVarName(t:TVar, name:String) {
Context.load("set_var_name", 2)(t, name);
}
/**
Converts type `t` to `haxe.macro.Type.ModuleType`.
**/
static public function toModuleType(t:Type):ModuleType {
#if (neko || eval)
return Context.load("type_to_module_type", 1)(t);
#else
return null;
#end
}
/**
Creates a type from the `haxe.macro.Type.ModuleType` argument.
**/
static public function fromModuleType(mt:ModuleType):Type {
#if (neko || eval)
return Context.load("module_type_to_type", 1)(mt);
#else
return null;
#end
}
#end
/**

View File

@ -167,7 +167,7 @@ class TypedExprTools {
}
}
#if (macro || display)
#if macro
static public function toString(t:TypedExpr, ?pretty = false):String {
return @:privateAccess haxe.macro.Context.sExpr(t, pretty);
}