// Value void Scanner::ScanValue() { // and check that simple key bool isSimpleKey = VerifySimpleKey(); m_canBeJSONFlow = false; if(isSimpleKey) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) m_simpleKeyAllowed = false; } else { // handle values diffently in the block context (and manage indents) if(InBlockContext()) { if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); PushIndentTo(INPUT.column(), IndentMarker::MAP); } // can only put a simple key here if we're in block context m_simpleKeyAllowed = InBlockContext(); } // eat Mark mark = INPUT.mark(); INPUT.eat(1); m_tokens.push(Token(Token::VALUE, mark)); }
// FlowEnd void Scanner::ScanFlowEnd() { if(InBlockContext()) throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); // we might have a solo entry in the flow context if(InFlowContext()) { if(m_flows.top() == FLOW_MAP && VerifySimpleKey()) m_tokens.push(Token(Token::VALUE, INPUT.mark())); else if(m_flows.top() == FLOW_SEQ) InvalidateSimpleKey(); } m_simpleKeyAllowed = false; m_canBeJSONFlow = true; // eat Mark mark = INPUT.mark(); char ch = INPUT.get(); // check that it matches the start FLOW_MARKER flowType = (ch == Keys::FlowSeqEnd ? FLOW_SEQ : FLOW_MAP); if(m_flows.top() != flowType) throw ParserException(mark, ErrorMsg::FLOW_END); m_flows.pop(); Token::TYPE type = (flowType ? Token::FLOW_SEQ_END : Token::FLOW_MAP_END); m_tokens.push(Token(type, mark)); }
// ScanToNextToken // . Eats input until we reach the next token-like thing. void Scanner::ScanToNextToken() { while(1) { // first eat whitespace while(IsWhitespaceToBeEaten(INPUT.peek())) INPUT.eat(1); // then eat a comment if(Exp::Comment.Matches(INPUT)) { // eat until line break while(INPUT && !Exp::Break.Matches(INPUT)) INPUT.eat(1); } // if it's NOT a line break, then we're done! if(!Exp::Break.Matches(INPUT)) break; // otherwise, let's eat the line break and keep going int n = Exp::Break.Match(INPUT); INPUT.eat(n); // oh yeah, and let's get rid of that simple key VerifySimpleKey(); // new line - we may be able to accept a simple key now if(m_flowLevel == 0) m_simpleKeyAllowed = true; } }
// FlowEntry void Scanner::ScanFlowEntry() { // we might have a solo entry in the flow context if (InFlowContext()) { if (m_flows.top() == FLOW_MAP && VerifySimpleKey()) m_tokens.push(Token(Token::VALUE, INPUT.mark())); else if (m_flows.top() == FLOW_SEQ) InvalidateSimpleKey(); } m_simpleKeyAllowed = true; m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); INPUT.eat(1); m_tokens.push(Token(Token::FLOW_ENTRY, mark)); }
// VerifyAllSimplyKeys // . Pops all simple keys (with checking, but if we can't verify one, then pop it anyways). void Scanner::VerifyAllSimpleKeys() { while(!m_simpleKeys.empty()) VerifySimpleKey(true); }
// ScanNextToken // . The main scanning function; here we branch out and // scan whatever the next token should be. void Scanner::ScanNextToken() { if(m_endedStream) return; if(!m_startedStream) return StartStream(); // get rid of whitespace, etc. (in between tokens it should be irrelevent) ScanToNextToken(); // check the latest simple key VerifySimpleKey(); // maybe need to end some blocks PopIndentTo(INPUT.column); // ***** // And now branch based on the next few characters! // ***** // end of stream if(INPUT.peek() == EOF) return EndStream(); if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) return ScanDirective(); // document token if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) return ScanDocStart(); if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) return ScanDocEnd(); // flow start/end/entry if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart) return ScanFlowStart(); if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) return ScanFlowEnd(); if(INPUT.peek() == Keys::FlowEntry) return ScanFlowEntry(); // block/map stuff if(Exp::BlockEntry.Matches(INPUT)) return ScanBlockEntry(); if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) return ScanKey(); if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) return ScanValue(); // alias/anchor if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) return ScanAnchorOrAlias(); // tag if(INPUT.peek() == Keys::Tag) return ScanTag(); // special scalars if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) return ScanBlockScalar(); if(INPUT.peek() == '\'' || INPUT.peek() == '\"') return ScanQuotedScalar(); // plain scalars if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) return ScanPlainScalar(); // don't know what it is! throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN); }