Skip to content

Commit 9bdcb8d

Browse files
committed
allow expansion of string.format arguments by fmt
1 parent 953462f commit 9bdcb8d

File tree

4 files changed

+118
-10
lines changed

4 files changed

+118
-10
lines changed

EmmyLua/CodeAnalysis/Compilation/Analyzer/DeclarationAnalyzer/AttachDeclarationAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private void AnalyzeGeneralDeclaration(LuaSyntaxElement attachedElement, List<Lu
7777
if (nameTypeDefine is { Name.RepresentText: { } name } &&
7878
declarations.FirstOrDefault() is { } firstDeclaration)
7979
{
80-
firstDeclaration.Info = firstDeclaration.Info with { DeclarationType = new LuaNamedType(name) };
80+
firstDeclaration.Info = firstDeclaration.Info with { DeclarationType = LuaNamedType.Create(name) };
8181
return;
8282
}
8383

EmmyLua/CodeAnalysis/Compilation/Infer/GenericInfer.cs

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using EmmyLua.CodeAnalysis.Compilation.Search;
1+
using EmmyLua.CodeAnalysis.Common;
2+
using EmmyLua.CodeAnalysis.Compilation.Declaration;
3+
using EmmyLua.CodeAnalysis.Compilation.Search;
24
using EmmyLua.CodeAnalysis.Compilation.Type;
35
using EmmyLua.CodeAnalysis.Syntax.Node.SyntaxNodes;
46

@@ -12,19 +14,42 @@ public static void InferByExpr(
1214
TypeSubstitution substitution,
1315
SearchContext context)
1416
{
15-
if (type is LuaTemplateType templateType && expr is LuaLiteralExprSyntax
16-
{
17-
Literal: LuaStringToken { } stringToken
18-
})
17+
if (SpecialInferByExpr(type, expr, substitution, context))
1918
{
20-
substitution.Add(templateType.TemplateName, new LuaNamedType(templateType.PrefixName + stringToken.Value));
2119
return;
2220
}
2321

2422
var exprType = context.InferAndUnwrap(expr);
2523
InferByType(type, exprType, substitution, context);
2624
}
2725

26+
private static bool SpecialInferByExpr(
27+
LuaType type,
28+
LuaExprSyntax expr,
29+
TypeSubstitution substitution,
30+
SearchContext context)
31+
{
32+
if (type is LuaTemplateType templateType && expr is LuaLiteralExprSyntax
33+
{
34+
Literal: LuaStringToken { } stringToken1
35+
})
36+
{
37+
substitution.Add(templateType.TemplateName, new LuaNamedType(templateType.PrefixName + stringToken1.Value));
38+
return true;
39+
}
40+
41+
if (type is LuaGenericType { Name: "strFmt" } genericType && expr is LuaLiteralExprSyntax
42+
{
43+
Literal: LuaStringToken { } stringToken2
44+
})
45+
{
46+
StrFmtInstantiateByString(genericType, stringToken2.Value, substitution, context);
47+
return true;
48+
}
49+
50+
return false;
51+
}
52+
2853
public static void InferByExpandTypeAndExprs(
2954
LuaExpandType expandType,
3055
IEnumerable<LuaExprSyntax> expr,
@@ -320,4 +345,70 @@ private static void TupleTypeInstantiateByType(
320345
}
321346
}
322347
}
348+
349+
private static void StrFmtInstantiateByString(
350+
LuaGenericType genericType,
351+
string fmt,
352+
TypeSubstitution substitution,
353+
SearchContext context)
354+
{
355+
var firstTemp = genericType.GenericArgs.FirstOrDefault();
356+
if (firstTemp is not LuaNamedType templateName)
357+
{
358+
return;
359+
}
360+
361+
var spreadParameter = new List<IDeclaration>();
362+
for(var i = 0; i < fmt.Length; i++)
363+
{
364+
var ch = fmt[i];
365+
if (fmt[i] == '%')
366+
{
367+
if (i + 1 < fmt.Length)
368+
{
369+
var nextCh = fmt[i + 1];
370+
if (nextCh == '%')
371+
{
372+
i++;
373+
}
374+
else
375+
{
376+
var index = i + 1;
377+
while (index < fmt.Length && char.IsDigit(fmt[index]))
378+
{
379+
index++;
380+
}
381+
382+
if (index < fmt.Length)
383+
{
384+
var type = fmt[index];
385+
if (type is 's' or 'q')
386+
{
387+
spreadParameter.Add(new LuaDeclaration(
388+
$"%{type}",
389+
new VirtualInfo(Builtin.Any)
390+
));
391+
}
392+
else if (type is 'c' or 'd' or 'i' or 'u' or 'x' or 'X' or 'o')
393+
{
394+
spreadParameter.Add(new LuaDeclaration(
395+
$"%{type}",
396+
new VirtualInfo(Builtin.Integer)
397+
));
398+
}
399+
else if (type is 'A' or 'a' or 'E' or 'e' or 'f' or 'G' or 'g')
400+
{
401+
spreadParameter.Add(new LuaDeclaration(
402+
$"%{type}",
403+
new VirtualInfo(Builtin.Number)
404+
));
405+
}
406+
}
407+
}
408+
}
409+
}
410+
}
411+
412+
substitution.AddSpreadParameter(templateName.Name, spreadParameter);
413+
}
323414
}

EmmyLua/CodeAnalysis/Compilation/Type/LuaTypes.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ public class LuaNamedType(
5353
LuaTypeAttribute attribute = LuaTypeAttribute.HasMember | LuaTypeAttribute.CanCall | LuaTypeAttribute.CanIndex)
5454
: LuaType(attribute), IEquatable<LuaNamedType>
5555
{
56+
public static LuaNamedType Create(string name, LuaTypeAttribute attribute = LuaTypeAttribute.HasMember | LuaTypeAttribute.CanCall | LuaTypeAttribute.CanIndex)
57+
{
58+
var buildType = Builtin.FromName(name);
59+
if (buildType is not null)
60+
{
61+
return buildType;
62+
}
63+
64+
return new LuaNamedType(name, attribute);
65+
}
66+
5667
public string Name { get; } = name;
5768

5869
public NamedTypeKind GetTypeKind(SearchContext context)

EmmyLua/Resources/std/string.lua

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ function string.dump(func, strip) end
8383
---@return number, number, string
8484
function string.find(s, pattern, init, plain) end
8585

86+
--- a built-in type
87+
--- represents a format string
88+
---@class strFmt<T> : string
89+
8690
---
8791
--- Returns a formatted version of its variable number of arguments following
8892
--- the description given in its first argument (which must be a string). The
@@ -112,10 +116,12 @@ function string.find(s, pattern, init, plain) end
112116
--- converted to one following the same rules of `tostring`. If the option
113117
--- has any modifier (flags, width, length), the string argument should not
114118
--- contain embedded zeros.
115-
---@param formatstring string
116-
---@param ... any
119+
---@generic T
120+
---@param fmt strFmt<T>
121+
---@param ... T...
117122
---@return string
118-
function string.format(formatstring, ...) end
123+
---@nodiscard
124+
function string.format(fmt, ...) end
119125

120126
---
121127
--- Returns an iterator function that, each time it is called, returns the

0 commit comments

Comments
 (0)