Skip to content

Commit

Permalink
yaml: cleanup API and docs
Browse files Browse the repository at this point in the history
- Rename YamlObj.content to val (leave old one deprecated)
- Use covaraince in YamlObj.val method subclasses
- Make YamlObj.make internal, hide fields
- Make more stuff nodoc
  • Loading branch information
briansfrank committed Jul 17, 2023
1 parent c5fb936 commit 25e2130
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 120 deletions.
103 changes: 63 additions & 40 deletions src/yaml/fan/YamlObj.fan
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,29 @@ abstract const class YamlObj

** The node's tag. Either a specific tag (e.g. 'tag:yaml.org,2002:str')
** or the non-specific tag '?'.
const Str tag := "?"
Str tag() { tagRef }
internal const Str tagRef

** The node's content. [YamlScalars]`yaml::YamlScalar` always have
** The node's content value. [YamlScalars]`yaml::YamlScalar` always have
** content of type 'Str', [YamlLists]`yaml::YamlList` with content
** type 'YamlObj[]', and [YamlMaps]`yaml::YamlMap` with 'YamlObj:YamlObj'.
const Obj content := 0 //the "?" and 0 are placeholders
virtual Obj val() { valRef }
internal const Obj valRef

@Deprecated { msg = "Use val" }
@NoDoc Obj content() { valRef }

** The text location from which this node was parsed.
const FileLoc loc := FileLoc.unknown
FileLoc loc() { locRef }
internal const FileLoc locRef

** Internal make
internal new make(Obj val, Str tag, FileLoc loc)
{
this.valRef = val
this.tagRef = tag
this.locRef = loc
}

//////////////////////////////////////////////////////////////////////////
// Public methods
Expand All @@ -64,11 +78,11 @@ abstract const class YamlObj
{
this.typeof == that?.typeof &&
this.tag == (that as YamlObj).tag &&
this.content == (that as YamlObj).content
this.val == (that as YamlObj).val
}

** Hash is based on tag and content
override Int hash() { 31 * tag.hash + content.hash }
override Int hash() { 31 * tag.hash + val.hash }

** Returns 'write' written into a string.
override Str toStr()
Expand Down Expand Up @@ -97,21 +111,26 @@ const class YamlScalar : YamlObj
{
// content : Str

** Creates a YamlScalar with the string 's' as content,
** Creates a YamlScalar with the string 'val' as content,
** found at location 'loc', with 'tag' as its tag.
new make(Str s, Str tag := "?", FileLoc loc := FileLoc.unknown)
new make(Str val, Str tag := "?", FileLoc loc := FileLoc.unknown)
: super(val, normTag(tag), loc)
{
this.content = s
this.loc = loc
}

if (tag == "!") this.tag = "tag:yaml.org,2002:str"
else if (tag != "") this.tag = tag
else this.tag = "?"
private static Str normTag(Str tag)
{
if (tag == "!") return "tag:yaml.org,2002:str"
if (tag != "") return tag
return "?"
}

** Convenience for creating a YamlScalar with an explicit file location but
** implicit tag.
new makeLoc(Str s, FileLoc loc) : this.make(s, "?", loc) {}
@NoDoc new makeLoc(Str s, FileLoc loc) : this.make(s, "?", loc) {}

** Content value as a string
override Str val() { valRef }

override internal Void writeInd(OutStream out, Int first, Int next := first)
{
Expand All @@ -121,7 +140,7 @@ const class YamlScalar : YamlObj
// Plain scalar
{
//cover when a plain scalar contains '\n'
out.writeChars(Regex("\\n(?=.)").matcher(content).replaceAll("\n\n" + (" " * next)) + "\n")
out.writeChars(Regex("\\n(?=.)").matcher(val).replaceAll("\n\n" + (" " * next)) + "\n")
}
else
// Non-plain - use quotation marks & escape chars
Expand All @@ -131,7 +150,7 @@ const class YamlScalar : YamlObj

out.writeChar('"')

(content as Str).each |c|
(val as Str).each |c|
{
// Escape chars
switch(c)
Expand Down Expand Up @@ -182,28 +201,30 @@ const class YamlList : YamlObj
{
// content : YamlObj[]

** Creates a YamlList with the list 's' as content,
** Creates a YamlList with the list 'val' as content,
** found at location 'loc', with 'tag' as its tag.
new make(YamlObj[] s, Str tag := "!", FileLoc loc := FileLoc.unknown)
new make(YamlObj[] val, Str tag := "!", FileLoc loc := FileLoc.unknown)
: super(val, normTag(tag), loc)
{
this.content = s
this.loc = loc
}

if (tag == "!" || tag == "") this.tag = "tag:yaml.org,2002:seq"
else this.tag = tag
private static Str normTag(Str tag)
{
if (tag == "!" || tag == "") return "tag:yaml.org,2002:seq"
return tag
}

** Convenience for creating a YamlList with an explicit file location but
** implicit tag.
new makeLoc(YamlObj[] s, FileLoc loc) : this.make(s, "!", loc) {}
@NoDoc new makeLoc(YamlObj[] s, FileLoc loc) : this.make(s, "!", loc) {}

** Content as a list
YamlObj[] list() { content }
** Content value as a list
override YamlObj[] val() { valRef }

** Iterate the list items
Void each(|YamlObj| f)
{
((YamlObj[])content).each(f)
((YamlObj[])val).each(f)
}

override internal Void writeInd(OutStream out, Int first, Int next := first)
Expand All @@ -215,7 +236,7 @@ const class YamlList : YamlObj
// normal list
else
{
contList := content as YamlObj[]
contList := val as YamlObj[]
isEmpty := contList.size == 0
isTagged := tag != "?" && tag != "tag:yaml.org,2002:seq"

Expand All @@ -237,7 +258,7 @@ const class YamlList : YamlObj
** Writes the content as a stream of YAML documents instead of a list
private Void writeStream(OutStream out)
{
contList := content as YamlObj[]
contList := val as YamlObj[]

if (contList.size != 0)
out.writeChars("%YAML 1.2\n")
Expand Down Expand Up @@ -267,27 +288,29 @@ const class YamlMap : YamlObj
{
// content : [YamlObj:YamlObj]

** Creates a YamlMap with the map 's' as content,
** Creates a YamlMap with the map 'val' as content,
** found at location 'loc', with 'tag' as its tag.
new make([YamlObj:YamlObj] s, Str tag := "!", FileLoc loc := FileLoc.unknown)
new make([YamlObj:YamlObj] val, Str tag := "!", FileLoc loc := FileLoc.unknown)
: super(val, normTag(tag), loc)
{
this.content = s
this.loc = loc
}

if (tag == "!" || tag == "") this.tag = "tag:yaml.org,2002:map"
else this.tag = tag
private static Str normTag(Str tag)
{
if (tag == "!" || tag == "") return "tag:yaml.org,2002:map"
return tag
}

** Convenience for creating a YamlMap with an explicit file location but
** implicit tag.
new makeLoc([YamlObj:YamlObj] s, FileLoc loc) : this.make(s, "!", loc) {}
@NoDoc new makeLoc([YamlObj:YamlObj] s, FileLoc loc) : this.make(s, "!", loc) {}

** Content as a map
[YamlObj:YamlObj] map() { content }
** Content value as a map
override [YamlObj:YamlObj] val() { valRef }

override internal Void writeInd(OutStream out, Int first, Int next := first)
{
contMap := content as YamlObj:YamlObj
contMap := val as YamlObj:YamlObj
isEmpty := contMap.keys.size == 0
isTagged := tag != "?" && tag != "tag:yaml.org,2002:map"

Expand All @@ -307,14 +330,14 @@ const class YamlMap : YamlObj
kStr := buf.toStr[0..-2] //strip ending '\n'

// Key fits on single line
if ((k.typeof == YamlScalar# || k.content == YamlObj[,] || k.content == [YamlObj:YamlObj][:]) &&
if ((k.typeof == YamlScalar# || k.val == YamlObj[,] || k.val == [YamlObj:YamlObj][:]) &&
!kStr.containsChar('\n') &&
kStr.size <= 1024)
{
out.writeChars(kStr + ":")

// Scalar
if (v.typeof == YamlScalar# || v.content == YamlObj[,] || v.content == [YamlObj:YamlObj][:])
if (v.typeof == YamlScalar# || v.val == YamlObj[,] || v.val == [YamlObj:YamlObj][:])
v.writeInd(out, 1, next + 1)
// Non-scalar
else
Expand Down
2 changes: 1 addition & 1 deletion src/yaml/fan/YamlParser.fan
Original file line number Diff line number Diff line change
Expand Up @@ -1295,7 +1295,7 @@ internal class YamlParser
private YamlObj setLoc(YamlObj obj, FileLoc loc)
{
return Type.of(obj).make(
[obj.content,
[obj.val,
obj.tag,
loc]
)
Expand Down
55 changes: 28 additions & 27 deletions src/yaml/fan/YamlSchema.fan
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ abstract const class YamlSchema
else if (obj == null ||
obj is Str) return f(obj)
// Simple - needs tag
else if (ser.simple) return YamlScalar(f(obj).content, "!fan/$type")
else if (ser.simple) return YamlScalar(f(obj).val, "!fan/$type")
// List
else if (obj is List) return YamlList(YamlObj[,].addAll((obj as List).map |v| { return recEncode(v, f) }))
// Map
Expand Down Expand Up @@ -154,6 +154,7 @@ abstract const class YamlSchema
**************************************************************************

** YamlTagErr indicates that a YAML tag is set that does not match its node's content.
@NoDoc
const class YamlTagErr : Err
{
** Used when the given tag cannot be assigned to the given node type,
Expand All @@ -164,7 +165,7 @@ const class YamlTagErr : Err
** Used when the YamlObj's tag and content do not match, e.g. combining the tag
** 'tag:yaml.org,2002:int' with the content '"true"'.
new makeContent(YamlObj obj)
: super.make("The tag \"$obj.tag\" does not fit the content \"$obj.content\".") {}
: super.make("The tag \"$obj.tag\" does not fit the content \"$obj.val\".") {}

new makeStr(Str msg) : super.make(msg) {}
}
Expand Down Expand Up @@ -194,22 +195,22 @@ const class FailsafeSchema : YamlSchema
switch (tag)
{
case "tag:yaml.org,2002:str":
return node.content
return node.val

case "tag:yaml.org,2002:seq":
return (node.content as YamlObj[]).map |n| { decode(n) }
return (node.val as YamlObj[]).map |n| { decode(n) }

case "tag:yaml.org,2002:map":
res := [:]
res.ordered = true
map := node.content as [YamlObj:YamlObj]
map := node.val as [YamlObj:YamlObj]
map.keys.each |k|
{
k2 := decode(k)
if (k2 == null)
throw NullErr("Maps in Fantom cannot contain null keys.")
if (res.containsKey(k2))
throw YamlTagErr("The key \"$k2\", generated by the current schema from \"$k.content\", is already present in this map.")
throw YamlTagErr("The key \"$k2\", generated by the current schema from \"$k.val\", is already present in this map.")
res.add(decode(k).toImmutable, decode(map[k]))
}
return res
Expand Down Expand Up @@ -298,13 +299,13 @@ const class JsonSchema : FailsafeSchema
return null

case "tag:yaml.org,2002:bool":
return node.content == "true"
return node.val == "true"

case "tag:yaml.org,2002:int":
return Int(node.content)
return Int(node.val)

case "tag:yaml.org,2002:float":
return Float(node.content)
return Float(node.val)

default:
throw Err("Internal error - all tags should have been covered.")
Expand Down Expand Up @@ -336,12 +337,12 @@ const class JsonSchema : FailsafeSchema
if (node.typeof != YamlScalar#)
return super.assignTag(node)

if (matchNull.matches(node.content)) return "tag:yaml.org,2002:null"
if (matchBool.matches(node.content)) return "tag:yaml.org,2002:bool"
if (matchInt.matches(node.content)) return "tag:yaml.org,2002:int"
if (matchFloat.matches(node.content)) return "tag:yaml.org,2002:float"
if (matchNull.matches(node.val)) return "tag:yaml.org,2002:null"
if (matchBool.matches(node.val)) return "tag:yaml.org,2002:bool"
if (matchInt.matches(node.val)) return "tag:yaml.org,2002:int"
if (matchFloat.matches(node.val)) return "tag:yaml.org,2002:float"

throw YamlTagErr("The plain content \"$node.content\" does not match any valid JSON type.")
throw YamlTagErr("The plain content \"$node.val\" does not match any valid JSON type.")
}

override Void validate(YamlObj node)
Expand All @@ -355,19 +356,19 @@ const class JsonSchema : FailsafeSchema
switch (node.tag)
{
case "tag:yaml.org,2002:null":
if (!matchNull.matches(node.content))
if (!matchNull.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:bool":
if (!matchBool.matches(node.content))
if (!matchBool.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:int":
if (!matchInt.matches(node.content))
if (!matchInt.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:float":
if (!matchFloat.matches(node.content))
if (!matchFloat.matches(node.val))
throw YamlTagErr(node)
}
}
Expand Down Expand Up @@ -408,7 +409,7 @@ const class CoreSchema : FailsafeSchema
// Create object
if (super.isRecognized(tag)) return super.decode(node)

cont := node.content as Str
cont := node.val as Str
switch (tag)
{
case "tag:yaml.org,2002:null":
Expand Down Expand Up @@ -461,10 +462,10 @@ const class CoreSchema : FailsafeSchema
if (node.typeof != YamlScalar#)
return super.assignTag(node)

if (matchNull.matches(node.content)) return "tag:yaml.org,2002:null"
if (matchBool.matches(node.content)) return "tag:yaml.org,2002:bool"
if (matchInt.matches(node.content)) return "tag:yaml.org,2002:int"
if (matchFloat.matches(node.content)) return "tag:yaml.org,2002:float"
if (matchNull.matches(node.val)) return "tag:yaml.org,2002:null"
if (matchBool.matches(node.val)) return "tag:yaml.org,2002:bool"
if (matchInt.matches(node.val)) return "tag:yaml.org,2002:int"
if (matchFloat.matches(node.val)) return "tag:yaml.org,2002:float"
return "tag:yaml.org,2002:str"
}

Expand All @@ -479,19 +480,19 @@ const class CoreSchema : FailsafeSchema
switch (node.tag)
{
case "tag:yaml.org,2002:null":
if (!matchNull.matches(node.content))
if (!matchNull.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:bool":
if (!matchBool.matches(node.content))
if (!matchBool.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:int":
if (!matchInt.matches(node.content))
if (!matchInt.matches(node.val))
throw YamlTagErr(node)

case "tag:yaml.org,2002:float":
if (!matchFloat.matches(node.content))
if (!matchFloat.matches(node.val))
throw YamlTagErr(node)
}
}
Expand Down
Loading

0 comments on commit 25e2130

Please sign in to comment.