parser.cpp 2.95 KB
Newer Older
Jesse Beder's avatar
Jesse Beder committed
1
2
3
4
#include <cstdio>
#include <sstream>

#include "directives.h"  // IWYU pragma: keep
Jesse Beder's avatar
Jesse Beder committed
5
#include "scanner.h"     // IWYU pragma: keep
6
#include "singledocparser.h"
7
#include "token.h"
Jesse Beder's avatar
Jesse Beder committed
8
9
#include "yaml-cpp/exceptions.h"  // IWYU pragma: keep
#include "yaml-cpp/parser.h"
10

Jesse Beder's avatar
Jesse Beder committed
11
namespace YAML {
Jesse Beder's avatar
Jesse Beder committed
12
13
class EventHandler;

14
Parser::Parser() : m_pScanner{}, m_pDirectives{} {}
Jesse Beder's avatar
Jesse Beder committed
15

16
Parser::Parser(std::istream& in) : Parser() { Load(in); }
Jesse Beder's avatar
Jesse Beder committed
17

18
Parser::~Parser() = default;
Jesse Beder's avatar
Jesse Beder committed
19

Ian Taylor's avatar
Ian Taylor committed
20
Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); }
Jesse Beder's avatar
Jesse Beder committed
21
22
23
24
25
26
27

void Parser::Load(std::istream& in) {
  m_pScanner.reset(new Scanner(in));
  m_pDirectives.reset(new Directives);
}

bool Parser::HandleNextDocument(EventHandler& eventHandler) {
28
  if (!m_pScanner)
Jesse Beder's avatar
Jesse Beder committed
29
30
31
    return false;

  ParseDirectives();
32
  if (m_pScanner->empty()) {
Jesse Beder's avatar
Jesse Beder committed
33
    return false;
34
  }
Jesse Beder's avatar
Jesse Beder committed
35
36
37
38
39
40
41
42
43

  SingleDocParser sdp(*m_pScanner, *m_pDirectives);
  sdp.HandleDocument(eventHandler);
  return true;
}

void Parser::ParseDirectives() {
  bool readDirective = false;

44
  while (!m_pScanner->empty()) {
Jesse Beder's avatar
Jesse Beder committed
45
    Token& token = m_pScanner->peek();
46
    if (token.type != Token::DIRECTIVE) {
Jesse Beder's avatar
Jesse Beder committed
47
      break;
48
    }
Jesse Beder's avatar
Jesse Beder committed
49
50
51

    // we keep the directives from the last document if none are specified;
    // but if any directives are specific, then we reset them
52
    if (!readDirective) {
Jesse Beder's avatar
Jesse Beder committed
53
      m_pDirectives.reset(new Directives);
54
    }
Jesse Beder's avatar
Jesse Beder committed
55
56
57
58
59
60
61
62

    readDirective = true;
    HandleDirective(token);
    m_pScanner->pop();
  }
}

void Parser::HandleDirective(const Token& token) {
63
  if (token.value == "YAML") {
Jesse Beder's avatar
Jesse Beder committed
64
    HandleYamlDirective(token);
65
  } else if (token.value == "TAG") {
Jesse Beder's avatar
Jesse Beder committed
66
    HandleTagDirective(token);
67
  }
Jesse Beder's avatar
Jesse Beder committed
68
69
70
}

void Parser::HandleYamlDirective(const Token& token) {
71
  if (token.params.size() != 1) {
Jesse Beder's avatar
Jesse Beder committed
72
    throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
73
  }
Jesse Beder's avatar
Jesse Beder committed
74

75
  if (!m_pDirectives->version.isDefault) {
Jesse Beder's avatar
Jesse Beder committed
76
    throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
77
  }
Jesse Beder's avatar
Jesse Beder committed
78
79
80
81
82

  std::stringstream str(token.params[0]);
  str >> m_pDirectives->version.major;
  str.get();
  str >> m_pDirectives->version.minor;
83
  if (!str || str.peek() != EOF) {
Jesse Beder's avatar
Jesse Beder committed
84
85
    throw ParserException(
        token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]);
86
  }
Jesse Beder's avatar
Jesse Beder committed
87

88
  if (m_pDirectives->version.major > 1) {
Jesse Beder's avatar
Jesse Beder committed
89
    throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
90
  }
Jesse Beder's avatar
Jesse Beder committed
91
92
93
94
95
96
97
98
99
100
101

  m_pDirectives->version.isDefault = false;
  // TODO: warning on major == 1, minor > 2?
}

void Parser::HandleTagDirective(const Token& token) {
  if (token.params.size() != 2)
    throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);

  const std::string& handle = token.params[0];
  const std::string& prefix = token.params[1];
102
  if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) {
Jesse Beder's avatar
Jesse Beder committed
103
    throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
104
  }
Jesse Beder's avatar
Jesse Beder committed
105
106
107
108
109

  m_pDirectives->tags[handle] = prefix;
}

void Parser::PrintTokens(std::ostream& out) {
110
  if (!m_pScanner) {
Jesse Beder's avatar
Jesse Beder committed
111
    return;
112
  }
Jesse Beder's avatar
Jesse Beder committed
113

114
  while (!m_pScanner->empty()) {
Jesse Beder's avatar
Jesse Beder committed
115
116
117
118
    out << m_pScanner->peek() << "\n";
    m_pScanner->pop();
  }
}
119
}  // namespace YAML