Yaml.h (11189B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <AppInstallerSHA256.h> 5 6 #include <fstream> 7 #include <map> 8 #include <memory> 9 #include <optional> 10 #include <stack> 11 #include <string> 12 #include <string_view> 13 #include <vector> 14 15 16 namespace AppInstaller::YAML 17 { 18 // A location within the stream. 19 struct Mark 20 { 21 Mark() = default; 22 Mark(size_t l, size_t c) : line(l), column(c) {} 23 24 size_t line = 0; 25 size_t column = 0; 26 }; 27 28 // An exception from YAML. 29 struct Exception : public wil::ResultException 30 { 31 // The type of error that occurred. 32 enum class Type 33 { 34 None, 35 Memory, 36 Reader, 37 Scanner, 38 Parser, 39 Composer, 40 Writer, 41 Emitter, 42 Policy, 43 }; 44 45 // Should only be used for Memory. 46 Exception(Type type); 47 48 // Should only be used for Reader. 49 Exception(Type type, const char* problem, size_t offset, int value); 50 51 // Used for Scanner, Parser, and Composer. 52 Exception(Type type, const char* problem, const Mark& problemMark, const char* context = {}, const Mark& contextMark = {}); 53 54 // Used for Writer and Emitter. 55 Exception(Type type, const char* problem); 56 57 const char* what() const noexcept override; 58 59 const Mark& GetMark() const; 60 61 private: 62 std::string m_what; 63 YAML::Mark m_mark; 64 }; 65 66 // A YAML node. 67 struct Node 68 { 69 // The node's type. 70 enum class Type 71 { 72 Invalid, 73 None, 74 Scalar, 75 Sequence, 76 Mapping 77 }; 78 79 // The node's tag 80 enum class TagType 81 { 82 Unknown, 83 Null, 84 Bool, 85 Str, 86 Int, 87 Float, 88 Timestamp, 89 Seq, 90 Map, 91 }; 92 93 Node() : m_type(Type::Invalid), m_tagType(TagType::Unknown) {} 94 Node(Type type, std::string tag, const Mark& mark); 95 96 // Sets the scalar value of the node. 97 void SetScalar(std::string value); 98 void SetScalar(std::string value, bool isQuoted); 99 100 // Adds a child node to the sequence. 101 template <typename... Args> 102 Node& AddSequenceNode(Args&&... args) 103 { 104 Require(Type::Sequence); 105 return m_sequence->emplace_back(std::forward<Args>(args)...); 106 } 107 108 // Merges sequence nodes. If both sequence have the specified key with the same value 109 // they will get merged together. All elements in sequence must have the key. 110 void MergeSequenceNode(Node other, std::string_view key, bool caseInsensitive = false); 111 112 // Adds a child node to the mapping. 113 template <typename... Args> 114 Node& AddMappingNode(Node&& key, Args&&... args) 115 { 116 Require(Type::Mapping); 117 return m_mapping->emplace(std::move(key), Node(std::forward<Args>(args)...))->second; 118 } 119 120 // Merge mapping node. If both contain a node with the same key preserve this. 121 void MergeMappingNode(Node other, bool caseInsensitive = false); 122 123 bool IsDefined() const { return m_type != Type::Invalid; } 124 bool IsNull() const { return m_type == Type::Invalid || m_type == Type::None || (m_type == Type::Scalar && m_scalar.empty()); } 125 bool IsScalar() const { return m_type == Type::Scalar; } 126 bool IsSequence() const { return m_type == Type::Sequence; } 127 bool IsMap() const { return m_type == Type::Mapping; } 128 Type GetType() const { return m_type; } 129 TagType GetTagType() const { return m_tagType; } 130 131 explicit operator bool() const { return IsDefined(); } 132 133 // Gets the scalar value as the requested type. 134 template <typename T> 135 T as() const 136 { 137 Require(Type::Scalar); 138 T* t = nullptr; 139 return as_dispatch(t); 140 } 141 142 template <typename T> 143 std::optional<T> try_as() const 144 { 145 if (m_type != Type::Scalar) 146 { 147 return {}; 148 } 149 150 T* t = nullptr; 151 return try_as_dispatch(t); 152 } 153 154 bool operator<(const Node& other) const; 155 156 // Gets a child node from the mapping by its name. 157 Node& operator[](std::string_view key); 158 const Node& operator[](std::string_view key) const; 159 160 // Gets a child node from the mapping by its name case-insensitive. 161 Node& GetChildNode(std::string_view key); 162 const Node& GetChildNode(std::string_view key) const; 163 164 // Gets a child node from the sequence by its index. 165 Node& operator[](size_t index); 166 const Node& operator[](size_t index) const; 167 168 // Gets the number of child nodes. 169 size_t size() const; 170 171 // Gets the mark for this node. 172 const Mark& Mark() const { return m_mark; } 173 174 // Gets the nodes in the sequence. 175 const std::vector<Node>& Sequence() const; 176 177 // Gets the nodes in the mapping. 178 const std::multimap<Node, Node>& Mapping() const; 179 180 private: 181 Node(std::string_view key) : m_type(Type::Scalar), m_scalar(key), m_tagType(TagType::Str) {} 182 183 // Require certain node types to; throwing if the requirement is not met. 184 void Require(Type type) const; 185 186 // The workers for the as function. 187 std::string as_dispatch(std::string*) const; 188 std::optional<std::string> try_as_dispatch(std::string*) const; 189 190 std::wstring as_dispatch(std::wstring*) const; 191 std::optional<std::wstring> try_as_dispatch(std::wstring*) const; 192 193 int64_t as_dispatch(int64_t*) const; 194 std::optional<int64_t> try_as_dispatch(int64_t*) const; 195 196 int as_dispatch(int*) const; 197 std::optional<int> try_as_dispatch(int*) const; 198 199 bool as_dispatch(bool*) const; 200 std::optional<bool> try_as_dispatch(bool*) const; 201 202 Type m_type; 203 std::string m_tag; 204 TagType m_tagType; 205 YAML::Mark m_mark; 206 std::string m_scalar; 207 std::optional<std::vector<Node>> m_sequence; 208 std::optional<std::multimap<Node, Node>> m_mapping; 209 }; 210 211 // Loads from the input; returns the root node of the first document. 212 Node Load(std::string_view input); 213 Node Load(const std::string& input); 214 Node Load(const std::filesystem::path& input); 215 Node Load(const std::filesystem::path& input, Utility::SHA256::HashBuffer& hashOut); 216 217 // Any emitter event. 218 // Not using enum class to enable existing code to function. 219 enum EmitterEvent 220 { 221 BeginSeq, 222 EndSeq, 223 BeginMap, 224 EndMap, 225 Key, 226 Value, 227 }; 228 229 // Sets the scalar style to use for the next scalar output. 230 enum class ScalarStyle 231 { 232 Any, 233 Plain, 234 SingleQuoted, 235 DoubleQuoted, 236 Literal, 237 Folded, 238 }; 239 240 // A schema header for a document. 241 struct DocumentSchemaHeader 242 { 243 DocumentSchemaHeader() = default; 244 DocumentSchemaHeader(std::string schemaHeaderString, const Mark& mark) : SchemaHeader(std::move(schemaHeaderString)), Mark(mark) {} 245 246 std::string SchemaHeader; 247 Mark Mark; 248 static constexpr std::string_view YamlLanguageServerKey = "yaml-language-server"; 249 }; 250 251 struct Document 252 { 253 Document() = default; 254 Document(Node root, DocumentSchemaHeader schemaHeader) : m_root(std::move(root)), m_schemaHeader(std::move(schemaHeader)) {} 255 256 const DocumentSchemaHeader& GetSchemaHeader() const { return m_schemaHeader; } 257 258 // Return r-values for move semantics 259 Node&& GetRoot() && { return std::move(m_root); } 260 261 private: 262 Node m_root; 263 DocumentSchemaHeader m_schemaHeader; 264 }; 265 266 // Forward declaration to allow pImpl in this Emitter. 267 namespace Wrapper 268 { 269 struct Document; 270 } 271 272 // Loads from the input; returns the root node of the first document. 273 Document LoadDocument(std::string_view input); 274 Document LoadDocument(const std::string& input); 275 Document LoadDocument(const std::filesystem::path& input); 276 Document LoadDocument(const std::filesystem::path& input, Utility::SHA256::HashBuffer& hashOut); 277 278 // A YAML emitter. 279 struct Emitter 280 { 281 Emitter(); 282 283 Emitter(const Emitter&) = delete; 284 Emitter& operator=(const Emitter&) = delete; 285 286 Emitter(Emitter&&) noexcept; 287 Emitter& operator=(Emitter&&) noexcept; 288 289 ~Emitter(); 290 291 // Emit events and values. 292 Emitter& operator<<(EmitterEvent event); 293 Emitter& operator<<(std::string_view value); 294 Emitter& operator<<(int64_t value); 295 Emitter& operator<<(int value); 296 Emitter& operator<<(bool value); 297 298 Emitter& operator<<(ScalarStyle style); 299 300 // Gets the result of the emitter; can only be retrieved once. 301 std::string str(); 302 303 // Gets the result of the emitter to out stream; can only be retrieved once. 304 void Emit(std::ostream& out); 305 306 private: 307 // Appends the given node to the current container if applicable. 308 void AppendNode(int id); 309 310 std::unique_ptr<Wrapper::Document> m_document; 311 312 // If set, stores the last Key that was set. 313 std::optional<int> m_keyId; 314 315 struct ContainerInfo 316 { 317 ContainerInfo(int id, bool map) : Id(id), IsMapping(map) {} 318 319 int Id; 320 bool IsMapping; 321 }; 322 323 // The stack of containers being emitted. 324 std::stack<ContainerInfo> m_containers; 325 326 // *** State Machine *** 327 328 // The type of input coming into the emitter. 329 enum class InputType 330 { 331 Scalar, 332 BeginSeq, 333 EndSeq, 334 BeginMap, 335 EndMap, 336 Key, 337 Value, 338 }; 339 340 // If set, defines the type of the next scalar (Key or Value). 341 std::optional<InputType> m_scalarType; 342 343 // If set, defines the style of the next scalar. 344 std::optional<ScalarStyle> m_scalarStyle; 345 346 // Converts the input type to a bitmask value. 347 size_t GetInputBitmask(InputType type); 348 349 // Checks the state of the emitter to ensure that the incoming value is acceptable. 350 void CheckInput(InputType type); 351 352 // The currently allowed input types. 353 size_t m_allowedInputs = 0; 354 355 template <InputType... types> 356 void SetAllowedInputs() 357 { 358 m_allowedInputs = (GetInputBitmask(types) | ...); 359 } 360 361 // Sets the allowed inputs for the container on the top of the stack. 362 void SetAllowedInputsForContainer(); 363 }; 364 }