// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text; using EpicGames.Core; namespace UnrealBuildTool { /// /// Stores information about a defined preprocessor macro /// class PreprocessorMacro { /// /// Name of the macro /// public readonly Identifier Name; /// /// Parameter names for the macro. The '...' placeholder is represented by the __VA_ARGS__ string. /// public readonly List? Parameters; /// /// Raw list of tokens for this macro /// public readonly List Tokens; /// /// Construct a preprocessor macro /// /// Name of the macro /// Parameter list for the macro. Should be null for object macros. Ownership of this list is transferred. /// Tokens for the macro. Ownership of this list is transferred. public PreprocessorMacro(Identifier name, List? parameters, List tokens) { Name = name; Parameters = parameters; Tokens = tokens; } /// /// Read a macro from a binary archive /// /// Reader to serialize from public PreprocessorMacro(BinaryArchiveReader reader) { Name = reader.ReadIdentifier(); Parameters = reader.ReadList(() => reader.ReadIdentifier()); Tokens = reader.ReadList(() => reader.ReadToken())!; } /// /// Write a macro to a binary archive /// /// Writer to serialize to public void Write(BinaryArchiveWriter writer) { writer.WriteIdentifier(Name); writer.WriteList(Parameters, x => writer.WriteIdentifier(x)); writer.WriteList(Tokens, x => writer.WriteToken(x)); } /// /// Finds the index of a parameter in the parameter list /// /// Parameter name to look for /// Index of the parameter, or -1 if it's not found. public int FindParameterIndex(Identifier parameter) { if (Parameters != null) { for (int idx = 0; idx < Parameters.Count; idx++) { if (Parameters[idx] == parameter) { return idx; } } } return -1; } /// /// Checks whether this macro definition is equivalent to another macro definition /// /// The macro definition to compare against /// True if the macro definitions are equivalent public bool IsEquivalentTo(PreprocessorMacro other) { if (this != other) { if (Name != other.Name || Tokens.Count != other.Tokens.Count) { return false; } if (Parameters != null) { if (other.Parameters == null || other.Parameters.Count != Parameters.Count || !Enumerable.SequenceEqual(Parameters, other.Parameters)) { return false; } } else { if (other.Parameters != null) { return false; } } if (!Enumerable.SequenceEqual(Tokens, other.Tokens)) { return false; } } return true; } /// /// True if the macro is an object macro /// public bool IsObjectMacro => Parameters == null; /// /// True if the macro is a function macro /// public bool IsFunctionMacro => Parameters != null; /// /// The number of required parameters. For variadic macros, the last parameter is optional. /// public int MinRequiredParameters => HasVariableArgumentList ? (Parameters!.Count - 1) : Parameters!.Count; /// /// True if the macro has a variable argument list /// public bool HasVariableArgumentList => Parameters!.Count > 0 && Parameters[^1] == Identifiers.__VA_ARGS__; /// /// Converts this macro to a string for debugging /// /// The tokens in this macro public override string ToString() { StringBuilder result = new(Name.ToString()); if (Parameters != null) { result.AppendFormat("({0})", String.Join(", ", Parameters)); } result.Append('='); if (Tokens.Count > 0) { result.Append(Tokens[0].Text); for (int idx = 1; idx < Tokens.Count; idx++) { if (Tokens[idx].HasLeadingSpace) { result.Append(' '); } result.Append(Tokens[idx].Text); } } return result.ToString(); } } }