otto.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. /*
  2. Package otto is a JavaScript parser and interpreter written natively in Go.
  3. http://godoc.org/github.com/robertkrimen/otto
  4. import (
  5. "github.com/robertkrimen/otto"
  6. )
  7. Run something in the VM
  8. vm := otto.New()
  9. vm.Run(`
  10. abc = 2 + 2;
  11. console.log("The value of abc is " + abc); // 4
  12. `)
  13. Get a value out of the VM
  14. value, err := vm.Get("abc")
  15. value, _ := value.ToInteger()
  16. }
  17. Set a number
  18. vm.Set("def", 11)
  19. vm.Run(`
  20. console.log("The value of def is " + def);
  21. // The value of def is 11
  22. `)
  23. Set a string
  24. vm.Set("xyzzy", "Nothing happens.")
  25. vm.Run(`
  26. console.log(xyzzy.length); // 16
  27. `)
  28. Get the value of an expression
  29. value, _ = vm.Run("xyzzy.length")
  30. {
  31. // value is an int64 with a value of 16
  32. value, _ := value.ToInteger()
  33. }
  34. An error happens
  35. value, err = vm.Run("abcdefghijlmnopqrstuvwxyz.length")
  36. if err != nil {
  37. // err = ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined
  38. // If there is an error, then value.IsUndefined() is true
  39. ...
  40. }
  41. Set a Go function
  42. vm.Set("sayHello", func(call otto.FunctionCall) otto.Value {
  43. fmt.Printf("Hello, %s.\n", call.Argument(0).String())
  44. return otto.Value{}
  45. })
  46. Set a Go function that returns something useful
  47. vm.Set("twoPlus", func(call otto.FunctionCall) otto.Value {
  48. right, _ := call.Argument(0).ToInteger()
  49. result, _ := vm.ToValue(2 + right)
  50. return result
  51. })
  52. Use the functions in JavaScript
  53. result, _ = vm.Run(`
  54. sayHello("Xyzzy"); // Hello, Xyzzy.
  55. sayHello(); // Hello, undefined
  56. result = twoPlus(2.0); // 4
  57. `)
  58. Parser
  59. A separate parser is available in the parser package if you're just interested in building an AST.
  60. http://godoc.org/github.com/robertkrimen/otto/parser
  61. Parse and return an AST
  62. filename := "" // A filename is optional
  63. src := `
  64. // Sample xyzzy example
  65. (function(){
  66. if (3.14159 > 0) {
  67. console.log("Hello, World.");
  68. return;
  69. }
  70. var xyzzy = NaN;
  71. console.log("Nothing happens.");
  72. return xyzzy;
  73. })();
  74. `
  75. // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
  76. program, err := parser.ParseFile(nil, filename, src, 0)
  77. otto
  78. You can run (Go) JavaScript from the commandline with: http://github.com/robertkrimen/otto/tree/master/otto
  79. $ go get -v github.com/robertkrimen/otto/otto
  80. Run JavaScript by entering some source on stdin or by giving otto a filename:
  81. $ otto example.js
  82. underscore
  83. Optionally include the JavaScript utility-belt library, underscore, with this import:
  84. import (
  85. "github.com/robertkrimen/otto"
  86. _ "github.com/robertkrimen/otto/underscore"
  87. )
  88. // Now every otto runtime will come loaded with underscore
  89. For more information: http://github.com/robertkrimen/otto/tree/master/underscore
  90. Caveat Emptor
  91. The following are some limitations with otto:
  92. * "use strict" will parse, but does nothing.
  93. * The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification.
  94. * Otto targets ES5. ES6 features (eg: Typed Arrays) are not supported.
  95. Regular Expression Incompatibility
  96. Go translates JavaScript-style regular expressions into something that is "regexp" compatible via `parser.TransformRegExp`.
  97. Unfortunately, RegExp requires backtracking for some patterns, and backtracking is not supported by the standard Go engine: https://code.google.com/p/re2/wiki/Syntax
  98. Therefore, the following syntax is incompatible:
  99. (?=) // Lookahead (positive), currently a parsing error
  100. (?!) // Lookahead (backhead), currently a parsing error
  101. \1 // Backreference (\1, \2, \3, ...), currently a parsing error
  102. A brief discussion of these limitations: "Regexp (?!re)" https://groups.google.com/forum/?fromgroups=#%21topic/golang-nuts/7qgSDWPIh_E
  103. More information about re2: https://code.google.com/p/re2/
  104. In addition to the above, re2 (Go) has a different definition for \s: [\t\n\f\r ].
  105. The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc.
  106. Halting Problem
  107. If you want to stop long running executions (like third-party code), you can use the interrupt channel to do this:
  108. package main
  109. import (
  110. "errors"
  111. "fmt"
  112. "os"
  113. "time"
  114. "github.com/robertkrimen/otto"
  115. )
  116. var halt = errors.New("Stahp")
  117. func main() {
  118. runUnsafe(`var abc = [];`)
  119. runUnsafe(`
  120. while (true) {
  121. // Loop forever
  122. }`)
  123. }
  124. func runUnsafe(unsafe string) {
  125. start := time.Now()
  126. defer func() {
  127. duration := time.Since(start)
  128. if caught := recover(); caught != nil {
  129. if caught == halt {
  130. fmt.Fprintf(os.Stderr, "Some code took to long! Stopping after: %v\n", duration)
  131. return
  132. }
  133. panic(caught) // Something else happened, repanic!
  134. }
  135. fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration)
  136. }()
  137. vm := otto.New()
  138. vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking
  139. go func() {
  140. time.Sleep(2 * time.Second) // Stop after two seconds
  141. vm.Interrupt <- func() {
  142. panic(halt)
  143. }
  144. }()
  145. vm.Run(unsafe) // Here be dragons (risky code)
  146. }
  147. Where is setTimeout/setInterval?
  148. These timing functions are not actually part of the ECMA-262 specification. Typically, they belong to the `windows` object (in the browser).
  149. It would not be difficult to provide something like these via Go, but you probably want to wrap otto in an event loop in that case.
  150. For an example of how this could be done in Go with otto, see natto:
  151. http://github.com/robertkrimen/natto
  152. Here is some more discussion of the issue:
  153. * http://book.mixu.net/node/ch2.html
  154. * http://en.wikipedia.org/wiki/Reentrancy_%28computing%29
  155. * http://aaroncrane.co.uk/2009/02/perl_safe_signals/
  156. */
  157. package otto
  158. import (
  159. "fmt"
  160. "strings"
  161. "github.com/robertkrimen/otto/file"
  162. "github.com/robertkrimen/otto/registry"
  163. )
  164. // Otto is the representation of the JavaScript runtime. Each instance of Otto has a self-contained namespace.
  165. type Otto struct {
  166. // Interrupt is a channel for interrupting the runtime. You can use this to halt a long running execution, for example.
  167. // See "Halting Problem" for more information.
  168. Interrupt chan func()
  169. runtime *_runtime
  170. }
  171. // New will allocate a new JavaScript runtime
  172. func New() *Otto {
  173. self := &Otto{
  174. runtime: newContext(),
  175. }
  176. self.runtime.otto = self
  177. self.runtime.traceLimit = 10
  178. self.Set("console", self.runtime.newConsole())
  179. registry.Apply(func(entry registry.Entry) {
  180. self.Run(entry.Source())
  181. })
  182. return self
  183. }
  184. func (otto *Otto) clone() *Otto {
  185. self := &Otto{
  186. runtime: otto.runtime.clone(),
  187. }
  188. self.runtime.otto = self
  189. return self
  190. }
  191. // Run will allocate a new JavaScript runtime, run the given source
  192. // on the allocated runtime, and return the runtime, resulting value, and
  193. // error (if any).
  194. //
  195. // src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.
  196. //
  197. // src may also be a Script.
  198. //
  199. // src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.
  200. //
  201. func Run(src interface{}) (*Otto, Value, error) {
  202. otto := New()
  203. value, err := otto.Run(src) // This already does safety checking
  204. return otto, value, err
  205. }
  206. // Run will run the given source (parsing it first if necessary), returning the resulting value and error (if any)
  207. //
  208. // src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.
  209. //
  210. // If the runtime is unable to parse source, then this function will return undefined and the parse error (nothing
  211. // will be evaluated in this case).
  212. //
  213. // src may also be a Script.
  214. //
  215. // src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.
  216. //
  217. func (self Otto) Run(src interface{}) (Value, error) {
  218. value, err := self.runtime.cmpl_run(src, nil)
  219. if !value.safe() {
  220. value = Value{}
  221. }
  222. return value, err
  223. }
  224. // Eval will do the same thing as Run, except without leaving the current scope.
  225. //
  226. // By staying in the same scope, the code evaluated has access to everything
  227. // already defined in the current stack frame. This is most useful in, for
  228. // example, a debugger call.
  229. func (self Otto) Eval(src interface{}) (Value, error) {
  230. if self.runtime.scope == nil {
  231. self.runtime.enterGlobalScope()
  232. defer self.runtime.leaveScope()
  233. }
  234. value, err := self.runtime.cmpl_eval(src, nil)
  235. if !value.safe() {
  236. value = Value{}
  237. }
  238. return value, err
  239. }
  240. // Get the value of the top-level binding of the given name.
  241. //
  242. // If there is an error (like the binding does not exist), then the value
  243. // will be undefined.
  244. func (self Otto) Get(name string) (Value, error) {
  245. value := Value{}
  246. err := catchPanic(func() {
  247. value = self.getValue(name)
  248. })
  249. if !value.safe() {
  250. value = Value{}
  251. }
  252. return value, err
  253. }
  254. func (self Otto) getValue(name string) Value {
  255. return self.runtime.globalStash.getBinding(name, false)
  256. }
  257. // Set the top-level binding of the given name to the given value.
  258. //
  259. // Set will automatically apply ToValue to the given value in order
  260. // to convert it to a JavaScript value (type Value).
  261. //
  262. // If there is an error (like the binding is read-only, or the ToValue conversion
  263. // fails), then an error is returned.
  264. //
  265. // If the top-level binding does not exist, it will be created.
  266. func (self Otto) Set(name string, value interface{}) error {
  267. {
  268. value, err := self.ToValue(value)
  269. if err != nil {
  270. return err
  271. }
  272. err = catchPanic(func() {
  273. self.setValue(name, value)
  274. })
  275. return err
  276. }
  277. }
  278. func (self Otto) setValue(name string, value Value) {
  279. self.runtime.globalStash.setValue(name, value, false)
  280. }
  281. func (self Otto) SetDebuggerHandler(fn func(vm *Otto)) {
  282. self.runtime.debugger = fn
  283. }
  284. func (self Otto) SetRandomSource(fn func() float64) {
  285. self.runtime.random = fn
  286. }
  287. // SetStackDepthLimit sets an upper limit to the depth of the JavaScript
  288. // stack. In simpler terms, this limits the number of "nested" function calls
  289. // you can make in a particular interpreter instance.
  290. //
  291. // Note that this doesn't take into account the Go stack depth. If your
  292. // JavaScript makes a call to a Go function, otto won't keep track of what
  293. // happens outside the interpreter. So if your Go function is infinitely
  294. // recursive, you're still in trouble.
  295. func (self Otto) SetStackDepthLimit(limit int) {
  296. self.runtime.stackLimit = limit
  297. }
  298. // SetStackTraceLimit sets an upper limit to the number of stack frames that
  299. // otto will use when formatting an error's stack trace. By default, the limit
  300. // is 10. This is consistent with V8 and SpiderMonkey.
  301. //
  302. // TODO: expose via `Error.stackTraceLimit`
  303. func (self Otto) SetStackTraceLimit(limit int) {
  304. self.runtime.traceLimit = limit
  305. }
  306. // MakeCustomError creates a new Error object with the given name and message,
  307. // returning it as a Value.
  308. func (self Otto) MakeCustomError(name, message string) Value {
  309. return self.runtime.toValue(self.runtime.newError(name, self.runtime.toValue(message), 0))
  310. }
  311. // MakeRangeError creates a new RangeError object with the given message,
  312. // returning it as a Value.
  313. func (self Otto) MakeRangeError(message string) Value {
  314. return self.runtime.toValue(self.runtime.newRangeError(self.runtime.toValue(message)))
  315. }
  316. // MakeSyntaxError creates a new SyntaxError object with the given message,
  317. // returning it as a Value.
  318. func (self Otto) MakeSyntaxError(message string) Value {
  319. return self.runtime.toValue(self.runtime.newSyntaxError(self.runtime.toValue(message)))
  320. }
  321. // MakeTypeError creates a new TypeError object with the given message,
  322. // returning it as a Value.
  323. func (self Otto) MakeTypeError(message string) Value {
  324. return self.runtime.toValue(self.runtime.newTypeError(self.runtime.toValue(message)))
  325. }
  326. // Context is a structure that contains information about the current execution
  327. // context.
  328. type Context struct {
  329. Filename string
  330. Line int
  331. Column int
  332. Callee string
  333. Symbols map[string]Value
  334. This Value
  335. Stacktrace []string
  336. }
  337. // Context returns the current execution context of the vm, traversing up to
  338. // ten stack frames, and skipping any innermost native function stack frames.
  339. func (self Otto) Context() Context {
  340. return self.ContextSkip(10, true)
  341. }
  342. // ContextLimit returns the current execution context of the vm, with a
  343. // specific limit on the number of stack frames to traverse, skipping any
  344. // innermost native function stack frames.
  345. func (self Otto) ContextLimit(limit int) Context {
  346. return self.ContextSkip(limit, true)
  347. }
  348. // ContextSkip returns the current execution context of the vm, with a
  349. // specific limit on the number of stack frames to traverse, optionally
  350. // skipping any innermost native function stack frames.
  351. func (self Otto) ContextSkip(limit int, skipNative bool) (ctx Context) {
  352. // Ensure we are operating in a scope
  353. if self.runtime.scope == nil {
  354. self.runtime.enterGlobalScope()
  355. defer self.runtime.leaveScope()
  356. }
  357. scope := self.runtime.scope
  358. frame := scope.frame
  359. for skipNative && frame.native && scope.outer != nil {
  360. scope = scope.outer
  361. frame = scope.frame
  362. }
  363. // Get location information
  364. ctx.Filename = "<unknown>"
  365. ctx.Callee = frame.callee
  366. switch {
  367. case frame.native:
  368. ctx.Filename = frame.nativeFile
  369. ctx.Line = frame.nativeLine
  370. ctx.Column = 0
  371. case frame.file != nil:
  372. ctx.Filename = "<anonymous>"
  373. if p := frame.file.Position(file.Idx(frame.offset)); p != nil {
  374. ctx.Line = p.Line
  375. ctx.Column = p.Column
  376. if p.Filename != "" {
  377. ctx.Filename = p.Filename
  378. }
  379. }
  380. }
  381. // Get the current scope this Value
  382. ctx.This = toValue_object(scope.this)
  383. // Build stacktrace (up to 10 levels deep)
  384. ctx.Symbols = make(map[string]Value)
  385. ctx.Stacktrace = append(ctx.Stacktrace, frame.location())
  386. for limit != 0 {
  387. // Get variables
  388. stash := scope.lexical
  389. for {
  390. for _, name := range getStashProperties(stash) {
  391. if _, ok := ctx.Symbols[name]; !ok {
  392. ctx.Symbols[name] = stash.getBinding(name, true)
  393. }
  394. }
  395. stash = stash.outer()
  396. if stash == nil || stash.outer() == nil {
  397. break
  398. }
  399. }
  400. scope = scope.outer
  401. if scope == nil {
  402. break
  403. }
  404. if scope.frame.offset >= 0 {
  405. ctx.Stacktrace = append(ctx.Stacktrace, scope.frame.location())
  406. }
  407. limit--
  408. }
  409. return
  410. }
  411. // Call the given JavaScript with a given this and arguments.
  412. //
  413. // If this is nil, then some special handling takes place to determine the proper
  414. // this value, falling back to a "standard" invocation if necessary (where this is
  415. // undefined).
  416. //
  417. // If source begins with "new " (A lowercase new followed by a space), then
  418. // Call will invoke the function constructor rather than performing a function call.
  419. // In this case, the this argument has no effect.
  420. //
  421. // // value is a String object
  422. // value, _ := vm.Call("Object", nil, "Hello, World.")
  423. //
  424. // // Likewise...
  425. // value, _ := vm.Call("new Object", nil, "Hello, World.")
  426. //
  427. // // This will perform a concat on the given array and return the result
  428. // // value is [ 1, 2, 3, undefined, 4, 5, 6, 7, "abc" ]
  429. // value, _ := vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc")
  430. //
  431. func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error) {
  432. thisValue := Value{}
  433. construct := false
  434. if strings.HasPrefix(source, "new ") {
  435. source = source[4:]
  436. construct = true
  437. }
  438. // FIXME enterGlobalScope
  439. self.runtime.enterGlobalScope()
  440. defer func() {
  441. self.runtime.leaveScope()
  442. }()
  443. if !construct && this == nil {
  444. program, err := self.runtime.cmpl_parse("", source+"()", nil)
  445. if err == nil {
  446. if node, ok := program.body[0].(*_nodeExpressionStatement); ok {
  447. if node, ok := node.expression.(*_nodeCallExpression); ok {
  448. var value Value
  449. err := catchPanic(func() {
  450. value = self.runtime.cmpl_evaluate_nodeCallExpression(node, argumentList)
  451. })
  452. if err != nil {
  453. return Value{}, err
  454. }
  455. return value, nil
  456. }
  457. }
  458. }
  459. } else {
  460. value, err := self.ToValue(this)
  461. if err != nil {
  462. return Value{}, err
  463. }
  464. thisValue = value
  465. }
  466. {
  467. this := thisValue
  468. fn, err := self.Run(source)
  469. if err != nil {
  470. return Value{}, err
  471. }
  472. if construct {
  473. result, err := fn.constructSafe(self.runtime, this, argumentList...)
  474. if err != nil {
  475. return Value{}, err
  476. }
  477. return result, nil
  478. }
  479. result, err := fn.Call(this, argumentList...)
  480. if err != nil {
  481. return Value{}, err
  482. }
  483. return result, nil
  484. }
  485. }
  486. // Object will run the given source and return the result as an object.
  487. //
  488. // For example, accessing an existing object:
  489. //
  490. // object, _ := vm.Object(`Number`)
  491. //
  492. // Or, creating a new object:
  493. //
  494. // object, _ := vm.Object(`({ xyzzy: "Nothing happens." })`)
  495. //
  496. // Or, creating and assigning an object:
  497. //
  498. // object, _ := vm.Object(`xyzzy = {}`)
  499. // object.Set("volume", 11)
  500. //
  501. // If there is an error (like the source does not result in an object), then
  502. // nil and an error is returned.
  503. func (self Otto) Object(source string) (*Object, error) {
  504. value, err := self.runtime.cmpl_run(source, nil)
  505. if err != nil {
  506. return nil, err
  507. }
  508. if value.IsObject() {
  509. return value.Object(), nil
  510. }
  511. return nil, fmt.Errorf("value is not an object")
  512. }
  513. // ToValue will convert an interface{} value to a value digestible by otto/JavaScript.
  514. func (self Otto) ToValue(value interface{}) (Value, error) {
  515. return self.runtime.safeToValue(value)
  516. }
  517. // Copy will create a copy/clone of the runtime.
  518. //
  519. // Copy is useful for saving some time when creating many similar runtimes.
  520. //
  521. // This method works by walking the original runtime and cloning each object, scope, stash,
  522. // etc. into a new runtime.
  523. //
  524. // Be on the lookout for memory leaks or inadvertent sharing of resources.
  525. func (in *Otto) Copy() *Otto {
  526. out := &Otto{
  527. runtime: in.runtime.clone(),
  528. }
  529. out.runtime.otto = out
  530. return out
  531. }
  532. // Object{}
  533. // Object is the representation of a JavaScript object.
  534. type Object struct {
  535. object *_object
  536. value Value
  537. }
  538. func _newObject(object *_object, value Value) *Object {
  539. // value MUST contain object!
  540. return &Object{
  541. object: object,
  542. value: value,
  543. }
  544. }
  545. // Call a method on the object.
  546. //
  547. // It is essentially equivalent to:
  548. //
  549. // var method, _ := object.Get(name)
  550. // method.Call(object, argumentList...)
  551. //
  552. // An undefined value and an error will result if:
  553. //
  554. // 1. There is an error during conversion of the argument list
  555. // 2. The property is not actually a function
  556. // 3. An (uncaught) exception is thrown
  557. //
  558. func (self Object) Call(name string, argumentList ...interface{}) (Value, error) {
  559. // TODO: Insert an example using JavaScript below...
  560. // e.g., Object("JSON").Call("stringify", ...)
  561. function, err := self.Get(name)
  562. if err != nil {
  563. return Value{}, err
  564. }
  565. return function.Call(self.Value(), argumentList...)
  566. }
  567. // Value will return self as a value.
  568. func (self Object) Value() Value {
  569. return self.value
  570. }
  571. // Get the value of the property with the given name.
  572. func (self Object) Get(name string) (Value, error) {
  573. value := Value{}
  574. err := catchPanic(func() {
  575. value = self.object.get(name)
  576. })
  577. if !value.safe() {
  578. value = Value{}
  579. }
  580. return value, err
  581. }
  582. // Set the property of the given name to the given value.
  583. //
  584. // An error will result if the setting the property triggers an exception (i.e. read-only),
  585. // or there is an error during conversion of the given value.
  586. func (self Object) Set(name string, value interface{}) error {
  587. {
  588. value, err := self.object.runtime.safeToValue(value)
  589. if err != nil {
  590. return err
  591. }
  592. err = catchPanic(func() {
  593. self.object.put(name, value, true)
  594. })
  595. return err
  596. }
  597. }
  598. // Keys gets the keys for the given object.
  599. //
  600. // Equivalent to calling Object.keys on the object.
  601. func (self Object) Keys() []string {
  602. var keys []string
  603. self.object.enumerate(false, func(name string) bool {
  604. keys = append(keys, name)
  605. return true
  606. })
  607. return keys
  608. }
  609. // KeysByParent gets the keys (and those of the parents) for the given object,
  610. // in order of "closest" to "furthest".
  611. func (self Object) KeysByParent() [][]string {
  612. var a [][]string
  613. for o := self.object; o != nil; o = o.prototype {
  614. var l []string
  615. o.enumerate(false, func(name string) bool {
  616. l = append(l, name)
  617. return true
  618. })
  619. a = append(a, l)
  620. }
  621. return a
  622. }
  623. // Class will return the class string of the object.
  624. //
  625. // The return value will (generally) be one of:
  626. //
  627. // Object
  628. // Function
  629. // Array
  630. // String
  631. // Number
  632. // Boolean
  633. // Date
  634. // RegExp
  635. //
  636. func (self Object) Class() string {
  637. return self.object.class
  638. }