Add compilation (Script, vm.Compile, etc.)

This commit is contained in:
Robert Krimen
2014-04-11 18:35:43 -07:00
parent 7163cd7841
commit ddca88af9b
7 changed files with 104 additions and 7 deletions

View File

@@ -392,6 +392,17 @@ this case, the this argument has no effect.
// 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
```go
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
```go
@@ -479,6 +490,22 @@ func (self Otto) ToValue(value interface{}) (Value, error)
ToValue will convert an interface{} value to a value digestible by
otto/JavaScript.
#### type Script
```go
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) String
```go
func (self *Script) String() string
```
#### type Value
```go

View File

@@ -357,7 +357,7 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface
}
if !construct && this == nil {
program, err := self.runtime.parse(source + "()")
program, err := self.runtime.parse("", source+"()")
if err == nil {
if node, ok := program.Body[0].(*ast.ExpressionStatement); ok {
if node, ok := node.Expression.(*ast.CallExpression); ok {

View File

@@ -1381,6 +1381,21 @@ func TestOttoRun(t *testing.T) {
Is(err, nil)
is(value, 12)
}
{
script, err := vm.Compile("", `var abc; if (!abc) abc = 0; abc += 2; abc;`)
Is(err, nil)
value, err = vm.Run(script)
Is(err, nil)
is(value, 14)
value, err = vm.Run(script)
Is(err, nil)
is(value, 16)
Is(script.String(), "// \nvar abc; if (!abc) abc = 0; abc += 2; abc;")
}
}
func Test_objectLength(t *testing.T) {

View File

@@ -65,6 +65,12 @@ the corresponding ast.FunctionExpression node.
The parameter list, if any, should be a comma-separated list of identifiers.
#### func ReadSource
```go
func ReadSource(filename string, src interface{}) ([]byte, error)
```
#### func TransformRegExp
```go

View File

@@ -93,7 +93,7 @@ func newParser(filename, src string) *_parser {
return _newParser(filename, src, 1)
}
func readSource(filename string, src interface{}) ([]byte, error) {
func ReadSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch src := src.(type) {
case string:
@@ -130,7 +130,7 @@ func readSource(filename string, src interface{}) ([]byte, error) {
// program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0)
//
func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error) {
str, err := readSource(filename, src)
str, err := ReadSource(filename, src)
if err != nil {
return nil, err
}

View File

@@ -398,16 +398,18 @@ func (runtime *_runtime) newGoArray(value reflect.Value) *_object {
return self
}
func (runtime *_runtime) parse(src interface{}) (*ast.Program, error) {
return parser.ParseFile(nil, "", src, 0)
func (runtime *_runtime) parse(filename string, src interface{}) (*ast.Program, error) {
return parser.ParseFile(nil, filename, src, 0)
}
func (self *_runtime) parseSource(src interface{}) (ast.Node, error) {
switch src := src.(type) {
case ast.Node:
return src, nil
case *Script:
return src.program, nil
}
return self.parse(src)
return self.parse("", src)
}
func (self *_runtime) run(src interface{}) (Value, error) {
@@ -446,7 +448,7 @@ func (self *_runtime) parseThrow(err error) {
}
func (self *_runtime) parseOrThrow(source string) *ast.Program {
program, err := self.parse(source)
program, err := self.parse("", source)
self.parseThrow(err) // Will panic/throw appropriately
return program
}

47
script.go Normal file
View File

@@ -0,0 +1,47 @@
package otto
import (
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/parser"
)
// Script is a handle for some (reusable) JavaScript.
// Passing a Script value to a run method will evaluate the JavaScript.
//
type Script struct {
program *ast.Program
filename string
src string
}
// 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 (self *Otto) Compile(filename string, src interface{}) (*Script, error) {
{
src, err := parser.ReadSource(filename, src)
if err != nil {
return nil, err
}
program, err := self.runtime.parse(filename, src)
if err != nil {
return nil, err
}
script := &Script{
program: program,
filename: filename,
src: string(src),
}
return script, nil
}
}
func (self *Script) String() string {
return "// " + self.filename + "\n" + self.src
}