MCPcopy Index your code
hub / github.com/robertkrimen/otto

github.com/robertkrimen/otto @v0.5.1 sqlite

repository ↗ · DeepWiki ↗ · release v0.5.1 ↗
2,094 symbols 8,367 edges 135 files 589 documented · 28% 5 cross-repo links
README

otto

GoDoc Reference

Basic Usage

Package otto is a JavaScript parser and interpreter written natively in Go.

To use import it with the following:

import (
   "github.com/robertkrimen/otto"
)

Run something in the VM

vm := otto.New()
vm.Run(`
    abc = 2 + 2;
    console.log("The value of abc is " + abc); // 4
`)

Get a value out of the VM

if value, err := vm.Get("abc"); err == nil {
    if value_int, err := value.ToInteger(); err == nil {
        fmt.Printf("", value_int, err)
    }
}

Set a number

vm.Set("def", 11)
vm.Run(`
    console.log("The value of def is " + def);
    // The value of def is 11
`)

Set a string

vm.Set("xyzzy", "Nothing happens.")
vm.Run(`
    console.log(xyzzy.length); // 16
`)

Get the value of an expression

value, _ = vm.Run("xyzzy.length")
{
    // value is an int64 with a value of 16
    value, _ := value.ToInteger()
}

An error happens

value, err = vm.Run("abcdefghijlmnopqrstuvwxyz.length")
if err != nil {
    // err = ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined
    // If there is an error, then value.IsUndefined() is true
    ...
}

Set a Go function

vm.Set("sayHello", func(call otto.FunctionCall) otto.Value {
    fmt.Printf("Hello, %s.\n", call.Argument(0).String())
    return otto.Value{}
})

Set a Go function that returns something useful

vm.Set("twoPlus", func(call otto.FunctionCall) otto.Value {
    right, _ := call.Argument(0).ToInteger()
    result, _ := vm.ToValue(2 + right)
    return result
})

Use the functions in JavaScript

result, _ = vm.Run(`
    sayHello("Xyzzy");      // Hello, Xyzzy.
    sayHello();             // Hello, undefined

    result = twoPlus(2.0); // 4
`)

Parser

A separate parser is available in the parser package if you're just interested in building an AST.

GoDoc Reference

Parse and return an AST

filename := "" // A filename is optional
src := `
    // Sample xyzzy example
    (function(){
        if (3.14159 > 0) {
            console.log("Hello, World.");
            return;
        }

        var xyzzy = NaN;
        console.log("Nothing happens.");
        return xyzzy;
    })();
`

// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, filename, src, 0)

Setup

You can run (Go) JavaScript from the command line with otto.

go install github.com/robertkrimen/otto/otto@latest

Run JavaScript by entering some source on stdin or by giving otto a filename:

otto example.js

Underscore

Optionally include the JavaScript utility-belt library, underscore, with this import:

import (
    "github.com/robertkrimen/otto"
    _ "github.com/robertkrimen/otto/underscore"
)

// Now every otto runtime will come loaded with underscore

For more information: underscore

Caveat Emptor

The following are some limitations with otto:

  • use strict will parse, but does nothing.
  • The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification.
  • Otto targets ES5. Some ES6 features e.g. Typed Arrays are not supported, PR's to add functionality are always welcome.

Regular Expression Incompatibility

Go translates JavaScript-style regular expressions into something that is "regexp" compatible via parser.TransformRegExp. Unfortunately, RegExp requires backtracking for some patterns, and backtracking is not supported by Go re2.

Therefore, the following syntax is incompatible:

(?=)  // Lookahead (positive), currently a parsing error
(?!)  // Lookahead (backhead), currently a parsing error
\1    // Backreference (\1, \2, \3, ...), currently a parsing error

A brief discussion of these limitations: Regexp (?!re)

More information about re2

In addition to the above, re2 (Go) has a different definition for \s: [\t\n\f\r ]. The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc.

Halting Problem

If you want to stop long running executions (like third-party code), you can use the interrupt channel to do this:

package main

import (
    "errors"
    "fmt"
    "os"
    "time"

    "github.com/robertkrimen/otto"
)

var halt = errors.New("Stahp")

func main() {
    runUnsafe(`var abc = [];`)
    runUnsafe(`
    while (true) {
        // Loop forever
    }`)
}

func runUnsafe(unsafe string) {
    start := time.Now()
    defer func() {
        duration := time.Since(start)
        if caught := recover(); caught != nil {
            if caught == halt {
                fmt.Fprintf(os.Stderr, "Some code took to long! Stopping after: %v\n", duration)
                return
            }
            panic(caught) // Something else happened, repanic!
        }
        fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration)
    }()

    vm := otto.New()
    vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking
    watchdogCleanup := make(chan struct{})
    defer close(watchdogCleanup)

    go func() {
        select {
        case <-time.After(2 * time.Second): // Stop after two seconds
            vm.Interrupt <- func() {
                panic(halt)
            }
        case <-watchdogCleanup:
        }
        close(vm.Interrupt)
    }()

    vm.Run(unsafe) // Here be dragons (risky code)
}

Where is setTimeout / setInterval?

These timing functions are not actually part of the ECMA-262 specification. Typically, they belong to the window object (in the browser). 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.

For an example of how this could be done in Go with otto, see natto.

Here is some more discussion of the issue:

Usage

var ErrVersion = errors.New("version mismatch")

type Error

type Error struct {}

An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc.

func (Error) Error

func (err Error) Error() string

Error returns a description of the error

    TypeError: 'def' is not a function

func (Error) String

func (err Error) String() string

String returns a description of the error and a trace of where the error occurred.

    TypeError: 'def' is not a function
        at xyz (<anonymous>:3:9)
        at <anonymous>:7:1/

type FunctionCall

type FunctionCall struct {
    This         Value
    ArgumentList []Value
    Otto         *Otto
}

FunctionCall is an encapsulation of a JavaScript function call.

func (FunctionCall) Argument

func (self FunctionCall) Argument(index int) Value

Argument will return the value of the argument at the given index.

If no such argument exists, undefined is returned.

type Object

type Object struct {}

Object is the representation of a JavaScript object.

func (Object) Call

func (self Object) Call(name string, argumentList ...interface{}) (Value, error)

Call a method on the object.

It is essentially equivalent to:

var method, _ := object.Get(name)
method.Call(object, argumentList...)

An undefined value and an error will result if:

  1. There is an error during conversion of the argument list
  2. The property is not actually a function
  3. An (uncaught) exception is thrown

func (Object) Class

func (self Object) Class() string

Class will return the class string of the object.

The return value will (generally) be one of:

    Object
    Function
    Array
    String
    Number
    Boolean
    Date
    RegExp

func (Object) Get

func (self Object) Get(name string) (Value, error)

Get the value of the property with the given name.

func (Object) Keys

func (self Object) Keys() []string

Get the keys for the object

Equivalent to calling Object.keys on the object

func (Object) Set

func (self Object) Set(name string, value interface{}) error

Set the property of the given name to the given value.

An error will result if the setting the property triggers an exception (i.e. read-only), or there is an error during conversion of the given value.

func (Object) Value

func (self Object) Value() Value

Value will return self as a value.

type Otto

type Otto struct {
    // Interrupt is a channel for interrupting the runtime. You can use this to halt a long running execution, for example.
    // See "Halting Problem" for more information.
    Interrupt chan func()
}

Otto is the representation of the JavaScript runtime. Each instance of Otto has a self-contained namespace.

func New

func New() *Otto

New will allocate a new JavaScript runtime

func Run

func Run(src interface{}) (*Otto, Value, error)

Run will allocate a new JavaScript runtime, run the given source on the allocated runtime, and return the runtime, resulting value, and error (if any).

src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.

src may also be a Script.

src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.

func (Otto) Call

func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error)

Call the given JavaScript with a given this and arguments.

If this is nil, then some special handling takes place to determine the proper this value, falling back to a "standard" invocation if necessary (where this is undefined).

If source begins with "new " (A lowercase new followed by a space), then Call will invoke the function constructor rather than performing a function call. In this case, the this argument has no effect.

// value is a String object
value, _ := vm.Call("Object", nil, "Hello, World.")

// Likewise...
value, _ := vm.Call("new Object", nil, "Hello, World.")

// This will perform a concat on the given array and return the result
// value is [ 1, 2, 3, undefined, 4, 5, 6, 7, "abc" ]
value, _ := vm.Call(`[ 1, 2, 3, undefined, 4 ].concat`, nil, 5, 6, 7, "abc")

func (*Otto) Compile

func (self *Otto) Compile(filename string, src interface{}) (*Script, error)

Compile will parse the given source and return a Script value or nil and an error if there was a problem during compilation.

script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`)
vm.Run(script)

func (*Otto) Copy

func (in *Otto) Copy() *Otto

Copy will create a copy/clone of the runtime.

Copy is useful for saving some time when creating many similar runtimes.

This method works by walking the original runtime and cloning each object, scope, stash, etc. into a new runtime.

Be on the lookout for memory leaks or inadvertent sharing of resources.

func (Otto) Get

func (self Otto) Get(name string) (Value, error)

Get the value of the top-level binding of the given name.

If there is an error (like the binding does not exist), then the value will be undefined.

func (Otto) Object

func (self Otto) Object(source string) (*Object, error)

Object will run the given source and return the result as an object.

For example, accessing an existing object:

object, _ := vm.Object(`Number`)

Or, creating a new object:

object, _ := vm.Object(`({ xyzzy: "Nothing happens." })`)

Or, creating and assigning an object:

object, _ := vm.Object(`xyzzy = {}`)
object.Set("volume", 11)

If there is an error (like the source does not result in an object), then nil and an error is returned.

func (Otto) Run

func (self Otto) Run(src interface{}) (Value, error)

Run will run the given source (parsing it first if necessary), returning the resulting value and error (if any)

src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.

If the runtime is unable to parse source, then this function will return undefined and the parse error (nothing will be evaluated in this case).

src may also be a Script.

src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.

func (Otto) Set

func (self Otto) Set(name string, value interface{}) error

Set the top-level binding of the given name to the given value.

Set will automatically apply ToValue to the given value in order to convert it to a JavaScript value (type Value).

If there is an error (like the binding is read-only, or the ToValue conversion fails), then an error is returned.

If the top-level binding does not exist, it will be created.

func (Otto) ToValue

func (self Otto) ToValue(value interface{}) (Value, error)

ToValue will convert an interface{} value to a value digestible by otto/JavaScript.

type Script

type Script struct {}

Script is a handle for some (reusable) JavaScript. Passing a Script value to a run method will evaluate the JavaScript.

func (*Script) St

Extension points exported contracts — how you extend this code

Node (Interface)
Node is implemented by types that represent a node. [44 implementers]
ast/node.go
Visitor (Interface)
Visitor Enter method is invoked for each node encountered by Walk. If the result visitor w is not nil, Walk visits each [2 …
ast/walk.go
Parser (Interface)
Parser is implemented by types which can parse JavaScript Code. [1 implementers]
parser/parser.go
DbgFunction (FuncType)
(no doc)
dbg/dbg.go
Expression (Interface)
Expression is implemented by types that represent an Expression. [22 implementers]
ast/node.go
Statement (Interface)
Statement is implemented by types which represent a statement. [21 implementers]
ast/node.go
Declaration (Interface)
Declaration is implemented by type which represent declarations. [2 implementers]
ast/node.go

Core symbols most depended-on inside this repo

Run
called by 264
otto.go
Set
called by 215
otto.go
New
called by 166
otto.go
Size
called by 165
ast/comments.go
Argument
called by 140
type_function.go
get
called by 116
object.go
Compile
called by 112
script.go
stringValue
called by 108
inline.go

Shape

Function 1,129
Method 746
Struct 182
TypeAlias 21
Interface 13
FuncType 3

Languages

Go97%
TypeScript3%

Modules by API surface

ast/node.go190 symbols
call_test.go93 symbols
cmpl_parse.go83 symbols
underscore/underscore-min.js72 symbols
value.go58 symbols
issue_test.go57 symbols
otto_test.go52 symbols
builtin_date.go52 symbols
reflect_test.go47 symbols
terst/terst.go40 symbols
stash.go40 symbols
runtime_test.go35 symbols

Dependencies from manifests, versioned

github.com/chzyer/testv1.0.0 · 1×
github.com/pmezard/go-difflibv1.0.0 · 1×
golang.org/x/textv0.4.0 · 1×
gopkg.in/readline.v1v1.0.0-2016072613511 · 1×
gopkg.in/sourcemap.v1v1.0.5 · 1×
gopkg.in/yaml.v3v3.0.1 · 1×

For agents

$ claude mcp add otto \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact