diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index b0bf010..a65f29a 100644 Binary files a/doc/doctrees/environment.pickle and b/doc/doctrees/environment.pickle differ diff --git a/doc/doctrees/tutorials/custom_types.doctree b/doc/doctrees/tutorials/custom_types.doctree index 5f0a456..46a4fd0 100644 Binary files a/doc/doctrees/tutorials/custom_types.doctree and b/doc/doctrees/tutorials/custom_types.doctree differ diff --git a/doc/html/_sources/tutorials/custom_types.txt b/doc/html/_sources/tutorials/custom_types.txt index 7137f07..da62c91 100644 --- a/doc/html/_sources/tutorials/custom_types.txt +++ b/doc/html/_sources/tutorials/custom_types.txt @@ -20,8 +20,9 @@ Constructor D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process each node to hold data type corresponding to its tag. *Constructor* stores a function for each supported tag to process it. These functions are supplied by -the user using the *addConstructor()* method. *Constructor* is then passed to -*Loader*, which parses YAML input. +the user using the *addConstructorXXX()* methods, where *XXX* is *Scalar*, +*Sequence* or *Mapping*. *Constructor* is then passed to *Loader*, which parses +YAML input. Struct types have no specific requirements for YAML support. Class types should define the *opEquals()* operator, as this is used in equality comparisons of @@ -41,17 +42,20 @@ following struct: } First, we need a function to construct our data type. It must take two *Mark* -structs, which store position of the node in the file, and either a *string*, an -array of *Node* or of *Node.Pair*, depending on whether we're constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions: +structs, which store position of the node in the file, and a reference to *Node* +to construct from. The node is guaranteed to contain either a *string*, an array +of *Node* or of *Node.Pair*, depending on whether we're constructing our value +from a scalar, sequence, or mapping, respectively. In this tutorial, we have +functions to construct a color from a scalar, using CSS-like format, RRGGBB, or +from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code +of these functions: .. code-block:: d - Color constructColorScalar(Mark start, Mark end, string value) + Color constructColorScalar(Mark start, Mark end, ref Node node) { + string value = node.get!string; + if(value.length != 6) { throw new ConstructorException("Invalid color: " ~ value, start, end); @@ -82,30 +86,21 @@ RRGGBB, or from a mapping, where we use the following format: return result; } - Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) + Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) + //Might throw if a value is missing or is not an integer. + try { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; } if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) @@ -146,8 +141,8 @@ Finally, the code to put it all together: { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; @@ -284,7 +279,7 @@ With the following code, we will add support for dumping the our Color type. } First we get the *Color* from the node. Then we convert it to a string with the -HTML-like format we've used before. Finally, we use the *representScalar()* +CSS-like format we've used before. Finally, we use the *representScalar()* method of *Representer* to get a scalar node ready for output. There are corresponding *representMapping()* and *representSequence()* methods as well, with examples in the diff --git a/doc/html/api/dyaml.constructor.html b/doc/html/api/dyaml.constructor.html index 697ca19..27b96d6 100644 --- a/doc/html/api/dyaml.constructor.html +++ b/doc/html/api/dyaml.constructor.html @@ -94,14 +94,15 @@ -
void addConstructor(T, U)(in string tag, T function(Mark, Mark, U) ctor); +
void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor);
-

Add a constructor function. +

Add a constructor function from scalar.

-

The function passed must two Marks (determining start and end positions of - the node in file) and either a string (if constructing from scalar), - an array of Nodes (from sequence) or an array of Node.Pair (from mapping). - The value returned by this function will be stored in the resulring node. +

The function must take two Marks (start and end positions of + the node in file) and a reference to Node to construct from. + The node contains a string for scalars, Node[] for sequences and + Node.Pair[] for mappings. + The value returned by this function will be stored in the resulting node.
Only one constructor function can be set for one tag. @@ -113,47 +114,61 @@ Constructor function. +

+
void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor); +
+

Add a constructor function from sequence. +

+See Also:
addConstructorScalar
+ +
+
void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor); +
+

Add a constructor function from a mapping. +

+See Also:
addConstructorScalar
+
-
YAMLNull constructNull(Mark start, Mark end, string value); +
YAMLNull constructNull(Mark start, Mark end, ref Node node);
-

Construct a null node.

+

Construct a null node.

-
YAMLMerge constructMerge(Mark start, Mark end, string value); +
YAMLMerge constructMerge(Mark start, Mark end, ref Node node);
-

Construct a merge node - a node that merges another node into a mapping.

+

Construct a merge node - a node that merges another node into a mapping.

-
bool constructBool(Mark start, Mark end, string value); +
bool constructBool(Mark start, Mark end, ref Node node);
-

Construct a boolean node.

+

Construct a boolean node.

-
long constructLong(Mark start, Mark end, string value); +
long constructLong(Mark start, Mark end, ref Node node);
-

Construct an integer (long) node.

+

Construct an integer (long) node.

-
real constructReal(Mark start, Mark end, string value); +
real constructReal(Mark start, Mark end, ref Node node);
-

Construct a floating point (real) node.

+

Construct a floating point (real) node.

-
ubyte[] constructBinary(Mark start, Mark end, string value); +
ubyte[] constructBinary(Mark start, Mark end, ref Node node);
-

Construct a binary (base64) node.

+

Construct a binary (base64) node.

-
SysTime constructTimestamp(Mark start, Mark end, string value); +
SysTime constructTimestamp(Mark start, Mark end, ref Node node);
-

Construct a timestamp (SysTime) node.

+

Construct a timestamp (SysTime) node.

-
string constructString(Mark start, Mark end, string value); +
string constructString(Mark start, Mark end, ref Node node);
-

Construct a string node.

+

Construct a string node.

Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes); @@ -161,29 +176,29 @@

Convert a sequence of single-element mappings into a sequence of pairs.

-
Pair[] constructOrderedMap(Mark start, Mark end, Node[] nodes); +
Pair[] constructOrderedMap(Mark start, Mark end, ref Node node);
-

Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.

+

Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.

-
Pair[] constructPairs(Mark start, Mark end, Node[] nodes); +
Pair[] constructPairs(Mark start, Mark end, ref Node node);
-

Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.

+

Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.

-
Node[] constructSet(Mark start, Mark end, Pair[] pairs); +
Node[] constructSet(Mark start, Mark end, ref Node node);
-

Construct a set node.

+

Construct a set node.

-
Node[] constructSequence(Mark start, Mark end, Node[] nodes); +
Node[] constructSequence(Mark start, Mark end, ref Node node);
-

Construct a sequence (array) node.

+

Construct a sequence (array) node.

-
Pair[] constructMap(Mark start, Mark end, Pair[] pairs); +
Pair[] constructMap(Mark start, Mark end, ref Node node);
-

Construct an unordered map (unordered set of key: value pairs without duplicates) node.

+

Construct an unordered map (unordered set of key: value pairs without duplicates) node.

diff --git a/doc/html/articles/spec_differences.html b/doc/html/articles/spec_differences.html index e0b8e1f..dd6c7fb 100644 --- a/doc/html/articles/spec_differences.html +++ b/doc/html/articles/spec_differences.html @@ -138,7 +138,7 @@ struct appears in Phobos.

diff --git a/doc/html/index.html b/doc/html/index.html index 4e17f43..b18e041 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -104,7 +104,7 @@ diff --git a/doc/html/search.html b/doc/html/search.html index af67bf2..15d9548 100644 --- a/doc/html/search.html +++ b/doc/html/search.html @@ -87,7 +87,7 @@ diff --git a/doc/html/searchindex.js b/doc/html/searchindex.js index 5059339..c856169 100644 --- a/doc/html/searchindex.js +++ b/doc/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({objects:{},terms:{represent:[2,3],all:[1,3,4],code:[0,1,3,4],representmap:3,scalar:[0,1,2,3,4],follow:[3,4],decid:3,depend:[0,3],show:[0,3],readabl:0,specif:[0,1,3,2],representsequ:3,program:4,digit:[3,4],sourc:[3,4],everi:3,string:[0,3,4],powervr:0,"void":[3,4],phobo:1,ident:3,failur:3,yamlexcept:[3,4],implicitli:[0,3],implement:[1,3],tri:1,gender:0,list:[0,1,2],iter:4,"try":[3,4],item:0,refer:[0,3],slower:0,past:4,fold:0,second:[0,4],design:0,pass:3,download:4,rrr:3,even:[1,4],index:[3,4],what:3,appear:1,compar:3,cast:3,preserv:[0,4],section:3,current:4,version:4,"new":3,method:[3,4],complex:[0,3],dyaml:[1,4],never:1,here:4,ggg:3,ldyaml:4,path:4,modifi:4,sinc:3,valu:[0,1,3,4],convert:[0,3,4],male:0,loos:1,datetim:0,omap:0,chang:[0,1,3],commonli:4,modul:4,unix:4,subnod:4,instal:4,articl:[0,2],regex:3,from:3,would:[3,4],doubl:0,two:[0,1,3],next:[3,4],few:1,call:[3,4],msg:3,type:[0,1,2,3,4],tell:4,more:[0,4],phone:0,known:[1,2,4],hold:3,must:[3,4],addrepresent:3,word:4,alia:[0,1],work:1,itself:3,can:[0,1,3,4],learn:4,purpos:3,root:[3,4],overrid:3,want:3,stream:[0,1],give:4,process:3,templat:3,topic:3,tag:[0,1,3,2],tab:1,serial:[0,3],cours:3,multipl:[0,1],newlin:0,quot:[0,1],getting_start:4,how:[3,4],foreach:[3,4],answer:[0,4],instead:0,simpl:[0,3,4],map:[0,1,2,3,4],mar:4,clone:0,variant:1,befor:3,ff0000:3,uint:3,mai:1,end:[0,1,3],data:[0,1,2,3,4],welcom:[2,4],ani:[0,3,4],stdio:4,explicit:[0,3],correspond:3,ambigu:1,caus:1,inform:[0,4],"switch":3,green:[0,3],allow:[0,1,4],first:[0,2,3,4],order:[1,4],over:4,move:4,orang:3,becaus:1,veri:1,hierarchi:0,still:[0,1],paramet:3,write:4,style:[0,4],precondit:3,yaml:[0,1,2,3,4],window:4,html:3,main:[3,4],might:[0,1,3,4],easier:0,them:[0,1,3,4],"float":[0,3],"return":[3,4],thei:[0,1,3,4],python:0,auto:3,"break":3,now:[1,3,4],introduct:[0,4],name:[0,3],separ:0,each:[0,3],found:[3,4],went:3,complet:3,mean:[1,3],compil:[3,4],unequ:[1,3],idea:4,"static":3,expect:[3,4],our:[3,4],extract:4,out:0,space:0,content:[1,3,4],rel:4,"0123456789abcdefabcdef":3,ref:3,red:[0,3],difficulti:1,advanc:0,"0123456789abcdef":3,base:[0,3],dictionari:0,put:[3,4],org:[1,3],"byte":1,thrown:4,pyyaml:[0,1],indent:[0,1],could:[3,4],keep:4,length:3,yamlcoloninflowcontext:1,confus:1,assign:0,radeon:0,oper:[0,3,4],onc:[0,1],arrai:[0,1,3,4],restrict:1,unlik:0,alreadi:[3,4],done:3,stabl:4,size:0,differ:[1,2,3,4],dump:[3,4],script:4,associ:[0,1,4],addimplicitresolv:3,system:[0,4],construct:[0,3],gpu:0,white:3,conveni:0,"final":[3,4],store:[0,3],adher:1,consol:4,option:[0,4],especi:0,ishexdigit:3,specifi:[0,3,4],pars:[0,3,4],somewhat:0,exactli:4,than:1,serv:4,remov:0,structur:[0,1],charact:[0,1,3],project:[2,4],str:[0,3],were:3,posit:3,argument:3,packag:[3,4],have:[0,3,4],tabl:0,need:[0,1,3,4],"null":0,lib:4,alias:[0,1,2],constructcolormap:3,note:[3,4],also:[0,3,4],read:[0,3,4],take:3,which:[0,1,3],brace:0,channel:3,uppercas:3,blue:[0,3],begin:[0,1],normal:4,previou:3,most:[0,3,4],regular:3,pair:[0,3],"class":[1,3],opequ:3,don:[1,3,4],later:3,flow:[0,1],doe:[0,1,4],bracket:0,cortex:0,fact:0,ldc:4,cdc:4,alphanumer:1,syntax:[0,2],identifi:[0,3],find:[3,4],onli:[3,4],explicitli:[0,3],just:[3,4],explain:4,should:[1,3,4],meant:4,std:[3,4],get:[2,3,4],express:3,cannot:[1,4],report:3,requir:3,whether:3,common:0,contain:[0,1,3,4],where:[0,3,4],wiki:1,set:[0,2,3,4],seq:0,see:[0,1,3],rgb:3,result:3,fail:1,close:1,athlon:0,representscalar:3,wikipedia:0,written:4,between:[0,1,2],"import":4,altern:3,accord:1,kei:[0,1,3,4],both:3,last:0,howev:[0,3],equal:3,comment:[0,4],etc:3,tutori:[2,3,4],context:[0,1],load:[1,3,4],bool:[0,3],color:[0,3],hyphen:0,loader:[3,4],colon:0,addconstructor:3,suppli:3,respect:3,bbb:3,empti:0,implicit:[0,3],json:0,basic:4,resolut:[0,3],anywher:0,assert:3,togeth:3,input:[3,4],"catch":3,"case":3,multi:0,therefor:[1,3],look:4,plain:[0,1,3],ffff00:3,defin:[0,3],ain:0,error:[3,4],anchor:[0,1,2],readi:3,non:[0,3],archiv:4,tediou:3,ascii:[1,3],dumper:[3,4],disabl:3,clearli:1,same:[0,1,3,4],check:[3,4],member:3,binari:0,instanc:[1,3,4],timestamp:0,android:0,document:[0,1,2,3,4],difficult:0,http:1,nest:0,user:[0,3],nodeexcept:3,markup:0,well:3,constructorexcept:3,person:0,exampl:[3,4],command:4,thi:[0,1,3,4],everyth:3,left:0,explan:4,systim:0,newest:4,execut:4,less:1,paragraph:0,gdc:4,human:0,yet:4,languag:[0,4],struct:[1,3,4],libdyaml:4,interptet:1,except:4,constructcolorscalar:3,add:[3,4],other:[1,4],els:0,match:3,build:4,real:0,format:[0,3,4],handl:[1,3],know:3,world:4,recurs:[0,1],tolow:3,like:3,success:3,arbitrari:3,resolv:[0,2,3],integ:[0,3,4],arthur:0,api:[2,3,4],singl:[0,1],output:[3,4],unnecessari:1,right:1,often:3,linux:[0,4],some:[0,1,3,4],guarante:3,ubyt:[0,3],librari:4,representcolor:3,lead:1,though:4,unord:1,condit:3,either:[0,3,4],object:3,run:4,acronym:0,usag:4,immut:3,unicod:1,chapter:0,comparison:3,about:[1,4],rare:1,usedefaultrepresent:3,page:0,constructor:[2,3],fals:3,produc:4,block:0,subset:0,within:1,encod:1,automat:4,bsd:0,mark:[0,1,3],your:[2,3,4],wai:[1,3],support:[0,1,3],question:0,"long":0,custom:[0,2,3],writeln:[3,4],start:[0,2,3,4],"function":3,form:3,continu:0,link:4,line:0,"true":3,conclus:4,"throw":[3,4],dmd:4,consist:0,possibl:[0,1,3,4],"default":[0,3],displai:4,until:0,directori:[3,4],problem:1,similar:[0,4],featur:[0,1],creat:[0,3,4],"int":[0,3,4],cover:4,dure:3,parser:[0,4],doesn:4,repres:[0,3,4],"char":3,exist:4,file:[1,3,4],yamlnul:0,isdigit:3,dent:0,simplest:4,probabl:0,hex:3,when:[3,4],detail:[0,1],invalid:3,valid:1,rrggbb:3,futur:[0,1],test:3,you:[0,3,4],node:[0,3,4],xxx:4,sequenc:[0,2,3,4],consid:[1,3],debian:0,reduc:0,longer:3,home:4,rule:1,hello:4,ignor:1,far:3,escap:0,cpu:0},objtypes:{},titles:["YAML syntax","Differences between D:YAML and the YAML specification","Welcome to D:YAML documentation!","Custom YAML data types","Getting started"],objnames:{},filenames:["tutorials/yaml_syntax","articles/spec_differences","index","tutorials/custom_types","tutorials/getting_started"]}) \ No newline at end of file +Search.setIndex({objects:{},terms:{represent:[2,3],all:[1,3,4],code:[0,1,3,4],representmap:3,scalar:[0,1,2,3,4],follow:[3,4],decid:3,depend:[0,3],show:[0,3],readabl:0,specif:[0,1,3,2],representsequ:3,program:4,digit:[3,4],sourc:[3,4],everi:3,string:[0,3,4],powervr:0,"void":[3,4],phobo:1,ident:3,failur:3,yamlexcept:[3,4],implicitli:[0,3],implement:[1,3],tri:1,gender:0,list:[0,1,2],iter:4,"try":[3,4],item:0,refer:[0,3],slower:0,past:4,fold:0,second:[0,4],design:0,pass:3,download:4,rrr:3,even:[1,4],index:[3,4],what:3,appear:1,compar:3,cast:3,preserv:[0,4],section:3,current:4,version:4,"new":3,method:[3,4],dyaml:[1,4],never:1,here:4,ggg:3,ldyaml:4,path:4,modifi:4,sinc:3,valu:[0,1,3,4],convert:[0,3,4],male:0,loos:1,datetim:0,omap:0,chang:[0,1,3],commonli:4,modul:4,unix:4,subnod:4,instal:4,articl:[0,2],regex:3,from:3,would:[3,4],doubl:0,two:[0,1,3],next:[3,4],few:1,call:[3,4],msg:3,type:[0,1,2,3,4],tell:4,more:[0,4],phone:0,known:[1,2,4],hold:3,must:[3,4],addrepresent:3,word:4,alia:[0,1],work:1,itself:3,can:[0,1,3,4],learn:4,purpos:3,root:[3,4],overrid:3,want:3,stream:[0,1],give:4,process:3,templat:3,topic:3,tag:[0,1,3,2],tab:1,serial:[0,3],addconstructorxxx:3,cours:3,multipl:[0,1],newlin:0,quot:[0,1],getting_start:4,how:[3,4],foreach:[3,4],answer:[0,4],instead:0,simpl:[0,3,4],css:3,map:[0,1,2,3,4],mar:4,clone:0,variant:1,befor:3,ff0000:3,uint:3,mai:1,end:[0,1,3],data:[0,1,2,3,4],welcom:[2,4],ani:[0,3,4],stdio:4,explicit:[0,3],correspond:3,ambigu:1,caus:1,inform:[0,4],green:[0,3],allow:[0,1,4],first:[0,2,3,4],order:[1,4],over:4,move:4,orang:3,becaus:1,veri:1,hierarchi:0,still:[0,1],paramet:3,write:4,style:[0,4],precondit:3,yaml:[0,1,2,3,4],window:4,complex:[0,3],main:[3,4],might:[0,1,3,4],easier:0,them:[0,1,3,4],"float":[0,3],"return":[3,4],thei:[0,1,3,4],python:0,auto:3,now:[1,3,4],introduct:[0,4],name:[0,3],separ:0,each:[0,3],found:[3,4],went:3,complet:3,mean:[1,3],compil:[3,4],unequ:[1,3],idea:4,"static":3,expect:[3,4],our:[3,4],extract:4,out:0,space:0,content:[1,3,4],rel:4,"0123456789abcdefabcdef":3,ref:3,red:[0,3],difficulti:1,advanc:0,"0123456789abcdef":3,base:[0,3],dictionari:0,put:[3,4],org:[1,3],"byte":1,thrown:4,pyyaml:[0,1],indent:[0,1],could:[3,4],keep:4,length:3,yamlcoloninflowcontext:1,confus:1,assign:0,radeon:0,oper:[0,3,4],onc:[0,1],arrai:[0,1,3,4],restrict:1,unlik:0,alreadi:[3,4],done:3,stabl:4,miss:3,addconstructormap:3,size:0,differ:[1,2,3,4],dump:[3,4],script:4,associ:[0,1,4],addimplicitresolv:3,system:[0,4],construct:[0,3],gpu:0,white:3,conveni:0,"final":[3,4],store:[0,3],adher:1,consol:4,option:[0,4],especi:0,ishexdigit:3,specifi:[0,3,4],pars:[0,3,4],somewhat:0,exactli:4,than:1,serv:4,remov:0,structur:[0,1],charact:[0,1,3],project:[2,4],str:[0,3],were:3,posit:3,argument:3,packag:[3,4],have:[0,3,4],tabl:0,need:[0,1,3,4],"null":0,lib:4,alias:[0,1,2],constructcolormap:3,note:[3,4],also:[0,3,4],read:[0,3,4],take:3,which:[0,1,3],brace:0,channel:3,uppercas:3,blue:[0,3],begin:[0,1],normal:4,previou:3,most:[0,3,4],regular:3,pair:[0,3],"class":[1,3],opequ:3,don:[1,3,4],later:3,flow:[0,1],doe:[0,1,4],bracket:0,cortex:0,fact:0,ldc:4,cdc:4,alphanumer:1,syntax:[0,2],identifi:[0,3],find:[3,4],onli:[3,4],explicitli:[0,3],just:[3,4],explain:4,should:[1,3,4],meant:4,std:[3,4],get:[2,3,4],express:3,cannot:[1,4],report:3,requir:3,whether:3,common:0,contain:[0,1,3,4],where:[0,3,4],wiki:1,set:[0,2,3,4],seq:0,see:[0,1,3],rgb:3,result:3,fail:1,close:1,athlon:0,representscalar:3,wikipedia:0,written:4,between:[0,1,2],"import":4,altern:3,accord:1,kei:[0,1,4],both:3,last:0,howev:[0,3],equal:3,comment:[0,4],etc:3,tutori:[2,3,4],context:[0,1],load:[1,3,4],bool:[0,3],color:[0,3],hyphen:0,loader:[3,4],colon:0,suppli:3,respect:3,addconstructorscalar:3,bbb:3,empti:0,implicit:[0,3],json:0,basic:4,xxx:[3,4],anywher:0,assert:3,togeth:3,input:[3,4],"catch":3,multi:0,therefor:[1,3],look:4,plain:[0,1,3],ffff00:3,defin:[0,3],ain:0,error:[3,4],anchor:[0,1,2],readi:3,non:[0,3],archiv:4,tediou:3,ascii:[1,3],dumper:[3,4],disabl:3,clearli:1,same:[0,1,3,4],check:[3,4],member:3,binari:0,instanc:[1,3,4],timestamp:0,android:0,document:[0,1,2,3,4],difficult:0,http:1,nest:0,user:[0,3],nodeexcept:3,markup:0,well:3,constructorexcept:3,person:0,exampl:[3,4],command:4,thi:[0,1,3,4],everyth:3,left:0,explan:4,systim:0,newest:4,execut:4,less:1,paragraph:0,gdc:4,human:0,yet:4,languag:[0,4],struct:[1,3,4],libdyaml:4,interptet:1,except:4,constructcolorscalar:3,add:[3,4],other:[1,4],els:0,match:3,build:4,real:0,format:[0,3,4],handl:[1,3],know:3,world:4,recurs:[0,1],tolow:3,like:3,success:3,arbitrari:3,resolv:[0,2,3],integ:[0,3,4],arthur:0,api:[2,3,4],singl:[0,1],output:[3,4],unnecessari:1,right:1,often:3,linux:[0,4],some:[0,1,3,4],guarante:3,ubyt:[0,3],librari:4,representcolor:3,lead:1,though:4,unord:1,condit:3,either:[0,3,4],object:3,run:4,acronym:0,usag:4,immut:3,unicod:1,chapter:0,comparison:3,about:[1,4],rare:1,usedefaultrepresent:3,page:0,constructor:[2,3],fals:3,produc:4,block:0,subset:0,within:1,encod:1,automat:4,bsd:0,mark:[0,1,3],your:[2,3,4],wai:[1,3],support:[0,1,3],question:0,"long":0,custom:[0,2,3],writeln:[3,4],start:[0,2,3,4],"function":3,form:3,continu:0,link:4,line:0,"true":3,conclus:4,"throw":[3,4],dmd:4,consist:0,possibl:[0,1,3,4],"default":[0,3],displai:4,until:0,directori:[3,4],problem:1,similar:[0,4],featur:[0,1],creat:[0,3,4],"int":[0,3,4],cover:4,dure:3,parser:[0,4],doesn:4,repres:[0,3,4],"char":3,exist:4,file:[1,3,4],yamlnul:0,isdigit:3,dent:0,simplest:4,probabl:0,hex:3,when:[3,4],detail:[0,1],invalid:3,valid:1,rrggbb:3,futur:[0,1],test:3,you:[0,3,4],node:[0,3,4],resolut:[0,3],sequenc:[0,2,3,4],consid:[1,3],debian:0,reduc:0,longer:3,home:4,rule:1,hello:4,ignor:1,far:3,escap:0,cpu:0},objtypes:{},titles:["YAML syntax","Differences between D:YAML and the YAML specification","Welcome to D:YAML documentation!","Custom YAML data types","Getting started"],objnames:{},filenames:["tutorials/yaml_syntax","articles/spec_differences","index","tutorials/custom_types","tutorials/getting_started"]}) \ No newline at end of file diff --git a/doc/html/tutorials/custom_types.html b/doc/html/tutorials/custom_types.html index 2c51903..f83e737 100644 --- a/doc/html/tutorials/custom_types.html +++ b/doc/html/tutorials/custom_types.html @@ -60,8 +60,9 @@ It is also possible to implicitly resolve custom tags, as we will show later.

D:YAML uses the Constructor class to process each node to hold data type corresponding to its tag. Constructor stores a function for each supported tag to process it. These functions are supplied by -the user using the addConstructor() method. Constructor is then passed to -Loader, which parses YAML input.

+the user using the addConstructorXXX() methods, where XXX is Scalar, +Sequence or Mapping. Constructor is then passed to Loader, which parses +YAML input.

Struct types have no specific requirements for YAML support. Class types should define the opEquals() operator, as this is used in equality comparisons of nodes. Default class opEquals() compares references, which means two identical @@ -77,14 +78,17 @@ following struct:

First, we need a function to construct our data type. It must take two Mark -structs, which store position of the node in the file, and either a string, an -array of Node or of Node.Pair, depending on whether we’re constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions:

-
Color constructColorScalar(Mark start, Mark end, string value)
+structs, which store position of the node in the file, and a reference to Node
+to construct from. The node is guaranteed to contain either a string, an array
+of Node or of Node.Pair, depending on whether we’re constructing our value
+from a scalar, sequence, or mapping, respectively. In this tutorial, we have
+functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
+from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
+of these functions:

+
Color constructColorScalar(Mark start, Mark end, ref Node node)
 {
+    string value = node.get!string;
+
     if(value.length != 6)
     {
         throw new ConstructorException("Invalid color: " ~ value, start, end);
@@ -115,30 +119,21 @@ RRGGBB, or from a mapping, where we use the following format:
     return result;
 }
 
-Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
+Color constructColorMapping(Mark start, Mark end, ref Node node)
 {
-    int r, g, b;
-    r = g = b = -1;
-    bool error = pairs.length != 3;
+    int r,g,b;
+    bool error = false;
 
-    foreach(ref pair; pairs)
+    //Might throw if a value is missing or is not an integer.
+    try
     {
-        //Key might not be a string, and value might not be an int,
-        //so we need to check for that
-        try
-        {
-            switch(pair.key.get!string)
-            {
-                case "r": r = pair.value.get!int; break;
-                case "g": g = pair.value.get!int; break;
-                case "b": b = pair.value.get!int; break;
-                default:  error = true;
-            }
-        }
-        catch(NodeException e)
-        {
-            error = true;
-        }
+        r = node["r"].get!int;
+        g = node["g"].get!int;
+        b = node["b"].get!int;
+    }
+    catch(NodeException e)
+    {
+        error = true;
     }
 
     if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
@@ -174,8 +169,8 @@ RRGGBB, or from a mapping, where we use the following format:
     {
         auto constructor = new Constructor;
         //both functions handle the same tag, but one handles scalar, one mapping.
-        constructor.addConstructor("!color", &constructColorScalar);
-        constructor.addConstructor("!color-mapping", &constructColorMapping);
+        constructor.addConstructorScalar("!color", &constructColorScalar);
+        constructor.addConstructorMapping("!color-mapping", &constructColorMapping);
 
         auto loader = Loader("input.yaml");
         loader.constructor = constructor;
@@ -292,7 +287,7 @@ loading the output.

First we get the Color from the node. Then we convert it to a string with the -HTML-like format we’ve used before. Finally, we use the representScalar() +CSS-like format we’ve used before. Finally, we use the representScalar() method of Representer to get a scalar node ready for output. There are corresponding representMapping() and representSequence() methods as well, with examples in the @@ -380,7 +375,7 @@ directory of the D:YAML package.

diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index 77c5422..530bd27 100644 --- a/doc/html/tutorials/getting_started.html +++ b/doc/html/tutorials/getting_started.html @@ -237,7 +237,7 @@ example in the example/getting_st
diff --git a/doc/html/tutorials/yaml_syntax.html b/doc/html/tutorials/yaml_syntax.html index 83da594..f3d0827 100644 --- a/doc/html/tutorials/yaml_syntax.html +++ b/doc/html/tutorials/yaml_syntax.html @@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).

diff --git a/docsrc/tutorials/custom_types.rst b/docsrc/tutorials/custom_types.rst index 7137f07..da62c91 100644 --- a/docsrc/tutorials/custom_types.rst +++ b/docsrc/tutorials/custom_types.rst @@ -20,8 +20,9 @@ Constructor D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process each node to hold data type corresponding to its tag. *Constructor* stores a function for each supported tag to process it. These functions are supplied by -the user using the *addConstructor()* method. *Constructor* is then passed to -*Loader*, which parses YAML input. +the user using the *addConstructorXXX()* methods, where *XXX* is *Scalar*, +*Sequence* or *Mapping*. *Constructor* is then passed to *Loader*, which parses +YAML input. Struct types have no specific requirements for YAML support. Class types should define the *opEquals()* operator, as this is used in equality comparisons of @@ -41,17 +42,20 @@ following struct: } First, we need a function to construct our data type. It must take two *Mark* -structs, which store position of the node in the file, and either a *string*, an -array of *Node* or of *Node.Pair*, depending on whether we're constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions: +structs, which store position of the node in the file, and a reference to *Node* +to construct from. The node is guaranteed to contain either a *string*, an array +of *Node* or of *Node.Pair*, depending on whether we're constructing our value +from a scalar, sequence, or mapping, respectively. In this tutorial, we have +functions to construct a color from a scalar, using CSS-like format, RRGGBB, or +from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code +of these functions: .. code-block:: d - Color constructColorScalar(Mark start, Mark end, string value) + Color constructColorScalar(Mark start, Mark end, ref Node node) { + string value = node.get!string; + if(value.length != 6) { throw new ConstructorException("Invalid color: " ~ value, start, end); @@ -82,30 +86,21 @@ RRGGBB, or from a mapping, where we use the following format: return result; } - Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) + Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) + //Might throw if a value is missing or is not an integer. + try { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; } if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) @@ -146,8 +141,8 @@ Finally, the code to put it all together: { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; @@ -284,7 +279,7 @@ With the following code, we will add support for dumping the our Color type. } First we get the *Color* from the node. Then we convert it to a string with the -HTML-like format we've used before. Finally, we use the *representScalar()* +CSS-like format we've used before. Finally, we use the *representScalar()* method of *Representer* to get a scalar node ready for output. There are corresponding *representMapping()* and *representSequence()* methods as well, with examples in the diff --git a/dyaml/constructor.d b/dyaml/constructor.d index d8fa438..f19202a 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -68,11 +68,11 @@ final class Constructor { private: ///Constructor functions from scalars. - Node.Value delegate(Mark, Mark, string) [Tag] fromScalar_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromScalar_; ///Constructor functions from sequences. - Node.Value delegate(Mark, Mark, Node[]) [Tag] fromSequence_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromSequence_; ///Constructor functions from mappings. - Node.Value delegate (Mark, Mark, Node.Pair[])[Tag] fromMapping_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromMapping_; public: /** @@ -85,26 +85,25 @@ final class Constructor */ this(in bool defaultConstructors = true) { - if(defaultConstructors) - { - addConstructor("tag:yaml.org,2002:null", &constructNull); - addConstructor("tag:yaml.org,2002:bool", &constructBool); - addConstructor("tag:yaml.org,2002:int", &constructLong); - addConstructor("tag:yaml.org,2002:float", &constructReal); - addConstructor("tag:yaml.org,2002:binary", &constructBinary); - addConstructor("tag:yaml.org,2002:timestamp", &constructTimestamp); - addConstructor("tag:yaml.org,2002:str", &constructString); + if(!defaultConstructors){return;} - ///In a mapping, the default value is kept as an entry with the '=' key. - addConstructor("tag:yaml.org,2002:value", &constructString); + addConstructorScalar("tag:yaml.org,2002:null", &constructNull); + addConstructorScalar("tag:yaml.org,2002:bool", &constructBool); + addConstructorScalar("tag:yaml.org,2002:int", &constructLong); + addConstructorScalar("tag:yaml.org,2002:float", &constructReal); + addConstructorScalar("tag:yaml.org,2002:binary", &constructBinary); + addConstructorScalar("tag:yaml.org,2002:timestamp", &constructTimestamp); + addConstructorScalar("tag:yaml.org,2002:str", &constructString); - addConstructor("tag:yaml.org,2002:omap", &constructOrderedMap); - addConstructor("tag:yaml.org,2002:pairs", &constructPairs); - addConstructor("tag:yaml.org,2002:set", &constructSet); - addConstructor("tag:yaml.org,2002:seq", &constructSequence); - addConstructor("tag:yaml.org,2002:map", &constructMap); - addConstructor("tag:yaml.org,2002:merge", &constructMerge); - } + ///In a mapping, the default value is kept as an entry with the '=' key. + addConstructorScalar("tag:yaml.org,2002:value", &constructString); + + addConstructorSequence("tag:yaml.org,2002:omap", &constructOrderedMap); + addConstructorSequence("tag:yaml.org,2002:pairs", &constructPairs); + addConstructorMapping("tag:yaml.org,2002:set", &constructSet); + addConstructorSequence("tag:yaml.org,2002:seq", &constructSequence); + addConstructorMapping("tag:yaml.org,2002:map", &constructMap); + addConstructorScalar("tag:yaml.org,2002:merge", &constructMerge); } ///Destroy the constructor. @@ -119,139 +118,129 @@ final class Constructor } /** - * Add a constructor function. + * Add a constructor function from scalar. * - * The function passed must two Marks (determining start and end positions of - * the node in file) and either a string (if constructing from scalar), - * an array of Nodes (from sequence) or an array of Node.Pair (from mapping). - * The value returned by this function will be stored in the resulring node. + * The function must take two Marks (start and end positions of + * the node in file) and a reference to Node to construct from. + * The node contains a string for scalars, Node[] for sequences and + * Node.Pair[] for mappings. + * The value returned by this function will be stored in the resulting node. * * Only one constructor function can be set for one tag. * * Params: tag = Tag for the function to handle. * ctor = Constructor function. */ - void addConstructor(T, U)(in string tag, T function(Mark, Mark, U) ctor) - if(is(U == string) || is(U == Node[]) || is(U == Node.Pair[])) + void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor) { - Node.Value delegate(Mark, Mark, U) deleg; + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!string)[t] = deleg; + } - //Type that natively fits into Node.Value. - static if(Node.Value.allowed!T) - { - deleg = (Mark s, Mark e, U p){return Node.Value(ctor(s,e,p));}; - } - //User defined type. - else - { - deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));}; - } + /** + * Add a constructor function from sequence. + * + * See_Also: addConstructorScalar + */ + void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + { + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!(Node[]))[t] = deleg; + } - const Tag t = Tag(tag); - - assert((t in fromScalar_) is null && - (t in fromSequence_) is null && - (t in fromMapping_) is null, - "Constructor function for tag " ~ tag ~ " is already " - "specified. Can't specify another one."); - - - static if(is(U == string)) - { - fromScalar_[t] = deleg; - } - else static if(is(U == Node[])) - { - fromSequence_[t] = deleg; - } - else static if(is(U == Node.Pair[])) - { - fromMapping_[t] = deleg; - } + /** + * Add a constructor function from a mapping. + * + * See_Also: addConstructorScalar + */ + void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + { + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!(Node.Pair[]))[t] = deleg; } package: /* - * Construct a node from scalar. + * Construct a node. * * Params: start = Start position of the node. * end = End position of the node. * tag = Tag (data type) of the node. - * value = String value of the node. + * value = Value to construct node from (string, nodes or pairs). * * Returns: Constructed node. */ - Node node(in Mark start, in Mark end, in Tag tag, string value) const + Node node(T)(in Mark start, in Mark end, in Tag tag, T value) + if(is(T : string) || is(T == Node[]) || is(T == Node.Pair[])) { - enforce((tag in fromScalar_) !is null, - new ConstructorException("Could not determine a constructor from " - "scalar for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromScalar_[tag](start, end, value), start, tag); + enforce((tag in *delegates!T) !is null, + new ConstructorException("Could not determine a constructor for tag " + ~ tag.get(), start, end)); + Node node = Node(value); + return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag); } - /* - * Construct a node from sequence. + private: + /* + * Add a constructor function. * - * Params: start = Start position of the node. - * end = End position of the node. - * tag = Tag (data type) of the node. - * value = Sequence to construct node from. - * - * Returns: Constructed node. - */ - Node node(in Mark start, in Mark end, in Tag tag, Node[] value) const + * Params: tag = Tag for the function to handle. + * ctor = Constructor function. + */ + auto addConstructor(T)(in Tag tag, T function(Mark, Mark, ref Node) ctor) { - enforce((tag in fromSequence_) !is null, - new ConstructorException("Could not determine a constructor from " - "sequence for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromSequence_[tag](start, end, value), start, tag); + assert((tag in fromScalar_) is null && + (tag in fromSequence_) is null && + (tag in fromMapping_) is null, + "Constructor function for tag " ~ tag.get ~ " is already " + "specified. Can't specify another one."); + + return (Mark s, Mark e, ref Node n) + { + static if(Node.Value.allowed!T){return Node.Value(ctor(s,e,n));} + else {return Node.userValue(ctor(s,e,n));} + }; } - /* - * Construct a node from mapping. - * - * Params: start = Start position of the node. - * end = End position of the node. - * tag = Tag (data type) of the node. - * value = Mapping to construct node from. - * - * Returns: Constructed node. - */ - Node node(in Mark start, in Mark end, in Tag tag, Node.Pair[] value) const + //Get the array of constructor functions for scalar, sequence or mapping. + auto delegates(T)() { - enforce((tag in fromMapping_) !is null, - new ConstructorException("Could not determine a constructor from " - "mapping for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromMapping_[tag](start, end, value), start, tag); + static if(is(T : string)) {return &fromScalar_;} + else static if(is(T : Node[])) {return &fromSequence_;} + else static if(is(T : Node.Pair[])){return &fromMapping_;} + else static assert(false); } } ///Construct a null node. -YAMLNull constructNull(Mark start, Mark end, string value) +YAMLNull constructNull(Mark start, Mark end, ref Node node) { return YAMLNull(); } ///Construct a merge node - a node that merges another node into a mapping. -YAMLMerge constructMerge(Mark start, Mark end, string value) +YAMLMerge constructMerge(Mark start, Mark end, ref Node node) { return YAMLMerge(); } ///Construct a boolean node. -bool constructBool(Mark start, Mark end, string value) +bool constructBool(Mark start, Mark end, ref Node node) { - value = value.toLower(); + string value = node.get!string().toLower(); if(["yes", "true", "on"].canFind(value)) {return true;} if(["no", "false", "off"].canFind(value)){return false;} throw new ConstructorException("Unable to parse boolean value: " ~ value, start, end); } ///Construct an integer (long) node. -long constructLong(Mark start, Mark end, string value) +long constructLong(Mark start, Mark end, ref Node node) { - value = value.replace("_", ""); + string value = node.get!string().replace("_", ""); const char c = value[0]; const long sign = c != '-' ? 1 : -1; if(c == '-' || c == '+') @@ -299,7 +288,7 @@ unittest { long getLong(string str) { - return constructLong(Mark(), Mark(), str); + return constructLong(Mark(), Mark(), Node(str)); } string canonical = "685230"; @@ -318,9 +307,9 @@ unittest } ///Construct a floating point (real) node. -real constructReal(Mark start, Mark end, string value) +real constructReal(Mark start, Mark end, ref Node node) { - value = value.replace("_", "").toLower(); + string value = node.get!string().replace("_", "").toLower(); const char c = value[0]; const real sign = c != '-' ? 1.0 : -1.0; if(c == '-' || c == '+') @@ -369,7 +358,7 @@ unittest real getReal(string str) { - return constructReal(Mark(), Mark(), str); + return constructReal(Mark(), Mark(), Node(str)); } string canonical = "6.8523015e+5"; @@ -388,8 +377,9 @@ unittest } ///Construct a binary (base64) node. -ubyte[] constructBinary(Mark start, Mark end, string value) +ubyte[] constructBinary(Mark start, Mark end, ref Node node) { + string value = node.get!string; //For an unknown reason, this must be nested to work (compiler bug?). try { @@ -411,13 +401,15 @@ unittest char[] buffer; buffer.length = 256; string input = cast(string)Base64.encode(test, buffer); - auto value = constructBinary(Mark(), Mark(), input); + auto value = constructBinary(Mark(), Mark(), Node(input)); assert(value == test); } ///Construct a timestamp (SysTime) node. -SysTime constructTimestamp(Mark start, Mark end, string value) +SysTime constructTimestamp(Mark start, Mark end, ref Node node) { + string value = node.get!string; + immutable YMDRegexp = regex("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)"); immutable HMSRegexp = regex("^[Tt \t]+([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(\\.[0-9]*)?"); immutable TZRegexp = regex("^[ \t]*Z|([-+][0-9][0-9]?)(:[0-9][0-9])?"); @@ -492,7 +484,7 @@ unittest string timestamp(string value) { - return constructTimestamp(Mark(), Mark(), value).toISOString(); + return constructTimestamp(Mark(), Mark(), Node(value)).toISOString(); } string canonical = "2001-12-15T02:59:43.1Z"; @@ -515,9 +507,9 @@ unittest } ///Construct a string node. -string constructString(Mark start, Mark end, string value) +string constructString(Mark start, Mark end, ref Node node) { - return value; + return node.get!string; } ///Convert a sequence of single-element mappings into a sequence of pairs. @@ -539,9 +531,9 @@ Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes) } ///Construct an ordered map (ordered sequence of key:value pairs without duplicates) node. -Node.Pair[] constructOrderedMap(Mark start, Mark end, Node[] nodes) +Node.Pair[] constructOrderedMap(Mark start, Mark end, ref Node node) { - auto pairs = getPairs("ordered map", start, end, nodes); + auto pairs = getPairs("ordered map", start, end, node.get!(Node[])); //TODO: the map here should be replaced with something with deterministic //memory allocation if possible. @@ -588,7 +580,7 @@ unittest bool hasDuplicates(Node[] nodes) { - return null !is collectException(constructOrderedMap(Mark(), Mark(), nodes)); + return null !is collectException(constructOrderedMap(Mark(), Mark(), Node(nodes))); } assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2))); @@ -600,14 +592,16 @@ unittest } ///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node. -Node.Pair[] constructPairs(Mark start, Mark end, Node[] nodes) +Node.Pair[] constructPairs(Mark start, Mark end, ref Node node) { - return getPairs("pairs", start, end, nodes); + return getPairs("pairs", start, end, node.get!(Node[])); } ///Construct a set node. -Node[] constructSet(Mark start, Mark end, Node.Pair[] pairs) +Node[] constructSet(Mark start, Mark end, ref Node node) { + auto pairs = node.get!(Node.Pair[]); + //In future, the map here should be replaced with something with deterministic //memory allocation if possible. //Detect duplicates. @@ -658,24 +652,25 @@ unittest } assert(null !is collectException - (constructSet(Mark(), Mark(), DuplicatesShort.dup))); + (constructSet(Mark(), Mark(), Node(DuplicatesShort.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), noDuplicatesShort.dup))); + (constructSet(Mark(), Mark(), Node(noDuplicatesShort.dup)))); assert(null !is collectException - (constructSet(Mark(), Mark(), DuplicatesLong.dup))); + (constructSet(Mark(), Mark(), Node(DuplicatesLong.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), noDuplicatesLong.dup))); + (constructSet(Mark(), Mark(), Node(noDuplicatesLong.dup)))); } ///Construct a sequence (array) node. -Node[] constructSequence(Mark start, Mark end, Node[] nodes) +Node[] constructSequence(Mark start, Mark end, ref Node node) { - return nodes; + return node.get!(Node[]); } ///Construct an unordered map (unordered set of key: value _pairs without duplicates) node. -Node.Pair[] constructMap(Mark start, Mark end, Node.Pair[] pairs) +Node.Pair[] constructMap(Mark start, Mark end, ref Node node) { + auto pairs = node.get!(Node.Pair[]); //TODO: the map here should be replaced with something with deterministic //memory allocation if possible. //Detect duplicates. diff --git a/dyaml/node.d b/dyaml/node.d index b47275e..f11b058 100644 --- a/dyaml/node.d +++ b/dyaml/node.d @@ -251,11 +251,12 @@ struct Node { tag_ = Tag(tag); + //Construction from raw node or pair array. static if(is(T == Node) || is(T == Node.Pair)) { value_ = Value(array); } - //Need to handle byte buffers separately + //Need to handle byte buffers separately. else static if(is(T == byte) || is(T == ubyte)) { value_ = Value(cast(ubyte[]) array); diff --git a/examples/constructor/main.d b/examples/constructor/main.d index 7cd5e2f..a80c0d7 100644 --- a/examples/constructor/main.d +++ b/examples/constructor/main.d @@ -10,70 +10,63 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, string value) +Color constructColorScalar(Mark start, Mark end, ref Node node) { - if(value.length != 6) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } - //We don't need to check for uppercase chars this way. - value = value.toLower(); + string value = node.get!string; - //Get value of a hex digit. - uint hex(char c) - { - if(!std.ascii.isHexDigit(c)) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } + if(value.length != 6) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); - if(std.ascii.isDigit(c)) - { - return c - '0'; - } - return c - 'a' + 10; - } + //Get value of a hex digit. + uint hex(char c) + { + if(!std.ascii.isHexDigit(c)) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } - Color result; - result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); - result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); - result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } - return result; + Color result; + result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + + return result; } -Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) +Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) - { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } - } + //Might throw if a value is missing or is not an integer. + try + { + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; + } - if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - { - throw new ConstructorException("Invalid color", start, end); - } + if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) + { + throw new ConstructorException("Invalid color", start, end); + } - return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); + return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } void main() @@ -85,8 +78,8 @@ void main() { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; diff --git a/examples/resolver/main.d b/examples/resolver/main.d index fd06cb4..b80b1e4 100644 --- a/examples/resolver/main.d +++ b/examples/resolver/main.d @@ -10,70 +10,63 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, string value) +Color constructColorScalar(Mark start, Mark end, ref Node node) { - if(value.length != 6) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } - //We don't need to check for uppercase chars this way. - value = value.toLower(); + string value = node.get!string; - //Get value of a hex digit. - uint hex(char c) - { - if(!std.ascii.isHexDigit(c)) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } + if(value.length != 6) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); - if(std.ascii.isDigit(c)) - { - return c - '0'; - } - return c - 'a' + 10; - } + //Get value of a hex digit. + uint hex(char c) + { + if(!std.ascii.isHexDigit(c)) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } - Color result; - result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); - result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); - result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } - return result; + Color result; + result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + + return result; } -Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) +Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) - { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } - } + //Might throw if a value is missing or is not an integer. + try + { + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; + } - if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - { - throw new ConstructorException("Invalid color", start, end); - } + if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) + { + throw new ConstructorException("Invalid color", start, end); + } - return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); + return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } void main() @@ -85,8 +78,8 @@ void main() { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto resolver = new Resolver; resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), diff --git a/test/data/construct-custom.data b/test/data/construct-custom.data index 4729be9..f17e4ed 100644 --- a/test/data/construct-custom.data +++ b/test/data/construct-custom.data @@ -1,6 +1,4 @@ --- -- !tag1 - x: 1 - !tag1 x: 1 'y': 2 diff --git a/test/src/constructor.d b/test/src/constructor.d index 2f97813..a8ba967 100644 --- a/test/src/constructor.d +++ b/test/src/constructor.d @@ -88,8 +88,7 @@ Node[] constructBool() Node[] constructCustom() { - return [Node([Node(new TestClass(1, 0, 0)), - Node(new TestClass(1, 2, 3)), + return [Node([Node(new TestClass(1, 2, 3)), Node(TestStruct(10))])]; } @@ -338,21 +337,17 @@ struct TestStruct } ///Constructor function for TestClass. -TestClass constructClass(Mark start, Mark end, Node.Pair[] pairs) +TestClass constructClass(Mark start, Mark end, ref Node node) { - int x, y, z; - foreach(ref pair; pairs) + try { - switch(pair.key.get!string) - { - case "x": x = pair.value.get!int; break; - case "y": y = pair.value.get!int; break; - case "z": z = pair.value.get!int; break; - default: break; - } + return new TestClass(node["x"].get!int, node["y"].get!int, node["z"].get!int); + } + catch(NodeException e) + { + throw new ConstructorException("Error constructing TestClass (missing data members?) " + ~ e.msg, start, end); } - - return new TestClass(x, y, z); } Node representClass(ref Node node, Representer representer) @@ -367,9 +362,9 @@ Node representClass(ref Node node, Representer representer) } ///Constructor function for TestStruct. -TestStruct constructStruct(Mark start, Mark end, string value) +TestStruct constructStruct(Mark start, Mark end, ref Node node) { - return TestStruct(to!int(value)); + return TestStruct(to!int(node.get!string)); } ///Representer function for TestStruct. @@ -395,8 +390,8 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy) new Exception("Unimplemented constructor test: " ~ base)); auto constructor = new Constructor; - constructor.addConstructor("!tag1", &constructClass); - constructor.addConstructor("!tag2", &constructStruct); + constructor.addConstructorMapping("!tag1", &constructClass); + constructor.addConstructorScalar("!tag2", &constructStruct); auto loader = Loader(dataFilename); loader.constructor = constructor; diff --git a/test/src/representer.d b/test/src/representer.d index aa33889..5178611 100644 --- a/test/src/representer.d +++ b/test/src/representer.d @@ -58,8 +58,8 @@ void testRepresenterTypes(bool verbose, string codeFilename) output = cast(string)emitStream.data; auto loadStream = new MemoryStream(emitStream.data); auto constructor = new Constructor; - constructor.addConstructor("!tag1", &constructClass); - constructor.addConstructor("!tag2", &constructStruct); + constructor.addConstructorMapping("!tag1", &constructClass); + constructor.addConstructorScalar("!tag2", &constructStruct); auto loader = Loader(loadStream); loader.name = "TEST";