Commit a372bfdc authored by Jesse Beder's avatar Jesse Beder
Browse files

Merged r295:305 from the tags branch to the trunk

parent fe57829a
...@@ -52,6 +52,7 @@ namespace YAML ...@@ -52,6 +52,7 @@ namespace YAML
Emitter& Write(double d); Emitter& Write(double d);
Emitter& Write(const _Alias& alias); Emitter& Write(const _Alias& alias);
Emitter& Write(const _Anchor& anchor); Emitter& Write(const _Anchor& anchor);
Emitter& Write(const _Tag& tag);
Emitter& Write(const _Comment& comment); Emitter& Write(const _Comment& comment);
Emitter& Write(const _Null& null); Emitter& Write(const _Null& null);
......
...@@ -80,6 +80,16 @@ namespace YAML ...@@ -80,6 +80,16 @@ namespace YAML
inline _Anchor Anchor(const std::string content) { inline _Anchor Anchor(const std::string content) {
return _Anchor(content); return _Anchor(content);
} }
struct _Tag {
_Tag(const std::string& content_): content(content_), verbatim(true) {}
std::string content;
bool verbatim;
};
inline _Tag VerbatimTag(const std::string& content) {
return _Tag(content);
}
struct _Comment { struct _Comment {
_Comment(const std::string& content_): content(content_) {} _Comment(const std::string& content_): content(content_) {}
......
...@@ -17,7 +17,12 @@ namespace YAML ...@@ -17,7 +17,12 @@ namespace YAML
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
const std::string YAML_VERSION = "bad YAML version: "; const std::string YAML_VERSION = "bad YAML version: ";
const std::string YAML_MAJOR_VERSION = "YAML major version too large"; const std::string YAML_MAJOR_VERSION = "YAML major version too large";
const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive";
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
const std::string CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle";
const std::string TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
const std::string END_OF_VERBATIM_TAG = "end of verbatim tag not found";
const std::string END_OF_MAP = "end of map not found"; const std::string END_OF_MAP = "end of map not found";
const std::string END_OF_MAP_FLOW = "end of map flow not found"; const std::string END_OF_MAP_FLOW = "end of map flow not found";
const std::string END_OF_SEQ = "end of sequence not found"; const std::string END_OF_SEQ = "end of sequence not found";
...@@ -57,6 +62,7 @@ namespace YAML ...@@ -57,6 +62,7 @@ namespace YAML
const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string";
const std::string INVALID_ANCHOR = "invalid anchor"; const std::string INVALID_ANCHOR = "invalid anchor";
const std::string INVALID_ALIAS = "invalid alias"; const std::string INVALID_ALIAS = "invalid alias";
const std::string INVALID_TAG = "invalid tag";
const std::string EXPECTED_KEY_TOKEN = "expected key token"; const std::string EXPECTED_KEY_TOKEN = "expected key token";
const std::string EXPECTED_VALUE_TOKEN = "expected value token"; const std::string EXPECTED_VALUE_TOKEN = "expected value token";
const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token";
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "iterator.h" #include "iterator.h"
#include "mark.h" #include "mark.h"
#include "noncopyable.h" #include "noncopyable.h"
#include "parserstate.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -21,6 +20,7 @@ namespace YAML ...@@ -21,6 +20,7 @@ namespace YAML
class Content; class Content;
class Scanner; class Scanner;
class Emitter; class Emitter;
class ParserState;
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
...@@ -75,6 +75,9 @@ namespace YAML ...@@ -75,6 +75,9 @@ namespace YAML
const Node *Identity() const { return m_pIdentity; } const Node *Identity() const { return m_pIdentity; }
bool IsAlias() const { return m_alias; } bool IsAlias() const { return m_alias; }
bool IsReferenced() const { return m_referenced; } bool IsReferenced() const { return m_referenced; }
// for tags
const std::string GetTag() const { return m_tag; } // TODO: should an aliased node return its alias's tag?
// emitting // emitting
friend Emitter& operator << (Emitter& out, const Node& node); friend Emitter& operator << (Emitter& out, const Node& node);
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "node.h" #include "node.h"
#include "parserstate.h"
#include "noncopyable.h" #include "noncopyable.h"
#include <ios> #include <ios>
#include <string> #include <string>
...@@ -16,6 +15,7 @@ ...@@ -16,6 +15,7 @@
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
class ParserState;
struct Token; struct Token;
class Parser: private noncopyable class Parser: private noncopyable
...@@ -33,13 +33,13 @@ namespace YAML ...@@ -33,13 +33,13 @@ namespace YAML
private: private:
void ParseDirectives(); void ParseDirectives();
void HandleDirective(Token *pToken); void HandleDirective(const Token& token);
void HandleYamlDirective(Token *pToken); void HandleYamlDirective(const Token& token);
void HandleTagDirective(Token *pToken); void HandleTagDirective(const Token& token);
private: private:
std::auto_ptr<Scanner> m_pScanner; std::auto_ptr<Scanner> m_pScanner;
ParserState m_state; std::auto_ptr<ParserState> m_pState;
}; };
} }
......
...@@ -146,6 +146,8 @@ namespace YAML ...@@ -146,6 +146,8 @@ namespace YAML
switch(curState) { switch(curState) {
// document-level // document-level
case ES_WAITING_FOR_DOC: case ES_WAITING_FOR_DOC:
m_stream << "---";
m_pState->RequireSeparation();
m_pState->SwitchState(ES_WRITING_DOC); m_pState->SwitchState(ES_WRITING_DOC);
return true; return true;
case ES_WRITING_DOC: case ES_WRITING_DOC:
...@@ -323,7 +325,10 @@ namespace YAML ...@@ -323,7 +325,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
if(flowType == Block) { if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n"; m_stream << "\n";
m_pState->UnsetSeparation(); m_pState->UnsetSeparation();
} }
...@@ -354,8 +359,12 @@ namespace YAML ...@@ -354,8 +359,12 @@ namespace YAML
// to a flow sequence if it is // to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY); assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) { if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent(); unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent) << "[]"; m_stream << IndentTo(curIndent);
m_stream << "[]";
} }
} else if(flowType == FT_FLOW) { } else if(flowType == FT_FLOW) {
// Note: flow sequences are allowed to be empty // Note: flow sequences are allowed to be empty
...@@ -384,7 +393,10 @@ namespace YAML ...@@ -384,7 +393,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
if(flowType == Block) { if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n"; m_stream << "\n";
m_pState->UnsetSeparation(); m_pState->UnsetSeparation();
} }
...@@ -415,8 +427,11 @@ namespace YAML ...@@ -415,8 +427,11 @@ namespace YAML
// to a flow sequence if it is // to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY); assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) { if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent(); unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent) << "{}"; m_stream << IndentTo(curIndent);
m_stream << "{}";
} }
} else if(flowType == FT_FLOW) { } else if(flowType == FT_FLOW) {
// Note: flow maps are allowed to be empty // Note: flow maps are allowed to be empty
...@@ -675,6 +690,22 @@ namespace YAML ...@@ -675,6 +690,22 @@ namespace YAML
return *this; return *this;
} }
Emitter& Emitter::Write(const _Tag& tag)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
if(!Utils::WriteTag(m_stream, tag.content)) {
m_pState->SetError(ErrorMsg::INVALID_TAG);
return *this;
}
m_pState->RequireSeparation();
// Note: no PostAtomicWrite() because we need another value for this node
return *this;
}
Emitter& Emitter::Write(const _Comment& comment) Emitter& Emitter::Write(const _Comment& comment)
{ {
if(!good()) if(!good())
......
...@@ -293,6 +293,24 @@ namespace YAML ...@@ -293,6 +293,24 @@ namespace YAML
out << "&"; out << "&";
return WriteAliasName(out, str); return WriteAliasName(out, str);
} }
bool WriteTag(ostream& out, const std::string& str)
{
out << "!<";
StringCharSource buffer(str.c_str(), str.size());
while(buffer) {
int n = Exp::URI.Match(buffer);
if(n <= 0)
return false;
while(--n >= 0) {
out << buffer[0];
++buffer;
}
}
out << ">";
return true;
}
} }
} }
...@@ -18,6 +18,7 @@ namespace YAML ...@@ -18,6 +18,7 @@ namespace YAML
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent); bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
bool WriteAlias(ostream& out, const std::string& str); bool WriteAlias(ostream& out, const std::string& str);
bool WriteAnchor(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str);
bool WriteTag(ostream& out, const std::string& str);
} }
} }
......
...@@ -25,6 +25,7 @@ namespace YAML ...@@ -25,6 +25,7 @@ namespace YAML
const RegEx Digit = RegEx('0', '9'); const RegEx Digit = RegEx('0', '9');
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
const RegEx AlphaNumeric = Alpha || Digit; const RegEx AlphaNumeric = Alpha || Digit;
const RegEx Word = AlphaNumeric || RegEx('-');
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1) // Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1)
const RegEx NotPrintable = RegEx(0) || const RegEx NotPrintable = RegEx(0) ||
...@@ -45,6 +46,8 @@ namespace YAML ...@@ -45,6 +46,8 @@ namespace YAML
ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)); ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR));
const RegEx Comment = RegEx('#'); const RegEx Comment = RegEx('#');
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak;
const RegEx URI = Word || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex + Hex);
const RegEx Tag = Word || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex + Hex);
// Plain scalar rules: // Plain scalar rules:
// . Cannot start with a blank. // . Cannot start with a blank.
...@@ -79,6 +82,8 @@ namespace YAML ...@@ -79,6 +82,8 @@ namespace YAML
const char Tag = '!'; const char Tag = '!';
const char LiteralScalar = '|'; const char LiteralScalar = '|';
const char FoldedScalar = '>'; const char FoldedScalar = '>';
const char VerbatimTagStart = '<';
const char VerbatimTagEnd = '>';
} }
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "aliascontent.h" #include "aliascontent.h"
#include "iterpriv.h" #include "iterpriv.h"
#include "emitter.h" #include "emitter.h"
#include "tag.h"
#include <stdexcept> #include <stdexcept>
namespace YAML namespace YAML
...@@ -137,10 +138,8 @@ namespace YAML ...@@ -137,10 +138,8 @@ namespace YAML
if(m_tag != "") if(m_tag != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
m_tag = state.TranslateTag(token.value); Tag tag(token);
m_tag = tag.Translate(state);
for(std::size_t i=0;i<token.params.size();i++)
m_tag += token.params[i];
pScanner->pop(); pScanner->pop();
} }
...@@ -241,7 +240,10 @@ namespace YAML ...@@ -241,7 +240,10 @@ namespace YAML
bool Node::GetScalar(std::string& s) const bool Node::GetScalar(std::string& s) const
{ {
if(!m_pContent) { if(!m_pContent) {
s = "~"; if(m_tag.empty())
s = "~";
else
s = "";
return true; return true;
} }
...@@ -258,7 +260,8 @@ namespace YAML ...@@ -258,7 +260,8 @@ namespace YAML
out << Anchor(node.m_anchor); out << Anchor(node.m_anchor);
} }
// TODO: write tag if(node.m_tag != "")
out << VerbatimTag(node.m_tag);
// write content // write content
if(node.m_pContent) if(node.m_pContent)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "parserstate.h"
#include <sstream> #include <sstream>
#include <cstdio> #include <cstdio>
...@@ -28,7 +29,7 @@ namespace YAML ...@@ -28,7 +29,7 @@ namespace YAML
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
{ {
m_pScanner.reset(new Scanner(in)); m_pScanner.reset(new Scanner(in));
m_state.Reset(); m_pState.reset(new ParserState);
} }
// GetNextDocument // GetNextDocument
...@@ -54,7 +55,7 @@ namespace YAML ...@@ -54,7 +55,7 @@ namespace YAML
m_pScanner->pop(); m_pScanner->pop();
// now parse our root node // now parse our root node
document.Parse(m_pScanner.get(), m_state); document.Parse(m_pScanner.get(), *m_pState);
// and finally eat any doc ends we see // and finally eat any doc ends we see
while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END) while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END)
...@@ -83,51 +84,59 @@ namespace YAML ...@@ -83,51 +84,59 @@ namespace YAML
// we keep the directives from the last document if none are specified; // we keep the directives from the last document if none are specified;
// but if any directives are specific, then we reset them // but if any directives are specific, then we reset them
if(!readDirective) if(!readDirective)
m_state.Reset(); m_pState.reset(new ParserState);
readDirective = true; readDirective = true;
HandleDirective(&token); HandleDirective(token);
m_pScanner->pop(); m_pScanner->pop();
} }
} }
void Parser::HandleDirective(Token *pToken) void Parser::HandleDirective(const Token& token)
{ {
if(pToken->value == "YAML") if(token.value == "YAML")
HandleYamlDirective(pToken); HandleYamlDirective(token);
else if(pToken->value == "TAG") else if(token.value == "TAG")
HandleTagDirective(pToken); HandleTagDirective(token);
} }
// HandleYamlDirective // HandleYamlDirective
// . Should be of the form 'major.minor' (like a version number) // . Should be of the form 'major.minor' (like a version number)
void Parser::HandleYamlDirective(Token *pToken) void Parser::HandleYamlDirective(const Token& token)
{ {
if(pToken->params.size() != 1) if(token.params.size() != 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_DIRECTIVE_ARGS); throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
if(!m_pState->version.isDefault)
throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
std::stringstream str(pToken->params[0]); std::stringstream str(token.params[0]);
str >> m_state.version.major; str >> m_pState->version.major;
str.get(); str.get();
str >> m_state.version.minor; str >> m_pState->version.minor;
if(!str || str.peek() != EOF) if(!str || str.peek() != EOF)
throw ParserException(pToken->mark, ErrorMsg::YAML_VERSION + pToken->params[0]); throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]);
if(m_state.version.major > 1) if(m_pState->version.major > 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_MAJOR_VERSION); throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
m_pState->version.isDefault = false;
// TODO: warning on major == 1, minor > 2? // TODO: warning on major == 1, minor > 2?
} }
// HandleTagDirective // HandleTagDirective
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
void Parser::HandleTagDirective(Token *pToken) void Parser::HandleTagDirective(const Token& token)
{ {
if(pToken->params.size() != 2) if(token.params.size() != 2)
throw ParserException(pToken->mark, ErrorMsg::TAG_DIRECTIVE_ARGS); throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
std::string handle = pToken->params[0], prefix = pToken->params[1]; const std::string& handle = token.params[0];
m_state.tags[handle] = prefix; const std::string& prefix = token.params[1];
if(m_pState->tags.find(handle) != m_pState->tags.end())
throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
m_pState->tags[handle] = prefix;
} }
void Parser::PrintTokens(std::ostream& out) void Parser::PrintTokens(std::ostream& out)
......
...@@ -2,23 +2,22 @@ ...@@ -2,23 +2,22 @@
namespace YAML namespace YAML
{ {
void ParserState::Reset() ParserState::ParserState()
{ {
// version // version
version.isDefault = true;
version.major = 1; version.major = 1;
version.minor = 2; version.minor = 2;
// and tags
tags.clear();
tags["!"] = "!";
tags["!!"] = "tag:yaml.org,2002:";
} }
std::string ParserState::TranslateTag(const std::string& handle) const const std::string ParserState::TranslateTagHandle(const std::string& handle) const
{ {
std::map <std::string, std::string>::const_iterator it = tags.find(handle); std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end()) if(it == tags.end()) {
if(handle == "!!")
return "tag:yaml.org,2002:";
return handle; return handle;
}
return it->second; return it->second;
} }
......
...@@ -10,16 +10,17 @@ ...@@ -10,16 +10,17 @@
namespace YAML namespace YAML
{ {
struct Version { struct Version {
bool isDefault;
int major, minor; int major, minor;
}; };
struct ParserState struct ParserState
{ {
ParserState();
const std::string TranslateTagHandle(const std::string& handle) const;
Version version; Version version;
std::map <std::string, std::string> tags; std::map <std::string, std::string> tags;
void Reset();
std::string TranslateTag(const std::string& handle) const;
}; };
} }
......
...@@ -37,12 +37,12 @@ namespace YAML ...@@ -37,12 +37,12 @@ namespace YAML
int Match(const std::string& str) const; int Match(const std::string& str) const;
int Match(const Stream& in) const; int Match(const Stream& in) const;
template <typename Source> int Match(const Source& source) const;
private: private:
RegEx(REGEX_OP op); RegEx(REGEX_OP op);
template <typename Source> bool IsValidSource(const Source& source) const; template <typename Source> bool IsValidSource(const Source& source) const;
template <typename Source> int Match(const Source& source) const;
template <typename Source> int MatchUnchecked(const Source& source) const; template <typename Source> int MatchUnchecked(const Source& source) const;
template <typename Source> int MatchOpEmpty(const Source& source) const; template <typename Source> int MatchOpEmpty(const Source& source) const;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include <cassert> #include <cassert>
#include <memory>
namespace YAML namespace YAML
{ {
...@@ -13,6 +14,9 @@ namespace YAML ...@@ -13,6 +14,9 @@ namespace YAML
Scanner::~Scanner() Scanner::~Scanner()
{ {
for(unsigned i=0;i<m_indentRefs.size();i++)
delete m_indentRefs[i];
m_indentRefs.clear();
} }
// empty // empty
...@@ -228,7 +232,9 @@ namespace YAML ...@@ -228,7 +232,9 @@ namespace YAML
{ {
m_startedStream = true; m_startedStream = true;
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_indents.push(IndentMarker(-1, IndentMarker::NONE)); IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE);
m_indentRefs.push_back(pIndent);
m_indents.push(pIndent);
m_anchors.clear(); m_anchors.clear();
} }
...@@ -257,8 +263,9 @@ namespace YAML ...@@ -257,8 +263,9 @@ namespace YAML
if(InFlowContext()) if(InFlowContext())
return 0; return 0;
IndentMarker indent(column, type); std::auto_ptr<IndentMarker> pIndent(new IndentMarker(column, type));
const IndentMarker& lastIndent = m_indents.top(); IndentMarker& indent = *pIndent;
const IndentMarker& lastIndent = *m_indents.top();
// is this actually an indentation? // is this actually an indentation?
if(indent.column < lastIndent.column) if(indent.column < lastIndent.column)
...@@ -276,13 +283,15 @@ namespace YAML ...@@ -276,13 +283,15 @@ namespace YAML
indent.pStartToken = &m_tokens.back(); indent.pStartToken = &m_tokens.back();
// and then the indent // and then the indent
m_indents.push(indent); m_indents.push(&indent);
return &m_indents.top(); m_indentRefs.push_back(pIndent.release());
return m_indentRefs.back();
} }
// PopIndentToHere // PopIndentToHere
// . Pops indentations off the stack until we reach the current indentation level, // . Pops indentations off the stack until we reach the current indentation level,
// and enqueues the proper token each time. // and enqueues the proper token each time.
// . Then pops all invalid indentations off.
void Scanner::PopIndentToHere() void Scanner::PopIndentToHere()
{ {
// are we in flow? // are we in flow?
...@@ -291,7 +300,7 @@ namespace YAML ...@@ -291,7 +300,7 @@ namespace YAML
// now pop away // now pop away
while(!m_indents.empty()) { while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
if(indent.column < INPUT.column()) if(indent.column < INPUT.column())
break; break;
if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT))) if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT)))
...@@ -299,6 +308,9 @@ namespace YAML ...@@ -299,6 +308,9 @@ namespace YAML
PopIndent(); PopIndent();
} }
while(!m_indents.empty() && m_indents.top()->status == IndentMarker::INVALID)
PopIndent();
} }
// PopAllIndents // PopAllIndents
...@@ -312,7 +324,7 @@ namespace YAML ...@@ -312,7 +324,7 @@ namespace YAML
// now pop away // now pop away
while(!m_indents.empty()) { while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
if(indent.type == IndentMarker::NONE) if(indent.type == IndentMarker::NONE)
break; break;
...@@ -324,17 +336,17 @@ namespace YAML ...@@ -324,17 +336,17 @@ namespace YAML
// . Pops a single indent, pushing the proper token // . Pops a single indent, pushing the proper token
void Scanner::PopIndent() void Scanner::PopIndent()
{ {
IndentMarker indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
IndentMarker::INDENT_TYPE type = indent.type;
m_indents.pop(); m_indents.pop();
if(!indent.isValid) {
if(indent.status != IndentMarker::VALID) {
InvalidateSimpleKey(); InvalidateSimpleKey();
return; return;
} }
if(type == IndentMarker::SEQ) if(indent.type == IndentMarker::SEQ)
m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark()));
else if(type == IndentMarker::MAP) else if(indent.type == IndentMarker::MAP)
m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark())); m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark()));
} }
...@@ -343,7 +355,7 @@ namespace YAML ...@@ -343,7 +355,7 @@ namespace YAML
{ {
if(m_indents.empty()) if(m_indents.empty())
return 0; return 0;
return m_indents.top().column; return m_indents.top()->column;
} }
// Save // Save
......
...@@ -36,11 +36,12 @@ namespace YAML ...@@ -36,11 +36,12 @@ namespace YAML
private: private:
struct IndentMarker { struct IndentMarker {
enum INDENT_TYPE { MAP, SEQ, NONE }; enum INDENT_TYPE { MAP, SEQ, NONE };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), isValid(true), pStartToken(0) {} enum STATUS { VALID, INVALID, UNKNOWN };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), status(VALID), pStartToken(0) {}
int column; int column;
INDENT_TYPE type; INDENT_TYPE type;
bool isValid; STATUS status;
Token *pStartToken; Token *pStartToken;
}; };
...@@ -118,10 +119,12 @@ namespace YAML ...@@ -118,10 +119,12 @@ namespace YAML
bool m_startedStream, m_endedStream; bool m_startedStream, m_endedStream;
bool m_simpleKeyAllowed; bool m_simpleKeyAllowed;
std::stack <SimpleKey> m_simpleKeys; std::stack <SimpleKey> m_simpleKeys;
std::stack <IndentMarker> m_indents; std::stack <IndentMarker *> m_indents;
std::vector <IndentMarker *> m_indentRefs; // for "garbage collection"
std::stack <FLOW_MARKER> m_flows; std::stack <FLOW_MARKER> m_flows;
std::map <std::string, const Node *> m_anchors; std::map <std::string, const Node *> m_anchors;
}; };
} }
#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
...@@ -40,3 +40,4 @@ namespace YAML ...@@ -40,3 +40,4 @@ namespace YAML
} }
#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "scanner.h"
#include "regex.h"
#include "exp.h"
#include "exceptions.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT)
{
std::string tag;
// eat the start character
INPUT.get();
while(INPUT) {
if(INPUT.peek() == Keys::VerbatimTagEnd) {
// eat the end character
INPUT.get();
return tag;
}
int n = Exp::URI.Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
throw ParserException(INPUT.mark(), ErrorMsg::END_OF_VERBATIM_TAG);
}
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle)
{
std::string tag;
canBeHandle = true;
Mark firstNonWordChar;
while(INPUT) {
if(INPUT.peek() == Keys::Tag) {
if(!canBeHandle)
throw ParserException(firstNonWordChar, ErrorMsg::CHAR_IN_TAG_HANDLE);
break;
}
int n = 0;
if(canBeHandle) {
n = Exp::Word.Match(INPUT);
if(n <= 0) {
canBeHandle = false;
firstNonWordChar = INPUT.mark();
}
}
if(!canBeHandle)
n = Exp::Tag.Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
return tag;
}
const std::string ScanTagSuffix(Stream& INPUT)
{
std::string tag;
while(INPUT) {
int n = Exp::Tag.Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
if(tag.empty())
throw ParserException(INPUT.mark(), ErrorMsg::TAG_WITH_NO_SUFFIX);
return tag;
}
}
#pragma once
#ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include "stream.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT);
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle);
const std::string ScanTagSuffix(Stream& INPUT);
}
#endif // SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include "scanscalar.h" #include "scanscalar.h"
#include "scantag.h"
#include "tag.h"
#include <sstream> #include <sstream>
namespace YAML namespace YAML
...@@ -24,12 +26,12 @@ namespace YAML ...@@ -24,12 +26,12 @@ namespace YAML
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
// store pos and eat indicator // store pos and eat indicator
Mark mark = INPUT.mark(); Token token(Token::DIRECTIVE, INPUT.mark());
INPUT.eat(1); INPUT.eat(1);
// read name // read name
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
name += INPUT.get(); token.value += INPUT.get();
// read parameters // read parameters
while(1) { while(1) {
...@@ -46,12 +48,9 @@ namespace YAML ...@@ -46,12 +48,9 @@ namespace YAML
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
param += INPUT.get(); param += INPUT.get();
params.push_back(param); token.params.push_back(param);
} }
Token token(Token::DIRECTIVE, mark);
token.value = name;
token.params = params;
m_tokens.push(token); m_tokens.push(token);
} }
...@@ -242,37 +241,34 @@ namespace YAML ...@@ -242,37 +241,34 @@ namespace YAML
// Tag // Tag
void Scanner::ScanTag() void Scanner::ScanTag()
{ {
std::string handle, suffix;
// insert a potential simple key // insert a potential simple key
InsertPotentialSimpleKey(); InsertPotentialSimpleKey();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
// eat the indicator Token token(Token::TAG, INPUT.mark());
Mark mark = INPUT.mark();
handle += INPUT.get();
// read the handle
while(INPUT && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT))
handle += INPUT.get();
// is there a suffix? // eat the indicator
if(INPUT.peek() == Keys::Tag) { INPUT.get();
// eat the indicator
handle += INPUT.get(); if(INPUT && INPUT.peek() == Keys::VerbatimTagStart){
std::string tag = ScanVerbatimTag(INPUT);
// then read it token.value = tag;
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) token.data = Tag::VERBATIM;
suffix += INPUT.get();
} else { } else {
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix bool canBeHandle;
suffix = handle.substr(1); token.value = ScanTagHandle(INPUT, canBeHandle);
handle = "!"; token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE);
// is there a suffix?
if(canBeHandle && INPUT.peek() == Keys::Tag) {
// eat the indicator
INPUT.get();
token.params.push_back(ScanTagSuffix(INPUT));
token.data = Tag::NAMED_HANDLE;
}
} }
Token token(Token::TAG, mark);
token.value = handle;
token.params.push_back(suffix);
m_tokens.push(token); m_tokens.push(token);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment