Browse code

A complete refactor/rewrite of the original seqbias code. This should behave more or less identically, but is much more coherent.

git-svn-id: file:///home/git/hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/seqbias@57223 bc3139a8-67e5-0310-9ffc-ced21a209358

Daniel Jones authored on 04/08/2011 07:36:48
Showing1 changed files
... ...
@@ -1,8 +1,8 @@
1
-#include "emitter.h"
1
+#include "yaml-cpp/emitter.h"
2 2
 #include "emitterstate.h"
3 3
 #include "emitterutils.h"
4 4
 #include "indentation.h"
5
-#include "exceptions.h"
5
+#include "yaml-cpp/exceptions.h"
6 6
 #include <sstream>
7 7
 
8 8
 namespace YAML
... ...
@@ -102,6 +102,12 @@ namespace YAML
102 102
 			return *this;
103 103
 		
104 104
 		switch(value) {
105
+			case BeginDoc:
106
+				EmitBeginDoc();
107
+				break;
108
+			case EndDoc:
109
+				EmitEndDoc();
110
+				break;
105 111
 			case BeginSeq:
106 112
 				EmitBeginSeq();
107 113
 				break;
... ...
@@ -120,6 +126,12 @@ namespace YAML
120 126
 			case Value:
121 127
 				EmitValue();
122 128
 				break;
129
+			case TagByKind:
130
+				EmitKindTag();
131
+				break;
132
+			case Newline:
133
+				EmitNewline();
134
+				break;
123 135
 			default:
124 136
 				m_pState->SetLocalValue(value);
125 137
 				break;
... ...
@@ -146,17 +158,18 @@ namespace YAML
146 158
 		switch(curState) {
147 159
 				// document-level
148 160
 			case ES_WAITING_FOR_DOC:
149
-				m_stream << "---";
150
-				m_pState->RequireSeparation();
151 161
 				m_pState->SwitchState(ES_WRITING_DOC);
152 162
 				return true;
153 163
 			case ES_WRITING_DOC:
154 164
 				return true;
165
+			case ES_DONE_WITH_DOC:
166
+				EmitBeginDoc();
167
+				return false;
155 168
 				
156 169
 				// block sequence
157 170
 			case ES_WAITING_FOR_BLOCK_SEQ_ENTRY:
158 171
 				m_stream << IndentTo(curIndent) << "-";
159
-				m_pState->RequireSeparation();
172
+				m_pState->RequireSoftSeparation();
160 173
 				m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY);
161 174
 				return true;
162 175
 			case ES_WRITING_BLOCK_SEQ_ENTRY:
... ...
@@ -174,7 +187,7 @@ namespace YAML
174 187
 				return true;
175 188
 			case ES_DONE_WITH_FLOW_SEQ_ENTRY:
176 189
 				m_stream << ',';
177
-				m_pState->RequireSeparation();
190
+				m_pState->RequireSoftSeparation();
178 191
 				m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
179 192
 				return false;
180 193
 				
... ...
@@ -185,7 +198,7 @@ namespace YAML
185 198
 			case ES_WAITING_FOR_BLOCK_MAP_KEY:
186 199
 				if(m_pState->CurrentlyInLongKey()) {
187 200
 					m_stream << IndentTo(curIndent) << '?';
188
-					m_pState->RequireSeparation();
201
+					m_pState->RequireSoftSeparation();
189 202
 				}
190 203
 				m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY);
191 204
 				return true;
... ...
@@ -195,10 +208,6 @@ namespace YAML
195 208
 				m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
196 209
 				return true;
197 210
 			case ES_WAITING_FOR_BLOCK_MAP_VALUE:
198
-				if(m_pState->CurrentlyInLongKey())
199
-					m_stream << IndentTo(curIndent);
200
-				m_stream << ':';
201
-				m_pState->RequireSeparation();
202 211
 				m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE);
203 212
 				return true;
204 213
 			case ES_WRITING_BLOCK_MAP_VALUE:
... ...
@@ -216,7 +225,7 @@ namespace YAML
216 225
 				if(m_pState->CurrentlyInLongKey()) {
217 226
 					EmitSeparationIfNecessary();
218 227
 					m_stream << '?';
219
-					m_pState->RequireSeparation();
228
+					m_pState->RequireSoftSeparation();
220 229
 				}
221 230
 				return true;
222 231
 			case ES_WRITING_FLOW_MAP_KEY:
... ...
@@ -226,7 +235,7 @@ namespace YAML
226 235
 				return true;
227 236
 			case ES_WAITING_FOR_FLOW_MAP_VALUE:
228 237
 				m_stream << ':';
229
-				m_pState->RequireSeparation();
238
+				m_pState->RequireSoftSeparation();
230 239
 				m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE);
231 240
 				return true;
232 241
 			case ES_WRITING_FLOW_MAP_VALUE:
... ...
@@ -280,6 +289,10 @@ namespace YAML
280 289
 				
281 290
 				// block map
282 291
 			case ES_WRITING_BLOCK_MAP_KEY:
292
+				if(!m_pState->CurrentlyInLongKey()) {
293
+					m_stream << ':';
294
+					m_pState->RequireSoftSeparation();
295
+				}
283 296
 				m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY);
284 297
 				break;
285 298
 			case ES_WRITING_BLOCK_MAP_VALUE:
... ...
@@ -306,11 +319,54 @@ namespace YAML
306 319
 		if(!good())
307 320
 			return;
308 321
 		
309
-		if(m_pState->RequiresSeparation())
322
+		if(m_pState->RequiresSoftSeparation())
310 323
 			m_stream << ' ';
324
+		else if(m_pState->RequiresHardSeparation())
325
+			m_stream << '\n';
311 326
 		m_pState->UnsetSeparation();
312 327
 	}
313 328
 	
329
+	// EmitBeginDoc
330
+	void Emitter::EmitBeginDoc()
331
+	{
332
+		if(!good())
333
+			return;
334
+		
335
+		EMITTER_STATE curState = m_pState->GetCurState();
336
+		if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) {
337
+			m_pState->SetError("Unexpected begin document");
338
+			return;
339
+		}
340
+		
341
+		if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC)
342
+			m_stream << '\n';		
343
+		m_stream << "---\n";
344
+
345
+		m_pState->UnsetSeparation();
346
+		m_pState->SwitchState(ES_WAITING_FOR_DOC);
347
+	}
348
+	
349
+	// EmitEndDoc
350
+	void Emitter::EmitEndDoc()
351
+	{
352
+		if(!good())
353
+			return;
354
+
355
+		
356
+		EMITTER_STATE curState = m_pState->GetCurState();
357
+		if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) {
358
+			m_pState->SetError("Unexpected end document");
359
+			return;
360
+		}
361
+		
362
+		if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC)
363
+			m_stream << '\n';		
364
+		m_stream << "...\n";
365
+		
366
+		m_pState->UnsetSeparation();
367
+		m_pState->SwitchState(ES_WAITING_FOR_DOC);
368
+	}
369
+
314 370
 	// EmitBeginSeq
315 371
 	void Emitter::EmitBeginSeq()
316 372
 	{
... ...
@@ -329,8 +385,10 @@ namespace YAML
329 385
 			   curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
330 386
 			   curState == ES_WRITING_DOC
331 387
 			) {
332
-				m_stream << "\n";
333
-				m_pState->UnsetSeparation();
388
+				if(m_pState->RequiresHardSeparation() || curState != ES_WRITING_DOC) {
389
+					m_stream << "\n";
390
+					m_pState->UnsetSeparation();
391
+				}
334 392
 			}
335 393
 			m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
336 394
 		} else if(flowType == Flow) {
... ...
@@ -397,8 +455,10 @@ namespace YAML
397 455
 			   curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
398 456
 			   curState == ES_WRITING_DOC
399 457
 			) {
400
-				m_stream << "\n";
401
-				m_pState->UnsetSeparation();
458
+				if(m_pState->RequiresHardSeparation() || (curState != ES_WRITING_DOC && curState != ES_WRITING_BLOCK_SEQ_ENTRY)) {
459
+					m_stream << "\n";
460
+					m_pState->UnsetSeparation();
461
+				}
402 462
 			}
403 463
 			m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY);
404 464
 		} else if(flowType == Flow) {
... ...
@@ -463,11 +523,12 @@ namespace YAML
463 523
 				m_stream << '\n';
464 524
 			unsigned curIndent = m_pState->GetCurIndent();
465 525
 			m_stream << IndentTo(curIndent);
526
+			m_pState->UnsetSeparation();
466 527
 			m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY);
467 528
 		} else if(flowType == FT_FLOW) {
468 529
 			if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) {
469 530
 				m_stream << ',';
470
-				m_pState->RequireSeparation();
531
+				m_pState->RequireSoftSeparation();
471 532
 			}
472 533
 			m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY);
473 534
 		} else
... ...
@@ -493,8 +554,12 @@ namespace YAML
493 554
 			return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN);
494 555
 
495 556
 		if(flowType == FT_BLOCK) {
496
-			if(m_pState->CurrentlyInLongKey())
557
+			if(m_pState->CurrentlyInLongKey()) {
497 558
 				m_stream << '\n';
559
+				m_stream << IndentTo(m_pState->GetCurIndent());
560
+				m_stream << ':';
561
+				m_pState->RequireSoftSeparation();
562
+			}
498 563
 			m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE);
499 564
 		} else if(flowType == FT_FLOW) {
500 565
 			m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE);
... ...
@@ -502,6 +567,28 @@ namespace YAML
502 567
 			assert(false);
503 568
 	}
504 569
 
570
+	// EmitNewline
571
+	void Emitter::EmitNewline()
572
+	{
573
+		if(!good())
574
+			return;
575
+
576
+		if(CanEmitNewline()) {
577
+			m_stream << '\n';
578
+			m_pState->UnsetSeparation();
579
+		}
580
+	}
581
+
582
+	bool Emitter::CanEmitNewline() const
583
+	{
584
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
585
+		if(flowType == FT_BLOCK && m_pState->CurrentlyInLongKey())
586
+			return true;
587
+
588
+		EMITTER_STATE curState = m_pState->GetCurState();
589
+		return curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_WAITING_FOR_BLOCK_MAP_VALUE && curState != ES_WRITING_BLOCK_MAP_VALUE;
590
+	}
591
+
505 592
 	// *******************************************************************************************
506 593
 	// overloads of Write
507 594
 	
... ...
@@ -548,7 +635,7 @@ namespace YAML
548 635
 		PostAtomicWrite();
549 636
 		return *this;
550 637
 	}
551
-	
638
+
552 639
 	void Emitter::PreWriteIntegralType(std::stringstream& str)
553 640
 	{
554 641
 		PreAtomicWrite();
... ...
@@ -569,13 +656,61 @@ namespace YAML
569 656
 				assert(false);
570 657
 		}
571 658
 	}
572
-	
659
+
660
+	void Emitter::PreWriteStreamable(std::stringstream& str)
661
+	{
662
+		PreAtomicWrite();
663
+		EmitSeparationIfNecessary();
664
+		str.precision(15);
665
+	}
666
+
573 667
 	void Emitter::PostWriteIntegralType(const std::stringstream& str)
574 668
 	{
575 669
 		m_stream << str.str();
576 670
 		PostAtomicWrite();
577 671
 	}
578
-	
672
+
673
+	void Emitter::PostWriteStreamable(const std::stringstream& str)
674
+	{
675
+		m_stream << str.str();
676
+		PostAtomicWrite();
677
+	}
678
+
679
+	const char *Emitter::ComputeFullBoolName(bool b) const
680
+	{
681
+		const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat());
682
+		const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
683
+		switch(mainFmt) {
684
+			case YesNoBool:
685
+				switch(caseFmt) {
686
+					case UpperCase: return b ? "YES" : "NO";
687
+					case CamelCase: return b ? "Yes" : "No";
688
+					case LowerCase: return b ? "yes" : "no";
689
+					default: break;
690
+				}
691
+				break;
692
+			case OnOffBool:
693
+				switch(caseFmt) {
694
+					case UpperCase: return b ? "ON" : "OFF";
695
+					case CamelCase: return b ? "On" : "Off";
696
+					case LowerCase: return b ? "on" : "off";
697
+					default: break;
698
+				}
699
+				break;
700
+			case TrueFalseBool:
701
+				switch(caseFmt) {
702
+					case UpperCase: return b ? "TRUE" : "FALSE";
703
+					case CamelCase: return b ? "True" : "False";
704
+					case LowerCase: return b ? "true" : "false";
705
+					default: break;
706
+				}
707
+				break;
708
+			default:
709
+				break;
710
+		}
711
+		return b ? "y" : "n"; // should never get here, but it can't hurt to give these answers
712
+	}
713
+
579 714
 	Emitter& Emitter::Write(bool b)
580 715
 	{
581 716
 		if(!good())
... ...
@@ -583,34 +718,13 @@ namespace YAML
583 718
 		
584 719
 		PreAtomicWrite();
585 720
 		EmitSeparationIfNecessary();
586
-		
587
-		// set up all possible bools to write
588
-		struct BoolName { std::string trueName, falseName; };
589
-		struct BoolFormatNames { BoolName upper, lower, camel; };
590
-		struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; };
591
-		
592
-		static const BoolTypes boolTypes = {
593
-			{ { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } },
594
-			{ { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } },
595
-			{ { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } }
596
-		};
597
-
598
-		// select the right one
599
-		EMITTER_MANIP boolFmt = m_pState->GetBoolFormat();
600
-		EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat();
601
-		EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat();
602
-		
603
-		const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff);
604
-		const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel);
605
-		const std::string& name = (b ? boolName.trueName : boolName.falseName);
606
-		
607
-		// and say it!
608
-		// TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly)
609
-		if(boolLengthFmt == ShortBool)
721
+	
722
+		const char *name = ComputeFullBoolName(b);
723
+		if(m_pState->GetBoolLengthFormat() == ShortBool)
610 724
 			m_stream << name[0];
611 725
 		else
612 726
 			m_stream << name;
613
-		
727
+
614 728
 		PostAtomicWrite();
615 729
 		return *this;
616 730
 	}
... ...
@@ -641,7 +755,7 @@ namespace YAML
641 755
 			m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
642 756
 			return *this;
643 757
 		}
644
-		m_pState->RequireSeparation();
758
+		m_pState->RequireHardSeparation();
645 759
 		// Note: no PostAtomicWrite() because we need another value for this node
646 760
 		return *this;
647 761
 	}
... ...
@@ -650,18 +764,33 @@ namespace YAML
650 764
 	{
651 765
 		if(!good())
652 766
 			return *this;
653
-		
767
+
654 768
 		PreAtomicWrite();
655 769
 		EmitSeparationIfNecessary();
656
-		if(!Utils::WriteTag(m_stream, tag.content)) {
770
+		
771
+		bool success = false;
772
+		if(tag.type == _Tag::Type::Verbatim)
773
+			success = Utils::WriteTag(m_stream, tag.content, true);
774
+		else if(tag.type == _Tag::Type::PrimaryHandle)
775
+			success = Utils::WriteTag(m_stream, tag.content, false);
776
+		else
777
+			success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);
778
+		
779
+		if(!success) {
657 780
 			m_pState->SetError(ErrorMsg::INVALID_TAG);
658 781
 			return *this;
659 782
 		}
660
-		m_pState->RequireSeparation();
783
+		
784
+		m_pState->RequireHardSeparation();
661 785
 		// Note: no PostAtomicWrite() because we need another value for this node
662 786
 		return *this;
663 787
 	}
664 788
 
789
+	void Emitter::EmitKindTag()
790
+	{
791
+		Write(LocalTag(""));
792
+	}
793
+
665 794
 	Emitter& Emitter::Write(const _Comment& comment)
666 795
 	{
667 796
 		if(!good())
... ...
@@ -683,5 +812,19 @@ namespace YAML
683 812
 		PostAtomicWrite();
684 813
 		return *this;
685 814
 	}
815
+
816
+	Emitter& Emitter::Write(const _Binary& binary)
817
+	{
818
+		Write(SecondaryTag("binary"));
819
+
820
+		if(!good())
821
+			return *this;
822
+		
823
+		PreAtomicWrite();
824
+		EmitSeparationIfNecessary();
825
+		Utils::WriteBinary(m_stream, binary.data, binary.size);
826
+		PostAtomicWrite();
827
+		return *this;
828
+	}
686 829
 }
687 830
 
Browse code

Added the seqbias package to the repository.

git-svn-id: file:///home/git/hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/seqbias@52013 bc3139a8-67e5-0310-9ffc-ced21a209358

Chao-Jen Wong authored on 22/01/2011 00:26:36
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,687 @@
1
+#include "emitter.h"
2
+#include "emitterstate.h"
3
+#include "emitterutils.h"
4
+#include "indentation.h"
5
+#include "exceptions.h"
6
+#include <sstream>
7
+
8
+namespace YAML
9
+{	
10
+	Emitter::Emitter(): m_pState(new EmitterState)
11
+	{
12
+	}
13
+	
14
+	Emitter::~Emitter()
15
+	{
16
+	}
17
+	
18
+	const char *Emitter::c_str() const
19
+	{
20
+		return m_stream.str();
21
+	}
22
+	
23
+	unsigned Emitter::size() const
24
+	{
25
+		return m_stream.pos();
26
+	}
27
+	
28
+	// state checking
29
+	bool Emitter::good() const
30
+	{
31
+		return m_pState->good();
32
+	}
33
+	
34
+	const std::string Emitter::GetLastError() const
35
+	{
36
+		return m_pState->GetLastError();
37
+	}
38
+
39
+	// global setters
40
+	bool Emitter::SetOutputCharset(EMITTER_MANIP value)
41
+	{
42
+		return m_pState->SetOutputCharset(value, GLOBAL);
43
+	}
44
+
45
+	bool Emitter::SetStringFormat(EMITTER_MANIP value)
46
+	{
47
+		return m_pState->SetStringFormat(value, GLOBAL);
48
+	}
49
+	
50
+	bool Emitter::SetBoolFormat(EMITTER_MANIP value)
51
+	{
52
+		bool ok = false;
53
+		if(m_pState->SetBoolFormat(value, GLOBAL))
54
+			ok = true;
55
+		if(m_pState->SetBoolCaseFormat(value, GLOBAL))
56
+			ok = true;
57
+		if(m_pState->SetBoolLengthFormat(value, GLOBAL))
58
+			ok = true;
59
+		return ok;
60
+	}
61
+	
62
+	bool Emitter::SetIntBase(EMITTER_MANIP value)
63
+	{
64
+		return m_pState->SetIntFormat(value, GLOBAL);
65
+	}
66
+	
67
+	bool Emitter::SetSeqFormat(EMITTER_MANIP value)
68
+	{
69
+		return m_pState->SetFlowType(GT_SEQ, value, GLOBAL);
70
+	}
71
+	
72
+	bool Emitter::SetMapFormat(EMITTER_MANIP value)
73
+	{
74
+		bool ok = false;
75
+		if(m_pState->SetFlowType(GT_MAP, value, GLOBAL))
76
+			ok = true;
77
+		if(m_pState->SetMapKeyFormat(value, GLOBAL))
78
+			ok = true;
79
+		return ok;
80
+	}
81
+	
82
+	bool Emitter::SetIndent(unsigned n)
83
+	{
84
+		return m_pState->SetIndent(n, GLOBAL);
85
+	}
86
+	
87
+	bool Emitter::SetPreCommentIndent(unsigned n)
88
+	{
89
+		return m_pState->SetPreCommentIndent(n, GLOBAL);
90
+	}
91
+	
92
+	bool Emitter::SetPostCommentIndent(unsigned n)
93
+	{
94
+		return m_pState->SetPostCommentIndent(n, GLOBAL);
95
+	}
96
+
97
+	// SetLocalValue
98
+	// . Either start/end a group, or set a modifier locally
99
+	Emitter& Emitter::SetLocalValue(EMITTER_MANIP value)
100
+	{
101
+		if(!good())
102
+			return *this;
103
+		
104
+		switch(value) {
105
+			case BeginSeq:
106
+				EmitBeginSeq();
107
+				break;
108
+			case EndSeq:
109
+				EmitEndSeq();
110
+				break;
111
+			case BeginMap:
112
+				EmitBeginMap();
113
+				break;
114
+			case EndMap:
115
+				EmitEndMap();
116
+				break;
117
+			case Key:
118
+				EmitKey();
119
+				break;
120
+			case Value:
121
+				EmitValue();
122
+				break;
123
+			default:
124
+				m_pState->SetLocalValue(value);
125
+				break;
126
+		}
127
+		return *this;
128
+	}
129
+	
130
+	Emitter& Emitter::SetLocalIndent(const _Indent& indent)
131
+	{
132
+		m_pState->SetIndent(indent.value, LOCAL);
133
+		return *this;
134
+	}
135
+
136
+	// GotoNextPreAtomicState
137
+	// . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom)
138
+	bool Emitter::GotoNextPreAtomicState()
139
+	{
140
+		if(!good())
141
+			return true;
142
+		
143
+		unsigned curIndent = m_pState->GetCurIndent();
144
+		
145
+		EMITTER_STATE curState = m_pState->GetCurState();
146
+		switch(curState) {
147
+				// document-level
148
+			case ES_WAITING_FOR_DOC:
149
+				m_stream << "---";
150
+				m_pState->RequireSeparation();
151
+				m_pState->SwitchState(ES_WRITING_DOC);
152
+				return true;
153
+			case ES_WRITING_DOC:
154
+				return true;
155
+				
156
+				// block sequence
157
+			case ES_WAITING_FOR_BLOCK_SEQ_ENTRY:
158
+				m_stream << IndentTo(curIndent) << "-";
159
+				m_pState->RequireSeparation();
160
+				m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY);
161
+				return true;
162
+			case ES_WRITING_BLOCK_SEQ_ENTRY:
163
+				return true;
164
+			case ES_DONE_WITH_BLOCK_SEQ_ENTRY:
165
+				m_stream << '\n';
166
+				m_pState->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
167
+				return false;
168
+				
169
+				// flow sequence
170
+			case ES_WAITING_FOR_FLOW_SEQ_ENTRY:
171
+				m_pState->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY);
172
+				return true;
173
+			case ES_WRITING_FLOW_SEQ_ENTRY:
174
+				return true;
175
+			case ES_DONE_WITH_FLOW_SEQ_ENTRY:
176
+				m_stream << ',';
177
+				m_pState->RequireSeparation();
178
+				m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
179
+				return false;
180
+				
181
+				// block map
182
+			case ES_WAITING_FOR_BLOCK_MAP_ENTRY:
183
+				m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
184
+				return true;
185
+			case ES_WAITING_FOR_BLOCK_MAP_KEY:
186
+				if(m_pState->CurrentlyInLongKey()) {
187
+					m_stream << IndentTo(curIndent) << '?';
188
+					m_pState->RequireSeparation();
189
+				}
190
+				m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY);
191
+				return true;
192
+			case ES_WRITING_BLOCK_MAP_KEY:
193
+				return true;
194
+			case ES_DONE_WITH_BLOCK_MAP_KEY:
195
+				m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
196
+				return true;
197
+			case ES_WAITING_FOR_BLOCK_MAP_VALUE:
198
+				if(m_pState->CurrentlyInLongKey())
199
+					m_stream << IndentTo(curIndent);
200
+				m_stream << ':';
201
+				m_pState->RequireSeparation();
202
+				m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE);
203
+				return true;
204
+			case ES_WRITING_BLOCK_MAP_VALUE:
205
+				return true;
206
+			case ES_DONE_WITH_BLOCK_MAP_VALUE:
207
+				m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
208
+				return true;
209
+				
210
+				// flow map
211
+			case ES_WAITING_FOR_FLOW_MAP_ENTRY:
212
+				m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
213
+				return true;
214
+			case ES_WAITING_FOR_FLOW_MAP_KEY:
215
+				m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY);
216
+				if(m_pState->CurrentlyInLongKey()) {
217
+					EmitSeparationIfNecessary();
218
+					m_stream << '?';
219
+					m_pState->RequireSeparation();
220
+				}
221
+				return true;
222
+			case ES_WRITING_FLOW_MAP_KEY:
223
+				return true;
224
+			case ES_DONE_WITH_FLOW_MAP_KEY:
225
+				m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
226
+				return true;
227
+			case ES_WAITING_FOR_FLOW_MAP_VALUE:
228
+				m_stream << ':';
229
+				m_pState->RequireSeparation();
230
+				m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE);
231
+				return true;
232
+			case ES_WRITING_FLOW_MAP_VALUE:
233
+				return true;
234
+			case ES_DONE_WITH_FLOW_MAP_VALUE:
235
+				m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
236
+				return true;
237
+			default:
238
+				assert(false);
239
+		}
240
+
241
+		assert(false);
242
+		return true;
243
+	}
244
+	
245
+	// PreAtomicWrite
246
+	// . Depending on the emitter state, write to the stream to get it
247
+	//   in position to do an atomic write (e.g., scalar, sequence, or map)
248
+	void Emitter::PreAtomicWrite()
249
+	{
250
+		if(!good())
251
+			return;
252
+		
253
+		while(!GotoNextPreAtomicState())
254
+			;
255
+	}
256
+	
257
+	// PostAtomicWrite
258
+	// . Clean up
259
+	void Emitter::PostAtomicWrite()
260
+	{
261
+		if(!good())
262
+			return;
263
+		
264
+		EMITTER_STATE curState = m_pState->GetCurState();
265
+		switch(curState) {
266
+				// document-level
267
+			case ES_WRITING_DOC:
268
+				m_pState->SwitchState(ES_DONE_WITH_DOC);
269
+				break;
270
+
271
+				// block seq
272
+			case ES_WRITING_BLOCK_SEQ_ENTRY:
273
+				m_pState->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY);
274
+				break;
275
+				
276
+				// flow seq
277
+			case ES_WRITING_FLOW_SEQ_ENTRY:
278
+				m_pState->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY);
279
+				break;
280
+				
281
+				// block map
282
+			case ES_WRITING_BLOCK_MAP_KEY:
283
+				m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY);
284
+				break;
285
+			case ES_WRITING_BLOCK_MAP_VALUE:
286
+				m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE);
287
+				break;
288
+				
289
+				// flow map
290
+			case ES_WRITING_FLOW_MAP_KEY:
291
+				m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY);
292
+				break;
293
+			case ES_WRITING_FLOW_MAP_VALUE:
294
+				m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE);
295
+				break;
296
+			default:
297
+				assert(false);
298
+		};
299
+				
300
+		m_pState->ClearModifiedSettings();
301
+	}
302
+	
303
+	// EmitSeparationIfNecessary
304
+	void Emitter::EmitSeparationIfNecessary()
305
+	{
306
+		if(!good())
307
+			return;
308
+		
309
+		if(m_pState->RequiresSeparation())
310
+			m_stream << ' ';
311
+		m_pState->UnsetSeparation();
312
+	}
313
+	
314
+	// EmitBeginSeq
315
+	void Emitter::EmitBeginSeq()
316
+	{
317
+		if(!good())
318
+			return;
319
+		
320
+		// must have a long key if we're emitting a sequence
321
+		m_pState->StartLongKey();
322
+		
323
+		PreAtomicWrite();
324
+		
325
+		EMITTER_STATE curState = m_pState->GetCurState();
326
+		EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
327
+		if(flowType == Block) {
328
+			if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
329
+			   curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
330
+			   curState == ES_WRITING_DOC
331
+			) {
332
+				m_stream << "\n";
333
+				m_pState->UnsetSeparation();
334
+			}
335
+			m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
336
+		} else if(flowType == Flow) {
337
+			EmitSeparationIfNecessary();
338
+			m_stream << "[";
339
+			m_pState->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
340
+		} else
341
+			assert(false);
342
+
343
+		m_pState->BeginGroup(GT_SEQ);
344
+	}
345
+	
346
+	// EmitEndSeq
347
+	void Emitter::EmitEndSeq()
348
+	{
349
+		if(!good())
350
+			return;
351
+		
352
+		if(m_pState->GetCurGroupType() != GT_SEQ)
353
+			return m_pState->SetError(ErrorMsg::UNEXPECTED_END_SEQ);
354
+		
355
+		EMITTER_STATE curState = m_pState->GetCurState();
356
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
357
+		if(flowType == FT_BLOCK) {
358
+			// Note: block sequences are *not* allowed to be empty, but we convert it
359
+			//       to a flow sequence if it is
360
+			assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
361
+			if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) {
362
+				// Note: only one of these will actually output anything for a given situation
363
+				EmitSeparationIfNecessary();
364
+				unsigned curIndent = m_pState->GetCurIndent();
365
+				m_stream << IndentTo(curIndent);
366
+
367
+				m_stream << "[]";
368
+			}
369
+		} else if(flowType == FT_FLOW) {
370
+			// Note: flow sequences are allowed to be empty
371
+			assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY);
372
+			m_stream << "]";
373
+		} else
374
+			assert(false);
375
+		
376
+		m_pState->PopState();
377
+		m_pState->EndGroup(GT_SEQ);
378
+
379
+		PostAtomicWrite();
380
+	}
381
+	
382
+	// EmitBeginMap
383
+	void Emitter::EmitBeginMap()
384
+	{
385
+		if(!good())
386
+			return;
387
+		
388
+		// must have a long key if we're emitting a map
389
+		m_pState->StartLongKey();
390
+
391
+		PreAtomicWrite();
392
+
393
+		EMITTER_STATE curState = m_pState->GetCurState();
394
+		EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
395
+		if(flowType == Block) {
396
+			if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
397
+			   curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
398
+			   curState == ES_WRITING_DOC
399
+			) {
400
+				m_stream << "\n";
401
+				m_pState->UnsetSeparation();
402
+			}
403
+			m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY);
404
+		} else if(flowType == Flow) {
405
+			EmitSeparationIfNecessary();
406
+			m_stream << "{";
407
+			m_pState->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY);
408
+		} else
409
+			assert(false);
410
+		
411
+		m_pState->BeginGroup(GT_MAP);
412
+	}
413
+	
414
+	// EmitEndMap
415
+	void Emitter::EmitEndMap()
416
+	{
417
+		if(!good())
418
+			return;
419
+		
420
+		if(m_pState->GetCurGroupType() != GT_MAP)
421
+			return m_pState->SetError(ErrorMsg::UNEXPECTED_END_MAP);
422
+
423
+		EMITTER_STATE curState = m_pState->GetCurState();
424
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
425
+		if(flowType == FT_BLOCK) {
426
+			// Note: block sequences are *not* allowed to be empty, but we convert it
427
+			//       to a flow sequence if it is
428
+			assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY);
429
+			if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) {
430
+				// Note: only one of these will actually output anything for a given situation
431
+				EmitSeparationIfNecessary();
432
+				unsigned curIndent = m_pState->GetCurIndent();
433
+				m_stream << IndentTo(curIndent);
434
+				m_stream << "{}";
435
+			}
436
+		} else if(flowType == FT_FLOW) {
437
+			// Note: flow maps are allowed to be empty
438
+			assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY);
439
+			m_stream << "}";
440
+		} else
441
+			assert(false);
442
+		
443
+		m_pState->PopState();
444
+		m_pState->EndGroup(GT_MAP);
445
+		
446
+		PostAtomicWrite();
447
+	}
448
+	
449
+	// EmitKey
450
+	void Emitter::EmitKey()
451
+	{
452
+		if(!good())
453
+			return;
454
+		
455
+		EMITTER_STATE curState = m_pState->GetCurState();
456
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
457
+		if(curState != ES_WAITING_FOR_BLOCK_MAP_ENTRY && curState != ES_DONE_WITH_BLOCK_MAP_VALUE
458
+		   && curState != ES_WAITING_FOR_FLOW_MAP_ENTRY && curState != ES_DONE_WITH_FLOW_MAP_VALUE)
459
+			return m_pState->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN);
460
+
461
+		if(flowType == FT_BLOCK) {
462
+			if(curState == ES_DONE_WITH_BLOCK_MAP_VALUE)
463
+				m_stream << '\n';
464
+			unsigned curIndent = m_pState->GetCurIndent();
465
+			m_stream << IndentTo(curIndent);
466
+			m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY);
467
+		} else if(flowType == FT_FLOW) {
468
+			if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) {
469
+				m_stream << ',';
470
+				m_pState->RequireSeparation();
471
+			}
472
+			m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY);
473
+		} else
474
+			assert(false);
475
+		
476
+		if(m_pState->GetMapKeyFormat() == LongKey)
477
+			m_pState->StartLongKey();
478
+		else if(m_pState->GetMapKeyFormat() == Auto)
479
+			m_pState->StartSimpleKey();
480
+		else
481
+			assert(false);
482
+	}
483
+	
484
+	// EmitValue
485
+	void Emitter::EmitValue()
486
+	{
487
+		if(!good())
488
+			return;
489
+
490
+		EMITTER_STATE curState = m_pState->GetCurState();
491
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
492
+		if(curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_DONE_WITH_FLOW_MAP_KEY)
493
+			return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN);
494
+
495
+		if(flowType == FT_BLOCK) {
496
+			if(m_pState->CurrentlyInLongKey())
497
+				m_stream << '\n';
498
+			m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE);
499
+		} else if(flowType == FT_FLOW) {
500
+			m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE);
501
+		} else
502
+			assert(false);
503
+	}
504
+
505
+	// *******************************************************************************************
506
+	// overloads of Write
507
+	
508
+	Emitter& Emitter::Write(const std::string& str)
509
+	{
510
+		if(!good())
511
+			return *this;
512
+		
513
+		// literal scalars must use long keys
514
+		if(m_pState->GetStringFormat() == Literal && m_pState->GetCurGroupFlowType() != FT_FLOW)
515
+			m_pState->StartLongKey();
516
+		
517
+		PreAtomicWrite();
518
+		EmitSeparationIfNecessary();
519
+		
520
+		bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
521
+		EMITTER_MANIP strFmt = m_pState->GetStringFormat();
522
+		FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
523
+		unsigned curIndent = m_pState->GetCurIndent();
524
+
525
+		switch(strFmt) {
526
+			case Auto:
527
+				Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
528
+				break;
529
+			case SingleQuoted:
530
+				if(!Utils::WriteSingleQuotedString(m_stream, str)) {
531
+					m_pState->SetError(ErrorMsg::SINGLE_QUOTED_CHAR);
532
+					return *this;
533
+				}
534
+				break;
535
+			case DoubleQuoted:
536
+				Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
537
+				break;
538
+			case Literal:
539
+				if(flowType == FT_FLOW)
540
+					Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
541
+				else
542
+					Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent());
543
+				break;
544
+			default:
545
+				assert(false);
546
+		}
547
+		
548
+		PostAtomicWrite();
549
+		return *this;
550
+	}
551
+	
552
+	void Emitter::PreWriteIntegralType(std::stringstream& str)
553
+	{
554
+		PreAtomicWrite();
555
+		EmitSeparationIfNecessary();
556
+		
557
+		EMITTER_MANIP intFmt = m_pState->GetIntFormat();
558
+		switch(intFmt) {
559
+			case Dec:
560
+				str << std::dec;
561
+				break;
562
+			case Hex:
563
+				str << std::hex;
564
+				break;
565
+				case Oct:
566
+				str << std::oct;
567
+				break;
568
+			default:
569
+				assert(false);
570
+		}
571
+	}
572
+	
573
+	void Emitter::PostWriteIntegralType(const std::stringstream& str)
574
+	{
575
+		m_stream << str.str();
576
+		PostAtomicWrite();
577
+	}
578
+	
579
+	Emitter& Emitter::Write(bool b)
580
+	{
581
+		if(!good())
582
+			return *this;
583
+		
584
+		PreAtomicWrite();
585
+		EmitSeparationIfNecessary();
586
+		
587
+		// set up all possible bools to write
588
+		struct BoolName { std::string trueName, falseName; };
589
+		struct BoolFormatNames { BoolName upper, lower, camel; };
590
+		struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; };
591
+		
592
+		static const BoolTypes boolTypes = {
593
+			{ { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } },
594
+			{ { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } },
595
+			{ { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } }
596
+		};
597
+
598
+		// select the right one
599
+		EMITTER_MANIP boolFmt = m_pState->GetBoolFormat();
600
+		EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat();
601
+		EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat();
602
+		
603
+		const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff);
604
+		const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel);
605
+		const std::string& name = (b ? boolName.trueName : boolName.falseName);
606
+		
607
+		// and say it!
608
+		// TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly)
609
+		if(boolLengthFmt == ShortBool)
610
+			m_stream << name[0];
611
+		else
612
+			m_stream << name;
613
+		
614
+		PostAtomicWrite();
615
+		return *this;
616
+	}
617
+
618
+	Emitter& Emitter::Write(const _Alias& alias)
619
+	{
620
+		if(!good())
621
+			return *this;
622
+		
623
+		PreAtomicWrite();
624
+		EmitSeparationIfNecessary();
625
+		if(!Utils::WriteAlias(m_stream, alias.content)) {
626
+			m_pState->SetError(ErrorMsg::INVALID_ALIAS);
627
+			return *this;
628
+		}
629
+		PostAtomicWrite();
630
+		return *this;
631
+	}
632
+	
633
+	Emitter& Emitter::Write(const _Anchor& anchor)
634
+	{
635
+		if(!good())
636
+			return *this;
637
+		
638
+		PreAtomicWrite();
639
+		EmitSeparationIfNecessary();
640
+		if(!Utils::WriteAnchor(m_stream, anchor.content)) {
641
+			m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
642
+			return *this;
643
+		}
644
+		m_pState->RequireSeparation();
645
+		// Note: no PostAtomicWrite() because we need another value for this node
646
+		return *this;
647
+	}
648
+	
649
+	Emitter& Emitter::Write(const _Tag& tag)
650
+	{
651
+		if(!good())
652
+			return *this;
653
+		
654
+		PreAtomicWrite();
655
+		EmitSeparationIfNecessary();
656
+		if(!Utils::WriteTag(m_stream, tag.content)) {
657
+			m_pState->SetError(ErrorMsg::INVALID_TAG);
658
+			return *this;
659
+		}
660
+		m_pState->RequireSeparation();
661
+		// Note: no PostAtomicWrite() because we need another value for this node
662
+		return *this;
663
+	}
664
+
665
+	Emitter& Emitter::Write(const _Comment& comment)
666
+	{
667
+		if(!good())
668
+			return *this;
669
+		
670
+		m_stream << Indentation(m_pState->GetPreCommentIndent());
671
+		Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent());
672
+		return *this;
673
+	}
674
+
675
+	Emitter& Emitter::Write(const _Null& /*null*/)
676
+	{
677
+		if(!good())
678
+			return *this;
679
+		
680
+		PreAtomicWrite();
681
+		EmitSeparationIfNecessary();
682
+		m_stream << "~";
683
+		PostAtomicWrite();
684
+		return *this;
685
+	}
686
+}
687
+