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