package goja

import (
	
	
	
	
	
	
	
	
	
	

	
)

const hex = "0123456789abcdef"

func ( *Runtime) ( FunctionCall) Value {
	 := json.NewDecoder(strings.NewReader(.Argument(0).toString().String()))

	,  := .builtinJSON_decodeValue()
	if errors.Is(, io.EOF) {
		panic(.newError(.getSyntaxError(), "Unexpected end of JSON input (%v)", .Error()))
	}
	if  != nil {
		panic(.newError(.getSyntaxError(), .Error()))
	}

	if ,  := .Token();  != io.EOF {
		panic(.newError(.getSyntaxError(), "Unexpected token at the end: %v", ))
	}

	var  func(FunctionCall) Value

	if  := .Argument(1);  != _undefined {
		, _ = .ToObject().self.assertCallable()
	}

	if  != nil {
		 := .NewObject()
		createDataPropertyOrThrow(, stringEmpty, )
		return .builtinJSON_reviveWalk(, , stringEmpty)
	}

	return 
}

func ( *Runtime) ( *json.Decoder,  json.Token) (Value, error) {
	switch tok := .(type) {
	case json.Delim:
		switch  {
		case '{':
			return .builtinJSON_decodeObject()
		case '[':
			return .builtinJSON_decodeArray()
		}
	case nil:
		return _null, nil
	case string:
		return newStringValue(), nil
	case float64:
		return floatToValue(), nil
	case bool:
		if  {
			return valueTrue, nil
		}
		return valueFalse, nil
	}
	return nil, fmt.Errorf("Unexpected token (%T): %v", , )
}

func ( *Runtime) ( *json.Decoder) (Value, error) {
	,  := .Token()
	if  != nil {
		return nil, 
	}
	return .builtinJSON_decodeToken(, )
}

func ( *Runtime) ( *json.Decoder) (*Object, error) {
	 := .NewObject()
	for {
		, ,  := .builtinJSON_decodeObjectKey()
		if  != nil {
			return nil, 
		}
		if  {
			break
		}
		,  := .builtinJSON_decodeValue()
		if  != nil {
			return nil, 
		}

		.self._putProp(unistring.NewFromString(), , true, true, true)
	}
	return , nil
}

func ( *Runtime) ( *json.Decoder) (string, bool, error) {
	,  := .Token()
	if  != nil {
		return "", false, 
	}
	switch tok := .(type) {
	case json.Delim:
		if  == '}' {
			return "", true, nil
		}
	case string:
		return , false, nil
	}

	return "", false, fmt.Errorf("Unexpected token (%T): %v", , )
}

func ( *Runtime) ( *json.Decoder) (*Object, error) {
	var  []Value
	for {
		,  := .Token()
		if  != nil {
			return nil, 
		}
		if ,  := .(json.Delim);  {
			if  == ']' {
				break
			}
		}
		,  := .builtinJSON_decodeToken(, )
		if  != nil {
			return nil, 
		}
		 = append(, )
	}
	return .newArrayValues(), nil
}

func ( *Runtime) ( func(FunctionCall) Value,  *Object,  Value) Value {
	 := nilSafe(.get(, nil))

	if ,  := .(*Object);  {
		if isArray() {
			 := toLength(.self.getStr("length", nil))
			for  := int64(0);  < ; ++ {
				 := asciiString(strconv.FormatInt(, 10))
				 := .(, , )
				if  == _undefined {
					.delete(, false)
				} else {
					createDataProperty(, , )
				}
			}
		} else {
			for ,  := range .self.stringKeys(false, nil) {
				 := .(, , )
				if  == _undefined {
					.self.deleteStr(.string(), false)
				} else {
					createDataProperty(, , )
				}
			}
		}
	}
	return (FunctionCall{
		This:      ,
		Arguments: []Value{, },
	})
}

type _builtinJSON_stringifyContext struct {
	r                *Runtime
	stack            []*Object
	propertyList     []Value
	replacerFunction func(FunctionCall) Value
	gap, indent      string
	buf              bytes.Buffer
	allAscii         bool
}

func ( *Runtime) ( FunctionCall) Value {
	 := _builtinJSON_stringifyContext{
		r:        ,
		allAscii: true,
	}

	,  := .Argument(1).(*Object)
	if  != nil {
		if isArray() {
			 := toLength(.self.getStr("length", nil))
			 := map[string]bool{}
			 := make([]Value, )
			 = 0
			for  := range  {
				var  string
				 := .self.getIdx(valueInt(int64()), nil)
				switch v := .(type) {
				case valueFloat, valueInt, String:
					 = .String()
				case *Object:
					switch .self.className() {
					case classNumber, classString:
						 = .String()
					default:
						continue
					}
				default:
					continue
				}
				if [] {
					continue
				}
				[] = true
				[] = newStringValue()
				 += 1
			}
			.propertyList = [0:]
		} else if ,  := .self.assertCallable();  {
			.replacerFunction = 
		}
	}
	if  := .Argument(2);  != _undefined {
		if ,  := .(*Object);  {
			switch oImpl := .self.(type) {
			case *primitiveValueObject:
				switch .pValue.(type) {
				case valueInt, valueFloat:
					 = .ToNumber()
				}
			case *stringObject:
				 = .ToString()
			}
		}
		 := false
		var  int64
		if ,  := .(valueInt);  {
			 = int64()
			 = true
		} else if ,  := .(valueFloat);  {
			 = int64()
			 = true
		}
		if  {
			if  > 0 {
				if  > 10 {
					 = 10
				}
				.gap = strings.Repeat(" ", int())
			}
		} else {
			if ,  := .(String);  {
				 := .String()
				if len() > 10 {
					.gap = [:10]
				} else {
					.gap = 
				}
			}
		}
	}

	if .do(.Argument(0)) {
		if .allAscii {
			return asciiString(.buf.String())
		} else {
			return &importedString{
				s: .buf.String(),
			}
		}
	}
	return _undefined
}

func ( *_builtinJSON_stringifyContext) ( Value) bool {
	 := .r.NewObject()
	createDataPropertyOrThrow(, stringEmpty, )
	return .str(stringEmpty, )
}

func ( *_builtinJSON_stringifyContext) ( Value,  *Object) bool {
	 := nilSafe(.get(, nil))

	switch .(type) {
	case *Object, *valueBigInt:
		if ,  := .r.getVStr(, "toJSON").(*Object);  {
			if ,  := .self.assertCallable();  {
				 = (FunctionCall{
					This:      ,
					Arguments: []Value{},
				})
			}
		}
	}

	if .replacerFunction != nil {
		 = .replacerFunction(FunctionCall{
			This:      ,
			Arguments: []Value{, },
		})
	}

	if ,  := .(*Object);  {
		switch o1 := .self.(type) {
		case *primitiveValueObject:
			switch pValue := .pValue.(type) {
			case valueInt, valueFloat:
				 = .ToNumber()
			default:
				 = 
			}
		case *stringObject:
			 = .toString()
		case *objectGoReflect:
			if .toJson != nil {
				 = .r.ToValue(.toJson())
			} else if ,  := .origValue.Interface().(json.Marshaler);  {
				,  := .MarshalJSON()
				if  != nil {
					panic(.r.NewGoError())
				}
				.buf.Write()
				.allAscii = false
				return true
			} else {
				switch .className() {
				case classNumber:
					 = .val.ordinaryToPrimitiveNumber()
				case classString:
					 = .val.ordinaryToPrimitiveString()
				case classBoolean:
					if .ToInteger() != 0 {
						 = valueTrue
					} else {
						 = valueFalse
					}
				}
				if .exportType() == typeBigInt {
					 = .val.ordinaryToPrimitiveNumber()
				}
			}
		}
	}

	switch value1 := .(type) {
	case valueBool:
		if  {
			.buf.WriteString("true")
		} else {
			.buf.WriteString("false")
		}
	case String:
		.quote()
	case valueInt:
		.buf.WriteString(.String())
	case valueFloat:
		if !math.IsNaN(float64()) && !math.IsInf(float64(), 0) {
			.buf.WriteString(.String())
		} else {
			.buf.WriteString("null")
		}
	case valueNull:
		.buf.WriteString("null")
	case *valueBigInt:
		.r.typeErrorResult(true, "Do not know how to serialize a BigInt")
	case *Object:
		for ,  := range .stack {
			if .SameAs() {
				.r.typeErrorResult(true, "Converting circular structure to JSON")
			}
		}
		.stack = append(.stack, )
		defer func() { .stack = .stack[:len(.stack)-1] }()
		if ,  := .self.assertCallable(); ! {
			if isArray() {
				.ja()
			} else {
				.jo()
			}
		} else {
			return false
		}
	default:
		return false
	}
	return true
}

func ( *_builtinJSON_stringifyContext) ( *Object) {
	var  string
	if .gap != "" {
		 = .indent
		.indent += .gap
	}
	 := toLength(.self.getStr("length", nil))
	if  == 0 {
		.buf.WriteString("[]")
		return
	}

	.buf.WriteByte('[')
	var  string
	if .gap != "" {
		.buf.WriteByte('\n')
		.buf.WriteString(.indent)
		 = ",\n" + .indent
	} else {
		 = ","
	}

	for  := int64(0);  < ; ++ {
		if !.str(asciiString(strconv.FormatInt(, 10)), ) {
			.buf.WriteString("null")
		}
		if  < -1 {
			.buf.WriteString()
		}
	}
	if .gap != "" {
		.buf.WriteByte('\n')
		.buf.WriteString()
		.indent = 
	}
	.buf.WriteByte(']')
}

func ( *_builtinJSON_stringifyContext) ( *Object) {
	var  string
	if .gap != "" {
		 = .indent
		.indent += .gap
	}

	.buf.WriteByte('{')
	 := .buf.Len()
	var  string
	if .gap != "" {
		.buf.WriteByte('\n')
		.buf.WriteString(.indent)
		 = ",\n" + .indent
	} else {
		 = ","
	}

	var  []Value
	if .propertyList == nil {
		 = .self.stringKeys(false, nil)
	} else {
		 = .propertyList
	}

	 := true
	for ,  := range  {
		 := .buf.Len()
		if ! {
			.buf.WriteString()
		}
		.quote(.toString())
		if .gap != "" {
			.buf.WriteString(": ")
		} else {
			.buf.WriteByte(':')
		}
		if .str(, ) {
			if  {
				 = false
			}
		} else {
			.buf.Truncate()
		}
	}

	if  {
		.buf.Truncate()
	} else {
		if .gap != "" {
			.buf.WriteByte('\n')
			.buf.WriteString()
			.indent = 
		}
	}
	.buf.WriteByte('}')
}

func ( *_builtinJSON_stringifyContext) ( String) {
	.buf.WriteByte('"')
	 := &lenientUtf16Decoder{utf16Reader: .utf16Reader()}
	for {
		, ,  := .ReadRune()
		if  != nil {
			break
		}
		switch  {
		case '"', '\\':
			.buf.WriteByte('\\')
			.buf.WriteByte(byte())
		case 0x08:
			.buf.WriteString(`\b`)
		case 0x09:
			.buf.WriteString(`\t`)
		case 0x0A:
			.buf.WriteString(`\n`)
		case 0x0C:
			.buf.WriteString(`\f`)
		case 0x0D:
			.buf.WriteString(`\r`)
		default:
			if  < 0x20 {
				.buf.WriteString(`\u00`)
				.buf.WriteByte(hex[>>4])
				.buf.WriteByte(hex[&0xF])
			} else {
				if utf16.IsSurrogate() {
					.buf.WriteString(`\u`)
					.buf.WriteByte(hex[>>12])
					.buf.WriteByte(hex[(>>8)&0xF])
					.buf.WriteByte(hex[(>>4)&0xF])
					.buf.WriteByte(hex[&0xF])
				} else {
					.buf.WriteRune()
					if .allAscii &&  >= utf8.RuneSelf {
						.allAscii = false
					}
				}
			}
		}
	}
	.buf.WriteByte('"')
}

func ( *Runtime) () *Object {
	 := .global.JSON
	if  == nil {
		 := .newBaseObject(.global.ObjectPrototype, classObject)
		 = .val
		.global.JSON = 
		._putProp("parse", .newNativeFunc(.builtinJSON_parse, "parse", 2), true, false, true)
		._putProp("stringify", .newNativeFunc(.builtinJSON_stringify, "stringify", 3), true, false, true)
		._putSym(SymToStringTag, valueProp(asciiString(classJSON), false, false, true))
	}
	return 
}