Browse Source

Improve MJSON handling

gingerBill 4 years ago
parent
commit
d452758afc
3 changed files with 83 additions and 66 deletions
  1. 16 18
      core/encoding/json/parser.odin
  2. 60 48
      core/encoding/json/unmarshal.odin
  3. 7 0
      core/encoding/json/validator.odin

+ 16 - 18
core/encoding/json/parser.odin

@@ -109,63 +109,61 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
 	token := p.curr_token
 	#partial switch token.kind {
 	case .Null:
-		value = Null{}
 		advance_token(p)
+		value = Null{}
 		return
 	case .False:
-		value = Boolean(false)
 		advance_token(p)
+		value = Boolean(false)
 		return
 	case .True:
-		value = Boolean(true)
 		advance_token(p)
+		value = Boolean(true)
 		return
 
 	case .Integer:
+		advance_token(p)
 		i, _ := strconv.parse_i64(token.text)
 		value = Integer(i)
-		advance_token(p)
 		return
 	case .Float:
+		advance_token(p)
 		f, _ := strconv.parse_f64(token.text)
 		value = Float(f)
-		advance_token(p)
 		return
+		
+	case .Ident:
+		if p.spec == .MJSON {
+			advance_token(p)
+			return string(token.text), nil
+		}
+		
 	case .String:
-		value = unquote_string(token, p.spec, p.allocator) or_return
 		advance_token(p)
-		return
+		return unquote_string(token, p.spec, p.allocator)
 
 	case .Open_Brace:
 		return parse_object(p)
 
 	case .Open_Bracket:
 		return parse_array(p)
-		
-	case .Ident:
-		if p.spec == .MJSON {
-			advance_token(p)
-			return string(token.text), nil
-		}
 
 	case:
 		if p.spec != .JSON {
-			#partial switch token.kind {
-			case .Infinity:
+			switch {
+			case allow_token(p, .Infinity):
 				inf: u64 = 0x7ff0000000000000
 				if token.text[0] == '-' {
 					inf = 0xfff0000000000000
 				}
 				value = transmute(f64)inf
-				advance_token(p)
 				return
-			case .NaN:
+			case allow_token(p, .NaN):
 				nan: u64 = 0x7ff7ffffffffffff
 				if token.text[0] == '-' {
 					nan = 0xfff7ffffffffffff
 				}
 				value = transmute(f64)nan
-				advance_token(p)
 				return
 			}
 		}

+ 60 - 48
core/encoding/json/unmarshal.odin

@@ -139,6 +139,56 @@ assign_float :: proc(val: any, i: $T) -> bool {
 }
 
 
+@(private)
+unmarsal_string :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool {
+	val := val
+	switch dst in &val {
+	case string:
+		dst = str
+		return true
+	case cstring:  
+		if str == "" {
+			dst = strings.clone_to_cstring("", p.allocator)
+		} else {
+			// NOTE: This is valid because 'clone_string' appends a NUL terminator
+			dst = cstring(raw_data(str)) 
+		}
+		return true
+	}
+	defer delete(str, p.allocator)
+	
+	#partial switch variant in ti.variant {
+	case reflect.Type_Info_Enum:
+		for name, i in variant.names {
+			if name == str {
+				assign_int(val, variant.values[i])
+				return true
+			}
+		}
+		// TODO(bill): should this be an error or not?
+		return true
+		
+	case reflect.Type_Info_Integer:
+		i := strconv.parse_i128(str) or_return
+		if assign_int(val, i) {
+			return true
+		}
+		if assign_float(val, i) {
+			return true
+		}
+	case reflect.Type_Info_Float:
+		f := strconv.parse_f64(str) or_return
+		if assign_int(val, f) {
+			return true
+		}
+		if assign_float(val, f) {
+			return true
+		}
+	}
+	
+	return false
+}
+
 
 @(private)
 unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
@@ -195,60 +245,22 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
 			}
 		}
 		return UNSUPPORTED_TYPE
-	case .String:
+		
+	case .Ident:
 		advance_token(p)
-		str := unquote_string(token, p.spec, p.allocator) or_return
-		val := any{v.data, ti.id}
-		switch dst in &val {
-		case string:
-			dst = str
-			return
-		case cstring:  
-			if str == "" {
-				dst = strings.clone_to_cstring("", p.allocator)
-			} else {
-				// NOTE: This is valid because 'clone_string' appends a NUL terminator
-				dst = cstring(raw_data(str)) 
+		if p.spec == .MJSON {
+			if unmarsal_string(p, any{v.data, ti.id}, token.text, ti) {
+				return nil
 			}
-			return
 		}
-		defer delete(str, p.allocator)
+		return UNSUPPORTED_TYPE
 		
-		#partial switch variant in ti.variant {
-		case reflect.Type_Info_Enum:
-			for name, i in variant.names {
-				if name == str {
-					assign_int(val, variant.values[i])
-					return nil
-				}
-			}
-			// TODO(bill): should this be an error or not?
+	case .String:
+		advance_token(p)
+		str := unquote_string(token, p.spec, p.allocator) or_return
+		if unmarsal_string(p, any{v.data, ti.id}, str, ti) {
 			return nil
-			
-		case reflect.Type_Info_Integer:
-			i, ok := strconv.parse_i128(token.text)
-			if !ok {
-				return UNSUPPORTED_TYPE
-			}
-			if assign_int(val, i) {
-				return
-			}
-			if assign_float(val, i) {
-				return
-			}
-		case reflect.Type_Info_Float:
-			f, ok := strconv.parse_f64(token.text)
-			if !ok {
-				return UNSUPPORTED_TYPE
-			}
-			if assign_int(val, f) {
-				return
-			}
-			if assign_float(val, f) {
-				return
-			}
 		}
-		
 		return UNSUPPORTED_TYPE
 
 

+ 7 - 0
core/encoding/json/validator.odin

@@ -102,6 +102,13 @@ validate_value :: proc(p: ^Parser) -> bool {
 
 	case .Open_Bracket:
 		return validate_array(p)
+		
+	case .Ident:
+		if p.spec == .MJSON {
+			advance_token(p)
+			return true
+		}
+		return false
 
 	case:
 		if p.spec != .JSON {