//===--- SyntaxDeserialization.h - Swift Syntax Deserialization --*- C++-*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file provides the deserialization from JSON to RawSyntax nodes and their // constituent parts. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SYNTAX_SERIALIZATION_SYNTAXDESERIALIZATION_H #define SWIFT_SYNTAX_SERIALIZATION_SYNTAXDESERIALIZATION_H #include "swift/Basic/StringExtras.h" #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/SyntaxNodes.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/YAMLTraits.h" #include namespace llvm { namespace yaml { /// Deserialization traits for SourcePresence. template <> struct ScalarEnumerationTraits { static void enumeration(IO &in, swift::SourcePresence &value) { in.enumCase(value, "Present", swift::SourcePresence::Present); in.enumCase(value, "Missing", swift::SourcePresence::Missing); } }; /// Deserialization traits for swift::tok. template <> struct ScalarEnumerationTraits { static void enumeration(IO &in, swift::tok &value) { #define TOKEN(name) in.enumCase(value, #name, swift::tok::name); #include "swift/Syntax/TokenKinds.def" } }; /// Deserialization traits for Trivia. /// An array of the underlying TriviaPieces will be deserialized as Trivia. template swift::TriviaPiece yamlize(IO &io, Context &Ctx) { io.beginMapping(); auto ret = MappingTraits::mapping(io); io.endMapping(); return ret; } template void yamlize(IO &io, std::vector &Seq, bool, Context &Ctx) { unsigned incnt = io.beginSequence(); for (unsigned i = 0; i < incnt; ++i) { void *SaveInfo; if (io.preflightElement(i, SaveInfo)) { Seq.push_back(yamlize(io, Ctx)); io.postflightElement(SaveInfo); } } io.endSequence(); } template <> struct SequenceTraits> { static size_t size(IO &in, std::vector &seq) { return seq.size(); } }; /// Deserialization traits for RawSyntax list. template <> struct SequenceTraits>> { static size_t size(IO &in, std::vector> &seq) { return seq.size(); } static swift::RC & element(IO &in, std::vector> &seq, size_t index) { if (seq.size() <= index) { seq.resize(index + 1); } return const_cast &>(seq[index]); } }; /// An adapter struct that provides a nested structure for token content. struct TokenDescription { bool hasValue = false; swift::tok Kind; StringRef Text; }; /// Desrialization traits for TokenDescription. /// TokenDescriptions always serialized with a token kind, which is /// the stringified version of their name in the tok:: enum. /// ``` /// { /// "kind": , /// } /// ``` /// /// For tokens that have some kind of text attached, like literals or /// identifiers, the serialized form will also have a "text" key containing /// that text as the value. template <> struct MappingTraits { static void mapping(IO &in, TokenDescription &value) { in.mapRequired("kind", value.Kind); value.hasValue = true; if (!swift::isTokenTextDetermined(value.Kind)) { in.mapRequired("text", value.Text); } else { value.Text = swift::getTokenText(value.Kind); } } }; /// Deserialization traits for RC. /// First it will check whether the node is null. /// Then this will be different depending if the raw syntax node is a Token or /// not. Token nodes will always have this structure: /// ``` /// { /// "tokenKind": { "kind": , "text": }, /// "leadingTrivia": [ ], /// "trailingTrivia": [ ], /// "presence": <"Present" or "Missing"> /// } /// ``` /// All other raw syntax nodes will have this structure: /// ``` /// { /// "kind": , /// "layout": [ ], /// "presence": <"Present" or "Missing"> /// } /// ``` template <> struct MappingTraits> { static void mapping(IO &in, swift::RC &value) { TokenDescription description; auto input = static_cast(&in); /// Check whether this is null if (input->getCurrentNode()->getType() != Node::NodeKind::NK_Mapping) { return; } in.mapOptional("tokenKind", description); if (description.hasValue) { swift::tok tokenKind = description.Kind; StringRef text = description.Text; std::vector leadingTrivia; in.mapRequired("leadingTrivia", leadingTrivia); std::vector trailingTrivia; in.mapRequired("trailingTrivia", trailingTrivia); swift::SourcePresence presence; in.mapRequired("presence", presence); /// FIXME: This is a workaround for existing bug from llvm yaml parser /// which would raise error when deserializing number with trailing /// character like "1\n". See https://bugs.llvm.org/show_bug.cgi?id=15505 StringRef nodeIdString; in.mapRequired("id", nodeIdString); unsigned nodeId = std::atoi(nodeIdString.data()); value = swift::RawSyntax::make(tokenKind, text, leadingTrivia, trailingTrivia, presence, /*Arena=*/nullptr, nodeId); } else { swift::SyntaxKind kind; in.mapRequired("kind", kind); std::vector> layout; in.mapRequired("layout", layout); swift::SourcePresence presence; in.mapRequired("presence", presence); /// FIXME: This is a workaround for existing bug from llvm yaml parser /// which would raise error when deserializing number with trailing /// character like "1\n". See https://bugs.llvm.org/show_bug.cgi?id=15505 StringRef nodeIdString; in.mapRequired("id", nodeIdString); unsigned nodeId = std::atoi(nodeIdString.data()); value = swift::RawSyntax::make(kind, layout, presence, /*Arena=*/nullptr, nodeId); } } }; } // end namespace yaml } // end namespace llvm namespace swift { namespace json { class SyntaxDeserializer { llvm::yaml::Input Input; public: SyntaxDeserializer(llvm::StringRef InputContent) : Input(InputContent) {} SyntaxDeserializer(llvm::MemoryBufferRef buffer) : Input(buffer) {} llvm::Optional getSourceFileSyntax() { swift::RC raw; Input >> raw; return swift::make(raw); } }; } // namespace json } // namespace swift #endif /* SWIFT_SYNTAX_SERIALIZATION_SYNTAXDESERIALIZATION_H */