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-2024 by The D Language Foundation, All Rights Reserved
9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
10 * License: $(LINK2 https://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
;
25 import dmd
.dsymbolsem
;
27 import dmd
.expression
;
32 import dmd
.common
.outbuffer
;
34 import dmd
.root
.stringtable
;
43 * The type of the visited expression.
53 * Compares 2 lambda functions described by their serialization.
56 * l1 = first lambda to be compared
57 * l2 = second lambda to be compared
58 * sc = the scope where the lambdas are compared
61 * `true` if the 2 lambda functions are equal, `false` otherwise
63 bool isSameFuncLiteral(FuncLiteralDeclaration l1
, FuncLiteralDeclaration l2
, Scope
* sc
)
66 if (auto ser1
= getSerialization(l1
, sc
))
68 //printf("l1 serialization: %.*s\n", cast(int)ser1.length, &ser1[0]);
69 if (auto ser2
= getSerialization(l2
, sc
))
71 //printf("l2 serialization: %.*s\n", cast(int)ser2.length, &ser2[0]);
74 mem
.xfree(cast(void*)ser2
.ptr
);
76 mem
.xfree(cast(void*)ser1
.ptr
);
82 * Computes the string representation of a
83 * lambda function described by the subtree starting from a
84 * $(REF dmd, func, FuncLiteralDeclaration).
86 * Limitations: only IntegerExps, Enums and function
87 * arguments are supported in the lambda function body. The
88 * arguments may be of any type (basic types, user defined types),
89 * except template instantiations. If a function call, a local
90 * variable or a template instance is encountered, the
91 * serialization is dropped and the function is considered
95 * fld = the starting AST node for the lambda function
96 * sc = the scope in which the lambda function is located
99 * The serialization of `fld` allocated with mem.
101 private string
getSerialization(FuncLiteralDeclaration
fld, Scope
* sc
)
103 scope serVisitor
= new SerializeVisitor(fld.parent
._scope
);
104 fld.accept(serVisitor
);
105 const len
= serVisitor
.buf
.length
;
109 return cast(string
)serVisitor
.buf
.extractSlice();
112 private extern (C
++) class SerializeVisitor
: SemanticTimeTransitiveVisitor
115 StringTable
!(const(char)[]) arg_hash
;
122 alias visit
= SemanticTimeTransitiveVisitor
.visit
;
124 this(Scope
* sc
) scope
130 * Entrypoint of the SerializeVisitor.
133 * fld = the lambda function for which the serialization is computed
135 override void visit(FuncLiteralDeclaration
fld)
137 assert(fld.type
.ty
!= Terror
);
139 printf("FuncLiteralDeclaration: %s\n", fld.toChars());
141 TypeFunction tf
= cast(TypeFunction
) fld.type
;
142 const dim
= cast(uint) tf
.parameterList
.length
;
143 // Start the serialization by printing the number of
144 // arguments the lambda has.
145 buf
.printf("%d:", dim
);
147 arg_hash
._init(dim
+ 1);
149 foreach (i
, fparam
; tf
.parameterList
)
151 if (fparam
.ident
!is null)
153 // the variable name is introduced into a hashtable
154 // where the key is the user defined name and the
155 // value is the cannonically name (arg0, arg1 ...)
156 auto key
= fparam
.ident
.toString();
158 value
.writestring("arg");
160 arg_hash
.insert(key
, value
.extractSlice());
161 // and the type of the variable is serialized.
166 // Now the function body can be serialized.
167 ReturnStatement rs
= fld.fbody
.endsWithReturnStatement();
178 override void visit(DotIdExp exp
)
181 printf("DotIdExp: %s\n", exp
.toChars());
185 // First we need to see what kind of expression e1 is.
186 // It might an enum member (enum.value) or the field of
187 // an argument (argX.value) if the argument is an aggregate
188 // type. This is reported through the et variable.
193 if (et
== ExpType
.EnumDecl
)
195 Dsymbol s
= d
.search(exp
.loc
, exp
.ident
);
198 if (auto em
= s
.isEnumMember())
200 em
.value
.accept(this);
207 else if (et
== ExpType
.Arg
)
209 buf
.setsize(buf
.length
-1);
211 buf
.writestring(exp
.ident
.toString());
216 bool checkArgument(const(char)* id
)
218 // The identifier may be an argument
219 auto stringtable_value
= arg_hash
.lookup(id
, strlen(id
));
220 if (stringtable_value
)
222 // In which case we need to update the serialization accordingly
223 const(char)[] gen_id
= stringtable_value
.value
;
232 override void visit(IdentifierExp exp
)
235 printf("IdentifierExp: %s\n", exp
.toChars());
240 auto id
= exp
.ident
.toChars();
242 // If it's not an argument
243 if (!checkArgument(id
))
245 // we must check what the identifier expression is.
247 Dsymbol s
= sc
.search(exp
.loc
, exp
.ident
, scopesym
);
250 auto v
= s
.isVarDeclaration();
251 // If it's a VarDeclaration, it must be a manifest constant
252 if (v
&& (v
.storage_class
& STC
.manifest
))
254 v
.getConstInitializer
.accept(this);
256 else if (auto em
= s
.isEnumDeclaration())
259 et
= ExpType
.EnumDecl
;
261 else if (auto fd
= s
.isFuncDeclaration())
263 writeMangledName(fd
);
265 // For anything else, the function is deemed uncomparable
271 // If it's an unknown symbol, consider the function incomparable
279 override void visit(DotVarExp exp
)
282 printf("DotVarExp: %s, var: %s, e1: %s\n", exp
.toChars(),
283 exp
.var
.toChars(), exp
.e1
.toChars());
289 buf
.setsize(buf
.length
-1);
291 buf
.writestring(exp
.var
.toChars());
295 override void visit(VarExp exp
)
298 printf("VarExp: %s, var: %s\n", exp
.toChars(), exp
.var
.toChars());
303 auto id
= exp
.var
.ident
.toChars();
304 if (!checkArgument(id
))
310 // serialize function calls
311 override void visit(CallExp exp
)
314 printf("CallExp: %s\n", exp
.toChars());
325 writeMangledName(exp
.f
);
329 foreach (arg
; *(exp
.arguments
))
336 override void visit(UnaExp exp
)
342 buf
.writestring(EXPtoString(exp
.op
));
345 buf
.writestring(")_");
348 override void visit(IntegerExp exp
)
353 buf
.print(exp
.toInteger());
357 override void visit(RealExp exp
)
362 buf
.writestring(exp
.toChars());
366 override void visit(BinExp exp
)
369 printf("BinExp: %s\n", exp
.toChars());
375 buf
.writestring(EXPtoString(exp
.op
).ptr
);
388 override void visit(TypeBasic t
)
390 buf
.writestring(t
.dstring
);
394 void writeMangledName(Dsymbol s
)
398 OutBuffer mangledName
;
399 mangleToBuffer(s
, mangledName
);
400 buf
.writestring(mangledName
[]);
407 private bool checkTemplateInstance(T
)(T t
)
408 if (is(T
== TypeStruct
) ||
is(T
== TypeClass
))
410 if (t
.sym
.parent
&& t
.sym
.parent
.isTemplateInstance())
418 override void visit(TypeStruct t
)
421 printf("TypeStruct: %s\n", t
.toChars
);
423 if (!checkTemplateInstance
!TypeStruct(t
))
424 writeMangledName(t
.sym
);
427 override void visit(TypeClass t
)
430 printf("TypeClass: %s\n", t
.toChars());
432 if (!checkTemplateInstance
!TypeClass(t
))
433 writeMangledName(t
.sym
);
436 override void visit(Parameter p
)
438 if (p
.type
.ty
== Tident
439 && (cast(TypeIdentifier
)p
.type
).ident
.toString().length
> 3
440 && strncmp((cast(TypeIdentifier
)p
.type
).ident
.toChars(), "__T", 3) == 0)
442 buf
.writestring("none_");
448 override void visit(StructLiteralExp e
) {
450 printf("StructLiteralExp: %s\n", e
.toChars
);
452 auto ty
= cast(TypeStruct
)e
.stype
;
455 writeMangledName(ty
.sym
);
456 auto dim
= e
.elements
.length
;
459 auto elem
= (*e
.elements
)[i
];
463 buf
.writestring("null_");
470 override void visit(ArrayLiteralExp
) { buf
.setsize(0); }
471 override void visit(AssocArrayLiteralExp
) { buf
.setsize(0); }
472 override void visit(MixinExp
) { buf
.setsize(0); }
473 override void visit(ComplexExp
) { buf
.setsize(0); }
474 override void visit(DeclarationExp
) { buf
.setsize(0); }
475 override void visit(DefaultInitExp
) { buf
.setsize(0); }
476 override void visit(DsymbolExp
) { buf
.setsize(0); }
477 override void visit(ErrorExp
) { buf
.setsize(0); }
478 override void visit(FuncExp
) { buf
.setsize(0); }
479 override void visit(HaltExp
) { buf
.setsize(0); }
480 override void visit(IntervalExp
) { buf
.setsize(0); }
481 override void visit(IsExp
) { buf
.setsize(0); }
482 override void visit(NewAnonClassExp
) { buf
.setsize(0); }
483 override void visit(NewExp
) { buf
.setsize(0); }
484 override void visit(NullExp
) { buf
.setsize(0); }
485 override void visit(ObjcClassReferenceExp
) { buf
.setsize(0); }
486 override void visit(OverExp
) { buf
.setsize(0); }
487 override void visit(ScopeExp
) { buf
.setsize(0); }
488 override void visit(StringExp
) { buf
.setsize(0); }
489 override void visit(SymbolExp
) { buf
.setsize(0); }
490 override void visit(TemplateExp
) { buf
.setsize(0); }
491 override void visit(ThisExp
) { buf
.setsize(0); }
492 override void visit(TraitsExp
) { buf
.setsize(0); }
493 override void visit(TupleExp
) { buf
.setsize(0); }
494 override void visit(TypeExp
) { buf
.setsize(0); }
495 override void visit(TypeidExp
) { buf
.setsize(0); }
496 override void visit(VoidInitExp
) { buf
.setsize(0); }