mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
208 lines
7.1 KiB
C++
208 lines
7.1 KiB
C++
//===--- 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 <forward_list>
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
|
|
/// Deserialization traits for SourcePresence.
|
|
template <> struct ScalarEnumerationTraits<swift::SourcePresence> {
|
|
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<swift::tok> {
|
|
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 <typename Context> swift::TriviaPiece yamlize(IO &io, Context &Ctx) {
|
|
io.beginMapping();
|
|
auto ret = MappingTraits<swift::TriviaPiece>::mapping(io);
|
|
io.endMapping();
|
|
return ret;
|
|
}
|
|
|
|
template <typename Context>
|
|
void yamlize(IO &io, std::vector<swift::TriviaPiece> &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<std::vector<swift::TriviaPiece>> {
|
|
static size_t size(IO &in, std::vector<swift::TriviaPiece> &seq) {
|
|
return seq.size();
|
|
}
|
|
};
|
|
|
|
/// Deserialization traits for RawSyntax list.
|
|
template <> struct SequenceTraits<std::vector<swift::RC<swift::RawSyntax>>> {
|
|
static size_t size(IO &in, std::vector<swift::RC<swift::RawSyntax>> &seq) {
|
|
return seq.size();
|
|
}
|
|
static swift::RC<swift::RawSyntax> &
|
|
element(IO &in, std::vector<swift::RC<swift::RawSyntax>> &seq, size_t index) {
|
|
if (seq.size() <= index) {
|
|
seq.resize(index + 1);
|
|
}
|
|
return const_cast<swift::RC<swift::RawSyntax> &>(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": <token name, e.g. "kw_struct">,
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// 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<TokenDescription> {
|
|
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<RawSyntax>.
|
|
/// 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": <token kind>, "text": <token text> },
|
|
/// "leadingTrivia": [ <trivia pieces...> ],
|
|
/// "trailingTrivia": [ <trivia pieces...> ],
|
|
/// "presence": <"Present" or "Missing">
|
|
/// }
|
|
/// ```
|
|
/// All other raw syntax nodes will have this structure:
|
|
/// ```
|
|
/// {
|
|
/// "kind": <syntax kind>,
|
|
/// "layout": [ <raw syntax nodes...> ],
|
|
/// "presence": <"Present" or "Missing">
|
|
/// }
|
|
/// ```
|
|
|
|
template <> struct MappingTraits<swift::RC<swift::RawSyntax>> {
|
|
static void mapping(IO &in, swift::RC<swift::RawSyntax> &value) {
|
|
TokenDescription description;
|
|
auto input = static_cast<Input *>(&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<swift::TriviaPiece> leadingTrivia;
|
|
in.mapRequired("leadingTrivia", leadingTrivia);
|
|
std::vector<swift::TriviaPiece> 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<swift::RC<swift::RawSyntax>> 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<swift::SourceFileSyntax> getSourceFileSyntax() {
|
|
swift::RC<swift::RawSyntax> raw;
|
|
Input >> raw;
|
|
return swift::make<swift::SourceFileSyntax>(raw);
|
|
}
|
|
};
|
|
} // namespace json
|
|
} // namespace swift
|
|
|
|
#endif /* SWIFT_SYNTAX_SERIALIZATION_SYNTAXDESERIALIZATION_H */
|