Skip to content

Commit db041ee

Browse files
committed
parsing <AssemblyAttribute> msbuild item
1 parent 5efa0e3 commit db041ee

File tree

2 files changed

+125
-3
lines changed

2 files changed

+125
-3
lines changed

src/Peachpie.CodeAnalysis/CommandLine/PhpCommandLineParser.cs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using System.Threading.Tasks;
1212
using System.IO;
1313
using Pchp.CodeAnalysis.Utilities;
14+
using Devsense.PHP.Syntax.Ast;
15+
using Devsense.PHP.Syntax;
1416

1517
namespace Pchp.CodeAnalysis.CommandLine
1618
{
@@ -165,6 +167,7 @@ internal override CommandLineArguments CommonParse(IEnumerable<string> args, str
165167
var additionalFiles = new List<CommandLineSourceFile>();
166168
var embeddedFiles = new List<CommandLineSourceFile>();
167169
var managedResources = new List<ResourceDescription>();
170+
var globalAttributes = new List<AttributeElement>();
168171
var defines = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
169172
string outputDirectory = baseDirectory;
170173
string subDirectory = null;
@@ -707,8 +710,24 @@ internal override CommandLineArguments CommonParse(IEnumerable<string> args, str
707710
break;
708711

709712
case "attr":
713+
710714
// FQN("value1","value2")
711715

716+
if (string.IsNullOrWhiteSpace(value))
717+
{
718+
diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
719+
break;
720+
}
721+
722+
if (TryParseAttributeSpec(value.Trim(), out var attr))
723+
{
724+
globalAttributes.Add(attr);
725+
}
726+
else
727+
{
728+
diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_BadCompilationOptionValue, Location.None, name, value));
729+
}
730+
712731
break;
713732

714733
default:
@@ -997,6 +1016,102 @@ private static void ParseDefine(string value, Dictionary<string, string> defines
9971016
}
9981017
}
9991018

1019+
private static bool TryParseAttributeSpec(string value, out AttributeElement attr)
1020+
{
1021+
attr = null;
1022+
1023+
ReadOnlySpan<char> fqn;
1024+
var signature = new List<ActualParam>();
1025+
var span = Devsense.PHP.Text.Span.Invalid;
1026+
1027+
// FQN("value1","value2")
1028+
var parenIdx = value.IndexOf('(');
1029+
if (parenIdx >= 0)
1030+
{
1031+
fqn = value.AsSpan(0, parenIdx);
1032+
1033+
var args = value.AsSpan(parenIdx).Trim();
1034+
1035+
bool ConsumeChar(ref ReadOnlySpan<char> text, char ch)
1036+
{
1037+
if (text.Length != 0 && text[0] == ch)
1038+
{
1039+
text = text.Slice(1);
1040+
return true;
1041+
}
1042+
return false;
1043+
}
1044+
1045+
bool ConsumeArg(ref ReadOnlySpan<char> text, out ActualParam p)
1046+
{
1047+
p = default(ActualParam);
1048+
1049+
if (!ConsumeChar(ref text, '"')) return false;
1050+
1051+
var str = new StringBuilder();
1052+
var escaped = false;
1053+
var closed = false;
1054+
while (text.Length != 0)
1055+
{
1056+
var ch = text[0];
1057+
text = text.Slice(1);
1058+
1059+
if (escaped) { }
1060+
else if (ch == '\\') { escaped = true; continue; }
1061+
else if (ch == '"') { closed = true; break; }
1062+
1063+
str.Append(ch);
1064+
}
1065+
1066+
if (!closed)
1067+
{
1068+
return false;
1069+
}
1070+
1071+
p = new ActualParam(
1072+
Devsense.PHP.Text.Span.Invalid,
1073+
new StringLiteral(Devsense.PHP.Text.Span.Invalid, str.ToString())
1074+
);
1075+
return true;
1076+
}
1077+
1078+
if (ConsumeChar(ref args, '('))
1079+
{
1080+
do
1081+
{
1082+
if (ConsumeChar(ref args, ')')) break;
1083+
if (ConsumeChar(ref args, ',')) continue;
1084+
if (ConsumeArg(ref args, out var p))
1085+
{
1086+
signature.Add(p);
1087+
continue;
1088+
}
1089+
break;
1090+
} while (args.Length != 0);
1091+
}
1092+
1093+
if (args.IsWhiteSpace() == false)
1094+
return false; // unexpected
1095+
}
1096+
else
1097+
{
1098+
fqn = value.AsSpan();
1099+
}
1100+
1101+
if (fqn.IsWhiteSpace())
1102+
{
1103+
return false;
1104+
}
1105+
1106+
//
1107+
attr = new AttributeElement(
1108+
span,
1109+
new ClassTypeRef(span, QualifiedName.Parse(fqn.Trim().ToString().Replace('.', QualifiedName.Separator), true)),
1110+
new CallSignature(signature, span)
1111+
);
1112+
return true;
1113+
}
1114+
10001115
internal override void GenerateErrorForNoFilesFoundInRecurse(string path, IList<Diagnostic> errors)
10011116
{
10021117
// nothing

src/Peachpie.NET.Sdk/BuildTask.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,20 @@ public override bool Execute()
217217
{
218218
foreach (var attr in AssemblyAttribute)
219219
{
220+
// metadata names
221+
var props = new HashSet<string>(
222+
attr.MetadataNames.OfType<string>(),
223+
StringComparer.OrdinalIgnoreCase
224+
);
225+
220226
// /attr:FQN("value1","value2","value3")
221-
args.Add($@"/attr:{attr.ItemSpec}:({
227+
args.Add($@"/attr:{attr.ItemSpec}({
222228
string.Join(
223229
",",
224230
Enumerable.Range(1, 128)
225-
.Select(n => attr.GetMetadata($"_Parameter{n}"))
226-
.TakeWhile(value => value != null)
231+
.Select(n => $"_Parameter{n}")
232+
.TakeWhile(prop => props.Contains(prop))
233+
.Select(prop => attr.GetMetadata(prop))
227234
.Select(value => $"\"{value.Replace("\"", "\\\"")}\"")
228235
)
229236
})");

0 commit comments

Comments
 (0)