Skip to content

Commit

Permalink
Fix 2 bugs when handling anchors
Browse files Browse the repository at this point in the history
- An anchor in a nested structure would break indentation state and
therefore parsing of the anchored structure
- An anchor outide the top-level would not be found while traversing
the AST (that is, traversing the AST was broken)
  • Loading branch information
MaybeJustJames committed May 19, 2021
1 parent 4246347 commit 5ed4a6c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 16 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Fixed
- A bug causing references in nested structures to break parsing
- A bug resolving aliases

## [2.0.1]
### Changed
Expand Down
30 changes: 20 additions & 10 deletions src/Yaml/Parser.elm
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ listElementValue indent =
, larger =
\indent_ ->
P.oneOf
[ anchor (elVal indent_)
[ anchor elVal
, reference
, elVal indent_
]
Expand Down Expand Up @@ -251,7 +251,7 @@ listInlineValue =
]
in
P.oneOf
[ anchor inlineVal
[ anchor (always inlineVal)
, reference
, inlineVal
]
Expand Down Expand Up @@ -435,7 +435,7 @@ recordElementValue indent =
, larger =
\indent_ ->
P.oneOf
[ anchor (elVal indent_)
[ anchor elVal
, reference
, elVal indent_
]
Expand Down Expand Up @@ -525,7 +525,7 @@ recordInlinePropertyValue =
]
in
P.oneOf
[ anchor propVal
[ anchor (always propVal)
, reference
, propVal
]
Expand Down Expand Up @@ -568,21 +568,20 @@ recordInlineOnDone elements element =
-- ANCHOR and REFERENCE


anchor : P.Parser Ast.Value -> P.Parser Ast.Value
anchor : (Int -> P.Parser Ast.Value) -> P.Parser Ast.Value
anchor valParser =
P.succeed Ast.Anchor_
|. P.symbol "&"
|= refName
|. U.whitespace
|= valParser
|= (P.getCol |> P.andThen valParser)


reference : P.Parser Ast.Value
reference =
P.succeed Ast.Alias_
|. P.symbol "*"
|= refName
|. U.whitespace


refName : P.Parser String
Expand All @@ -591,8 +590,19 @@ refName =
|= (P.getChompedString <|
P.chompWhile
(\c ->
not <|
List.member c [ ' ', ',', '[', ']', '{', '}' ]
not
(List.member c
[ '\u{000D}'
, '\n'
, ' '
, '\t'
, ','
, '['
, ']'
, '{'
, '}'
]
)
)
)

Expand All @@ -611,8 +621,8 @@ deref ast =
_ ->
d
)
Dict.empty
ast
Dict.empty

replaceAnchors : Ast.Value -> Ast.Value
replaceAnchors v =
Expand Down
12 changes: 6 additions & 6 deletions src/Yaml/Parser/Ast.elm
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ toStringProperty ( name, value ) =
name ++ ": " ++ toString value


fold : (Value -> b -> b) -> b -> Value -> b
fold f z value =
fold : (Value -> b -> b) -> Value -> b -> b
fold f value z =
case value of
String_ _ ->
f value z
Expand All @@ -125,13 +125,13 @@ fold f z value =
f value z

List_ l ->
List.foldl f (f value z) l
f value (List.foldl (fold f) z l)

Record_ r ->
List.foldl f (f value z) (Dict.values r)
f value (List.foldl (fold f) z (Dict.values r))

Anchor_ _ a ->
fold f (f value z) a
Anchor_ nm a ->
f value (fold f a z)


map : (Value -> Value) -> Value -> Value
Expand Down
63 changes: 63 additions & 0 deletions tests/TestParser.elm
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,55 @@ suite =
, ( "b", Ast.Record_ (Dict.singleton "foo" (Ast.String_ "bar")) )
]
)
, Test.test "Real data with anchor and alias" <|
\_ ->
expectValue testYamlData <|
Ast.Record_
(Dict.singleton
"graph"
(Ast.Record_
(Dict.singleton
"processors"
(Ast.Record_
(Dict.fromList
[ ( "ripple_filter1"
, Ast.Record_
(Dict.singleton "options"
(Ast.Record_
(Dict.singleton
"filter"
(Ast.Record_
(Dict.singleton
"file"
(Ast.String_ "path/test/f.ext")
)
)
)
)
)
)
, ( "ripple_filter2"
, Ast.Record_
(Dict.singleton "options"
(Ast.Record_
(Dict.singleton
"filter"
(Ast.Record_
(Dict.singleton
"file"
(Ast.String_ "path/test/f.ext")
)
)
)
)
)
)
]
)
)
)
)
)

-- TODO: This is temporarily removed because it is a valid test case that should pass
-- , Test.test "weird colon record" <|
Expand All @@ -504,3 +553,17 @@ expectErr : String -> Expect.Expectation
expectErr subject =
Parser.fromString subject
|> Expect.err


testYamlData : String
testYamlData =
"""
graph:
processors:
ripple_filter1:
options: &1
filter:
file: path/test/f.ext
ripple_filter2:
options: *1
"""

0 comments on commit 5ed4a6c

Please sign in to comment.