parent
							
								
									e82951fe23
								
							
						
					
					
						commit
						beaf3e90af
					
				
					 6 changed files with 217 additions and 0 deletions
				
			
		
							
								
								
									
										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 "value-to-xml.hh" | ||||
| #include "value-to-json.hh" | ||||
| #include "json-to-value.hh" | ||||
| #include "names.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
 | ||||
|    as an input by derivations. */ | ||||
| static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Value & v) | ||||
|  | @ -1396,6 +1405,7 @@ void EvalState::createBaseEnv() | |||
|     // Creating files
 | ||||
|     addPrimOp("__toXML", 1, prim_toXML); | ||||
|     addPrimOp("__toJSON", 1, prim_toJSON); | ||||
|     addPrimOp("__fromJSON", 1, prim_fromJSON); | ||||
|     addPrimOp("__toFile", 2, prim_toFile); | ||||
|     addPrimOp("__filterSource", 2, prim_filterSource); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue