json: parsing of arrays
(and assorted bugfixes in parsing of objects that were found in the process of adapting that code for arrays.)
This commit is contained in:
parent
b073937523
commit
0ef4932962
@ -58,6 +58,15 @@ func parseValue(p *peeker) (node, zcl.Diagnostics) {
|
|||||||
Subject: &tok.Range,
|
Subject: &tok.Range,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case tokenEOF:
|
||||||
|
return nil, zcl.Diagnostics{
|
||||||
|
{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Missing value",
|
||||||
|
Detail: "The JSON data ends prematurely.",
|
||||||
|
Subject: &tok.Range,
|
||||||
|
},
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, zcl.Diagnostics{
|
return nil, zcl.Diagnostics{
|
||||||
{
|
{
|
||||||
@ -132,7 +141,7 @@ Token:
|
|||||||
|
|
||||||
valNode, valDiags := parseValue(p)
|
valNode, valDiags := parseValue(p)
|
||||||
diags = diags.Extend(valDiags)
|
diags = diags.Extend(valDiags)
|
||||||
if keyNode == nil {
|
if valNode == nil {
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,14 +166,14 @@ Token:
|
|||||||
|
|
||||||
switch p.Peek().Type {
|
switch p.Peek().Type {
|
||||||
case tokenComma:
|
case tokenComma:
|
||||||
p.Read()
|
comma := p.Read()
|
||||||
if p.Peek().Type == tokenBraceC {
|
if p.Peek().Type == tokenBraceC {
|
||||||
// Special error message for this common mistake
|
// Special error message for this common mistake
|
||||||
return nil, diags.Append(&zcl.Diagnostic{
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
Severity: zcl.DiagError,
|
Severity: zcl.DiagError,
|
||||||
Summary: "Trailing comma in object",
|
Summary: "Trailing comma in object",
|
||||||
Detail: "JSON does not permit a trailing comma after the final attribute in an object.",
|
Detail: "JSON does not permit a trailing comma after the final attribute in an object.",
|
||||||
Subject: &colon.Range,
|
Subject: &comma.Range,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
continue Token
|
continue Token
|
||||||
@ -189,7 +198,7 @@ Token:
|
|||||||
Severity: zcl.DiagError,
|
Severity: zcl.DiagError,
|
||||||
Summary: "Missing attribute seperator comma",
|
Summary: "Missing attribute seperator comma",
|
||||||
Detail: "A comma must appear between each attribute declaration in an object.",
|
Detail: "A comma must appear between each attribute declaration in an object.",
|
||||||
Subject: &colon.Range,
|
Subject: p.Peek().Range.Ptr(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +213,78 @@ Token:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseArray(p *peeker) (node, zcl.Diagnostics) {
|
func parseArray(p *peeker) (node, zcl.Diagnostics) {
|
||||||
return nil, nil
|
var diags zcl.Diagnostics
|
||||||
|
|
||||||
|
open := p.Read()
|
||||||
|
vals := []node{}
|
||||||
|
|
||||||
|
Token:
|
||||||
|
for {
|
||||||
|
if p.Peek().Type == tokenBrackC {
|
||||||
|
break Token
|
||||||
|
}
|
||||||
|
|
||||||
|
valNode, valDiags := parseValue(p)
|
||||||
|
diags = diags.Extend(valDiags)
|
||||||
|
if valNode == nil {
|
||||||
|
return nil, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
vals = append(vals, valNode)
|
||||||
|
|
||||||
|
switch p.Peek().Type {
|
||||||
|
case tokenComma:
|
||||||
|
comma := p.Read()
|
||||||
|
if p.Peek().Type == tokenBrackC {
|
||||||
|
// Special error message for this common mistake
|
||||||
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Trailing comma in array",
|
||||||
|
Detail: "JSON does not permit a trailing comma after the final attribute in an array.",
|
||||||
|
Subject: &comma.Range,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue Token
|
||||||
|
case tokenColon:
|
||||||
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Invalid array value",
|
||||||
|
Detail: "A colon is not used to introduce values in a JSON array.",
|
||||||
|
Subject: p.Peek().Range.Ptr(),
|
||||||
|
})
|
||||||
|
case tokenEOF:
|
||||||
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Unclosed object",
|
||||||
|
Detail: "No closing bracket was found for this JSON array.",
|
||||||
|
Subject: &open.Range,
|
||||||
|
})
|
||||||
|
case tokenBraceC:
|
||||||
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Mismatched brackets",
|
||||||
|
Detail: "A JSON array must be closed with a bracket, not a brace.",
|
||||||
|
Subject: p.Peek().Range.Ptr(),
|
||||||
|
})
|
||||||
|
case tokenBrackC:
|
||||||
|
break Token
|
||||||
|
default:
|
||||||
|
return nil, diags.Append(&zcl.Diagnostic{
|
||||||
|
Severity: zcl.DiagError,
|
||||||
|
Summary: "Missing attribute seperator comma",
|
||||||
|
Detail: "A comma must appear between each value in an array.",
|
||||||
|
Subject: p.Peek().Range.Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
close := p.Read()
|
||||||
|
return &arrayVal{
|
||||||
|
Values: vals,
|
||||||
|
SrcRange: zcl.RangeBetween(open.Range, close.Range),
|
||||||
|
OpenRange: open.Range,
|
||||||
|
}, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNumber(p *peeker) (node, zcl.Diagnostics) {
|
func parseNumber(p *peeker) (node, zcl.Diagnostics) {
|
||||||
|
@ -314,6 +314,136 @@ func TestParse(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
`[]`,
|
||||||
|
&arrayVal{
|
||||||
|
Values: []node{},
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 3, Byte: 2},
|
||||||
|
},
|
||||||
|
OpenRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true]`,
|
||||||
|
&arrayVal{
|
||||||
|
Values: []node{
|
||||||
|
&booleanVal{
|
||||||
|
Value: true,
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 7, Byte: 6},
|
||||||
|
},
|
||||||
|
OpenRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true, false]`,
|
||||||
|
&arrayVal{
|
||||||
|
Values: []node{
|
||||||
|
&booleanVal{
|
||||||
|
Value: true,
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&booleanVal{
|
||||||
|
Value: false,
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 8, Byte: 7},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 13, Byte: 12},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 14, Byte: 13},
|
||||||
|
},
|
||||||
|
OpenRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[[]]`,
|
||||||
|
&arrayVal{
|
||||||
|
Values: []node{
|
||||||
|
&arrayVal{
|
||||||
|
Values: []node{},
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
|
||||||
|
},
|
||||||
|
OpenRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 3, Byte: 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SrcRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 5, Byte: 4},
|
||||||
|
},
|
||||||
|
OpenRange: zcl.Range{
|
||||||
|
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
|
||||||
|
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`]`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true,]`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[[],]`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`["hello":true]`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true}`,
|
||||||
|
nil,
|
||||||
|
1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
Loading…
Reference in New Issue
Block a user