/
Context.hx
645 lines (523 loc) · 19.3 KB
/
Context.hx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
/*
* 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.
*/
package haxe.macro;
import haxe.macro.Expr;
import haxe.macro.Type.TypedExpr;
enum Message {
Info(msg:String, pos:Position);
Warning(msg:String, pos:Position);
}
/**
Context provides an API for macro programming.
It contains common functions that interact with the macro interpreter to
query or set information. Other API functions are available in the tools
classes:
- `haxe.macro.ComplexTypeTools`
- `haxe.macro.ExprTools`
- `haxe.macro.TypeTools`
**/
class Context {
#if (neko || eval || display)
/**
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);
}
/**
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);
}
/**
Displays a compilation warning `msg` at the given `Position` `pos`.
**/
public static function warning(msg:String, pos:Position) {
load("warning", 2)(msg, pos);
}
/**
Displays a compilation info `msg` at the given `Position` `pos`.
**/
public static function info(msg:String, pos:Position) {
load("info", 2)(msg, pos);
}
/**
Gets a list of all current compilation info/warning messages.
**/
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);
}
/**
Resolves a file name `file` based on the current class paths.
The resolution follows the usual class path rules where the last
declared class path has priority.
If a class path was declared relative, this method returns the relative
file path. Otherwise it returns the absolute file path.
**/
public static function resolvePath(file:String):String {
return load("resolve_path", 1)(file);
}
/**
Returns an `Array` of current class paths in the order of their
declaration.
Modifying the returned array has no effect on the compiler. Class paths
can be added using `haxe.macro.Compiler.addClassPath`.
**/
public static function getClassPath():Array<String> {
return load("class_path", 0)();
}
/**
Check if current display position is within `pos`.
**/
public static function containsDisplayPosition(pos:Position):Bool {
return load("contains_display_position", 1)(pos);
}
/**
Returns the position at which the macro was called.
**/
public static function currentPos():Position {
return load("current_pos", 0)();
}
/**
Returns the type which is expected at the place the macro is called.
This affects usages such as `var x:Int = macroCall()`, where the
expected type will be reported as `Int`.
Might return `null` if no specific type is expected or if the calling
macro is not an expression-macro.
**/
public static function getExpectedType():Null<Type> {
return load("get_expected_type", 0)();
}
/**
Returns the call arguments that lead to the invocation of the current
`@:genericBuild` macro, if available.
Returns `null` if the current macro is not a `@:genericBuild` macro.
**/
public static function getCallArguments():Null<Array<Expr>> {
return load("get_call_arguments", 0)();
}
/**
Returns the current class in which the macro was called.
If no such class exists, `null` is returned.
**/
public static function getLocalClass():Null<Type.Ref<Type.ClassType>> {
var l:Type = load("get_local_type", 0)();
if (l == null)
return null;
return switch (l) {
case TInst(c, _): c;
default: null;
}
}
/**
Returns the current module path in/on which the macro was called.
**/
public static function getLocalModule():String {
return load("get_local_module", 0)();
}
/**
Returns the current type in/on which the macro was called.
If no such type exists, `null` is returned.
**/
public static function getLocalType():Null<Type> {
return load("get_local_type", 0)();
}
/**
Returns the name of the method from which the macro was called.
If no such method exists, `null` is returned.
**/
public static function getLocalMethod():Null<String> {
return load("get_local_method", 0)();
}
/**
Returns an `Array` of classes which are available for `using` usage in
the context the macro was called.
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalUsing():Array<Type.Ref<Type.ClassType>> {
return load("get_local_using", 0)();
}
/**
Returns an `Array` of all imports in the context the macro was called.
Modifying the returned array has no effect on the compiler.
**/
public static function getLocalImports():Array<ImportExpr> {
return load("get_local_imports", 0)();
}
/**
Returns a map of local variables accessible in the context the macro was
called.
The keys of the returned map are the variable names, the values are
their types.
Modifying the returned map has no effect on the compiler.
**/
@:deprecated("Use Context.getLocalTVars() instead")
public static function getLocalVars():Map<String, Type> {
return load("local_vars", 1)(false);
}
/**
Similar to `getLocalVars`, but returns elements of type `TVar` instead
of `Type`.
**/
public static function getLocalTVars():Map<String, Type.TVar> {
return load("local_vars", 1)(true);
}
/**
Tells if the conditional compilation flag `s` has been set.
Compiler flags are set using the `-D` command line parameter, or
by calling `haxe.macro.Compiler.define`.
@see https://haxe.org/manual/lf-condition-compilation.html
**/
public static function defined(s:String):Bool {
return load("defined", 1)(s);
}
/**
Returns the value defined for the conditional compilation flag `key`.
If no value is defined for `key`, `null` is returned.
Compiler flags values are set using the `-D key=value` command line
parameter, or by calling `haxe.macro.Compiler.define`.
The default value is `"1"`.
@see https://haxe.org/manual/lf-condition-compilation.html
**/
public static function definedValue(key:String):String {
return load("defined_value", 1)(key);
}
/**
Returns a map of all conditional compilation flags that have been set.
Compiler flags are set using the `-D` command line parameter, or
by calling `haxe.macro.Compiler.define`.
Modifying the returned map has no effect on the compiler.
@see https://haxe.org/manual/lf-condition-compilation.html
**/
public static function getDefines():Map<String, String> {
return load("get_defines", 0)();
}
/**
Resolves a type identified by `name`.
The resolution follows the usual class path rules where the last
declared class path has priority.
If no type can be found, an exception of type `String` is thrown.
**/
public static function getType(name:String):Type {
return load("get_type", 1)(name);
}
/**
Resolves a module identified by `name` and returns an `Array` of all
its contained types.
The resolution follows the usual class path rules where the last
declared class path has priority.
If no module can be found, an exception of type `String` is thrown.
**/
public static function getModule(name:String):Array<Type> {
return load("get_module", 1)(name);
}
/**
Parses `expr` as Haxe code, returning the corresponding AST.
String interpolation of single quote strings within `expr` is not
supported.
The provided `Position` `pos` is used for all generated inner AST nodes.
**/
public static function parse(expr:String, pos:Position):Expr {
return load("do_parse", 3)(expr, pos, false);
}
/**
Similar to `parse`, but error positions are reported within the provided
String `expr`.
**/
public static function parseInlineString(expr:String, pos:Position):Expr {
return load("do_parse", 3)(expr, pos, true);
}
/**
Builds an expression from `v`.
This method generates AST nodes depending on the macro-runtime value of
`v`. As such, only basic types and enums are supported and the behavior
for other types is undefined.
The provided `Position` `pos` is used for all generated inner AST nodes.
**/
public static function makeExpr(v:Dynamic, pos:Position):Expr {
return load("make_expr", 2)(v, pos);
}
/**
Returns a hashed MD5 signature of value `v`.
**/
public static function signature(v:Dynamic):String {
return load("signature", 1)(v);
}
/**
Adds a callback function `callback` which is invoked after the
compiler's typing phase, just before its generation phase.
The callback receives an `Array` containing all types which are about
to be generated. Modifications are limited to metadata, it is mainly
intended to obtain information.
By default, the callback is made before types are stored in the compilation
server, if active. This means that any effect persists for the next compilation.
If `persistent` is set to `false`, changes to types made by the callback only
affect the current compilation. If no compilation server is used, this flag has
no effect.
*Note*: the callback is still invoked when generation is disabled with `--no-output`.
**/
public static function onGenerate(callback:Array<Type>->Void, persistent:Bool = true) {
load("on_generate", 2)(callback, persistent);
}
/**
Adds a callback function `callback` which is invoked after the compiler
generation phase.
Compilation has completed at this point and cannot be influenced
anymore. However, contextual information is still available.
*Note*: the callback is still invoked when generation is disabled with `--no-output`.
**/
public static function onAfterGenerate(callback:Void->Void) {
load("on_after_generate", 1)(callback);
}
/**
Adds a callback function `callback` which is invoked after the compiler
is done typing, but before optimization. The callback receives the types
which have been typed.
It is possible to define new types in the callback, in which case it
will be called again with the new types as argument.
**/
public static function onAfterTyping(callback:Array<haxe.macro.Type.ModuleType>->Void) {
load("on_after_typing", 1)(callback);
}
/**
Adds a callback function `callback` which is invoked when a type name
cannot be resolved.
The callback may return a type definition, which is then used for the
expected type. If it returns `null`, the type is considered to still not
exist.
**/
public static function onTypeNotFound(callback:String->TypeDefinition) {
load("on_type_not_found", 1)(callback);
}
/**
Types expression `e` and returns its type.
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
**/
public static function typeof(e:Expr):Type {
return load("typeof", 1)(e);
}
/**
Types expression `e` and returns the corresponding `TypedExpr`.
Typing the expression may result in a compiler error which can be
caught using `try ... catch`.
**/
public static function typeExpr(e:Expr):TypedExpr {
return load("type_expr", 1)(e);
}
/**
Resolve type `t` and returns the corresponding `Type`.
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.
**/
public static function resolveType(t:ComplexType, p:Position):Type {
return load("resolve_type", 2)(t, p);
}
/**
Returns the `ComplexType` corresponding to the given `Type` `t`.
See `haxe.macro.TypeTools.toComplexType` for details.
**/
public static function toComplexType(t:Type):Null<ComplexType> {
return load("to_complex_type", 1)(t);
}
/**
Tries to unify `t1` and `t2` and returns `true` if successful.
**/
public static function unify(t1:Type, t2:Type):Bool {
return load("unify", 2)(t1, t2);
}
/**
Follows a type.
See `haxe.macro.TypeTools.follow` for details.
**/
public static function follow(t:Type, ?once:Bool):Type {
return load("follow", 2)(t, once);
}
/**
Follows a type, including abstracts' underlying implementation
See `haxe.macro.TypeTools.followWithAbstracts` for details.
**/
public static function followWithAbstracts(t:Type, once:Bool = false):Type {
return load("follow_with_abstracts", 2)(t, once);
}
/**
Returns the information stored in `Position` `p`.
**/
public static function getPosInfos(p:Position):{min:Int, max:Int, file:String} {
return load("get_pos_infos", 1)(p);
}
/**
Builds a `Position` from `inf`.
**/
public static function makePosition(inf:{min:Int, max:Int, file:String}):Position {
return load("make_position", 3)(inf.min, inf.max, inf.file);
}
/**
Returns a map of all registered resources for this compilation unit.
Modifying the returned map has no effect on the compilation, use
`haxe.macro.Context.addResource` to add new resources to the compilation unit.
**/
public static function getResources():Map<String, haxe.io.Bytes> {
return load("get_resources", 0)();
}
/**
Makes resource `data` available as `name`.
The resource is then available using the `haxe.macro.Resource` API.
If a previous resource was bound to `name`, it is overwritten.
Compilation server : when using the compilation server, the resource is bound
to the Haxe module which calls the macro, so it will be included again if
that module is reused. If this resource concerns several modules, prefix its
name with a `$` sign, this will bind it to the macro module instead.
**/
public static function addResource(name:String, data:haxe.io.Bytes) {
load("add_resource", 2)(name, data);
}
/**
Returns an `Array` of fields of the class which is to be built.
This is only defined for `@:build/@:autoBuild` macros.
**/
public static function getBuildFields():Array<Field> {
return load("get_build_fields", 0)();
}
/**
Defines a new type from `TypeDefinition` `t`.
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.
**/
public static function defineType(t:TypeDefinition, ?moduleDependency:String):Void {
load("define_type", 2)(t, moduleDependency);
}
/**
Defines a new module as `modulePath` with several `TypeDefinition`
`types`. This is analogous to defining a .hx file.
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.
**/
public static function defineModule(modulePath:String, types:Array<TypeDefinition>, ?imports:Array<ImportExpr>, ?usings:Array<TypePath>):Void {
if (imports == null)
imports = [];
if (usings == null)
usings = [];
load("define_module", 4)(modulePath, types, imports, usings);
}
/**
Returns a syntax-level expression corresponding to typed expression `t`.
This process may lose some information.
**/
public static function getTypedExpr(t:Type.TypedExpr):Expr {
return load("get_typed_expr", 1)(t);
}
/**
Store typed expression `t` internally and give a syntax-level expression
that can be returned from a macro and will be replaced by the stored
typed expression.
If `t` is `null` or invalid, an exception is thrown.
NOTE: the returned value references an internally stored typed expression
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.
**/
public static function storeTypedExpr(t:Type.TypedExpr):Expr {
return load("store_typed_expr", 1)(t);
}
/**
Types expression `e`, stores the resulting typed expression internally and
returns a syntax-level expression that can be returned from a macro and
will be replaced by the stored typed expression.
If `e` is `null` or invalid, an exception is thrown.
A call to `storeExpr(e)` is equivalent to `storeTypedExpr(typeExpr(e))` without
the overhead of encoding and decoding between regular and macro runtime.
NOTE: the returned value references an internally stored typed expression
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.
**/
public static function storeExpr(e:Expr):Expr {
return load("store_expr", 1)(e);
}
/**
Manually adds a dependency between module `modulePath` and an external
file `externFile`.
This affects the compilation cache, causing the module to be typed if
`externFile` has changed.
Has no effect if the compilation cache is not used.
**/
public static function registerModuleDependency(modulePath:String, externFile:String) {
load("register_module_dependency", 2)(modulePath, externFile);
}
/**
Creates a timer which will be printed in the compilation report
if `--times` compilation argument is set.
Note that a timer may be omitted from the report if the amount of time
measured is too small.
This method immediately starts a timer and returns a function to stop it:
```
var stopTimer = haxe.macro.Context.timer("my heavy task");
runTask();
stopTimer();
```
**/
public static function timer(id:String):()->Void {
return load("timer", 1)(id);
}
@:deprecated
public static function registerModuleReuseCall(modulePath:String, macroCall:String) {
throw "This method is no longer supported. See https://github.com/HaxeFoundation/haxe/issues/5746";
}
@:deprecated
public static function onMacroContextReused(callb:Void->Bool) {
throw "This method is no longer supported. See https://github.com/HaxeFoundation/haxe/issues/5746";
}
@:allow(haxe.macro.TypeTools)
@:allow(haxe.macro.MacroStringTools)
@:allow(haxe.macro.TypedExprTools)
@:allow(haxe.macro.PositionTools)
static function load(f:String, nargs:Int):Dynamic {
#if neko
return neko.Lib.load("macro", f, nargs);
#elseif eval
return eval.vm.Context.callMacroApi(f);
#else
return Reflect.makeVarArgs(function(_) return throw "Can't be called outside of macro");
#end
}
private static function includeFile(file:String, position:String) {
load("include_file", 2)(file, position);
}
private static function sExpr(e:TypedExpr, pretty:Bool):String {
return haxe.macro.Context.load("s_expr", 2)(e, pretty);
}
#end
}