builtin_json.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package otto
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strings"
  7. )
  8. type _builtinJSON_parseContext struct {
  9. call FunctionCall
  10. reviver Value
  11. }
  12. func builtinJSON_parse(call FunctionCall) Value {
  13. ctx := _builtinJSON_parseContext{
  14. call: call,
  15. }
  16. revive := false
  17. if reviver := call.Argument(1); reviver.isCallable() {
  18. revive = true
  19. ctx.reviver = reviver
  20. }
  21. var root interface{}
  22. err := json.Unmarshal([]byte(call.Argument(0).string()), &root)
  23. if err != nil {
  24. panic(call.runtime.panicSyntaxError(err.Error()))
  25. }
  26. value, exists := builtinJSON_parseWalk(ctx, root)
  27. if !exists {
  28. value = Value{}
  29. }
  30. if revive {
  31. root := ctx.call.runtime.newObject()
  32. root.put("", value, false)
  33. return builtinJSON_reviveWalk(ctx, root, "")
  34. }
  35. return value
  36. }
  37. func builtinJSON_reviveWalk(ctx _builtinJSON_parseContext, holder *_object, name string) Value {
  38. value := holder.get(name)
  39. if object := value._object(); object != nil {
  40. if isArray(object) {
  41. length := int64(objectLength(object))
  42. for index := int64(0); index < length; index += 1 {
  43. name := arrayIndexToString(index)
  44. value := builtinJSON_reviveWalk(ctx, object, name)
  45. if value.IsUndefined() {
  46. object.delete(name, false)
  47. } else {
  48. object.defineProperty(name, value, 0111, false)
  49. }
  50. }
  51. } else {
  52. object.enumerate(false, func(name string) bool {
  53. value := builtinJSON_reviveWalk(ctx, object, name)
  54. if value.IsUndefined() {
  55. object.delete(name, false)
  56. } else {
  57. object.defineProperty(name, value, 0111, false)
  58. }
  59. return true
  60. })
  61. }
  62. }
  63. return ctx.reviver.call(ctx.call.runtime, toValue_object(holder), name, value)
  64. }
  65. func builtinJSON_parseWalk(ctx _builtinJSON_parseContext, rawValue interface{}) (Value, bool) {
  66. switch value := rawValue.(type) {
  67. case nil:
  68. return nullValue, true
  69. case bool:
  70. return toValue_bool(value), true
  71. case string:
  72. return toValue_string(value), true
  73. case float64:
  74. return toValue_float64(value), true
  75. case []interface{}:
  76. arrayValue := make([]Value, len(value))
  77. for index, rawValue := range value {
  78. if value, exists := builtinJSON_parseWalk(ctx, rawValue); exists {
  79. arrayValue[index] = value
  80. }
  81. }
  82. return toValue_object(ctx.call.runtime.newArrayOf(arrayValue)), true
  83. case map[string]interface{}:
  84. object := ctx.call.runtime.newObject()
  85. for name, rawValue := range value {
  86. if value, exists := builtinJSON_parseWalk(ctx, rawValue); exists {
  87. object.put(name, value, false)
  88. }
  89. }
  90. return toValue_object(object), true
  91. }
  92. return Value{}, false
  93. }
  94. type _builtinJSON_stringifyContext struct {
  95. call FunctionCall
  96. stack []*_object
  97. propertyList []string
  98. replacerFunction *Value
  99. gap string
  100. }
  101. func builtinJSON_stringify(call FunctionCall) Value {
  102. ctx := _builtinJSON_stringifyContext{
  103. call: call,
  104. stack: []*_object{nil},
  105. }
  106. replacer := call.Argument(1)._object()
  107. if replacer != nil {
  108. if isArray(replacer) {
  109. length := objectLength(replacer)
  110. seen := map[string]bool{}
  111. propertyList := make([]string, length)
  112. length = 0
  113. for index, _ := range propertyList {
  114. value := replacer.get(arrayIndexToString(int64(index)))
  115. switch value.kind {
  116. case valueObject:
  117. switch value.value.(*_object).class {
  118. case classString:
  119. case classNumber:
  120. default:
  121. continue
  122. }
  123. case valueString:
  124. case valueNumber:
  125. default:
  126. continue
  127. }
  128. name := value.string()
  129. if seen[name] {
  130. continue
  131. }
  132. seen[name] = true
  133. length += 1
  134. propertyList[index] = name
  135. }
  136. ctx.propertyList = propertyList[0:length]
  137. } else if replacer.class == classFunction {
  138. value := toValue_object(replacer)
  139. ctx.replacerFunction = &value
  140. }
  141. }
  142. if spaceValue, exists := call.getArgument(2); exists {
  143. if spaceValue.kind == valueObject {
  144. switch spaceValue.value.(*_object).class {
  145. case classString:
  146. spaceValue = toValue_string(spaceValue.string())
  147. case classNumber:
  148. spaceValue = spaceValue.numberValue()
  149. }
  150. }
  151. switch spaceValue.kind {
  152. case valueString:
  153. value := spaceValue.string()
  154. if len(value) > 10 {
  155. ctx.gap = value[0:10]
  156. } else {
  157. ctx.gap = value
  158. }
  159. case valueNumber:
  160. value := spaceValue.number().int64
  161. if value > 10 {
  162. value = 10
  163. } else if value < 0 {
  164. value = 0
  165. }
  166. ctx.gap = strings.Repeat(" ", int(value))
  167. }
  168. }
  169. holder := call.runtime.newObject()
  170. holder.put("", call.Argument(0), false)
  171. value, exists := builtinJSON_stringifyWalk(ctx, "", holder)
  172. if !exists {
  173. return Value{}
  174. }
  175. valueJSON, err := json.Marshal(value)
  176. if err != nil {
  177. panic(call.runtime.panicTypeError(err.Error()))
  178. }
  179. if ctx.gap != "" {
  180. valueJSON1 := bytes.Buffer{}
  181. json.Indent(&valueJSON1, valueJSON, "", ctx.gap)
  182. valueJSON = valueJSON1.Bytes()
  183. }
  184. return toValue_string(string(valueJSON))
  185. }
  186. func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, holder *_object) (interface{}, bool) {
  187. value := holder.get(key)
  188. if value.IsObject() {
  189. object := value._object()
  190. if toJSON := object.get("toJSON"); toJSON.IsFunction() {
  191. value = toJSON.call(ctx.call.runtime, value, key)
  192. } else {
  193. // If the object is a GoStruct or something that implements json.Marshaler
  194. if object.objectClass.marshalJSON != nil {
  195. marshaler := object.objectClass.marshalJSON(object)
  196. if marshaler != nil {
  197. return marshaler, true
  198. }
  199. }
  200. }
  201. }
  202. if ctx.replacerFunction != nil {
  203. value = ctx.replacerFunction.call(ctx.call.runtime, toValue_object(holder), key, value)
  204. }
  205. if value.kind == valueObject {
  206. switch value.value.(*_object).class {
  207. case classBoolean:
  208. value = value._object().value.(Value)
  209. case classString:
  210. value = toValue_string(value.string())
  211. case classNumber:
  212. value = value.numberValue()
  213. }
  214. }
  215. switch value.kind {
  216. case valueBoolean:
  217. return value.bool(), true
  218. case valueString:
  219. return value.string(), true
  220. case valueNumber:
  221. integer := value.number()
  222. switch integer.kind {
  223. case numberInteger:
  224. return integer.int64, true
  225. case numberFloat:
  226. return integer.float64, true
  227. default:
  228. return nil, true
  229. }
  230. case valueNull:
  231. return nil, true
  232. case valueObject:
  233. holder := value._object()
  234. if value := value._object(); nil != value {
  235. for _, object := range ctx.stack {
  236. if holder == object {
  237. panic(ctx.call.runtime.panicTypeError("Converting circular structure to JSON"))
  238. }
  239. }
  240. ctx.stack = append(ctx.stack, value)
  241. defer func() { ctx.stack = ctx.stack[:len(ctx.stack)-1] }()
  242. }
  243. if isArray(holder) {
  244. var length uint32
  245. switch value := holder.get(propertyLength).value.(type) {
  246. case uint32:
  247. length = value
  248. case int:
  249. if value >= 0 {
  250. length = uint32(value)
  251. }
  252. default:
  253. panic(ctx.call.runtime.panicTypeError(fmt.Sprintf("JSON.stringify: invalid length: %v (%[1]T)", value)))
  254. }
  255. array := make([]interface{}, length)
  256. for index, _ := range array {
  257. name := arrayIndexToString(int64(index))
  258. value, _ := builtinJSON_stringifyWalk(ctx, name, holder)
  259. array[index] = value
  260. }
  261. return array, true
  262. } else if holder.class != classFunction {
  263. object := map[string]interface{}{}
  264. if ctx.propertyList != nil {
  265. for _, name := range ctx.propertyList {
  266. value, exists := builtinJSON_stringifyWalk(ctx, name, holder)
  267. if exists {
  268. object[name] = value
  269. }
  270. }
  271. } else {
  272. // Go maps are without order, so this doesn't conform to the ECMA ordering
  273. // standard, but oh well...
  274. holder.enumerate(false, func(name string) bool {
  275. value, exists := builtinJSON_stringifyWalk(ctx, name, holder)
  276. if exists {
  277. object[name] = value
  278. }
  279. return true
  280. })
  281. }
  282. return object, true
  283. }
  284. }
  285. return nil, false
  286. }