2 * Implements the serialization of a lambda function.
4 * The serializationis computed by visiting the abstract syntax subtree of the given lambda function.
5 * The serialization is a string which contains the type of the parameters and the string
6 * represantation of the lambda expression.
8 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
9 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
10 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d)
12 * Documentation: https://dlang.org/phobos/dmd_lambdacomp.html
13 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lambdacomp.d
16 module dmd
.lambdacomp
;
18 import core
.stdc
.stdio
;
19 import core
.stdc
.string
;
22 import dmd
.declaration
;
26 import dmd
.expression
;
31 import dmd
.common
.outbuffer
;
33 import dmd
.root
.stringtable
;
42 * The type of the visited expression.
52 * Compares 2 lambda functions described by their serialization.
55 * l1 = first lambda to be compared
56 * l2 = second lambda to be compared
57 * sc = the scope where the lambdas are compared
60 * `true` if the 2 lambda functions are equal, `false` otherwise
62 bool isSameFuncLiteral(FuncLiteralDeclaration l1
, FuncLiteralDeclaration l2
, Scope
* sc
)
65 if (auto ser1
= getSerialization(l1
, sc
))
67 //printf("l1 serialization: %.*s\n", cast(int)ser1.length, &ser1[0]);
68 if (auto ser2
= getSerialization(l2
, sc
))
70 //printf("l2 serialization: %.*s\n", cast(int)ser2.length, &ser2[0]);
73 mem
.xfree(cast(void*)ser2
.ptr
);
75 mem
.xfree(cast(void*)ser1
.ptr
);
81 * Computes the string representation of a
82 * lambda function described by the subtree starting from a
83 * $(REF dmd, func, FuncLiteralDeclaration).
85 * Limitations: only IntegerExps, Enums and function
86 * arguments are supported in the lambda function body. The
87 * arguments may be of any type (basic types, user defined types),
88 * except template instantiations. If a function call, a local
89 * variable or a template instance is encountered, the
90 * serialization is dropped and the function is considered
94 * fld = the starting AST node for the lambda function
95 * sc = the scope in which the lambda function is located
98 * The serialization of `fld` allocated with mem.
100 private string
getSerialization(FuncLiteralDeclaration
fld, Scope
* sc
)
102 scope serVisitor
= new SerializeVisitor(fld.parent
._scope
);
103 fld.accept(serVisitor
);
104 const len
= serVisitor
.buf
.length
;
108 return cast(string
)serVisitor
.buf
.extractSlice();
111 private extern (C
++) class SerializeVisitor
: SemanticTimeTransitiveVisitor
114 StringTable
!(const(char)[]) arg_hash
;
121 alias visit
= SemanticTimeTransitiveVisitor
.visit
;
129 * Entrypoint of the SerializeVisitor.
132 * fld = the lambda function for which the serialization is computed
134 override void visit(FuncLiteralDeclaration
fld)
136 assert(fld.type
.ty
!= Terror
);
138 printf("FuncLiteralDeclaration: %s\n", fld.toChars());
140 TypeFunction tf
= cast(TypeFunction
) fld.type
;
141 const dim
= cast(uint) tf
.parameterList
.length
;
142 // Start the serialization by printing the number of
143 // arguments the lambda has.
144 buf
.printf("%d:", dim
);
146 arg_hash
._init(dim
+ 1);
148 foreach (i
, fparam
; tf
.parameterList
)
150 if (fparam
.ident
!is null)
152 // the variable name is introduced into a hashtable
153 // where the key is the user defined name and the
154 // value is the cannonically name (arg0, arg1 ...)
155 auto key
= fparam
.ident
.toString();
157 value
.writestring("arg");
159 arg_hash
.insert(key
, value
.extractSlice());
160 // and the type of the variable is serialized.
165 // Now the function body can be serialized.
166 ReturnStatement rs
= fld.fbody
.endsWithReturnStatement();
177 override void visit(DotIdExp exp
)
180 printf("DotIdExp: %s\n", exp
.toChars());
184 // First we need to see what kind of expression e1 is.
185 // It might an enum member (enum.value) or the field of
186 // an argument (argX.value) if the argument is an aggregate
187 // type. This is reported through the et variable.
192 if (et
== ExpType
.EnumDecl
)
194 Dsymbol s
= d
.search(exp
.loc
, exp
.ident
);
197 if (auto em
= s
.isEnumMember())
199 em
.value
.accept(this);
206 else if (et
== ExpType
.Arg
)
208 buf
.setsize(buf
.length
-1);
210 buf
.writestring(exp
.ident
.toString());
215 bool checkArgument(const(char)* id
)
217 // The identifier may be an argument
218 auto stringtable_value
= arg_hash
.lookup(id
, strlen(id
));
219 if (stringtable_value
)
221 // In which case we need to update the serialization accordingly
222 const(char)[] gen_id
= stringtable_value
.value
;
231 override void visit(IdentifierExp exp
)
234 printf("IdentifierExp: %s\n", exp
.toChars());
239 auto id
= exp
.ident
.toChars();
241 // If it's not an argument
242 if (!checkArgument(id
))
244 // we must check what the identifier expression is.
246 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, &scopesym
);
249 auto v
= s
.isVarDeclaration();
250 // If it's a VarDeclaration, it must be a manifest constant
251 if (v
&& (v
.storage_class
& STC
.manifest
))
253 v
.getConstInitializer
.accept(this);
255 else if (auto em
= s
.isEnumDeclaration())
258 et
= ExpType
.EnumDecl
;
260 else if (auto fd
= s
.isFuncDeclaration())
262 writeMangledName(fd
);
264 // For anything else, the function is deemed uncomparable
270 // If it's an unknown symbol, consider the function incomparable
278 override void visit(DotVarExp exp
)
281 printf("DotVarExp: %s, var: %s, e1: %s\n", exp
.toChars(),
282 exp
.var
.toChars(), exp
.e1
.toChars());
288 buf
.setsize(buf
.length
-1);
290 buf
.writestring(exp
.var
.toChars());
294 override void visit(VarExp exp
)
297 printf("VarExp: %s, var: %s\n", exp
.toChars(), exp
.var
.toChars());
302 auto id
= exp
.var
.ident
.toChars();
303 if (!checkArgument(id
))
309 // serialize function calls
310 override void visit(CallExp exp
)
313 printf("CallExp: %s\n", exp
.toChars());
324 writeMangledName(exp
.f
);
328 foreach (arg
; *(exp
.arguments
))
335 override void visit(UnaExp exp
)
341 buf
.writestring(EXPtoString(exp
.op
));
344 buf
.writestring(")_");
347 override void visit(IntegerExp exp
)
352 buf
.print(exp
.toInteger());
356 override void visit(RealExp exp
)
361 buf
.writestring(exp
.toChars());
365 override void visit(BinExp exp
)
368 printf("BinExp: %s\n", exp
.toChars());
374 buf
.writestring(EXPtoString(exp
.op
).ptr
);
387 override void visit(TypeBasic t
)
389 buf
.writestring(t
.dstring
);
393 void writeMangledName(Dsymbol s
)
397 OutBuffer mangledName
;
398 mangleToBuffer(s
, &mangledName
);
399 buf
.writestring(mangledName
[]);
406 private bool checkTemplateInstance(T
)(T t
)
407 if (is(T
== TypeStruct
) ||
is(T
== TypeClass
))
409 if (t
.sym
.parent
&& t
.sym
.parent
.isTemplateInstance())
417 override void visit(TypeStruct t
)
420 printf("TypeStruct: %s\n", t
.toChars
);
422 if (!checkTemplateInstance
!TypeStruct(t
))
423 writeMangledName(t
.sym
);
426 override void visit(TypeClass t
)
429 printf("TypeClass: %s\n", t
.toChars());
431 if (!checkTemplateInstance
!TypeClass(t
))
432 writeMangledName(t
.sym
);
435 override void visit(Parameter p
)
437 if (p
.type
.ty
== Tident
438 && (cast(TypeIdentifier
)p
.type
).ident
.toString().length
> 3
439 && strncmp((cast(TypeIdentifier
)p
.type
).ident
.toChars(), "__T", 3) == 0)
441 buf
.writestring("none_");
447 override void visit(StructLiteralExp e
) {
449 printf("StructLiteralExp: %s\n", e
.toChars
);
451 auto ty
= cast(TypeStruct
)e
.stype
;
454 writeMangledName(ty
.sym
);
455 auto dim
= e
.elements
.dim
;
458 auto elem
= (*e
.elements
)[i
];
462 buf
.writestring("null_");
469 override void visit(ArrayLiteralExp
) { buf
.setsize(0); }
470 override void visit(AssocArrayLiteralExp
) { buf
.setsize(0); }
471 override void visit(MixinExp
) { buf
.setsize(0); }
472 override void visit(ComplexExp
) { buf
.setsize(0); }
473 override void visit(DeclarationExp
) { buf
.setsize(0); }
474 override void visit(DefaultInitExp
) { buf
.setsize(0); }
475 override void visit(DsymbolExp
) { buf
.setsize(0); }
476 override void visit(ErrorExp
) { buf
.setsize(0); }
477 override void visit(FuncExp
) { buf
.setsize(0); }
478 override void visit(HaltExp
) { buf
.setsize(0); }
479 override void visit(IntervalExp
) { buf
.setsize(0); }
480 override void visit(IsExp
) { buf
.setsize(0); }
481 override void visit(NewAnonClassExp
) { buf
.setsize(0); }
482 override void visit(NewExp
) { buf
.setsize(0); }
483 override void visit(NullExp
) { buf
.setsize(0); }
484 override void visit(ObjcClassReferenceExp
) { buf
.setsize(0); }
485 override void visit(OverExp
) { buf
.setsize(0); }
486 override void visit(ScopeExp
) { buf
.setsize(0); }
487 override void visit(StringExp
) { buf
.setsize(0); }
488 override void visit(SymbolExp
) { buf
.setsize(0); }
489 override void visit(TemplateExp
) { buf
.setsize(0); }
490 override void visit(ThisExp
) { buf
.setsize(0); }
491 override void visit(TraitsExp
) { buf
.setsize(0); }
492 override void visit(TupleExp
) { buf
.setsize(0); }
493 override void visit(TypeExp
) { buf
.setsize(0); }
494 override void visit(TypeidExp
) { buf
.setsize(0); }
495 override void visit(VoidInitExp
) { buf
.setsize(0); }