parent
							
								
									e82951fe23
								
							
						
					
					
						commit
						beaf3e90af
					
				
					 6 changed files with 217 additions and 0 deletions
				
			
		|  | @ -257,6 +257,22 @@ stdenv.mkDerivation { | ||||||
|   </varlistentry> |   </varlistentry> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |   <varlistentry><term><function>builtins.fromJSON</function> <replaceable>e</replaceable></term> | ||||||
|  | 
 | ||||||
|  |     <listitem><para>Convert a JSON string to a Nix | ||||||
|  |     value. For example, | ||||||
|  | 
 | ||||||
|  | <programlisting> | ||||||
|  | builtins.fromJSON ''{"x": [1, 2, 3], "y": null}'' | ||||||
|  | </programlisting> | ||||||
|  | 
 | ||||||
|  |     returns the value <literal>{ x = [ 1 2 3 ]; y = null; | ||||||
|  |     }</literal>. Floating point numbers are not | ||||||
|  |     supported.</para></listitem> | ||||||
|  | 
 | ||||||
|  |   </varlistentry> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|   <varlistentry><term><function>builtins.getAttr</function> |   <varlistentry><term><function>builtins.getAttr</function> | ||||||
|   <replaceable>s</replaceable> <replaceable>set</replaceable></term> |   <replaceable>s</replaceable> <replaceable>set</replaceable></term> | ||||||
| 
 | 
 | ||||||
|  | @ -762,6 +778,7 @@ in foo</programlisting> | ||||||
| 
 | 
 | ||||||
|   </varlistentry> |   </varlistentry> | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|   <varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term> |   <varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term> | ||||||
| 
 | 
 | ||||||
|     <listitem><para>Convert the string value |     <listitem><para>Convert the string value | ||||||
|  |  | ||||||
							
								
								
									
										144
									
								
								src/libexpr/json-to-value.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/libexpr/json-to-value.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,144 @@ | ||||||
|  | #include "config.h" | ||||||
|  | #include "json-to-value.hh" | ||||||
|  | 
 | ||||||
|  | #include <cstring> | ||||||
|  | 
 | ||||||
|  | namespace nix { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void skipWhitespace(const char * & s) | ||||||
|  | { | ||||||
|  |     while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #if HAVE_BOEHMGC | ||||||
|  | typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; | ||||||
|  | #else | ||||||
|  | typedef std::vector<Value *> ValueVector; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static string parseJSONString(const char * & s) | ||||||
|  | { | ||||||
|  |     string res; | ||||||
|  |     if (*s++ != '"') throw JSONParseError("expected JSON string"); | ||||||
|  |     while (*s != '"') { | ||||||
|  |         if (!*s) throw JSONParseError("got end-of-string in JSON string"); | ||||||
|  |         if (*s == '\\') { | ||||||
|  |             s++; | ||||||
|  |             if (*s == '"') res += '"'; | ||||||
|  |             else if (*s == '\\') res += '\\'; | ||||||
|  |             else if (*s == '/') res += '/'; | ||||||
|  |             else if (*s == '/') res += '/'; | ||||||
|  |             else if (*s == 'b') res += '\b'; | ||||||
|  |             else if (*s == 'f') res += '\f'; | ||||||
|  |             else if (*s == 'n') res += '\n'; | ||||||
|  |             else if (*s == 'r') res += '\r'; | ||||||
|  |             else if (*s == 't') res += '\t'; | ||||||
|  |             else if (*s == 'u') throw JSONParseError("\\u characters in JSON strings are currently not supported"); | ||||||
|  |             else throw JSONParseError("invalid escaped character in JSON string"); | ||||||
|  |             s++; | ||||||
|  |         } else | ||||||
|  |             res += *s++; | ||||||
|  |     } | ||||||
|  |     s++; | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static void parseJSON(EvalState & state, const char * & s, Value & v) | ||||||
|  | { | ||||||
|  |     skipWhitespace(s); | ||||||
|  | 
 | ||||||
|  |     if (!*s) throw JSONParseError("expected JSON value"); | ||||||
|  | 
 | ||||||
|  |     if (*s == '[') { | ||||||
|  |         s++; | ||||||
|  |         ValueVector values; | ||||||
|  |         values.reserve(128); | ||||||
|  |         skipWhitespace(s); | ||||||
|  |         while (1) { | ||||||
|  |             if (values.empty() && *s == ']') break; | ||||||
|  |             Value * v2 = state.allocValue(); | ||||||
|  |             parseJSON(state, s, *v2); | ||||||
|  |             values.push_back(v2); | ||||||
|  |             skipWhitespace(s); | ||||||
|  |             if (*s == ']') break; | ||||||
|  |             if (*s != ',') throw JSONParseError("expected `,' or `]' after JSON array element"); | ||||||
|  |             s++; | ||||||
|  |         } | ||||||
|  |         s++; | ||||||
|  |         state.mkList(v, values.size()); | ||||||
|  |         for (size_t n = 0; n < values.size(); ++n) | ||||||
|  |             v.list.elems[n] = values[n]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (*s == '{') { | ||||||
|  |         s++; | ||||||
|  |         state.mkAttrs(v, 1); | ||||||
|  |         while (1) { | ||||||
|  |             skipWhitespace(s); | ||||||
|  |             if (v.attrs->empty() && *s == '}') break; | ||||||
|  |             string name = parseJSONString(s); | ||||||
|  |             skipWhitespace(s); | ||||||
|  |             if (*s != ':') throw JSONParseError("expected `:' in JSON object"); | ||||||
|  |             s++; | ||||||
|  |             Value * v2 = state.allocValue(); | ||||||
|  |             parseJSON(state, s, *v2); | ||||||
|  |             v.attrs->push_back(Attr(state.symbols.create(name), v2)); | ||||||
|  |             skipWhitespace(s); | ||||||
|  |             if (*s == '}') break; | ||||||
|  |             if (*s != ',') throw JSONParseError("expected `,' or `}' after JSON member"); | ||||||
|  |             s++; | ||||||
|  |         } | ||||||
|  |         v.attrs->sort(); | ||||||
|  |         s++; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (*s == '"') { | ||||||
|  |         mkString(v, parseJSONString(s)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (isdigit(*s) || *s == '-') { | ||||||
|  |         bool neg = false; | ||||||
|  |         if (*s == '-') { | ||||||
|  |             neg = true; | ||||||
|  |             if (!*++s) throw JSONParseError("unexpected end of JSON number"); | ||||||
|  |         } | ||||||
|  |         NixInt n = 0; | ||||||
|  |         // FIXME: detect overflow
 | ||||||
|  |         while (isdigit(*s)) n = n * 10 + (*s++ - '0'); | ||||||
|  |         if (*s == '.' || *s == 'e') throw JSONParseError("floating point JSON numbers are not supported"); | ||||||
|  |         mkInt(v, neg ? -n : n); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (strncmp(s, "true", 4) == 0) { | ||||||
|  |         s += 4; | ||||||
|  |         mkBool(v, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (strncmp(s, "false", 5) == 0) { | ||||||
|  |         s += 5; | ||||||
|  |         mkBool(v, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else if (strncmp(s, "null", 4) == 0) { | ||||||
|  |         s += 4; | ||||||
|  |         mkNull(v); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     else throw JSONParseError("unrecognised JSON value"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void parseJSON(EvalState & state, const string & s_, Value & v) | ||||||
|  | { | ||||||
|  |     const char * s = s_.c_str(); | ||||||
|  |     parseJSON(state, s, v); | ||||||
|  |     skipWhitespace(s); | ||||||
|  |     if (*s) throw JSONParseError(format("expected end-of-string while parsing JSON value: %1%") % s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/libexpr/json-to-value.hh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/libexpr/json-to-value.hh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "eval.hh" | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | namespace nix { | ||||||
|  | 
 | ||||||
|  | MakeError(JSONParseError, EvalError) | ||||||
|  | 
 | ||||||
|  | void parseJSON(EvalState & state, const string & s, Value & v); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include "archive.hh" | #include "archive.hh" | ||||||
| #include "value-to-xml.hh" | #include "value-to-xml.hh" | ||||||
| #include "value-to-json.hh" | #include "value-to-json.hh" | ||||||
|  | #include "json-to-value.hh" | ||||||
| #include "names.hh" | #include "names.hh" | ||||||
| #include "eval-inline.hh" | #include "eval-inline.hh" | ||||||
| 
 | 
 | ||||||
|  | @ -775,6 +776,14 @@ static void prim_toJSON(EvalState & state, const Pos & pos, Value * * args, Valu | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /* Parse a JSON string to a value. */ | ||||||
|  | static void prim_fromJSON(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
|  | { | ||||||
|  |     string s = state.forceStringNoCtx(*args[0], pos); | ||||||
|  |     parseJSON(state, s, v); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* Store a string in the Nix store as a source file that can be used
 | /* Store a string in the Nix store as a source file that can be used
 | ||||||
|    as an input by derivations. */ |    as an input by derivations. */ | ||||||
| static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) | static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||||
|  | @ -1396,6 +1405,7 @@ void EvalState::createBaseEnv() | ||||||
|     // Creating files
 |     // Creating files
 | ||||||
|     addPrimOp("__toXML", 1, prim_toXML); |     addPrimOp("__toXML", 1, prim_toXML); | ||||||
|     addPrimOp("__toJSON", 1, prim_toJSON); |     addPrimOp("__toJSON", 1, prim_toJSON); | ||||||
|  |     addPrimOp("__fromJSON", 1, prim_fromJSON); | ||||||
|     addPrimOp("__toFile", 2, prim_toFile); |     addPrimOp("__toFile", 2, prim_toFile); | ||||||
|     addPrimOp("__filterSource", 2, prim_filterSource); |     addPrimOp("__filterSource", 2, prim_filterSource); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								tests/lang/eval-okay-fromjson.exp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/lang/eval-okay-fromjson.exp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | true | ||||||
							
								
								
									
										32
									
								
								tests/lang/eval-okay-fromjson.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/lang/eval-okay-fromjson.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | # RFC 7159, section 13. | ||||||
|  | builtins.fromJSON | ||||||
|  |   '' | ||||||
|  |     { | ||||||
|  |       "Image": { | ||||||
|  |           "Width":  800, | ||||||
|  |           "Height": 600, | ||||||
|  |           "Title":  "View from 15th Floor", | ||||||
|  |           "Thumbnail": { | ||||||
|  |               "Url":    "http://www.example.com/image/481989943", | ||||||
|  |               "Height": 125, | ||||||
|  |               "Width":  100 | ||||||
|  |           }, | ||||||
|  |           "Animated" : false, | ||||||
|  |           "IDs": [116, 943, 234, 38793, true  ,false,null, -100] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |   '' | ||||||
|  | == | ||||||
|  |   { Image = | ||||||
|  |     { Width = 800; | ||||||
|  |       Height = 600; | ||||||
|  |       Title = "View from 15th Floor"; | ||||||
|  |       Thumbnail = | ||||||
|  |         { Url = http://www.example.com/image/481989943; | ||||||
|  |           Height = 125; | ||||||
|  |           Width = 100; | ||||||
|  |         }; | ||||||
|  |       Animated = false; | ||||||
|  |       IDs = [ 116 943 234 38793 true false null (0-100) ]; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue