/// <summary> /// Expect DOCUMENT-END. /// </summary> private void EmitDocumentEnd(Event evt) { DocumentEnd documentEnd = evt as DocumentEnd; if (documentEnd != null) { WriteIndent(); if (!documentEnd.IsImplicit) { WriteIndicator("...", true, false, false); WriteIndent(); } state = EmitterState.YAML_EMIT_DOCUMENT_START_STATE; tagDirectives.Clear(); } else { throw new YamlException("Expected DOCUMENT-END."); } }
/// <summary> /// Expect DOCUMENT-START or STREAM-END. /// </summary> private void EmitDocumentStart(Event evt, bool isFirst) { DocumentStart documentStart = evt as DocumentStart; if (documentStart != null) { bool isImplicit = documentStart.IsImplicit && isFirst && !isCanonical; if (documentStart.Version != null && isOpenEnded) { WriteIndicator("...", true, false, false); WriteIndent(); } if (documentStart.Version != null) { AnalyzeVersionDirective(documentStart.Version); isImplicit = false; WriteIndicator("%YAML", true, false, false); WriteIndicator(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", Constants.MajorVersion, Constants.MinorVersion), true, false, false); WriteIndent(); } if (documentStart.Tags != null) { foreach (var tagDirective in documentStart.Tags) { AppendTagDirective(tagDirective, false); } } foreach (var tagDirective in Constants.DefaultTagDirectives) { AppendTagDirective(tagDirective, true); } if (documentStart.Tags != null && documentStart.Tags.Count != 0) { isImplicit = false; foreach (var tagDirective in documentStart.Tags) { WriteIndicator("%TAG", true, false, false); WriteTagHandle(tagDirective.Handle); WriteTagContent(tagDirective.Prefix, true); WriteIndent(); } } if (CheckEmptyDocument()) { isImplicit = false; } if (!isImplicit) { WriteIndent(); WriteIndicator("---", true, false, false); if (isCanonical) { WriteIndent(); } } state = EmitterState.YAML_EMIT_DOCUMENT_CONTENT_STATE; } else if (evt is IStreamEnd) { if (isOpenEnded) { WriteIndicator("...", true, false, false); WriteIndent(); } state = EmitterState.YAML_EMIT_END_STATE; } else { throw new YamlException("Expected DOCUMENT-START or STREAM-END"); } }
/// <summary> /// Expect a block item node. /// </summary> private void EmitBlockSequenceItem(Event evt, bool isFirst) { if (isFirst) { IncreaseIndent(false, (isMappingContext && !isIndentation)); } if (evt is ISequenceEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); WriteIndicator("-", true, false, true); states.Push(EmitterState.YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE); EmitNode(evt, false, false, false); }
/// <summary> /// Expect the root node. /// </summary> private void EmitDocumentContent(Event evt) { states.Push(EmitterState.YAML_EMIT_DOCUMENT_END_STATE); EmitNode(evt, true, false, false); }
/// <summary> /// Expect a block key node. /// </summary> private void EmitBlockMappingKey(Event evt, bool isFirst) { if (isFirst) { IncreaseIndent(false, false); } if (evt is IMappingEnd) { indent = indents.Pop(); state = states.Pop(); return; } WriteIndent(); if (CheckSimpleKey()) { states.Push(EmitterState.YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE); EmitNode(evt, false, true, true); } else { WriteIndicator("?", true, false, true); states.Push(EmitterState.YAML_EMIT_BLOCK_MAPPING_VALUE_STATE); EmitNode(evt, false, true, false); } }
/// <summary> /// Expect a block value node. /// </summary> private void EmitBlockMappingValue(Event evt, bool isSimple) { if (isSimple) { WriteIndicator(":", false, false, false); } else { WriteIndent(); WriteIndicator(":", true, false, true); } states.Push(EmitterState.YAML_EMIT_BLOCK_MAPPING_KEY_STATE); EmitNode(evt, false, true, false); }
/// <summary> /// Emit an evt. /// </summary> public void Emit(Event @event) { events.Enqueue(@event); while (!NeedMoreEvents()) { Event current = events.Peek(); AnalyzeEvent(current); StateMachine(current); // Only dequeue after calling state_machine because it checks how many events are in the queue. events.Dequeue(); } }
/// <summary> /// Expect MAPPING-START. /// </summary> private void EmitMappingStart(Event evt) { ProcessAnchor(); ProcessTag(); MappingStart mappingStart = (MappingStart)evt; if (flowLevel != 0 || isCanonical || mappingStart.Style == YamlStyle.Flow || CheckEmptyMapping()) { state = EmitterState.YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; } else { state = EmitterState.YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; } }
/// <summary> /// Determine an acceptable scalar style. /// </summary> private void SelectScalarStyle(Event evt) { Scalar scalar = (Scalar)evt; ScalarStyle style = scalar.Style; bool noTag = tagData.handle == null && tagData.suffix == null; if (noTag && !scalar.IsPlainImplicit && !scalar.IsQuotedImplicit) { throw new YamlException("Neither tag nor isImplicit flags are specified."); } if (style == ScalarStyle.Any) { style = scalarData.isMultiline ? ScalarStyle.Folded : ScalarStyle.Plain; } if (isCanonical) { style = ScalarStyle.DoubleQuoted; } if (isSimpleKeyContext && scalarData.isMultiline) { style = ScalarStyle.DoubleQuoted; } if (style == ScalarStyle.Plain) { if ((flowLevel != 0 && !scalarData.isFlowPlainAllowed) || (flowLevel == 0 && !scalarData.isBlockPlainAllowed)) { style = ScalarStyle.SingleQuoted; } if (string.IsNullOrEmpty(scalarData.value) && (flowLevel != 0 || isSimpleKeyContext)) { style = ScalarStyle.SingleQuoted; } if (noTag && !scalar.IsPlainImplicit) { style = ScalarStyle.SingleQuoted; } } if (style == ScalarStyle.SingleQuoted) { if (!scalarData.isSingleQuotedAllowed) { style = ScalarStyle.DoubleQuoted; } } if (style == ScalarStyle.Literal || style == ScalarStyle.Folded) { if (!scalarData.isBlockAllowed || flowLevel != 0 || isSimpleKeyContext) { style = ScalarStyle.DoubleQuoted; } } // TODO: What is this code supposed to mean? //if (noTag && !scalar.IsQuotedImplicit && style != ScalarStyle.Plain) //{ // tagData.handle = "!"; //} scalarData.style = style; }
/// <summary> /// State dispatcher. /// </summary> private void StateMachine(Event evt) { switch (state) { case EmitterState.YAML_EMIT_STREAM_START_STATE: EmitStreamStart(evt); break; case EmitterState.YAML_EMIT_FIRST_DOCUMENT_START_STATE: EmitDocumentStart(evt, true); break; case EmitterState.YAML_EMIT_DOCUMENT_START_STATE: EmitDocumentStart(evt, false); break; case EmitterState.YAML_EMIT_DOCUMENT_CONTENT_STATE: EmitDocumentContent(evt); break; case EmitterState.YAML_EMIT_DOCUMENT_END_STATE: EmitDocumentEnd(evt); break; case EmitterState.YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: EmitFlowSequenceItem(evt, true); break; case EmitterState.YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: EmitFlowSequenceItem(evt, false); break; case EmitterState.YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: EmitFlowMappingKey(evt, true); break; case EmitterState.YAML_EMIT_FLOW_MAPPING_KEY_STATE: EmitFlowMappingKey(evt, false); break; case EmitterState.YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: EmitFlowMappingValue(evt, true); break; case EmitterState.YAML_EMIT_FLOW_MAPPING_VALUE_STATE: EmitFlowMappingValue(evt, false); break; case EmitterState.YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: EmitBlockSequenceItem(evt, true); break; case EmitterState.YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: EmitBlockSequenceItem(evt, false); break; case EmitterState.YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: EmitBlockMappingKey(evt, true); break; case EmitterState.YAML_EMIT_BLOCK_MAPPING_KEY_STATE: EmitBlockMappingKey(evt, false); break; case EmitterState.YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: EmitBlockMappingValue(evt, true); break; case EmitterState.YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: EmitBlockMappingValue(evt, false); break; case EmitterState.YAML_EMIT_END_STATE: throw new YamlException("Expected nothing after STREAM-END"); default: Debug.Assert(false, "Invalid state."); throw new InvalidOperationException("Invalid state"); } }
/// <summary> /// Expect STREAM-START. /// </summary> private void EmitStreamStart(Event evt) { if (!(evt is IStreamStart)) { throw new ArgumentException("Expected STREAM-START.", "evt"); } indent = -1; line = 0; column = 0; isWhitespace = true; isIndentation = true; state = EmitterState.YAML_EMIT_FIRST_DOCUMENT_START_STATE; }
/// <summary> /// Expect SEQUENCE-START. /// </summary> private void EmitSequenceStart(Event evt) { ProcessAnchor(); ProcessTag(); SequenceStart sequenceStart = (SequenceStart)evt; if (flowLevel != 0 || isCanonical || sequenceStart.Style == YamlStyle.Flow || CheckEmptySequence()) { state = EmitterState.YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; } else { state = EmitterState.YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; } }
/// <summary> /// Expect SCALAR. /// </summary> private void EmitScalar(Event evt) { SelectScalarStyle(evt); ProcessAnchor(); ProcessTag(); IncreaseIndent(true, false); ProcessScalar(); indent = indents.Pop(); state = states.Pop(); }
/// <summary> /// Expect a flow key node. /// </summary> private void EmitFlowMappingKey(Event evt, bool isFirst) { if (isFirst) { WriteIndicator("{", true, true, false); IncreaseIndent(true, false); ++flowLevel; } if (evt is IMappingEnd) { --flowLevel; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", false, false, false); WriteIndent(); } WriteIndicator("}", false, false, false); state = states.Pop(); return; } if (!isFirst) { WriteIndicator(",", false, false, false); } if (isCanonical || column > bestWidth) { WriteIndent(); } if (!isCanonical && CheckSimpleKey()) { states.Push(EmitterState.YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE); EmitNode(evt, false, true, true); } else { WriteIndicator("?", true, false, false); states.Push(EmitterState.YAML_EMIT_FLOW_MAPPING_VALUE_STATE); EmitNode(evt, false, true, false); } }
/// <summary> /// Check if the evt data is valid. /// </summary> private void AnalyzeEvent(Event evt) { anchorData.anchor = null; tagData.handle = null; tagData.suffix = null; AnchorAlias alias = evt as AnchorAlias; if (alias != null) { AnalyzeAnchor(alias.Value, true); return; } NodeEvent nodeEvent = evt as NodeEvent; if (nodeEvent != null) { Scalar scalar = evt as Scalar; if (scalar != null) { AnalyzeScalar(scalar.Value); } AnalyzeAnchor(nodeEvent.Anchor, false); if (!string.IsNullOrEmpty(nodeEvent.Tag) && (isCanonical || nodeEvent.IsCanonical)) { AnalyzeTag(nodeEvent.Tag); } return; } }
/// <summary> /// Expect a flow value node. /// </summary> private void EmitFlowMappingValue(Event evt, bool isSimple) { if (isSimple) { WriteIndicator(":", false, false, false); } else { if (isCanonical || column > bestWidth) { WriteIndent(); } WriteIndicator(":", true, false, false); } states.Push(EmitterState.YAML_EMIT_FLOW_MAPPING_KEY_STATE); EmitNode(evt, false, true, false); }
/// <summary> /// /// Expect a flow item node. /// </summary> private void EmitFlowSequenceItem(Event evt, bool isFirst) { if (isFirst) { WriteIndicator("[", true, true, false); IncreaseIndent(true, false); ++flowLevel; } if (evt is ISequenceEnd) { --flowLevel; indent = indents.Pop(); if (isCanonical && !isFirst) { WriteIndicator(",", false, false, false); WriteIndent(); } WriteIndicator("]", false, false, false); state = states.Pop(); return; } if (!isFirst) { WriteIndicator(",", false, false, false); } if (isCanonical || column > bestWidth) { WriteIndent(); } states.Push(EmitterState.YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE); EmitNode(evt, false, false, false); }