Skip to content

Commit 500180b

Browse files
authored
support implicit null (#727)
1 parent e61dcd0 commit 500180b

File tree

6 files changed

+47
-22
lines changed

6 files changed

+47
-22
lines changed

ast/ast.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ func checkLineBreak(t *token.Token) bool {
317317
// bar: null # comment
318318
//
319319
// baz: 1
320-
if prev.Type == token.NullType {
320+
if prev.Type == token.NullType || prev.Type == token.ImplicitNullType {
321321
return strings.Count(prev.Origin, lbc) > 0
322322
}
323323
if lineDiff-adjustment > 0 {
@@ -627,6 +627,12 @@ func (n *NullNode) GetValue() interface{} {
627627

628628
// String returns `null` text
629629
func (n *NullNode) String() string {
630+
if n.Token.Type == token.ImplicitNullType {
631+
if n.Comment != nil {
632+
return n.Comment.String()
633+
}
634+
return ""
635+
}
630636
if n.Comment != nil {
631637
return addCommentString("null", n.Comment)
632638
}
@@ -1437,7 +1443,12 @@ func (n *MappingValueNode) toString() string {
14371443
valueIndentLevel := n.Value.GetToken().Position.IndentLevel
14381444
keyComment := n.Key.GetComment()
14391445
if _, ok := n.Value.(ScalarNode); ok {
1440-
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
1446+
value := n.Value.String()
1447+
if value == "" {
1448+
// implicit null value.
1449+
return fmt.Sprintf("%s%s:", space, n.Key.String())
1450+
}
1451+
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), value)
14411452
} else if keyIndentLevel < valueIndentLevel && !n.IsFlowStyle {
14421453
if keyComment != nil {
14431454
return fmt.Sprintf(
@@ -1812,13 +1823,18 @@ func (n *AnchorNode) AddColumn(col int) {
18121823

18131824
// String anchor to text
18141825
func (n *AnchorNode) String() string {
1826+
anchor := "&" + n.Name.String()
18151827
value := n.Value.String()
18161828
if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
1817-
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
1829+
return fmt.Sprintf("%s\n%s", anchor, value)
18181830
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
1819-
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
1831+
return fmt.Sprintf("%s\n%s", anchor, value)
1832+
}
1833+
if value == "" {
1834+
// implicit null value.
1835+
return anchor
18201836
}
1821-
return fmt.Sprintf("&%s %s", n.Name.String(), value)
1837+
return fmt.Sprintf("%s %s", anchor, value)
18221838
}
18231839

18241840
// MarshalYAML encodes to a YAML text

parser/context.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,15 @@ func (c *context) next() bool {
120120
}
121121

122122
func (c *context) insertNullToken(tk *Token) *Token {
123-
nullToken := c.createNullToken(tk)
123+
nullToken := c.createImplicitNullToken(tk)
124124
c.insertToken(nullToken)
125125
c.goNext()
126126

127127
return nullToken
128128
}
129129

130130
func (c *context) addNullValueToken(tk *Token) *Token {
131-
nullToken := c.createNullToken(tk)
131+
nullToken := c.createImplicitNullToken(tk)
132132
rawTk := nullToken.RawToken()
133133

134134
// add space for map or sequence value.
@@ -140,10 +140,12 @@ func (c *context) addNullValueToken(tk *Token) *Token {
140140
return nullToken
141141
}
142142

143-
func (c *context) createNullToken(base *Token) *Token {
143+
func (c *context) createImplicitNullToken(base *Token) *Token {
144144
pos := *(base.RawToken().Position)
145145
pos.Column++
146-
return &Token{Token: token.New("null", " null", &pos)}
146+
tk := token.New("null", " null", &pos)
147+
tk.Type = token.ImplicitNullType
148+
return &Token{Token: tk}
147149
}
148150

149151
func (c *context) insertToken(tk *Token) {

parser/parser.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ func (p *parser) parseScalarValue(ctx *context, tk *Token) (ast.ScalarNode, erro
304304
switch tk.Type() {
305305
case token.MergeKeyType:
306306
return newMergeKeyNode(ctx, tk)
307-
case token.NullType:
307+
case token.NullType, token.ImplicitNullType:
308308
return newNullNode(ctx, tk)
309309
case token.BoolType:
310310
return newBoolNode(ctx, tk)
@@ -747,7 +747,7 @@ func (p *parser) parseMapValue(ctx *context, key ast.MapKeyNode, colonTk *Token)
747747
// next
748748
group := &TokenGroup{
749749
Type: TokenGroupAnchor,
750-
Tokens: []*Token{tk, ctx.createNullToken(tk)},
750+
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
751751
}
752752
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
753753
if err != nil {
@@ -784,7 +784,7 @@ func (p *parser) parseMapValue(ctx *context, key ast.MapKeyNode, colonTk *Token)
784784
// next
785785
group := &TokenGroup{
786786
Type: TokenGroupAnchor,
787-
Tokens: []*Token{tk, ctx.createNullToken(tk)},
787+
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
788788
}
789789
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
790790
if err != nil {
@@ -976,7 +976,7 @@ func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
976976

977977
func (p *parser) parseTagValue(ctx *context, tagRawTk *token.Token, tk *Token) (ast.Node, error) {
978978
if tk == nil {
979-
return newNullNode(ctx, ctx.createNullToken(&Token{Token: tagRawTk}))
979+
return newNullNode(ctx, ctx.createImplicitNullToken(&Token{Token: tagRawTk}))
980980
}
981981
switch token.ReservedTagKeyword(tagRawTk.Value) {
982982
case token.MappingTag, token.SetTag:
@@ -1141,7 +1141,7 @@ func (p *parser) parseSequenceValue(ctx *context, seqTk *Token) (ast.Node, error
11411141
// -
11421142
group := &TokenGroup{
11431143
Type: TokenGroupAnchor,
1144-
Tokens: []*Token{tk, ctx.createNullToken(tk)},
1144+
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
11451145
}
11461146
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
11471147
if err != nil {
@@ -1178,7 +1178,7 @@ func (p *parser) parseSequenceValue(ctx *context, seqTk *Token) (ast.Node, error
11781178
// next
11791179
group := &TokenGroup{
11801180
Type: TokenGroupAnchor,
1181-
Tokens: []*Token{tk, ctx.createNullToken(tk)},
1181+
Tokens: []*Token{tk, ctx.createImplicitNullToken(tk)},
11821182
}
11831183
anchor, err := p.parseAnchor(ctx.withGroup(group), group)
11841184
if err != nil {

parser/parser_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ a: 0 - 1
311311
- a:
312312
b: c
313313
d: e
314-
- f: null
314+
- f:
315315
g: h
316316
`,
317317
},
@@ -351,7 +351,7 @@ a:
351351
- a :
352352
b: c
353353
`, `
354-
- a: null
354+
- a:
355355
b: c
356356
`,
357357
},
@@ -740,8 +740,8 @@ d: e
740740
`,
741741
`
742742
a:
743-
b: &anchor null
744-
c: &anchor2 null
743+
b: &anchor
744+
c: &anchor2
745745
d: e
746746
`,
747747
},
@@ -1567,7 +1567,7 @@ foo:
15671567
`
15681568
expected := `
15691569
foo:
1570-
bar: null # comment
1570+
bar: # comment
15711571
baz: 1`
15721572
f, err := parser.ParseBytes([]byte(content), parser.ParseComments)
15731573
if err != nil {
@@ -1590,7 +1590,7 @@ foo:
15901590
`
15911591
expected := `
15921592
foo:
1593-
bar: null
1593+
bar:
15941594
# comment
15951595
baz: 1`
15961596
f, err := parser.ParseBytes([]byte(content), parser.ParseComments)
@@ -1620,7 +1620,7 @@ baz: 1`
16201620
}
16211621
expected := `
16221622
foo:
1623-
bar: null
1623+
bar:
16241624
# comment
16251625
baz: 1`
16261626
got := f.Docs[0].String()

parser/token.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ func isScalarType(tk *Token) bool {
709709
typ == token.LiteralType ||
710710
typ == token.FoldedType ||
711711
typ == token.NullType ||
712+
typ == token.ImplicitNullType ||
712713
typ == token.BoolType ||
713714
typ == token.IntegerType ||
714715
typ == token.BinaryIntegerType ||

token/token.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ const (
102102
SpaceType
103103
// NullType type for Null token
104104
NullType
105+
// ImplicitNullType type for implicit Null token.
106+
// This is used when explicit keywords such as null or ~ are not specified.
107+
// It is distinguished during encoding and output as an empty string.
108+
ImplicitNullType
105109
// InfinityType type for Infinity token
106110
InfinityType
107111
// NanType type for Nan token
@@ -187,6 +191,8 @@ func (t Type) String() string {
187191
return "Float"
188192
case NullType:
189193
return "Null"
194+
case ImplicitNullType:
195+
return "ImplicitNull"
190196
case InfinityType:
191197
return "Infinity"
192198
case NanType:

0 commit comments

Comments
 (0)