YAML(全称:YAML Ain't Markup Language)是一种人类可读的数据序列化格式。它常用来写配置文件、数据交换或者作为存储格式。YAML的设计目标是简洁、易读,且容易与其他编程语言和数据格式(比如JSON、XML)互操作。

YAML 的主要特点包括:

  1. 简洁和易读:相比JSON,YAML更加直观和简洁。比如,YAML使用缩进来表示层级关系,而JSON使用大括号和方括号。
  2. 支持多种数据类型:包括标量(字符串、整数、浮点数等)、列表、字典(键值对)、日期等。
  3. 支持复杂结构:可以用来表示复杂的数据结构,如多层嵌套的对象和数组。
  4. 注释支持:YAML文件可以包含注释,注释以 # 开头,帮助解释配置项的用途。

 

出处:https://github.com/HotKeyIt/Yaml/blob/master/Yaml.ahk

 

Yaml.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
Yaml(YamlText,IsFile=1,YamlObj=0){ ; Version 1.0.0.17 http://www.autohotkey.com/forum/viewtopic.php?t=70559
static
static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
static BackupVars:="LVL,SEQ,KEY,SCA,TYP,VAL,CMT,LFL,CNT",IncompleteSeqMap
local maxLVL:=0,LastContObj:=0,LastContKEY:=0,LinesAdded:=0,_LVLChanged:=0,_LVL,_SEQ,_KEY,_SCA,_TYP,_VAL,_CMT,_LFL,_CNT,_NXT,__LVL,__SEQ,__KEY,__SCA,__TYP,__VAL,__CMT,__LFL,__CNT,__NXT
AutoTrim % ((AutoTrim:=A_AutoTrim)="On")?"Off":"Off"
LVL0:=pYaml:=YamlObj?YamlObj:Object("base",base),__LVL:=0,__LVL0:=0
If IsFile
FileRead,YamlText,%YamlText%
Loop,Parse,YamlText,`n,`r
{
If (!_CNT && (A_LoopField=""||RegExMatch(A_LoopField,"^\s+$"))){ ;&&__KEY=""&&__SEQ="")){
If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
If (__KEY!="")
Yaml_Continue(LastContObj:=LVL%__LVL%["",Obj],LastContKEY:=__key,"",__SCA)
else Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=Obj,"",__SCA,__SEQ)
} else If (__SEQ && OBJ){
Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,__SEQ)
} else If (OBJ){
Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,1)
} else if (__KEY!="")
Yaml_Continue(LastContObj:=LVL%__LVL%,LastContKEY:=__KEY,"",__SCA)
else LinesAdded--
LinesAdded++
Continue
} else If (!_CNT && LastContObj
&& ( RegExMatch(A_LoopField,"^(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)")
|| RegExMatch(A_LoopField,"^(---)|\s*(-\s)") )){
If !__SCA
LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded)
LastContObj:=0,LastContKEY:=0,LinesAdded:=0
}
If InStr(A_LoopField,"#"){
If (RegexMatch(A_LoopField,"^\s*#.*") || InStr(A_LoopField,"%YAML")=1) ;Comments only, do not parse
continue
else if Yaml_IsQuoted(LTrim(A_LoopField,"- ")) || RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+|'.+)$")&&!RegExMatch(A_LoopField,"[^\\]""\s+#")
LoopField:=A_LoopField
else if RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1)
LoopField:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1)-1)
else LoopField:=A_LoopField
} else LoopField:=A_LoopField
If _CNT {
If Yaml_IsSeqMap(RegExReplace(IncompleteSeqMap LoopField,"^(\s+)?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?"))
LoopField:=IncompleteSeqMap LoopField,_CNT:=0,IncompleteSeqMap:=""
else {
IncompleteSeqMap.=LoopField
continue
}
}
If (LoopField="---"){
Loop % (maxLVL)
LVL%A_Index%:=""
Loop,Parse,BackupVars,`,
__%A_LoopField%:="",__%A_LoopField%0:=""
Loop,Parse,BackupVars,`,
Loop % maxLVL
__%A_LoopField%%A_Index%:=""
maxLVL:=0
__LVL:=0,__LVL0:=0
If !IsObject(pYaml[""])
pYaml[""]:=LVL0:=Object("base",base)
pYaml[""].Insert(LVL0:=Object("base",base))
Continue
} else if (LoopField="..."){
LVL0:=pYaml
Loop % maxLVL
LVL%A_Index%:=""
Loop,Parse,BackupVars,`,
__%A_LoopField%:="",__%A_LoopField%0:=""
Loop,Parse,BackupVars,`,
Loop % maxLVL
__%A_LoopField%%A_Index%:=""
maxLVL:=0
__LVL:=0,__LVL0:=0
Continue
}
If (SubStr(LoopField,0)=":")
LoopField.=A_Space ; add space to force RegEx to match even if the value and space after collon is missing e.g. Object:`n objects item
RegExMatch(LoopField,"S)^(?<LVL>\s+)?(?<SEQ>-\s)?(?<KEY>"".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*(?<SCA>[\|\>][+-]?)?\s*(?<TYP>!!\w+\s)?\s*(?<VAL>"".+""|'.+'|.+)?\s*$",_)
If _KEY ;cut off (:)
StringTrimRight,_KEY,_KEY,2
_KEY:=Yaml_UnQuoteIfNeed(_KEY)
If IsVal:=Yaml_IsQuoted(_VAL)
_VAL:=Yaml_UnQuoteIfNeed(_VAL)
;determine current level
_LVL:=Yaml_S2I(_LVL)
If _LVL-__LVL>1||(_LVL>__LVL&&_LVLChanged) ;&&!(__SEQ&&__KEY!=""&&_KEY!="")) ; (__SEQ?2:1)
{
Loop % (_LVLChanged?_LVL-_LVLChanged:_LVL-__LVL-1)
LoopField:=SubStr(LoopField,SubStr(LoopField,1,1)=A_Tab?1:2)
_LVL:=_LVLChanged?_LVLChanged:__LVL+1,_LVLChanged:=_LVLChanged?_LVLChanged:_LVL ;__LVL%_LVL%:=__LVL%_NXT% ; (__SEQ?2:1)
} else if _LVLChanged
_LVL:=_LVLChanged
else _LVLChanged:=0
If (maxLVL<_LVL)
maxLVL:=_LVL+(_SEQ?1:0)
; Cut off the leading tabs/spaces conform _LVL
SubStr:=0,Tabs:=0
Loop,Parse,LoopField
If (_LVL*2=SubStr || !SubStr:=SubStr+(A_LoopField=A_Tab?2:1)), Tabs:=Tabs+(A_LoopField=A_Tab?1:0)
break
_LFL:=SubStr(LoopField,SubStr-Tabs+1+(_SEQ?2:0))
_LFL:=Yaml_UnQuoteIfNeed(_LFL)
_NXT:=_LVL+1 ;next indentation level
__NXT:=_NXT+1
_PRV:=_LVL=0?0:_LVL-1
Loop,Parse,BackupVars,`,
__%A_LoopField%:=__%A_LoopField%%_PRV%
If RegExMatch(_LFL,"^-\s*$"){
_SEQ:="-",_KEY:="",_VAL:=""
}
If (!IsVal && !_CNT && (_CNT:=Yaml_Incomplete(Trim(_LFL))||Yaml_Incomplete(Trim(_VAL)))){
IncompleteSeqMap:=LoopField
continue
}
If (_LVL<__LVL){ ;Reset Objects and Backup vars
Loop % (maxLVL)
If (A_Index>_LVL){
Loop,Parse,BackupVars,`,
__%A_LoopField%%maxLVL%:=""
LVL%A_Index%:="",maxLVL:=maxLVL-1
}
If (_LVL=0 && !__LVL:=__LVL0:=0)
Loop,Parse,BackupVars,`,
__%A_LoopField%:="",__%A_LoopField%0:=""
}
If (_SEQ&&_LVL>__LVL&&(__VAL!=""||__SCA))
_SEQ:="",_KEY:="",_VAL:="",_LFL:="- " _LFL
If (__CNT)||(_LVL>__LVL&&(__KEY!=""&&_KEY="")&&(__VAL!=""||__SCA))||(__SEQ&&__SCA)
_KEY:="",_VAL:=""
If (__CNT||(_LVL>__LVL&&(__KEY!=""||(__SEQ&&(__LFL||__SCA)&&!Yaml_IsSeqMap(__LFL)))&&!(_SEQ||_KEY!=""))){
If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
If __KEY!=
Yaml_Continue(LVL%__LVL%["",Obj],__key,_LFL,__SCA),__CNT:=Yaml_SeqMap(LVL%__LVL%["",OBJ],__KEY,LVL%__LVL%["",OBJ,__KEY])?"":__CNT
else Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ),__CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT
} else If (__SEQ && OBJ){
Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ)
__CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT
} else If (OBJ && __KEY=""){
Yaml_Continue(LVL%__LVL%[""],OBJ,_LFL,__SCA,1)
__CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],1)?"":__CNT
} else {
Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA)
__CNT:=Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY])?"":__CNT
}
Continue
}
;Create sequence or map
If (__SEQ&&(_LVL>__LVL)&&_KEY!=""&&__KEY!=""){
OBJ:=LVL%__LVL%[""].MaxIndex()
If _SEQ {
If !Yaml_SeqMap(LVL%_LVL%["",OBJ,__KEY,""],_KEY,_VAL){
If !IsObject(LVL%__LVL%["",OBJ,__KEY,""])
LVL%__LVL%["",OBJ,__KEY,""]:={base:base}
LVL%__LVL%["",OBJ,__KEY,""].Insert({(_KEY):_VAL!=""?_VAL:(LVL%_NXT%:={base:base}),base:base})
}
} else If !Yaml_SeqMap(LVL%_LVL%["",OBJ],_KEY,_VAL){
LVL%__LVL%["",OBJ,_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:={base:base})
}
If _VAL!=
continue
} else If (_SEQ){
If !IsObject(LVL%_LVL%[""])
LVL%_LVL%[""]:=Object("base",base)
While (SubStr(_LFL,1,2)="- "){
_LFL:=SubStr(_LFL,3),_KEY:=(_KEY!="")?_LFL:=SubStr(_KEY,3):_KEY,LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("",Object("base",base),"base",base)),_LVL:=_LVL+1,_NXT:=_NXT+1,__NXT:=_NXT+1,_PRV:=_LVL-1,maxLVL:=(maxLVL<_LVL)?_LVL:maxLVL
Loop,Parse,BackupVars,`,
__%A_LoopField%:=_%A_LoopField%
,__%A_LoopField%%_PRV%:=_%A_LoopField%
}
If (_KEY="" && _VAL="" && !IsVal){
If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)
LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("base",base))
} else If (_KEY!="") {
LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,LVL%_NXT%:=Object("base",base),"base",base))
If !Yaml_SeqMap(LVL%__NXT%,_KEY,_VAL){
LVL%_LVL%[""].Remove()
LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,(_VAL!=""||IsVal)?_VAL:LVL%_NXT%:=Object("base",base),"base",base))
}
} else {
If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)
LVL%_LVL%[""].Insert(_LFL)
}
If !LVL%_LVL%[""].MaxIndex()
LVL%_LVL%.Remove("")
} else if (_KEY!=""){
If (__SEQ && _LVL>__LVL) {
If (OBJ:=LVL%_PRV%[""].MaxIndex())&&IsObject(LVL%_PRV%["",OBJ]){
If !Yaml_SeqMap(LVL%_PRV%["",OBJ],_KEY,_VAL)
LVL%_PRV%["",OBJ,_KEY]:=(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base))
} else {
LVL%_PRV%[""].Insert(Object(_KEY,(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base)),"base",base))
Yaml_SeqMap(LVL%_PRV%["",OBJ?OBJ+1:1],_KEY,_VAL)
}
} else
If !Yaml_SeqMap(LVL%_LVL%,_KEY,_VAL)
LVL%_LVL%[_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:=Object("base",base))
} else if (_LVL>__LVL && (__KEY!="")) {
If (__VAL!="" || __SCA){
Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA)
Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY])
Continue
} else {
If !Yaml_SeqMap(LVL%__LVL%[__KEY],_KEY,_VAL) ;!!! no Scalar???
LVL%__LVL%[__KEY,_KEY]:=_VAL
Continue
}
} else {
If (_LVL>__LVL&&(OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
If __CNT
Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1)
If (__CNT:=Yaml_SeqMap(LVL%__LVL%[""],"",_LFL)?"":1)
LVL%__LVL%[""].Insert(_LFL)
} else {
If !IsObject(LVL%_LVL%[""])
LVL%_LVL%[""]:=Object("base",base)
If __CNT
Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1)
If (__CNT:=Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)?"":1)
LVL%_LVL%[""].Insert(_LFL)
}
Continue
}
Loop,Parse,BackupVars,`,
__%A_LoopField%:=_%A_LoopField%
,__%A_LoopField%%_LVL%:=_%A_LoopField%
}
If (LastContObj && !__SCA)
LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded)
AutoTrim %AutoTrim%
Loop,Parse,BackupVars,`,
If !(__%A_LoopField%:="")
Loop % maxLVL
__%A_LoopField%%A_Index%:=""
Return pYaml,pYaml.base:=base
}
Yaml_Save(obj,file,level=""){
FileMove,% file,% file ".bakupyml",1
FileAppend,% obj.Dump(),% file
If !ErrorLevel
FileDelete,% file ".bakupyml"
else {
FileMove,% file ".bakupyml",% file
MsgBox,0, Error creating file, old file was restored.
}
}
Yaml_Call(NotSupported,f,p*){
If (p.MaxIndex()>1){
Loop % p.MaxIndex()
If A_Index>1
f:=f[""][p[A_Index-1]]
}
Return (!p.MaxIndex()?f[""].MaxIndex():f[""][p[p.MaxIndex()]])
}
Yaml_Merge(obj,merge){
for k,v in merge
{
If IsObject(v){
If obj.HasKey(k){
If IsObject(obj[k])
Yaml_Merge(obj[k],v)
else obj[k]:=v
} else obj[k]:=v
} else obj[k]:=v
}
}
Yaml_Add(O,Yaml="",IsFile=0){
static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
If Yaml_IsSeqMap(Trim(Yaml)){
If !IsObject(O[""])
O[""]:=Object("base",base)
Yaml_SeqMap(O[""],"",Yaml)
} else Yaml(Yaml,IsFile,O)
}
Yaml_Dump(O,J="",R=0,Q=0){
static M1:="{",M2:="}",S1:="[",S2:="]",N:="`n",C:=", ",S:="- ",E:="",K:=": "
local dump:="",M,MX,F,I,key,value
If (J=0&&!R)
dump.= S1
for key in O
M:=A_Index
If IsObject(O[""]){
M--
for key in O[""]
MX:=A_Index
If IsObject(O[""][""])
MX--
If O[""].MaxIndex()
for key, value in O[""]
{
If key=
continue
I++
F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E
If (J!=""&&J<=R){
dump.=(F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value)) (I=MX&&!M?E:C) ;(Q="S"&&I=1?S1:E)(Q="S"&&I=MX?S2:E)
} else if F,dump:=dump N Yaml_I2S(R) S
dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E)
else {
; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\[']|:\s|\s#")
dump .= Yaml_EscIfNeed(value)
; else {
; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)=N?"":"-") "`n$1"),"ms)(*ANYCRLF)\R",N Yaml_I2S(R+1)))
; StringReplace,value,value,% N Yaml_I2S(R+1) N Yaml_I2S(R+1),% N Yaml_I2S(R+1),A
; dump.=value
; }
}
}
}
I=0
for key, value in O
{
If key=
continue
I++
F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E
If (J=0&&!R)
dump.= M1
If (J!=""&&J<=R){
dump.=(Q="S"&&I=1?M1:E) Yaml_EscIfNeed(key) K
dump.=F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value)
dump.=(Q="S"&&I=M?M2:E) (J!=0||R?(I=M?E:C):E)
} else if F,dump:=dump N Yaml_I2S(R) Yaml_EscIfNeed(key) K
dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E)
else {
; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\['\t]|:\s|\s#")
dump .= Yaml_EscIfNeed(value)
; else {
; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)="`n"?"":"-") "`n$1"),"ms)(*ANYCRLF)\R","`n" Yaml_I2S(R+1)))
; StringReplace,value,value,% "`n" Yaml_I2S(R+1) "`n" Yaml_I2S(R+1),% "`n" Yaml_I2S(R+1),A
; dump.= value
; }
}
If (J=0&&!R){
dump.=M2 (I<M?C:E)
}
}
If (J=0&&!R)
dump.=S2
If (R=0)
dump:=RegExReplace(dump,"^\R+")
Return dump
}
Yaml_UniChar( string ) {
static a:="`a",b:="`b",t:="`t",n:="`n",v:="`v",f:="`f",r:="`r",e:=Chr(0x1B)
Loop,Parse,string,\
{
If (A_Index=1){
var.=A_LoopField
continue
} else If lastempty {
var.="\" A_LoopField
lastempty:=0
Continue
} else if (A_LoopField=""){
lastempty:=1
Continue
}
If InStr("ux",SubStr(A_LoopField,1,1))
str:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K")-1)
else
str:=SubStr(A_LoopField,1,1)
If (str=="N")
str:="\x85"
else if (str=="P")
str:="\x2029"
else if (str=0)
str:="\x0"
else if (str=="L")
str:="\x2028"
else if (str=="_")
str:="\xA0"
If RegexMatch(str,"i)^[ux][\da-f]+$")
var.=Chr(Abs("0x" SubStr(str,2)))
else If str in a,b,t,n,v,f,r,e
var.=%str%
else var.=str
If InStr("ux",SubStr(A_LoopField,1,1))
var.=SubStr(A_LoopField,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K"))
else var.=SubStr(A_LoopField,2)
}
return var
}
Yaml_CharUni( string ) {
static ascii:={"\":"\","`a": "a","`b": "b","`t": "t","`n": "n","`v": "v","`f": "f","`r": "r",Chr(0x1B): "e","""": """",Chr(0x85): "N",Chr(0x2029): "P",Chr(0x2028): "L","": "0",Chr(0xA0): "_"}
If !RegexMatch(string,"[\x{007F}-\x{FFFF}]"){
Loop,Parse,string
{
If ascii[A_LoopField]
var.="\" ascii[A_LoopField]
else
var.=A_LoopField
}
return var
}
format:=A_FormatInteger
SetFormat,Integer,H
Loop,Parse,string
{
If ascii[A_LoopField]
var.="\" ascii[A_LoopField]
else if Asc(A_LoopField)<128
var.=A_LoopField
else {
str:=SubStr(Asc(A_LoopField),3)
var.="\u" (StrLen(str)<2?"000":StrLen(str)<3?"00":StrLen(str)<4?"0":"") str
}
}
SetFormat,Integer,%Format%
return var
}
Yaml_EscIfNeed(s){
If (s="")
return "''"
else If RegExMatch(s,"m)[\{\[""'\r\n]|:\s|,\s|\s#")||RegExMatch(s,"^[\s#\\\-:>]")||RegExMatch(s,"m)\s$")||RegExMatch(s,"m)[\x{7F}-\x{7FFFFFFF}]")
return ("""" . Yaml_CharUni(s) . """")
else return s
}
Yaml_IsQuoted(ByRef s){
return InStr(".''."""".","." SubStr(Trim(s),1,1) SubStr(Trim(s),0) ".")?1:0
}
Yaml_UnQuoteIfNeed(s){
s:=Trim(s)
If !(SubStr(s,1,1)=""""&&SubStr(s,0)="""")
return (SubStr(s,1,1)="'"&&SubStr(s,0)="'")?SubStr(s,2,StrLen(s)-2):s
else return Yaml_UniChar(SubStr(s,2,StrLen(s)-2))
}
Yaml_S2I(str){
local idx:=0
Loop,Parse,str
If (A_LoopField=A_Tab)
idx++
else if !Mod(A_index,2)
idx++
Return idx
}
Yaml_I2S(idx){
Loop % idx
str .= " "
Return str
}
Yaml_Continue(Obj,key,value,scalar="",isval=0){
If !IsObject(isObj:=obj[key])
v:=isObj
If scalar {
StringTrimLeft,scaopt,scalar,1
scalar:=Asc(scalar)=124?"`n":" "
} else scalar:=" ",scaopt:="-"
temp := (value=""?"`n":(SubStr(v,0)="`n"&&scalar="`n"?"":(v=""?"":scalar))) value (scaopt!="-"?(v&&value=""?"`n":""):"")
obj[key]:=Yaml_UnQuoteIfNeed(v temp)
}
Yaml_Quote(ByRef L,F,Q,B,ByRef E){
Return (F="\"&&!E&&(E:=1))||(E&&!(E:=0)&&(L:=L ("\" F)))
}
Yaml_SeqMap(o,k,v,isVal=0){
v:=Trim(v,A_Tab A_Space "`n"),m:=SubStr(v,1,1) SubStr(v,0)
If Yaml_IsSeqMap(v)
return m="[]"?Yaml_Seq(o,k,SubStr(v,2,StrLen(v)-2),isVal):m="{}"?Yaml_Map(o,k,SubStr(v,2,StrLen(v)-2),isVal):0
}
Yaml_Seq(obj,key,value,isVal=0){
static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
ContinueNext:=0
If (obj=""){
If (SubStr(value,0)!="]")
Return 0
else
value:=SubStr(value,2,StrLen(value)-2)
} else {
If (key=""){
obj.Insert(Object("",cObj:=Object("base",base),"base",base))
} else if (isval && IsObject(obj[key,""])){
cObj:=obj[key,""]
} else obj[key]:=Object("",cObj:=Object("base",base),"base",base)
}
Count:=StrLen(value)
Loop,Parse,value
{
If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0))
Continue
If (Quote){
If (A_LoopField=Quote){
Quote=
If Bracket
LF.= A_LoopField
else LF:=SubStr(LF,2)
Continue
}
LF .= A_LoopField
continue
} else if (!Quote&&InStr("""'",A_LoopField)){
Quote:=A_LoopField
If !Bracket
VQ:=Quote
LF.=A_LoopField
Continue
} else if (!Quote&&Bracket){
If (Asc(A_LoopField)=Asc(Bracket)+2)
BCount--
else if (A_LoopField=Bracket)
BCount++
If (BCount=0)
Bracket=
LF .= A_LoopField
Continue
} else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){
Bracket:=A_LoopField
BCount:=1
LF.=A_LoopField
Continue
}
If (A_Index=Count)
LF .= A_LoopField
else if (!Quote&&!Bracket&&A_LoopField=","&&(!InStr("0123456789",SubStr(value,A_Index-1,1)) | !InStr("0123456789",SubStr(value,A_Index+1,1)))){
ContinueNext:=SubStr(value,A_Index+1,1)=A_Space||SubStr(value,A_Index+1,1)=A_Tab
LF:=LF
} else {
LF .= A_LoopField
continue
}
If (obj=""){
If !VQ
If (Asc(LF)=91 && !Yaml_Seq("","",LF))
||(Asc(LF)=123 && !Yaml_Map("","",LF))
Return 0
} else {
If (VQ || !Yaml_SeqMap(cObj,"",LF))
cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF))
}
LF:="",VQ:=""
}
If (LF){
If (obj=""){
If !VQ
If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF))
Return 0
} else If (VQ || !Yaml_SeqMap(cObj,"",LF))
cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF))
}
Return (obj=""?(Quote Bracket=""):1)
}
Yaml_Map(obj,key,value,isVal=0){
static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
ContinueNext:=0
If (obj=""){
If (SubStr(value,0)!="}")
Return 0
else
value:=SubStr(value,2,StrLen(value)-2)
} else {
If (key="")
obj.Insert(cObj:=Object("base",base))
else obj[key]:=(cObj:=Object("base",base))
}
Count:=StrLen(value)
Loop,Parse,value
{
If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0))
Continue
If (Quote){
If (A_LoopField=Quote){
Quote=
LF.=A_LoopField
} else LF .= A_LoopField
continue
} else if (!Quote&&(k=""||v="")&&InStr("""'",A_LoopField)){
Quote:=A_LoopField
If (k && !Bracket)
VQ:=Quote
else if !Bracket
KQ:=Quote
LF.=Quote
Continue
} else If (k!=""&&LF=""&&InStr("`n`r `t",A_LoopField)){
Continue
}
If (!Quote&&Bracket){
If (Asc(A_LoopField)=Asc(Bracket)+2)
BCount--
else if (A_LoopField=Bracket)
BCount++
If (BCount=0)
Bracket=
LF .= A_LoopField
Continue
} else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){
Bracket:=A_LoopField
BCount=1
LF.=A_LoopField
Continue
}
If (A_Index=Count&&k!=""){
v:=LF A_LoopField
v:=Trim(v)
If (InStr("""'",SubStr(v,0))&&SubStr(v,1,1)=SubStr(v,0))
v:=SubStr(v,2,StrLen(v)-2)
} else If (!Quote&&!Bracket&&k!=""&&A_LoopField=","&&SubStr(value,A_Index+1,1)=A_Space){
ContinueNext:=1
LF:=Trim(LF)
If VQ
LF:=SubStr(LF,2,StrLen(LF)-2)
v:=LF,LF:=""
} else if (!Quote&&!Bracket&&k=""&&A_LoopField=":"){
LF:=Trim(LF)
If (InStr("""'",SubStr(LF,0))&&SubStr(LF,1,1)=SubStr(LF,0))
LF:=SubStr(LF,2,StrLen(LF)-2)
k:=LF,LF:=""
continue
} else {
LF .= A_LoopField
continue
}
If (obj=""){
If VQ=
If (Asc(v)=91 && !Yaml_Seq("","",v))
||(Asc(v)=123 && !Yaml_Map("","",v))
Return 0
} else {
If (VQ || !Yaml_SeqMap(cObj,k,v))
cObj[KQ?Yaml_UniChar(k):k]:=(VQ?Yaml_UniChar(v):Trim(v))
}
k:="",v:="",VQ:="",KQ:=""
}
If (k){
If (obj=""){
If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF))
Return 0
} else {
LF:=Trim(LF)
If (VQ)
LF:=SubStr(LF,2,StrLen(LF)-2),cObj[k]:=Yaml_UniChar(LF)
else If (!Yaml_SeqMap(cObj,k,LF))
cObj[k]:=Trim(LF)
}
}
Return (obj=""?(Quote Bracket=""):1)
}
Yaml_Incomplete(value){
return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && !Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space)))
|| (Asc(Trim(value,"`n" A_Tab A_Space))=123 && !Yaml_Map("","",Trim(value,"`n" A_Tab A_Space)))
}
Yaml_IsSeqMap(value){
return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space)))
|| (Asc(Trim(value,"`n" A_Tab A_Space))=123 && Yaml_Map("","",Trim(value,"`n" A_Tab A_Space)))
}
Yaml(YamlText,IsFile=1,YamlObj=0){ ; Version 1.0.0.17 http://www.autohotkey.com/forum/viewtopic.php?t=70559 static static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}} static BackupVars:="LVL,SEQ,KEY,SCA,TYP,VAL,CMT,LFL,CNT",IncompleteSeqMap local maxLVL:=0,LastContObj:=0,LastContKEY:=0,LinesAdded:=0,_LVLChanged:=0,_LVL,_SEQ,_KEY,_SCA,_TYP,_VAL,_CMT,_LFL,_CNT,_NXT,__LVL,__SEQ,__KEY,__SCA,__TYP,__VAL,__CMT,__LFL,__CNT,__NXT AutoTrim % ((AutoTrim:=A_AutoTrim)="On")?"Off":"Off" LVL0:=pYaml:=YamlObj?YamlObj:Object("base",base),__LVL:=0,__LVL0:=0 If IsFile FileRead,YamlText,%YamlText% Loop,Parse,YamlText,`n,`r { If (!_CNT && (A_LoopField=""||RegExMatch(A_LoopField,"^\s+$"))){ ;&&__KEY=""&&__SEQ="")){ If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){ If (__KEY!="") Yaml_Continue(LastContObj:=LVL%__LVL%["",Obj],LastContKEY:=__key,"",__SCA) else Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=Obj,"",__SCA,__SEQ) } else If (__SEQ && OBJ){ Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,__SEQ) } else If (OBJ){ Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,1) } else if (__KEY!="") Yaml_Continue(LastContObj:=LVL%__LVL%,LastContKEY:=__KEY,"",__SCA) else LinesAdded-- LinesAdded++ Continue } else If (!_CNT && LastContObj && ( RegExMatch(A_LoopField,"^(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)") || RegExMatch(A_LoopField,"^(---)|\s*(-\s)") )){ If !__SCA LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded) LastContObj:=0,LastContKEY:=0,LinesAdded:=0 } If InStr(A_LoopField,"#"){ If (RegexMatch(A_LoopField,"^\s*#.*") || InStr(A_LoopField,"%YAML")=1) ;Comments only, do not parse continue else if Yaml_IsQuoted(LTrim(A_LoopField,"- ")) || RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+|'.+)$")&&!RegExMatch(A_LoopField,"[^\\]""\s+#") LoopField:=A_LoopField else if RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1) LoopField:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1)-1) else LoopField:=A_LoopField } else LoopField:=A_LoopField If _CNT { If Yaml_IsSeqMap(RegExReplace(IncompleteSeqMap LoopField,"^(\s+)?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?")) LoopField:=IncompleteSeqMap LoopField,_CNT:=0,IncompleteSeqMap:="" else { IncompleteSeqMap.=LoopField continue } } If (LoopField="---"){ Loop % (maxLVL) LVL%A_Index%:="" Loop,Parse,BackupVars,`, __%A_LoopField%:="",__%A_LoopField%0:="" Loop,Parse,BackupVars,`, Loop % maxLVL __%A_LoopField%%A_Index%:="" maxLVL:=0 __LVL:=0,__LVL0:=0 If !IsObject(pYaml[""]) pYaml[""]:=LVL0:=Object("base",base) pYaml[""].Insert(LVL0:=Object("base",base)) Continue } else if (LoopField="..."){ LVL0:=pYaml Loop % maxLVL LVL%A_Index%:="" Loop,Parse,BackupVars,`, __%A_LoopField%:="",__%A_LoopField%0:="" Loop,Parse,BackupVars,`, Loop % maxLVL __%A_LoopField%%A_Index%:="" maxLVL:=0 __LVL:=0,__LVL0:=0 Continue } If (SubStr(LoopField,0)=":") LoopField.=A_Space ; add space to force RegEx to match even if the value and space after collon is missing e.g. Object:`n objects item RegExMatch(LoopField,"S)^(?<LVL>\s+)?(?<SEQ>-\s)?(?<KEY>"".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*(?<SCA>[\|\>][+-]?)?\s*(?<TYP>!!\w+\s)?\s*(?<VAL>"".+""|'.+'|.+)?\s*$",_) If _KEY ;cut off (:) StringTrimRight,_KEY,_KEY,2 _KEY:=Yaml_UnQuoteIfNeed(_KEY) If IsVal:=Yaml_IsQuoted(_VAL) _VAL:=Yaml_UnQuoteIfNeed(_VAL) ;determine current level _LVL:=Yaml_S2I(_LVL) If _LVL-__LVL>1||(_LVL>__LVL&&_LVLChanged) ;&&!(__SEQ&&__KEY!=""&&_KEY!="")) ; (__SEQ?2:1) { Loop % (_LVLChanged?_LVL-_LVLChanged:_LVL-__LVL-1) LoopField:=SubStr(LoopField,SubStr(LoopField,1,1)=A_Tab?1:2) _LVL:=_LVLChanged?_LVLChanged:__LVL+1,_LVLChanged:=_LVLChanged?_LVLChanged:_LVL ;__LVL%_LVL%:=__LVL%_NXT% ; (__SEQ?2:1) } else if _LVLChanged _LVL:=_LVLChanged else _LVLChanged:=0 If (maxLVL<_LVL) maxLVL:=_LVL+(_SEQ?1:0) ; Cut off the leading tabs/spaces conform _LVL SubStr:=0,Tabs:=0 Loop,Parse,LoopField If (_LVL*2=SubStr || !SubStr:=SubStr+(A_LoopField=A_Tab?2:1)), Tabs:=Tabs+(A_LoopField=A_Tab?1:0) break _LFL:=SubStr(LoopField,SubStr-Tabs+1+(_SEQ?2:0)) _LFL:=Yaml_UnQuoteIfNeed(_LFL) _NXT:=_LVL+1 ;next indentation level __NXT:=_NXT+1 _PRV:=_LVL=0?0:_LVL-1 Loop,Parse,BackupVars,`, __%A_LoopField%:=__%A_LoopField%%_PRV% If RegExMatch(_LFL,"^-\s*$"){ _SEQ:="-",_KEY:="",_VAL:="" } If (!IsVal && !_CNT && (_CNT:=Yaml_Incomplete(Trim(_LFL))||Yaml_Incomplete(Trim(_VAL)))){ IncompleteSeqMap:=LoopField continue } If (_LVL<__LVL){ ;Reset Objects and Backup vars Loop % (maxLVL) If (A_Index>_LVL){ Loop,Parse,BackupVars,`, __%A_LoopField%%maxLVL%:="" LVL%A_Index%:="",maxLVL:=maxLVL-1 } If (_LVL=0 && !__LVL:=__LVL0:=0) Loop,Parse,BackupVars,`, __%A_LoopField%:="",__%A_LoopField%0:="" } If (_SEQ&&_LVL>__LVL&&(__VAL!=""||__SCA)) _SEQ:="",_KEY:="",_VAL:="",_LFL:="- " _LFL If (__CNT)||(_LVL>__LVL&&(__KEY!=""&&_KEY="")&&(__VAL!=""||__SCA))||(__SEQ&&__SCA) _KEY:="",_VAL:="" If (__CNT||(_LVL>__LVL&&(__KEY!=""||(__SEQ&&(__LFL||__SCA)&&!Yaml_IsSeqMap(__LFL)))&&!(_SEQ||_KEY!=""))){ If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){ If __KEY!= Yaml_Continue(LVL%__LVL%["",Obj],__key,_LFL,__SCA),__CNT:=Yaml_SeqMap(LVL%__LVL%["",OBJ],__KEY,LVL%__LVL%["",OBJ,__KEY])?"":__CNT else Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ),__CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT } else If (__SEQ && OBJ){ Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ) __CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT } else If (OBJ && __KEY=""){ Yaml_Continue(LVL%__LVL%[""],OBJ,_LFL,__SCA,1) __CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],1)?"":__CNT } else { Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA) __CNT:=Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY])?"":__CNT } Continue } ;Create sequence or map If (__SEQ&&(_LVL>__LVL)&&_KEY!=""&&__KEY!=""){ OBJ:=LVL%__LVL%[""].MaxIndex() If _SEQ { If !Yaml_SeqMap(LVL%_LVL%["",OBJ,__KEY,""],_KEY,_VAL){ If !IsObject(LVL%__LVL%["",OBJ,__KEY,""]) LVL%__LVL%["",OBJ,__KEY,""]:={base:base} LVL%__LVL%["",OBJ,__KEY,""].Insert({(_KEY):_VAL!=""?_VAL:(LVL%_NXT%:={base:base}),base:base}) } } else If !Yaml_SeqMap(LVL%_LVL%["",OBJ],_KEY,_VAL){ LVL%__LVL%["",OBJ,_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:={base:base}) } If _VAL!= continue } else If (_SEQ){ If !IsObject(LVL%_LVL%[""]) LVL%_LVL%[""]:=Object("base",base) While (SubStr(_LFL,1,2)="- "){ _LFL:=SubStr(_LFL,3),_KEY:=(_KEY!="")?_LFL:=SubStr(_KEY,3):_KEY,LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("",Object("base",base),"base",base)),_LVL:=_LVL+1,_NXT:=_NXT+1,__NXT:=_NXT+1,_PRV:=_LVL-1,maxLVL:=(maxLVL<_LVL)?_LVL:maxLVL Loop,Parse,BackupVars,`, __%A_LoopField%:=_%A_LoopField% ,__%A_LoopField%%_PRV%:=_%A_LoopField% } If (_KEY="" && _VAL="" && !IsVal){ If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL) LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("base",base)) } else If (_KEY!="") { LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,LVL%_NXT%:=Object("base",base),"base",base)) If !Yaml_SeqMap(LVL%__NXT%,_KEY,_VAL){ LVL%_LVL%[""].Remove() LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,(_VAL!=""||IsVal)?_VAL:LVL%_NXT%:=Object("base",base),"base",base)) } } else { If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL) LVL%_LVL%[""].Insert(_LFL) } If !LVL%_LVL%[""].MaxIndex() LVL%_LVL%.Remove("") } else if (_KEY!=""){ If (__SEQ && _LVL>__LVL) { If (OBJ:=LVL%_PRV%[""].MaxIndex())&&IsObject(LVL%_PRV%["",OBJ]){ If !Yaml_SeqMap(LVL%_PRV%["",OBJ],_KEY,_VAL) LVL%_PRV%["",OBJ,_KEY]:=(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base)) } else { LVL%_PRV%[""].Insert(Object(_KEY,(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base)),"base",base)) Yaml_SeqMap(LVL%_PRV%["",OBJ?OBJ+1:1],_KEY,_VAL) } } else If !Yaml_SeqMap(LVL%_LVL%,_KEY,_VAL) LVL%_LVL%[_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:=Object("base",base)) } else if (_LVL>__LVL && (__KEY!="")) { If (__VAL!="" || __SCA){ Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA) Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY]) Continue } else { If !Yaml_SeqMap(LVL%__LVL%[__KEY],_KEY,_VAL) ;!!! no Scalar??? LVL%__LVL%[__KEY,_KEY]:=_VAL Continue } } else { If (_LVL>__LVL&&(OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){ If __CNT Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1) If (__CNT:=Yaml_SeqMap(LVL%__LVL%[""],"",_LFL)?"":1) LVL%__LVL%[""].Insert(_LFL) } else { If !IsObject(LVL%_LVL%[""]) LVL%_LVL%[""]:=Object("base",base) If __CNT Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1) If (__CNT:=Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)?"":1) LVL%_LVL%[""].Insert(_LFL) } Continue } Loop,Parse,BackupVars,`, __%A_LoopField%:=_%A_LoopField% ,__%A_LoopField%%_LVL%:=_%A_LoopField% } If (LastContObj && !__SCA) LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded) AutoTrim %AutoTrim% Loop,Parse,BackupVars,`, If !(__%A_LoopField%:="") Loop % maxLVL __%A_LoopField%%A_Index%:="" Return pYaml,pYaml.base:=base } Yaml_Save(obj,file,level=""){ FileMove,% file,% file ".bakupyml",1 FileAppend,% obj.Dump(),% file If !ErrorLevel FileDelete,% file ".bakupyml" else { FileMove,% file ".bakupyml",% file MsgBox,0, Error creating file, old file was restored. } } Yaml_Call(NotSupported,f,p*){ If (p.MaxIndex()>1){ Loop % p.MaxIndex() If A_Index>1 f:=f[""][p[A_Index-1]] } Return (!p.MaxIndex()?f[""].MaxIndex():f[""][p[p.MaxIndex()]]) } Yaml_Merge(obj,merge){ for k,v in merge { If IsObject(v){ If obj.HasKey(k){ If IsObject(obj[k]) Yaml_Merge(obj[k],v) else obj[k]:=v } else obj[k]:=v } else obj[k]:=v } } Yaml_Add(O,Yaml="",IsFile=0){ static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}} If Yaml_IsSeqMap(Trim(Yaml)){ If !IsObject(O[""]) O[""]:=Object("base",base) Yaml_SeqMap(O[""],"",Yaml) } else Yaml(Yaml,IsFile,O) } Yaml_Dump(O,J="",R=0,Q=0){ static M1:="{",M2:="}",S1:="[",S2:="]",N:="`n",C:=", ",S:="- ",E:="",K:=": " local dump:="",M,MX,F,I,key,value If (J=0&&!R) dump.= S1 for key in O M:=A_Index If IsObject(O[""]){ M-- for key in O[""] MX:=A_Index If IsObject(O[""][""]) MX-- If O[""].MaxIndex() for key, value in O[""] { If key= continue I++ F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E If (J!=""&&J<=R){ dump.=(F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value)) (I=MX&&!M?E:C) ;(Q="S"&&I=1?S1:E)(Q="S"&&I=MX?S2:E) } else if F,dump:=dump N Yaml_I2S(R) S dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E) else { ; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\[']|:\s|\s#") dump .= Yaml_EscIfNeed(value) ; else { ; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)=N?"":"-") "`n$1"),"ms)(*ANYCRLF)\R",N Yaml_I2S(R+1))) ; StringReplace,value,value,% N Yaml_I2S(R+1) N Yaml_I2S(R+1),% N Yaml_I2S(R+1),A ; dump.=value ; } } } } I=0 for key, value in O { If key= continue I++ F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E If (J=0&&!R) dump.= M1 If (J!=""&&J<=R){ dump.=(Q="S"&&I=1?M1:E) Yaml_EscIfNeed(key) K dump.=F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value) dump.=(Q="S"&&I=M?M2:E) (J!=0||R?(I=M?E:C):E) } else if F,dump:=dump N Yaml_I2S(R) Yaml_EscIfNeed(key) K dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E) else { ; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\['\t]|:\s|\s#") dump .= Yaml_EscIfNeed(value) ; else { ; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)="`n"?"":"-") "`n$1"),"ms)(*ANYCRLF)\R","`n" Yaml_I2S(R+1))) ; StringReplace,value,value,% "`n" Yaml_I2S(R+1) "`n" Yaml_I2S(R+1),% "`n" Yaml_I2S(R+1),A ; dump.= value ; } } If (J=0&&!R){ dump.=M2 (I<M?C:E) } } If (J=0&&!R) dump.=S2 If (R=0) dump:=RegExReplace(dump,"^\R+") Return dump } Yaml_UniChar( string ) { static a:="`a",b:="`b",t:="`t",n:="`n",v:="`v",f:="`f",r:="`r",e:=Chr(0x1B) Loop,Parse,string,\ { If (A_Index=1){ var.=A_LoopField continue } else If lastempty { var.="\" A_LoopField lastempty:=0 Continue } else if (A_LoopField=""){ lastempty:=1 Continue } If InStr("ux",SubStr(A_LoopField,1,1)) str:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K")-1) else str:=SubStr(A_LoopField,1,1) If (str=="N") str:="\x85" else if (str=="P") str:="\x2029" else if (str=0) str:="\x0" else if (str=="L") str:="\x2028" else if (str=="_") str:="\xA0" If RegexMatch(str,"i)^[ux][\da-f]+$") var.=Chr(Abs("0x" SubStr(str,2))) else If str in a,b,t,n,v,f,r,e var.=%str% else var.=str If InStr("ux",SubStr(A_LoopField,1,1)) var.=SubStr(A_LoopField,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K")) else var.=SubStr(A_LoopField,2) } return var } Yaml_CharUni( string ) { static ascii:={"\":"\","`a": "a","`b": "b","`t": "t","`n": "n","`v": "v","`f": "f","`r": "r",Chr(0x1B): "e","""": """",Chr(0x85): "N",Chr(0x2029): "P",Chr(0x2028): "L","": "0",Chr(0xA0): "_"} If !RegexMatch(string,"[\x{007F}-\x{FFFF}]"){ Loop,Parse,string { If ascii[A_LoopField] var.="\" ascii[A_LoopField] else var.=A_LoopField } return var } format:=A_FormatInteger SetFormat,Integer,H Loop,Parse,string { If ascii[A_LoopField] var.="\" ascii[A_LoopField] else if Asc(A_LoopField)<128 var.=A_LoopField else { str:=SubStr(Asc(A_LoopField),3) var.="\u" (StrLen(str)<2?"000":StrLen(str)<3?"00":StrLen(str)<4?"0":"") str } } SetFormat,Integer,%Format% return var } Yaml_EscIfNeed(s){ If (s="") return "''" else If RegExMatch(s,"m)[\{\[""'\r\n]|:\s|,\s|\s#")||RegExMatch(s,"^[\s#\\\-:>]")||RegExMatch(s,"m)\s$")||RegExMatch(s,"m)[\x{7F}-\x{7FFFFFFF}]") return ("""" . Yaml_CharUni(s) . """") else return s } Yaml_IsQuoted(ByRef s){ return InStr(".''."""".","." SubStr(Trim(s),1,1) SubStr(Trim(s),0) ".")?1:0 } Yaml_UnQuoteIfNeed(s){ s:=Trim(s) If !(SubStr(s,1,1)=""""&&SubStr(s,0)="""") return (SubStr(s,1,1)="'"&&SubStr(s,0)="'")?SubStr(s,2,StrLen(s)-2):s else return Yaml_UniChar(SubStr(s,2,StrLen(s)-2)) } Yaml_S2I(str){ local idx:=0 Loop,Parse,str If (A_LoopField=A_Tab) idx++ else if !Mod(A_index,2) idx++ Return idx } Yaml_I2S(idx){ Loop % idx str .= " " Return str } Yaml_Continue(Obj,key,value,scalar="",isval=0){ If !IsObject(isObj:=obj[key]) v:=isObj If scalar { StringTrimLeft,scaopt,scalar,1 scalar:=Asc(scalar)=124?"`n":" " } else scalar:=" ",scaopt:="-" temp := (value=""?"`n":(SubStr(v,0)="`n"&&scalar="`n"?"":(v=""?"":scalar))) value (scaopt!="-"?(v&&value=""?"`n":""):"") obj[key]:=Yaml_UnQuoteIfNeed(v temp) } Yaml_Quote(ByRef L,F,Q,B,ByRef E){ Return (F="\"&&!E&&(E:=1))||(E&&!(E:=0)&&(L:=L ("\" F))) } Yaml_SeqMap(o,k,v,isVal=0){ v:=Trim(v,A_Tab A_Space "`n"),m:=SubStr(v,1,1) SubStr(v,0) If Yaml_IsSeqMap(v) return m="[]"?Yaml_Seq(o,k,SubStr(v,2,StrLen(v)-2),isVal):m="{}"?Yaml_Map(o,k,SubStr(v,2,StrLen(v)-2),isVal):0 } Yaml_Seq(obj,key,value,isVal=0){ static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}} ContinueNext:=0 If (obj=""){ If (SubStr(value,0)!="]") Return 0 else value:=SubStr(value,2,StrLen(value)-2) } else { If (key=""){ obj.Insert(Object("",cObj:=Object("base",base),"base",base)) } else if (isval && IsObject(obj[key,""])){ cObj:=obj[key,""] } else obj[key]:=Object("",cObj:=Object("base",base),"base",base) } Count:=StrLen(value) Loop,Parse,value { If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0)) Continue If (Quote){ If (A_LoopField=Quote){ Quote= If Bracket LF.= A_LoopField else LF:=SubStr(LF,2) Continue } LF .= A_LoopField continue } else if (!Quote&&InStr("""'",A_LoopField)){ Quote:=A_LoopField If !Bracket VQ:=Quote LF.=A_LoopField Continue } else if (!Quote&&Bracket){ If (Asc(A_LoopField)=Asc(Bracket)+2) BCount-- else if (A_LoopField=Bracket) BCount++ If (BCount=0) Bracket= LF .= A_LoopField Continue } else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){ Bracket:=A_LoopField BCount:=1 LF.=A_LoopField Continue } If (A_Index=Count) LF .= A_LoopField else if (!Quote&&!Bracket&&A_LoopField=","&&(!InStr("0123456789",SubStr(value,A_Index-1,1)) | !InStr("0123456789",SubStr(value,A_Index+1,1)))){ ContinueNext:=SubStr(value,A_Index+1,1)=A_Space||SubStr(value,A_Index+1,1)=A_Tab LF:=LF } else { LF .= A_LoopField continue } If (obj=""){ If !VQ If (Asc(LF)=91 && !Yaml_Seq("","",LF)) ||(Asc(LF)=123 && !Yaml_Map("","",LF)) Return 0 } else { If (VQ || !Yaml_SeqMap(cObj,"",LF)) cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF)) } LF:="",VQ:="" } If (LF){ If (obj=""){ If !VQ If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF)) Return 0 } else If (VQ || !Yaml_SeqMap(cObj,"",LF)) cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF)) } Return (obj=""?(Quote Bracket=""):1) } Yaml_Map(obj,key,value,isVal=0){ static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}} ContinueNext:=0 If (obj=""){ If (SubStr(value,0)!="}") Return 0 else value:=SubStr(value,2,StrLen(value)-2) } else { If (key="") obj.Insert(cObj:=Object("base",base)) else obj[key]:=(cObj:=Object("base",base)) } Count:=StrLen(value) Loop,Parse,value { If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0)) Continue If (Quote){ If (A_LoopField=Quote){ Quote= LF.=A_LoopField } else LF .= A_LoopField continue } else if (!Quote&&(k=""||v="")&&InStr("""'",A_LoopField)){ Quote:=A_LoopField If (k && !Bracket) VQ:=Quote else if !Bracket KQ:=Quote LF.=Quote Continue } else If (k!=""&&LF=""&&InStr("`n`r `t",A_LoopField)){ Continue } If (!Quote&&Bracket){ If (Asc(A_LoopField)=Asc(Bracket)+2) BCount-- else if (A_LoopField=Bracket) BCount++ If (BCount=0) Bracket= LF .= A_LoopField Continue } else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){ Bracket:=A_LoopField BCount=1 LF.=A_LoopField Continue } If (A_Index=Count&&k!=""){ v:=LF A_LoopField v:=Trim(v) If (InStr("""'",SubStr(v,0))&&SubStr(v,1,1)=SubStr(v,0)) v:=SubStr(v,2,StrLen(v)-2) } else If (!Quote&&!Bracket&&k!=""&&A_LoopField=","&&SubStr(value,A_Index+1,1)=A_Space){ ContinueNext:=1 LF:=Trim(LF) If VQ LF:=SubStr(LF,2,StrLen(LF)-2) v:=LF,LF:="" } else if (!Quote&&!Bracket&&k=""&&A_LoopField=":"){ LF:=Trim(LF) If (InStr("""'",SubStr(LF,0))&&SubStr(LF,1,1)=SubStr(LF,0)) LF:=SubStr(LF,2,StrLen(LF)-2) k:=LF,LF:="" continue } else { LF .= A_LoopField continue } If (obj=""){ If VQ= If (Asc(v)=91 && !Yaml_Seq("","",v)) ||(Asc(v)=123 && !Yaml_Map("","",v)) Return 0 } else { If (VQ || !Yaml_SeqMap(cObj,k,v)) cObj[KQ?Yaml_UniChar(k):k]:=(VQ?Yaml_UniChar(v):Trim(v)) } k:="",v:="",VQ:="",KQ:="" } If (k){ If (obj=""){ If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF)) Return 0 } else { LF:=Trim(LF) If (VQ) LF:=SubStr(LF,2,StrLen(LF)-2),cObj[k]:=Yaml_UniChar(LF) else If (!Yaml_SeqMap(cObj,k,LF)) cObj[k]:=Trim(LF) } } Return (obj=""?(Quote Bracket=""):1) } Yaml_Incomplete(value){ return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && !Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space))) || (Asc(Trim(value,"`n" A_Tab A_Space))=123 && !Yaml_Map("","",Trim(value,"`n" A_Tab A_Space))) } Yaml_IsSeqMap(value){ return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space))) || (Asc(Trim(value,"`n" A_Tab A_Space))=123 && Yaml_Map("","",Trim(value,"`n" A_Tab A_Space))) }
Yaml(YamlText,IsFile=1,YamlObj=0){ ; Version 1.0.0.17 http://www.autohotkey.com/forum/viewtopic.php?t=70559
  static
  static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
  static BackupVars:="LVL,SEQ,KEY,SCA,TYP,VAL,CMT,LFL,CNT",IncompleteSeqMap
  local maxLVL:=0,LastContObj:=0,LastContKEY:=0,LinesAdded:=0,_LVLChanged:=0,_LVL,_SEQ,_KEY,_SCA,_TYP,_VAL,_CMT,_LFL,_CNT,_NXT,__LVL,__SEQ,__KEY,__SCA,__TYP,__VAL,__CMT,__LFL,__CNT,__NXT
  AutoTrim % ((AutoTrim:=A_AutoTrim)="On")?"Off":"Off"
  LVL0:=pYaml:=YamlObj?YamlObj:Object("base",base),__LVL:=0,__LVL0:=0
  If IsFile
    FileRead,YamlText,%YamlText%
  Loop,Parse,YamlText,`n,`r
  {
    If (!_CNT && (A_LoopField=""||RegExMatch(A_LoopField,"^\s+$"))){ ;&&__KEY=""&&__SEQ="")){
      If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
        If (__KEY!="")
          Yaml_Continue(LastContObj:=LVL%__LVL%["",Obj],LastContKEY:=__key,"",__SCA)
        else Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=Obj,"",__SCA,__SEQ)
      } else If (__SEQ && OBJ){
        Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,__SEQ)
      } else If (OBJ){
        Yaml_Continue(LastContObj:=LVL%__LVL%[""],LastContKEY:=OBJ,"",__SCA,1)
      } else if (__KEY!="")
        Yaml_Continue(LastContObj:=LVL%__LVL%,LastContKEY:=__KEY,"",__SCA)
      else LinesAdded--
      LinesAdded++
      Continue
    } else If (!_CNT && LastContObj
    && ( RegExMatch(A_LoopField,"^(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)")
    || RegExMatch(A_LoopField,"^(---)|\s*(-\s)") )){
      If !__SCA
        LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded)
      LastContObj:=0,LastContKEY:=0,LinesAdded:=0
    }
    If InStr(A_LoopField,"#"){
      If (RegexMatch(A_LoopField,"^\s*#.*") || InStr(A_LoopField,"%YAML")=1) ;Comments only, do not parse
        continue
      else if Yaml_IsQuoted(LTrim(A_LoopField,"- ")) || RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+|'.+)$")&&!RegExMatch(A_LoopField,"[^\\]""\s+#")
        LoopField:=A_LoopField
      else if RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1)
        LoopField:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"\s+#.*$","",RegExMatch(A_LoopField,"(---)?\s*?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*([\|\>][+-]?)?\s*(!!\w+\s)?\s*("".+""|'.+')?\K")-1)-1)
      else LoopField:=A_LoopField
    } else LoopField:=A_LoopField
    If _CNT {
      If Yaml_IsSeqMap(RegExReplace(IncompleteSeqMap LoopField,"^(\s+)?(-\s)?("".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?"))
        LoopField:=IncompleteSeqMap LoopField,_CNT:=0,IncompleteSeqMap:=""
      else {
        IncompleteSeqMap.=LoopField
        continue
      }
    }
    If (LoopField="---"){
      Loop % (maxLVL)
        LVL%A_Index%:=""
      Loop,Parse,BackupVars,`,
        __%A_LoopField%:="",__%A_LoopField%0:=""
      Loop,Parse,BackupVars,`,
        Loop % maxLVL
        __%A_LoopField%%A_Index%:=""
      maxLVL:=0
      __LVL:=0,__LVL0:=0
      If !IsObject(pYaml[""])
        pYaml[""]:=LVL0:=Object("base",base)
      pYaml[""].Insert(LVL0:=Object("base",base))
      Continue
    } else if (LoopField="..."){
      LVL0:=pYaml
      Loop % maxLVL
        LVL%A_Index%:=""
      Loop,Parse,BackupVars,`,
        __%A_LoopField%:="",__%A_LoopField%0:=""
      Loop,Parse,BackupVars,`,
        Loop % maxLVL
        __%A_LoopField%%A_Index%:=""
      maxLVL:=0
      __LVL:=0,__LVL0:=0
      Continue
    }
    If (SubStr(LoopField,0)=":")
      LoopField.=A_Space ; add space to force RegEx to match even if the value and space after collon is missing e.g. Object:`n  objects item
    RegExMatch(LoopField,"S)^(?<LVL>\s+)?(?<SEQ>-\s)?(?<KEY>"".+""\s*:\s|'.+'\s*:\s|[^:""'\{\[]+\s*:\s)?\s*(?<SCA>[\|\>][+-]?)?\s*(?<TYP>!!\w+\s)?\s*(?<VAL>"".+""|'.+'|.+)?\s*$",_)
    If _KEY ;cut off (:)
     StringTrimRight,_KEY,_KEY,2
    _KEY:=Yaml_UnQuoteIfNeed(_KEY)
    If IsVal:=Yaml_IsQuoted(_VAL)
      _VAL:=Yaml_UnQuoteIfNeed(_VAL)
    ;determine current level
    _LVL:=Yaml_S2I(_LVL)
    If _LVL-__LVL>1||(_LVL>__LVL&&_LVLChanged) ;&&!(__SEQ&&__KEY!=""&&_KEY!="")) ; (__SEQ?2:1)
    {
      Loop % (_LVLChanged?_LVL-_LVLChanged:_LVL-__LVL-1)
        LoopField:=SubStr(LoopField,SubStr(LoopField,1,1)=A_Tab?1:2)
      _LVL:=_LVLChanged?_LVLChanged:__LVL+1,_LVLChanged:=_LVLChanged?_LVLChanged:_LVL ;__LVL%_LVL%:=__LVL%_NXT% ; (__SEQ?2:1)
    } else if _LVLChanged
      _LVL:=_LVLChanged
    else _LVLChanged:=0
    If (maxLVL<_LVL)
      maxLVL:=_LVL+(_SEQ?1:0)
    ; Cut off the leading tabs/spaces conform _LVL
    SubStr:=0,Tabs:=0
    Loop,Parse,LoopField
      If (_LVL*2=SubStr || !SubStr:=SubStr+(A_LoopField=A_Tab?2:1)), Tabs:=Tabs+(A_LoopField=A_Tab?1:0)
        break
    _LFL:=SubStr(LoopField,SubStr-Tabs+1+(_SEQ?2:0))
    _LFL:=Yaml_UnQuoteIfNeed(_LFL)
    _NXT:=_LVL+1 ;next indentation level
    __NXT:=_NXT+1
    _PRV:=_LVL=0?0:_LVL-1
    Loop,Parse,BackupVars,`,
      __%A_LoopField%:=__%A_LoopField%%_PRV%
    If RegExMatch(_LFL,"^-\s*$"){
      _SEQ:="-",_KEY:="",_VAL:=""
    }
    If (!IsVal && !_CNT && (_CNT:=Yaml_Incomplete(Trim(_LFL))||Yaml_Incomplete(Trim(_VAL)))){
      IncompleteSeqMap:=LoopField
      continue
    }
    If (_LVL<__LVL){ ;Reset Objects and Backup vars
      Loop % (maxLVL)
        If (A_Index>_LVL){
          Loop,Parse,BackupVars,`,
            __%A_LoopField%%maxLVL%:=""
          LVL%A_Index%:="",maxLVL:=maxLVL-1
        }
      If (_LVL=0 && !__LVL:=__LVL0:=0)
        Loop,Parse,BackupVars,`,
          __%A_LoopField%:="",__%A_LoopField%0:=""
    }
    If (_SEQ&&_LVL>__LVL&&(__VAL!=""||__SCA))
      _SEQ:="",_KEY:="",_VAL:="",_LFL:="- " _LFL
    If (__CNT)||(_LVL>__LVL&&(__KEY!=""&&_KEY="")&&(__VAL!=""||__SCA))||(__SEQ&&__SCA)
      _KEY:="",_VAL:=""
    If (__CNT||(_LVL>__LVL&&(__KEY!=""||(__SEQ&&(__LFL||__SCA)&&!Yaml_IsSeqMap(__LFL)))&&!(_SEQ||_KEY!=""))){
      If ((OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
        If __KEY!=
          Yaml_Continue(LVL%__LVL%["",Obj],__key,_LFL,__SCA),__CNT:=Yaml_SeqMap(LVL%__LVL%["",OBJ],__KEY,LVL%__LVL%["",OBJ,__KEY])?"":__CNT
        else Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ),__CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT
      } else If (__SEQ && OBJ){
        Yaml_Continue(LVL%__LVL%[""],Obj,_LFL,__SCA,__SEQ)
        __CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],__SEQ)?"":__CNT
      } else If (OBJ && __KEY=""){
        Yaml_Continue(LVL%__LVL%[""],OBJ,_LFL,__SCA,1)
        __CNT:=Yaml_SeqMap(LVL%__LVL%[""],OBJ,LVL%__LVL%["",OBJ],1)?"":__CNT
      } else {
        Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA)
        __CNT:=Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY])?"":__CNT
      }
      Continue
    }
    ;Create sequence or map
    If (__SEQ&&(_LVL>__LVL)&&_KEY!=""&&__KEY!=""){
      OBJ:=LVL%__LVL%[""].MaxIndex()
      If _SEQ {
          If !Yaml_SeqMap(LVL%_LVL%["",OBJ,__KEY,""],_KEY,_VAL){
            If !IsObject(LVL%__LVL%["",OBJ,__KEY,""])
              LVL%__LVL%["",OBJ,__KEY,""]:={base:base}
            LVL%__LVL%["",OBJ,__KEY,""].Insert({(_KEY):_VAL!=""?_VAL:(LVL%_NXT%:={base:base}),base:base})
          }
      } else If !Yaml_SeqMap(LVL%_LVL%["",OBJ],_KEY,_VAL){
        LVL%__LVL%["",OBJ,_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:={base:base})
      }
      If _VAL!=
        continue
    } else If (_SEQ){
      If !IsObject(LVL%_LVL%[""])
        LVL%_LVL%[""]:=Object("base",base)
      While (SubStr(_LFL,1,2)="- "){
        _LFL:=SubStr(_LFL,3),_KEY:=(_KEY!="")?_LFL:=SubStr(_KEY,3):_KEY,LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("",Object("base",base),"base",base)),_LVL:=_LVL+1,_NXT:=_NXT+1,__NXT:=_NXT+1,_PRV:=_LVL-1,maxLVL:=(maxLVL<_LVL)?_LVL:maxLVL
        Loop,Parse,BackupVars,`,
          __%A_LoopField%:=_%A_LoopField%
          ,__%A_LoopField%%_PRV%:=_%A_LoopField%
      }
      If (_KEY="" && _VAL="" && !IsVal){
        If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)
          LVL%_LVL%[""].Insert(LVL%_NXT%:=Object("base",base))
      } else If (_KEY!="") {
        LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,LVL%_NXT%:=Object("base",base),"base",base))
        If !Yaml_SeqMap(LVL%__NXT%,_KEY,_VAL){
          LVL%_LVL%[""].Remove()
          LVL%_LVL%[""].Insert(LVL%__NXT%:=Object(_KEY,(_VAL!=""||IsVal)?_VAL:LVL%_NXT%:=Object("base",base),"base",base))
        }
      } else {
        If !Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)
          LVL%_LVL%[""].Insert(_LFL)
      }
      If !LVL%_LVL%[""].MaxIndex()
        LVL%_LVL%.Remove("")
    } else if (_KEY!=""){
      If (__SEQ && _LVL>__LVL) {
        If (OBJ:=LVL%_PRV%[""].MaxIndex())&&IsObject(LVL%_PRV%["",OBJ]){
          If !Yaml_SeqMap(LVL%_PRV%["",OBJ],_KEY,_VAL)
            LVL%_PRV%["",OBJ,_KEY]:=(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base))
        } else {
          LVL%_PRV%[""].Insert(Object(_KEY,(_VAL!=""||IsVal)?_VAL:(LVL%_NXT%:=Object("base",base)),"base",base))
          Yaml_SeqMap(LVL%_PRV%["",OBJ?OBJ+1:1],_KEY,_VAL)
        }
      } else
        If !Yaml_SeqMap(LVL%_LVL%,_KEY,_VAL)
          LVL%_LVL%[_KEY]:=_VAL!=""?_VAL:(LVL%_NXT%:=Object("base",base))
    } else if (_LVL>__LVL && (__KEY!="")) {
      If (__VAL!="" || __SCA){
        Yaml_Continue(LVL%__LVL%,__KEY,_LFL,__SCA)
        Yaml_SeqMap(LVL%__LVL%,__KEY,LVL%__LVL%[__KEY])
        Continue
      } else {
        If !Yaml_SeqMap(LVL%__LVL%[__KEY],_KEY,_VAL) ;!!! no Scalar???
          LVL%__LVL%[__KEY,_KEY]:=_VAL
          Continue
      }
    } else {
      If (_LVL>__LVL&&(OBJ:=LVL%__LVL%[""].MaxIndex())&&IsObject(LVL%__LVL%["",OBJ])&&__SEQ){
        If __CNT
          Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1)
        If (__CNT:=Yaml_SeqMap(LVL%__LVL%[""],"",_LFL)?"":1)
          LVL%__LVL%[""].Insert(_LFL) 
      } else {
        If !IsObject(LVL%_LVL%[""])
          LVL%_LVL%[""]:=Object("base",base)
        If __CNT
          Yaml_Continue(LVL%__LVL%[""],LVL%__LVL%[""].MaxIndex(),_LFL,__SCA,1)
        If (__CNT:=Yaml_SeqMap(LVL%_LVL%[""],"",_LFL)?"":1)
          LVL%_LVL%[""].Insert(_LFL)
      }
      Continue
    }
    Loop,Parse,BackupVars,`,
      __%A_LoopField%:=_%A_LoopField%
      ,__%A_LoopField%%_LVL%:=_%A_LoopField%
  }
  If (LastContObj && !__SCA)
      LastContObj[LastContKEY]:=SubStr(LastContObj[LastContKEY],1,-1*LinesAdded)
  AutoTrim %AutoTrim%
  Loop,Parse,BackupVars,`,
      If !(__%A_LoopField%:="")
        Loop % maxLVL
          __%A_LoopField%%A_Index%:=""
  Return pYaml,pYaml.base:=base
}
Yaml_Save(obj,file,level=""){
  FileMove,% file,% file ".bakupyml",1
  FileAppend,% obj.Dump(),% file
  If !ErrorLevel
    FileDelete,% file ".bakupyml"
  else {
    FileMove,% file ".bakupyml",% file
    MsgBox,0, Error creating file, old file was restored.
  }
}
Yaml_Call(NotSupported,f,p*){
  If (p.MaxIndex()>1){
    Loop % p.MaxIndex()
      If A_Index>1
        f:=f[""][p[A_Index-1]]
  }
  Return (!p.MaxIndex()?f[""].MaxIndex():f[""][p[p.MaxIndex()]])
}
Yaml_Merge(obj,merge){
  for k,v in merge
  {
    If IsObject(v){
      If obj.HasKey(k){
        If IsObject(obj[k])
          Yaml_Merge(obj[k],v)
        else obj[k]:=v
      } else obj[k]:=v
    } else obj[k]:=v
  }
}
Yaml_Add(O,Yaml="",IsFile=0){
  static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
  If Yaml_IsSeqMap(Trim(Yaml)){
    If !IsObject(O[""])
      O[""]:=Object("base",base)
    Yaml_SeqMap(O[""],"",Yaml)
  } else Yaml(Yaml,IsFile,O)
}
Yaml_Dump(O,J="",R=0,Q=0){
  static M1:="{",M2:="}",S1:="[",S2:="]",N:="`n",C:=", ",S:="- ",E:="",K:=": "
  local dump:="",M,MX,F,I,key,value
  If (J=0&&!R)
    dump.= S1
  for key in O
    M:=A_Index
  If IsObject(O[""]){
    M--
    for key in O[""]
      MX:=A_Index
    If IsObject(O[""][""])
      MX--
    If O[""].MaxIndex()
      for key, value in O[""]
      {
        If key=
          continue
        I++
        F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E
        If (J!=""&&J<=R){
          dump.=(F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value)) (I=MX&&!M?E:C) ;(Q="S"&&I=1?S1:E)(Q="S"&&I=MX?S2:E)
        } else if F,dump:=dump N Yaml_I2S(R) S
          dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E)
        else {
          ; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\[']|:\s|\s#")
            dump .= Yaml_EscIfNeed(value)
          ; else {
            ; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)=N?"":"-") "`n$1"),"ms)(*ANYCRLF)\R",N Yaml_I2S(R+1)))
            ; StringReplace,value,value,% N Yaml_I2S(R+1) N Yaml_I2S(R+1),% N Yaml_I2S(R+1),A
            ; dump.=value
          ; }
        }
      }
  }
  I=0
  for key, value in O
  {
    If key=
      continue
    I++
    F:=IsObject(value)?(IsObject(value[""])?"S":"M"):E
    If (J=0&&!R)
      dump.= M1
    If (J!=""&&J<=R){
      dump.=(Q="S"&&I=1?M1:E) Yaml_EscIfNeed(key) K
      dump.=F?(%F%1 Yaml_Dump(value,J,R+1,F) %F%2):Yaml_EscIfNeed(value)
      dump.=(Q="S"&&I=M?M2:E) (J!=0||R?(I=M?E:C):E)
    } else if F,dump:=dump N Yaml_I2S(R) Yaml_EscIfNeed(key) K
      dump.= (J!=""&&J<=(R+1)?%F%1:E) Yaml_Dump(value,J,R+1,F) (J!=""&&J<=(R+1)?%F%2:E)
    else {
      ; If RegexMatch(value,"[\x{007F}-\x{FFFF}""\{\['\t]|:\s|\s#")
        dump .= Yaml_EscIfNeed(value)
      ; else {
        ; value:= (value=""?"''":RegExReplace(RegExReplace(Value,"m)^(.*[\r\n].*)$","|" (SubStr(value,-1)="`n`n"?"+":SubStr(value,0)="`n"?"":"-") "`n$1"),"ms)(*ANYCRLF)\R","`n" Yaml_I2S(R+1)))
        ; StringReplace,value,value,% "`n" Yaml_I2S(R+1) "`n" Yaml_I2S(R+1),% "`n" Yaml_I2S(R+1),A
        ; dump.= value
      ; }
    }
    If (J=0&&!R){
      dump.=M2 (I<M?C:E)
    }
  }
  If (J=0&&!R)
    dump.=S2
  If (R=0)
    dump:=RegExReplace(dump,"^\R+")
  Return dump
}
Yaml_UniChar( string ) {
  static a:="`a",b:="`b",t:="`t",n:="`n",v:="`v",f:="`f",r:="`r",e:=Chr(0x1B)
  Loop,Parse,string,\
  {
    If (A_Index=1){
      var.=A_LoopField
      continue
    } else If lastempty {
      var.="\" A_LoopField
      lastempty:=0
      Continue
    } else if (A_LoopField=""){
      lastempty:=1
      Continue
    }
    If InStr("ux",SubStr(A_LoopField,1,1))
      str:=SubStr(A_LoopField,1,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K")-1)
    else
      str:=SubStr(A_LoopField,1,1)
    If (str=="N")
      str:="\x85"
    else if (str=="P")
      str:="\x2029"
    else if (str=0)
      str:="\x0"
    else if (str=="L")
      str:="\x2028"
    else if (str=="_")
      str:="\xA0"
    If RegexMatch(str,"i)^[ux][\da-f]+$")
      var.=Chr(Abs("0x" SubStr(str,2)))
    else If str in a,b,t,n,v,f,r,e
      var.=%str%
    else var.=str
    If InStr("ux",SubStr(A_LoopField,1,1))
      var.=SubStr(A_LoopField,RegExMatch(A_LoopField,"^[ux]?([\dA-F]{4})?([\dA-F]{2})?\K"))
    else var.=SubStr(A_LoopField,2)
  }
  return var
}
Yaml_CharUni( string ) {
  static ascii:={"\":"\","`a": "a","`b": "b","`t": "t","`n": "n","`v": "v","`f": "f","`r": "r",Chr(0x1B): "e","""": """",Chr(0x85): "N",Chr(0x2029): "P",Chr(0x2028): "L","": "0",Chr(0xA0): "_"}
  If !RegexMatch(string,"[\x{007F}-\x{FFFF}]"){
    Loop,Parse,string
    {
      If ascii[A_LoopField]
        var.="\" ascii[A_LoopField]
      else
        var.=A_LoopField
    }
    return var
  }
  format:=A_FormatInteger
  SetFormat,Integer,H
  Loop,Parse,string
  {
    If ascii[A_LoopField]
        var.="\" ascii[A_LoopField]
    else if Asc(A_LoopField)<128
      var.=A_LoopField
    else {
      str:=SubStr(Asc(A_LoopField),3)	
      var.="\u" (StrLen(str)<2?"000":StrLen(str)<3?"00":StrLen(str)<4?"0":"") str
    }
  }
  SetFormat,Integer,%Format%
  return var
}
Yaml_EscIfNeed(s){
  If (s="")
    return "''"
  else If RegExMatch(s,"m)[\{\[""'\r\n]|:\s|,\s|\s#")||RegExMatch(s,"^[\s#\\\-:>]")||RegExMatch(s,"m)\s$")||RegExMatch(s,"m)[\x{7F}-\x{7FFFFFFF}]")
    return ("""" . Yaml_CharUni(s) . """")
  else return s
}
Yaml_IsQuoted(ByRef s){
  return InStr(".''."""".","." SubStr(Trim(s),1,1) SubStr(Trim(s),0) ".")?1:0
}
Yaml_UnQuoteIfNeed(s){
  s:=Trim(s)
  If !(SubStr(s,1,1)=""""&&SubStr(s,0)="""")
    return (SubStr(s,1,1)="'"&&SubStr(s,0)="'")?SubStr(s,2,StrLen(s)-2):s
  else return Yaml_UniChar(SubStr(s,2,StrLen(s)-2))
}
Yaml_S2I(str){
  local idx:=0
  Loop,Parse,str
    If (A_LoopField=A_Tab)
      idx++
    else if !Mod(A_index,2)
      idx++
  Return idx
}
Yaml_I2S(idx){
  Loop % idx
    str .= "  "
  Return str
}
Yaml_Continue(Obj,key,value,scalar="",isval=0){
  If !IsObject(isObj:=obj[key])
    v:=isObj
  If scalar {
    StringTrimLeft,scaopt,scalar,1
    scalar:=Asc(scalar)=124?"`n":" "
  } else scalar:=" ",scaopt:="-"
  temp := (value=""?"`n":(SubStr(v,0)="`n"&&scalar="`n"?"":(v=""?"":scalar))) value (scaopt!="-"?(v&&value=""?"`n":""):"")
  obj[key]:=Yaml_UnQuoteIfNeed(v temp)
}
Yaml_Quote(ByRef L,F,Q,B,ByRef E){
  Return (F="\"&&!E&&(E:=1))||(E&&!(E:=0)&&(L:=L ("\" F)))
}
Yaml_SeqMap(o,k,v,isVal=0){
  v:=Trim(v,A_Tab A_Space "`n"),m:=SubStr(v,1,1) SubStr(v,0)
  If Yaml_IsSeqMap(v)
    return m="[]"?Yaml_Seq(o,k,SubStr(v,2,StrLen(v)-2),isVal):m="{}"?Yaml_Map(o,k,SubStr(v,2,StrLen(v)-2),isVal):0
}
Yaml_Seq(obj,key,value,isVal=0){
  static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
  ContinueNext:=0
  If (obj=""){
    If (SubStr(value,0)!="]")
      Return 0
    else
      value:=SubStr(value,2,StrLen(value)-2)
  } else {
    If (key=""){
      obj.Insert(Object("",cObj:=Object("base",base),"base",base))
    } else if (isval && IsObject(obj[key,""])){
        cObj:=obj[key,""]
    } else obj[key]:=Object("",cObj:=Object("base",base),"base",base)
  }
  Count:=StrLen(value)
  Loop,Parse,value
  {
    If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0))
      Continue
    If (Quote){
      If (A_LoopField=Quote){
        Quote=
        If Bracket
          LF.= A_LoopField
        else LF:=SubStr(LF,2)
        Continue
      }
      LF .= A_LoopField
      continue
    } else if (!Quote&&InStr("""'",A_LoopField)){
      Quote:=A_LoopField
      If !Bracket
        VQ:=Quote
      LF.=A_LoopField
      Continue
    } else if (!Quote&&Bracket){
      If (Asc(A_LoopField)=Asc(Bracket)+2)
        BCount--
      else if (A_LoopField=Bracket)
        BCount++
      If (BCount=0)
        Bracket=
      LF .= A_LoopField
      Continue
    } else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){
      Bracket:=A_LoopField
      BCount:=1
      LF.=A_LoopField
      Continue
    }
    If (A_Index=Count)
      LF .= A_LoopField
    else if (!Quote&&!Bracket&&A_LoopField=","&&(!InStr("0123456789",SubStr(value,A_Index-1,1)) | !InStr("0123456789",SubStr(value,A_Index+1,1)))){
      ContinueNext:=SubStr(value,A_Index+1,1)=A_Space||SubStr(value,A_Index+1,1)=A_Tab
      LF:=LF
    } else {
      LF .= A_LoopField
      continue
    }
    If (obj=""){
      If !VQ
        If (Asc(LF)=91 && !Yaml_Seq("","",LF))
          ||(Asc(LF)=123 && !Yaml_Map("","",LF))
          Return 0
    } else {
      If (VQ || !Yaml_SeqMap(cObj,"",LF))
        cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF))
    }
    LF:="",VQ:=""
  }
  If (LF){
    If (obj=""){
      If !VQ
        If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF))
          Return 0
    } else If (VQ || !Yaml_SeqMap(cObj,"",LF))
      cObj.Insert(VQ?Yaml_UniChar(LF):Trim(LF))
  }
  Return (obj=""?(Quote Bracket=""):1)
}
Yaml_Map(obj,key,value,isVal=0){
  static base:={Dump:"Yaml_Dump",Save:"Yaml_Save",Add:"Yaml_Add",Merge:"Yaml_Merge",__Delete:"__Delete",_Insert:"_Insert",_Remove:"_Remove",_GetCapacity:"_GetCapacity",_SetCapacity:"_SetCapacity",_GetAddress:"_GetAddress",_MaxIndex:"_MaxIndex",_MinIndex:"_MinIndex",_NewEnum:"_NewEnum",_HasKey:"_HasKey",_Clone:"_Clone",Insert:"Insert",Remove:"Remove",GetCapacity:"GetCapacity",SetCapacity:"SetCapacity",GetAddress:"GetAddress",MaxIndex:"MaxIndex",MinIndex:"MinIndex",NewEnum:"NewEnum",HasKey:"HasKey",Clone:"Clone",base:{__Call:"Yaml_Call"}}
  ContinueNext:=0
  If (obj=""){
    If (SubStr(value,0)!="}")
      Return 0
    else
      value:=SubStr(value,2,StrLen(value)-2)
  } else {
    If (key="")
      obj.Insert(cObj:=Object("base",base))
    else obj[key]:=(cObj:=Object("base",base))
  }
  Count:=StrLen(value)
  Loop,Parse,value
  {

    If ((Quote=""""&&Yaml_Quote(LF,A_LoopField,Quote,Bracket,Escape)) || (ContinueNext && !ContinueNext:=0))
      Continue
    If (Quote){
      If (A_LoopField=Quote){
        Quote=
        LF.=A_LoopField
      } else LF .= A_LoopField
      continue
    } else if (!Quote&&(k=""||v="")&&InStr("""'",A_LoopField)){
      Quote:=A_LoopField
      If (k && !Bracket)
        VQ:=Quote
      else if !Bracket
        KQ:=Quote
      LF.=Quote
      Continue
    } else If (k!=""&&LF=""&&InStr("`n`r `t",A_LoopField)){
      Continue
    }
    If (!Quote&&Bracket){
      If (Asc(A_LoopField)=Asc(Bracket)+2)
        BCount--
      else if (A_LoopField=Bracket)
        BCount++
      If (BCount=0)
        Bracket=
      LF .= A_LoopField
      Continue
    } else if (!Quote&&!Bracket&&InStr("[{",A_LoopField)){
      Bracket:=A_LoopField
      BCount=1
      LF.=A_LoopField
      Continue
    }
    If (A_Index=Count&&k!=""){
      v:=LF A_LoopField
      v:=Trim(v)
      If (InStr("""'",SubStr(v,0))&&SubStr(v,1,1)=SubStr(v,0))
        v:=SubStr(v,2,StrLen(v)-2)
    } else If (!Quote&&!Bracket&&k!=""&&A_LoopField=","&&SubStr(value,A_Index+1,1)=A_Space){
      ContinueNext:=1
      LF:=Trim(LF)
      If VQ
        LF:=SubStr(LF,2,StrLen(LF)-2)
      v:=LF,LF:=""
    } else if (!Quote&&!Bracket&&k=""&&A_LoopField=":"){
      LF:=Trim(LF)
      If (InStr("""'",SubStr(LF,0))&&SubStr(LF,1,1)=SubStr(LF,0))
        LF:=SubStr(LF,2,StrLen(LF)-2)
      k:=LF,LF:=""
      continue
    } else {
      LF .= A_LoopField
      continue
    }
    If (obj=""){
      If VQ=
        If (Asc(v)=91 && !Yaml_Seq("","",v))
          ||(Asc(v)=123 && !Yaml_Map("","",v))
          Return 0
    } else {
      If (VQ || !Yaml_SeqMap(cObj,k,v))
        cObj[KQ?Yaml_UniChar(k):k]:=(VQ?Yaml_UniChar(v):Trim(v))
    }
    k:="",v:="",VQ:="",KQ:=""
  }
  If (k){
    If (obj=""){
      If (Asc(LF)=91 && !Yaml_Seq("","",LF))||(Asc(LF)=123 && !Yaml_Map("","",LF))
        Return 0
    } else {
      LF:=Trim(LF)
      If (VQ)
        LF:=SubStr(LF,2,StrLen(LF)-2),cObj[k]:=Yaml_UniChar(LF)
      else If (!Yaml_SeqMap(cObj,k,LF))
        cObj[k]:=Trim(LF)
    }
  }
  Return (obj=""?(Quote Bracket=""):1)
}
Yaml_Incomplete(value){
  return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && !Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space)))
      || (Asc(Trim(value,"`n" A_Tab A_Space))=123 && !Yaml_Map("","",Trim(value,"`n" A_Tab A_Space)))
}
Yaml_IsSeqMap(value){
  return (Asc(Trim(value,"`n" A_Tab A_Space))=91 && Yaml_Seq("","",Trim(value,"`n" A_Tab A_Space)))
      || (Asc(Trim(value,"`n" A_Tab A_Space))=123 && Yaml_Map("","",Trim(value,"`n" A_Tab A_Space)))
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。