Merge pull request #536 from zsfelfoldi/develop
using robertkrimen/otto, godeps updated
This commit is contained in:
		
						commit
						3133372a6a
					
				
							
								
								
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							| @ -47,8 +47,8 @@ | ||||
| 			"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/obscuren/otto", | ||||
| 			"Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19" | ||||
| 			"ImportPath": "github.com/robertkrimen/otto", | ||||
| 			"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/obscuren/qml", | ||||
|  | ||||
							
								
								
									
										1066
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/ast/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1066
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/ast/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										496
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/ast/node.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										496
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/ast/node.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,496 +0,0 @@ | ||||
| /* | ||||
| Package ast declares types representing a JavaScript AST. | ||||
| 
 | ||||
| Warning | ||||
| 
 | ||||
| The parser and AST interfaces are still works-in-progress (particularly where | ||||
| node types are concerned) and may change in the future. | ||||
| 
 | ||||
| */ | ||||
| package ast | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| // All nodes implement the Node interface.
 | ||||
| type Node interface { | ||||
| 	Idx0() file.Idx // The index of the first character belonging to the node
 | ||||
| 	Idx1() file.Idx // The index of the first character immediately after the node
 | ||||
| } | ||||
| 
 | ||||
| // ========== //
 | ||||
| // Expression //
 | ||||
| // ========== //
 | ||||
| 
 | ||||
| type ( | ||||
| 	// All expression nodes implement the Expression interface.
 | ||||
| 	Expression interface { | ||||
| 		Node | ||||
| 		_expressionNode() | ||||
| 	} | ||||
| 
 | ||||
| 	ArrayLiteral struct { | ||||
| 		LeftBracket  file.Idx | ||||
| 		RightBracket file.Idx | ||||
| 		Value        []Expression | ||||
| 	} | ||||
| 
 | ||||
| 	AssignExpression struct { | ||||
| 		Operator token.Token | ||||
| 		Left     Expression | ||||
| 		Right    Expression | ||||
| 	} | ||||
| 
 | ||||
| 	BadExpression struct { | ||||
| 		From file.Idx | ||||
| 		To   file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	BinaryExpression struct { | ||||
| 		Operator   token.Token | ||||
| 		Left       Expression | ||||
| 		Right      Expression | ||||
| 		Comparison bool | ||||
| 	} | ||||
| 
 | ||||
| 	BooleanLiteral struct { | ||||
| 		Idx     file.Idx | ||||
| 		Literal string | ||||
| 		Value   bool | ||||
| 	} | ||||
| 
 | ||||
| 	BracketExpression struct { | ||||
| 		Left         Expression | ||||
| 		Member       Expression | ||||
| 		LeftBracket  file.Idx | ||||
| 		RightBracket file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	CallExpression struct { | ||||
| 		Callee           Expression | ||||
| 		LeftParenthesis  file.Idx | ||||
| 		ArgumentList     []Expression | ||||
| 		RightParenthesis file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	ConditionalExpression struct { | ||||
| 		Test       Expression | ||||
| 		Consequent Expression | ||||
| 		Alternate  Expression | ||||
| 	} | ||||
| 
 | ||||
| 	DotExpression struct { | ||||
| 		Left       Expression | ||||
| 		Identifier Identifier | ||||
| 	} | ||||
| 
 | ||||
| 	FunctionLiteral struct { | ||||
| 		Function      file.Idx | ||||
| 		Name          *Identifier | ||||
| 		ParameterList *ParameterList | ||||
| 		Body          Statement | ||||
| 		Source        string | ||||
| 
 | ||||
| 		DeclarationList []Declaration | ||||
| 	} | ||||
| 
 | ||||
| 	Identifier struct { | ||||
| 		Name string | ||||
| 		Idx  file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	NewExpression struct { | ||||
| 		New              file.Idx | ||||
| 		Callee           Expression | ||||
| 		LeftParenthesis  file.Idx | ||||
| 		ArgumentList     []Expression | ||||
| 		RightParenthesis file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	NullLiteral struct { | ||||
| 		Idx     file.Idx | ||||
| 		Literal string | ||||
| 	} | ||||
| 
 | ||||
| 	NumberLiteral struct { | ||||
| 		Idx     file.Idx | ||||
| 		Literal string | ||||
| 		Value   interface{} | ||||
| 	} | ||||
| 
 | ||||
| 	ObjectLiteral struct { | ||||
| 		LeftBrace  file.Idx | ||||
| 		RightBrace file.Idx | ||||
| 		Value      []Property | ||||
| 	} | ||||
| 
 | ||||
| 	ParameterList struct { | ||||
| 		Opening file.Idx | ||||
| 		List    []*Identifier | ||||
| 		Closing file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	Property struct { | ||||
| 		Key   string | ||||
| 		Kind  string | ||||
| 		Value Expression | ||||
| 	} | ||||
| 
 | ||||
| 	RegExpLiteral struct { | ||||
| 		Idx     file.Idx | ||||
| 		Literal string | ||||
| 		Pattern string | ||||
| 		Flags   string | ||||
| 		Value   string | ||||
| 	} | ||||
| 
 | ||||
| 	SequenceExpression struct { | ||||
| 		Sequence []Expression | ||||
| 	} | ||||
| 
 | ||||
| 	StringLiteral struct { | ||||
| 		Idx     file.Idx | ||||
| 		Literal string | ||||
| 		Value   string | ||||
| 	} | ||||
| 
 | ||||
| 	ThisExpression struct { | ||||
| 		Idx file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	UnaryExpression struct { | ||||
| 		Operator token.Token | ||||
| 		Idx      file.Idx // If a prefix operation
 | ||||
| 		Operand  Expression | ||||
| 		Postfix  bool | ||||
| 	} | ||||
| 
 | ||||
| 	VariableExpression struct { | ||||
| 		Name        string | ||||
| 		Idx         file.Idx | ||||
| 		Initializer Expression | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // _expressionNode
 | ||||
| 
 | ||||
| func (*ArrayLiteral) _expressionNode()          {} | ||||
| func (*AssignExpression) _expressionNode()      {} | ||||
| func (*BadExpression) _expressionNode()         {} | ||||
| func (*BinaryExpression) _expressionNode()      {} | ||||
| func (*BooleanLiteral) _expressionNode()        {} | ||||
| func (*BracketExpression) _expressionNode()     {} | ||||
| func (*CallExpression) _expressionNode()        {} | ||||
| func (*ConditionalExpression) _expressionNode() {} | ||||
| func (*DotExpression) _expressionNode()         {} | ||||
| func (*FunctionLiteral) _expressionNode()       {} | ||||
| func (*Identifier) _expressionNode()            {} | ||||
| func (*NewExpression) _expressionNode()         {} | ||||
| func (*NullLiteral) _expressionNode()           {} | ||||
| func (*NumberLiteral) _expressionNode()         {} | ||||
| func (*ObjectLiteral) _expressionNode()         {} | ||||
| func (*RegExpLiteral) _expressionNode()         {} | ||||
| func (*SequenceExpression) _expressionNode()    {} | ||||
| func (*StringLiteral) _expressionNode()         {} | ||||
| func (*ThisExpression) _expressionNode()        {} | ||||
| func (*UnaryExpression) _expressionNode()       {} | ||||
| func (*VariableExpression) _expressionNode()    {} | ||||
| 
 | ||||
| // ========= //
 | ||||
| // Statement //
 | ||||
| // ========= //
 | ||||
| 
 | ||||
| type ( | ||||
| 	// All statement nodes implement the Statement interface.
 | ||||
| 	Statement interface { | ||||
| 		Node | ||||
| 		_statementNode() | ||||
| 	} | ||||
| 
 | ||||
| 	BadStatement struct { | ||||
| 		From file.Idx | ||||
| 		To   file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	BlockStatement struct { | ||||
| 		LeftBrace  file.Idx | ||||
| 		List       []Statement | ||||
| 		RightBrace file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	BranchStatement struct { | ||||
| 		Idx   file.Idx | ||||
| 		Token token.Token | ||||
| 		Label *Identifier | ||||
| 	} | ||||
| 
 | ||||
| 	CaseStatement struct { | ||||
| 		Case       file.Idx | ||||
| 		Test       Expression | ||||
| 		Consequent []Statement | ||||
| 	} | ||||
| 
 | ||||
| 	CatchStatement struct { | ||||
| 		Catch     file.Idx | ||||
| 		Parameter *Identifier | ||||
| 		Body      Statement | ||||
| 	} | ||||
| 
 | ||||
| 	DebuggerStatement struct { | ||||
| 		Debugger file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	DoWhileStatement struct { | ||||
| 		Do   file.Idx | ||||
| 		Test Expression | ||||
| 		Body Statement | ||||
| 	} | ||||
| 
 | ||||
| 	EmptyStatement struct { | ||||
| 		Semicolon file.Idx | ||||
| 	} | ||||
| 
 | ||||
| 	ExpressionStatement struct { | ||||
| 		Expression Expression | ||||
| 	} | ||||
| 
 | ||||
| 	ForInStatement struct { | ||||
| 		For    file.Idx | ||||
| 		Into   Expression | ||||
| 		Source Expression | ||||
| 		Body   Statement | ||||
| 	} | ||||
| 
 | ||||
| 	ForStatement struct { | ||||
| 		For         file.Idx | ||||
| 		Initializer Expression | ||||
| 		Update      Expression | ||||
| 		Test        Expression | ||||
| 		Body        Statement | ||||
| 	} | ||||
| 
 | ||||
| 	IfStatement struct { | ||||
| 		If         file.Idx | ||||
| 		Test       Expression | ||||
| 		Consequent Statement | ||||
| 		Alternate  Statement | ||||
| 	} | ||||
| 
 | ||||
| 	LabelledStatement struct { | ||||
| 		Label     *Identifier | ||||
| 		Colon     file.Idx | ||||
| 		Statement Statement | ||||
| 	} | ||||
| 
 | ||||
| 	ReturnStatement struct { | ||||
| 		Return   file.Idx | ||||
| 		Argument Expression | ||||
| 	} | ||||
| 
 | ||||
| 	SwitchStatement struct { | ||||
| 		Switch       file.Idx | ||||
| 		Discriminant Expression | ||||
| 		Default      int | ||||
| 		Body         []*CaseStatement | ||||
| 	} | ||||
| 
 | ||||
| 	ThrowStatement struct { | ||||
| 		Throw    file.Idx | ||||
| 		Argument Expression | ||||
| 	} | ||||
| 
 | ||||
| 	TryStatement struct { | ||||
| 		Try     file.Idx | ||||
| 		Body    Statement | ||||
| 		Catch   *CatchStatement | ||||
| 		Finally Statement | ||||
| 	} | ||||
| 
 | ||||
| 	VariableStatement struct { | ||||
| 		Var  file.Idx | ||||
| 		List []Expression | ||||
| 	} | ||||
| 
 | ||||
| 	WhileStatement struct { | ||||
| 		While file.Idx | ||||
| 		Test  Expression | ||||
| 		Body  Statement | ||||
| 	} | ||||
| 
 | ||||
| 	WithStatement struct { | ||||
| 		With   file.Idx | ||||
| 		Object Expression | ||||
| 		Body   Statement | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // _statementNode
 | ||||
| 
 | ||||
| func (*BadStatement) _statementNode()        {} | ||||
| func (*BlockStatement) _statementNode()      {} | ||||
| func (*BranchStatement) _statementNode()     {} | ||||
| func (*CaseStatement) _statementNode()       {} | ||||
| func (*CatchStatement) _statementNode()      {} | ||||
| func (*DebuggerStatement) _statementNode()   {} | ||||
| func (*DoWhileStatement) _statementNode()    {} | ||||
| func (*EmptyStatement) _statementNode()      {} | ||||
| func (*ExpressionStatement) _statementNode() {} | ||||
| func (*ForInStatement) _statementNode()      {} | ||||
| func (*ForStatement) _statementNode()        {} | ||||
| func (*IfStatement) _statementNode()         {} | ||||
| func (*LabelledStatement) _statementNode()   {} | ||||
| func (*ReturnStatement) _statementNode()     {} | ||||
| func (*SwitchStatement) _statementNode()     {} | ||||
| func (*ThrowStatement) _statementNode()      {} | ||||
| func (*TryStatement) _statementNode()        {} | ||||
| func (*VariableStatement) _statementNode()   {} | ||||
| func (*WhileStatement) _statementNode()      {} | ||||
| func (*WithStatement) _statementNode()       {} | ||||
| 
 | ||||
| // =========== //
 | ||||
| // Declaration //
 | ||||
| // =========== //
 | ||||
| 
 | ||||
| type ( | ||||
| 	// All declaration nodes implement the Declaration interface.
 | ||||
| 	Declaration interface { | ||||
| 		_declarationNode() | ||||
| 	} | ||||
| 
 | ||||
| 	FunctionDeclaration struct { | ||||
| 		Function *FunctionLiteral | ||||
| 	} | ||||
| 
 | ||||
| 	VariableDeclaration struct { | ||||
| 		Var  file.Idx | ||||
| 		List []*VariableExpression | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // _declarationNode
 | ||||
| 
 | ||||
| func (*FunctionDeclaration) _declarationNode() {} | ||||
| func (*VariableDeclaration) _declarationNode() {} | ||||
| 
 | ||||
| // ==== //
 | ||||
| // Node //
 | ||||
| // ==== //
 | ||||
| 
 | ||||
| type Program struct { | ||||
| 	Body []Statement | ||||
| 
 | ||||
| 	DeclarationList []Declaration | ||||
| } | ||||
| 
 | ||||
| // ==== //
 | ||||
| // Idx0 //
 | ||||
| // ==== //
 | ||||
| 
 | ||||
| func (self *ArrayLiteral) Idx0() file.Idx          { return self.LeftBracket } | ||||
| func (self *AssignExpression) Idx0() file.Idx      { return self.Left.Idx0() } | ||||
| func (self *BadExpression) Idx0() file.Idx         { return self.From } | ||||
| func (self *BinaryExpression) Idx0() file.Idx      { return self.Left.Idx0() } | ||||
| func (self *BooleanLiteral) Idx0() file.Idx        { return self.Idx } | ||||
| func (self *BracketExpression) Idx0() file.Idx     { return self.Left.Idx0() } | ||||
| func (self *CallExpression) Idx0() file.Idx        { return self.Callee.Idx0() } | ||||
| func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() } | ||||
| func (self *DotExpression) Idx0() file.Idx         { return self.Left.Idx0() } | ||||
| func (self *FunctionLiteral) Idx0() file.Idx       { return self.Function } | ||||
| func (self *Identifier) Idx0() file.Idx            { return self.Idx } | ||||
| func (self *NewExpression) Idx0() file.Idx         { return self.New } | ||||
| func (self *NullLiteral) Idx0() file.Idx           { return self.Idx } | ||||
| func (self *NumberLiteral) Idx0() file.Idx         { return self.Idx } | ||||
| func (self *ObjectLiteral) Idx0() file.Idx         { return self.LeftBrace } | ||||
| func (self *RegExpLiteral) Idx0() file.Idx         { return self.Idx } | ||||
| func (self *SequenceExpression) Idx0() file.Idx    { return self.Sequence[0].Idx0() } | ||||
| func (self *StringLiteral) Idx0() file.Idx         { return self.Idx } | ||||
| func (self *ThisExpression) Idx0() file.Idx        { return self.Idx } | ||||
| func (self *UnaryExpression) Idx0() file.Idx       { return self.Idx } | ||||
| func (self *VariableExpression) Idx0() file.Idx    { return self.Idx } | ||||
| 
 | ||||
| func (self *BadStatement) Idx0() file.Idx        { return self.From } | ||||
| func (self *BlockStatement) Idx0() file.Idx      { return self.LeftBrace } | ||||
| func (self *BranchStatement) Idx0() file.Idx     { return self.Idx } | ||||
| func (self *CaseStatement) Idx0() file.Idx       { return self.Case } | ||||
| func (self *CatchStatement) Idx0() file.Idx      { return self.Catch } | ||||
| func (self *DebuggerStatement) Idx0() file.Idx   { return self.Debugger } | ||||
| func (self *DoWhileStatement) Idx0() file.Idx    { return self.Do } | ||||
| func (self *EmptyStatement) Idx0() file.Idx      { return self.Semicolon } | ||||
| func (self *ExpressionStatement) Idx0() file.Idx { return self.Expression.Idx0() } | ||||
| func (self *ForInStatement) Idx0() file.Idx      { return self.For } | ||||
| func (self *ForStatement) Idx0() file.Idx        { return self.For } | ||||
| func (self *IfStatement) Idx0() file.Idx         { return self.If } | ||||
| func (self *LabelledStatement) Idx0() file.Idx   { return self.Label.Idx0() } | ||||
| func (self *Program) Idx0() file.Idx             { return self.Body[0].Idx0() } | ||||
| func (self *ReturnStatement) Idx0() file.Idx     { return self.Return } | ||||
| func (self *SwitchStatement) Idx0() file.Idx     { return self.Switch } | ||||
| func (self *ThrowStatement) Idx0() file.Idx      { return self.Throw } | ||||
| func (self *TryStatement) Idx0() file.Idx        { return self.Try } | ||||
| func (self *VariableStatement) Idx0() file.Idx   { return self.Var } | ||||
| func (self *WhileStatement) Idx0() file.Idx      { return self.While } | ||||
| func (self *WithStatement) Idx0() file.Idx       { return self.With } | ||||
| 
 | ||||
| // ==== //
 | ||||
| // Idx1 //
 | ||||
| // ==== //
 | ||||
| 
 | ||||
| func (self *ArrayLiteral) Idx1() file.Idx          { return self.RightBracket } | ||||
| func (self *AssignExpression) Idx1() file.Idx      { return self.Right.Idx1() } | ||||
| func (self *BadExpression) Idx1() file.Idx         { return self.To } | ||||
| func (self *BinaryExpression) Idx1() file.Idx      { return self.Right.Idx1() } | ||||
| func (self *BooleanLiteral) Idx1() file.Idx        { return file.Idx(int(self.Idx) + len(self.Literal)) } | ||||
| func (self *BracketExpression) Idx1() file.Idx     { return self.RightBracket + 1 } | ||||
| func (self *CallExpression) Idx1() file.Idx        { return self.RightParenthesis + 1 } | ||||
| func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() } | ||||
| func (self *DotExpression) Idx1() file.Idx         { return self.Identifier.Idx1() } | ||||
| func (self *FunctionLiteral) Idx1() file.Idx       { return self.Body.Idx1() } | ||||
| func (self *Identifier) Idx1() file.Idx            { return file.Idx(int(self.Idx) + len(self.Name)) } | ||||
| func (self *NewExpression) Idx1() file.Idx         { return self.RightParenthesis + 1 } | ||||
| func (self *NullLiteral) Idx1() file.Idx           { return file.Idx(int(self.Idx) + 4) } // "null"
 | ||||
| func (self *NumberLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) } | ||||
| func (self *ObjectLiteral) Idx1() file.Idx         { return self.RightBrace } | ||||
| func (self *RegExpLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) } | ||||
| func (self *SequenceExpression) Idx1() file.Idx    { return self.Sequence[0].Idx1() } | ||||
| func (self *StringLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) } | ||||
| func (self *ThisExpression) Idx1() file.Idx        { return self.Idx } | ||||
| func (self *UnaryExpression) Idx1() file.Idx { | ||||
| 	if self.Postfix { | ||||
| 		return self.Operand.Idx1() + 2 // ++ --
 | ||||
| 	} | ||||
| 	return self.Operand.Idx1() | ||||
| } | ||||
| func (self *VariableExpression) Idx1() file.Idx { | ||||
| 	if self.Initializer == nil { | ||||
| 		return file.Idx(int(self.Idx) + len(self.Name) + 1) | ||||
| 	} | ||||
| 	return self.Initializer.Idx1() | ||||
| } | ||||
| 
 | ||||
| func (self *BadStatement) Idx1() file.Idx        { return self.To } | ||||
| func (self *BlockStatement) Idx1() file.Idx      { return self.RightBrace + 1 } | ||||
| func (self *BranchStatement) Idx1() file.Idx     { return self.Idx } | ||||
| func (self *CaseStatement) Idx1() file.Idx       { return self.Consequent[len(self.Consequent)-1].Idx1() } | ||||
| func (self *CatchStatement) Idx1() file.Idx      { return self.Body.Idx1() } | ||||
| func (self *DebuggerStatement) Idx1() file.Idx   { return self.Debugger + 8 } | ||||
| func (self *DoWhileStatement) Idx1() file.Idx    { return self.Test.Idx1() } | ||||
| func (self *EmptyStatement) Idx1() file.Idx      { return self.Semicolon + 1 } | ||||
| func (self *ExpressionStatement) Idx1() file.Idx { return self.Expression.Idx1() } | ||||
| func (self *ForInStatement) Idx1() file.Idx      { return self.Body.Idx1() } | ||||
| func (self *ForStatement) Idx1() file.Idx        { return self.Body.Idx1() } | ||||
| func (self *IfStatement) Idx1() file.Idx { | ||||
| 	if self.Alternate != nil { | ||||
| 		return self.Alternate.Idx1() | ||||
| 	} | ||||
| 	return self.Consequent.Idx1() | ||||
| } | ||||
| func (self *LabelledStatement) Idx1() file.Idx { return self.Colon + 1 } | ||||
| func (self *Program) Idx1() file.Idx           { return self.Body[len(self.Body)-1].Idx1() } | ||||
| func (self *ReturnStatement) Idx1() file.Idx   { return self.Return } | ||||
| func (self *SwitchStatement) Idx1() file.Idx   { return self.Body[len(self.Body)-1].Idx1() } | ||||
| func (self *ThrowStatement) Idx1() file.Idx    { return self.Throw } | ||||
| func (self *TryStatement) Idx1() file.Idx      { return self.Try } | ||||
| func (self *VariableStatement) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() } | ||||
| func (self *WhileStatement) Idx1() file.Idx    { return self.Body.Idx1() } | ||||
| func (self *WithStatement) Idx1() file.Idx     { return self.Body.Idx1() } | ||||
							
								
								
									
										85
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/builtin_error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/builtin_error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,85 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| func (runtime *_runtime) newEvalError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.EvalErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinEvalError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newEvalError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewEvalError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newEvalError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newTypeError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.TypeErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinTypeError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newTypeError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewTypeError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newTypeError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newRangeError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.RangeErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinRangeError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newRangeError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewRangeError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newRangeError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newURIError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.URIErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newReferenceError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.ReferenceErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinReferenceError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newReferenceError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewReferenceError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newReferenceError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newSyntaxError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.SyntaxErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinSyntaxError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newSyntaxError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewSyntaxError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newSyntaxError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func builtinURIError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newURIError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewURIError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newURIError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
							
								
								
									
										144
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/clone.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/clone.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,144 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| type _clone struct { | ||||
| 	runtime *_runtime | ||||
| 	stash   struct { | ||||
| 		object                 map[*_object]*_object | ||||
| 		objectEnvironment      map[*_objectEnvironment]*_objectEnvironment | ||||
| 		declarativeEnvironment map[*_declarativeEnvironment]*_declarativeEnvironment | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) clone() *_runtime { | ||||
| 
 | ||||
| 	self := &_runtime{} | ||||
| 	clone := &_clone{ | ||||
| 		runtime: self, | ||||
| 	} | ||||
| 	clone.stash.object = make(map[*_object]*_object) | ||||
| 	clone.stash.objectEnvironment = make(map[*_objectEnvironment]*_objectEnvironment) | ||||
| 	clone.stash.declarativeEnvironment = make(map[*_declarativeEnvironment]*_declarativeEnvironment) | ||||
| 
 | ||||
| 	globalObject := clone.object(runtime.GlobalObject) | ||||
| 	self.GlobalEnvironment = self.newObjectEnvironment(globalObject, nil) | ||||
| 	self.GlobalObject = globalObject | ||||
| 	self.Global = _global{ | ||||
| 		clone.object(runtime.Global.Object), | ||||
| 		clone.object(runtime.Global.Function), | ||||
| 		clone.object(runtime.Global.Array), | ||||
| 		clone.object(runtime.Global.String), | ||||
| 		clone.object(runtime.Global.Boolean), | ||||
| 		clone.object(runtime.Global.Number), | ||||
| 		clone.object(runtime.Global.Math), | ||||
| 		clone.object(runtime.Global.Date), | ||||
| 		clone.object(runtime.Global.RegExp), | ||||
| 		clone.object(runtime.Global.Error), | ||||
| 		clone.object(runtime.Global.EvalError), | ||||
| 		clone.object(runtime.Global.TypeError), | ||||
| 		clone.object(runtime.Global.RangeError), | ||||
| 		clone.object(runtime.Global.ReferenceError), | ||||
| 		clone.object(runtime.Global.SyntaxError), | ||||
| 		clone.object(runtime.Global.URIError), | ||||
| 		clone.object(runtime.Global.JSON), | ||||
| 
 | ||||
| 		clone.object(runtime.Global.ObjectPrototype), | ||||
| 		clone.object(runtime.Global.FunctionPrototype), | ||||
| 		clone.object(runtime.Global.ArrayPrototype), | ||||
| 		clone.object(runtime.Global.StringPrototype), | ||||
| 		clone.object(runtime.Global.BooleanPrototype), | ||||
| 		clone.object(runtime.Global.NumberPrototype), | ||||
| 		clone.object(runtime.Global.DatePrototype), | ||||
| 		clone.object(runtime.Global.RegExpPrototype), | ||||
| 		clone.object(runtime.Global.ErrorPrototype), | ||||
| 		clone.object(runtime.Global.EvalErrorPrototype), | ||||
| 		clone.object(runtime.Global.TypeErrorPrototype), | ||||
| 		clone.object(runtime.Global.RangeErrorPrototype), | ||||
| 		clone.object(runtime.Global.ReferenceErrorPrototype), | ||||
| 		clone.object(runtime.Global.SyntaxErrorPrototype), | ||||
| 		clone.object(runtime.Global.URIErrorPrototype), | ||||
| 	} | ||||
| 
 | ||||
| 	self.EnterGlobalExecutionContext() | ||||
| 
 | ||||
| 	self.eval = self.GlobalObject.property["eval"].value.(Value).value.(*_object) | ||||
| 	self.GlobalObject.prototype = self.Global.ObjectPrototype | ||||
| 
 | ||||
| 	return self | ||||
| } | ||||
| func (clone *_clone) object(self0 *_object) *_object { | ||||
| 	if self1, exists := clone.stash.object[self0]; exists { | ||||
| 		return self1 | ||||
| 	} | ||||
| 	self1 := &_object{} | ||||
| 	clone.stash.object[self0] = self1 | ||||
| 	return self0.objectClass.clone(self0, self1, clone) | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) declarativeEnvironment(self0 *_declarativeEnvironment) (*_declarativeEnvironment, bool) { | ||||
| 	if self1, exists := clone.stash.declarativeEnvironment[self0]; exists { | ||||
| 		return self1, true | ||||
| 	} | ||||
| 	self1 := &_declarativeEnvironment{} | ||||
| 	clone.stash.declarativeEnvironment[self0] = self1 | ||||
| 	return self1, false | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) objectEnvironment(self0 *_objectEnvironment) (*_objectEnvironment, bool) { | ||||
| 	if self1, exists := clone.stash.objectEnvironment[self0]; exists { | ||||
| 		return self1, true | ||||
| 	} | ||||
| 	self1 := &_objectEnvironment{} | ||||
| 	clone.stash.objectEnvironment[self0] = self1 | ||||
| 	return self1, false | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) value(self0 Value) Value { | ||||
| 	self1 := self0 | ||||
| 	switch value := self0.value.(type) { | ||||
| 	case *_object: | ||||
| 		self1.value = clone.object(value) | ||||
| 	} | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) valueArray(self0 []Value) []Value { | ||||
| 	self1 := make([]Value, len(self0)) | ||||
| 	for index, value := range self0 { | ||||
| 		self1[index] = clone.value(value) | ||||
| 	} | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) environment(self0 _environment) _environment { | ||||
| 	if self0 == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return self0.clone(clone) | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) property(self0 _property) _property { | ||||
| 	self1 := self0 | ||||
| 	if value, valid := self0.value.(Value); valid { | ||||
| 		self1.value = clone.value(value) | ||||
| 	} else { | ||||
| 		panic(fmt.Errorf("self0.value.(Value) != true")) | ||||
| 	} | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) declarativeProperty(self0 _declarativeProperty) _declarativeProperty { | ||||
| 	self1 := self0 | ||||
| 	self1.value = clone.value(self0.value) | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) callFunction(self0 _callFunction) _callFunction { | ||||
| 	if self0 == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return self0.clone(clone) | ||||
| } | ||||
							
								
								
									
										46
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/cmpl_function.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/cmpl_function.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,46 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| // _cmpl_nodeCallFunction
 | ||||
| type _cmpl_nodeCallFunction struct { | ||||
| 	node             *_nodeFunctionLiteral | ||||
| 	scopeEnvironment _environment // Can be either Lexical or Variable
 | ||||
| } | ||||
| 
 | ||||
| func new_nodeCallFunction(node *_nodeFunctionLiteral, scopeEnvironment _environment) *_cmpl_nodeCallFunction { | ||||
| 	self := &_cmpl_nodeCallFunction{ | ||||
| 		node: node, | ||||
| 	} | ||||
| 	self.scopeEnvironment = scopeEnvironment | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (self _cmpl_nodeCallFunction) Dispatch(function *_object, environment *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value { | ||||
| 	return runtime.cmpl_call_nodeFunction(function, environment, self.node, this, argumentList) | ||||
| } | ||||
| 
 | ||||
| func (self _cmpl_nodeCallFunction) ScopeEnvironment() _environment { | ||||
| 	return self.scopeEnvironment | ||||
| } | ||||
| 
 | ||||
| func (self _cmpl_nodeCallFunction) Source(object *_object) string { | ||||
| 	return self.node.source | ||||
| } | ||||
| 
 | ||||
| func (self0 _cmpl_nodeCallFunction) clone(clone *_clone) _callFunction { | ||||
| 	return _cmpl_nodeCallFunction{ | ||||
| 		node:             self0.node, | ||||
| 		scopeEnvironment: clone.environment(self0.scopeEnvironment), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ---
 | ||||
| 
 | ||||
| func (runtime *_runtime) newNodeFunctionObject(node *_nodeFunctionLiteral, scopeEnvironment _environment) *_object { | ||||
| 	self := runtime.newClassObject("Function") | ||||
| 	self.value = _functionObject{ | ||||
| 		call:      new_nodeCallFunction(node, scopeEnvironment), | ||||
| 		construct: defaultConstructFunction, | ||||
| 	} | ||||
| 	self.defineProperty("length", toValue_int(len(node.parameterList)), 0000, false) | ||||
| 	return self | ||||
| } | ||||
							
								
								
									
										387
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/dbg/dbg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										387
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/dbg/dbg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,387 +0,0 @@ | ||||
| // This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) from github.com/robertkrimen/dbg
 | ||||
| 
 | ||||
| /* | ||||
| Package dbg is a println/printf/log-debugging utility library. | ||||
| 
 | ||||
|     import ( | ||||
|         Dbg "github.com/robertkrimen/dbg" | ||||
|     ) | ||||
| 
 | ||||
|     dbg, dbgf := Dbg.New() | ||||
| 
 | ||||
|     dbg("Emit some debug stuff", []byte{120, 121, 122, 122, 121}, math.Pi) | ||||
|     # "2013/01/28 16:50:03 Emit some debug stuff [120 121 122 122 121] 3.141592653589793" | ||||
| 
 | ||||
|     dbgf("With a %s formatting %.2f", "little", math.Pi) | ||||
|     # "2013/01/28 16:51:55 With a little formatting (3.14)" | ||||
| 
 | ||||
|     dbgf("%/fatal//A fatal debug statement: should not be here") | ||||
|     # "A fatal debug statement: should not be here" | ||||
|     # ...and then, os.Exit(1) | ||||
| 
 | ||||
|     dbgf("%/panic//Can also panic %s", "this") | ||||
|     # "Can also panic this" | ||||
|     # ...as a panic, equivalent to: panic("Can also panic this") | ||||
| 
 | ||||
|     dbgf("Any %s arguments without a corresponding %%", "extra", "are treated like arguments to dbg()") | ||||
|     # "2013/01/28 17:14:40 Any extra arguments (without a corresponding %) are treated like arguments to dbg()" | ||||
| 
 | ||||
|     dbgf("%d %d", 1, 2, 3, 4, 5) | ||||
|     # "2013/01/28 17:16:32 Another example: 1 2 3 4 5" | ||||
| 
 | ||||
|     dbgf("%@: Include the function name for a little context (via %s)", "%@") | ||||
|     # "2013... github.com/robertkrimen/dbg.TestSynopsis: Include the function name for a little context (via %@)" | ||||
| 
 | ||||
| By default, dbg uses log (log.Println, log.Printf, log.Panic, etc.) for output. | ||||
| However, you can also provide your own output destination by invoking dbg.New with | ||||
| a customization function: | ||||
| 
 | ||||
|     import ( | ||||
|         "bytes" | ||||
|         Dbg "github.com/robertkrimen/dbg" | ||||
|         "os" | ||||
|     ) | ||||
| 
 | ||||
|     # dbg to os.Stderr | ||||
|     dbg, dbgf := Dbg.New(func(dbgr *Dbgr) { | ||||
|         dbgr.SetOutput(os.Stderr) | ||||
|     }) | ||||
| 
 | ||||
|     # A slightly contrived example: | ||||
|     var buffer bytes.Buffer | ||||
|     dbg, dbgf := New(func(dbgr *Dbgr) { | ||||
|         dbgr.SetOutput(&buffer) | ||||
|     }) | ||||
| 
 | ||||
| */ | ||||
| package dbg | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| ) | ||||
| 
 | ||||
| type _frmt struct { | ||||
| 	ctl          string | ||||
| 	format       string | ||||
| 	operandCount int | ||||
| 	panic        bool | ||||
| 	fatal        bool | ||||
| 	check        bool | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	ctlTest = regexp.MustCompile(`^\s*%/`) | ||||
| 	ctlScan = regexp.MustCompile(`%?/(panic|fatal|check)(?:\s|$)`) | ||||
| ) | ||||
| 
 | ||||
| func operandCount(format string) int { | ||||
| 	count := 0 | ||||
| 	end := len(format) | ||||
| 	for at := 0; at < end; { | ||||
| 		for at < end && format[at] != '%' { | ||||
| 			at++ | ||||
| 		} | ||||
| 		at++ | ||||
| 		if at < end { | ||||
| 			if format[at] != '%' && format[at] != '@' { | ||||
| 				count++ | ||||
| 			} | ||||
| 			at++ | ||||
| 		} | ||||
| 	} | ||||
| 	return count | ||||
| } | ||||
| 
 | ||||
| func parseFormat(format string) (frmt _frmt) { | ||||
| 	if ctlTest.MatchString(format) { | ||||
| 		format = strings.TrimLeftFunc(format, unicode.IsSpace) | ||||
| 		index := strings.Index(format, "//") | ||||
| 		if index != -1 { | ||||
| 			frmt.ctl = format[0:index] | ||||
| 			format = format[index+2:] // Skip the second slash via +2 (instead of +1)
 | ||||
| 		} else { | ||||
| 			frmt.ctl = format | ||||
| 			format = "" | ||||
| 		} | ||||
| 		for _, tmp := range ctlScan.FindAllStringSubmatch(frmt.ctl, -1) { | ||||
| 			for _, value := range tmp[1:] { | ||||
| 				switch value { | ||||
| 				case "panic": | ||||
| 					frmt.panic = true | ||||
| 				case "fatal": | ||||
| 					frmt.fatal = true | ||||
| 				case "check": | ||||
| 					frmt.check = true | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	frmt.format = format | ||||
| 	frmt.operandCount = operandCount(format) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| type Dbgr struct { | ||||
| 	emit _emit | ||||
| } | ||||
| 
 | ||||
| type DbgFunction func(values ...interface{}) | ||||
| 
 | ||||
| func NewDbgr() *Dbgr { | ||||
| 	self := &Dbgr{} | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| New will create and return a pair of debugging functions. You can customize where | ||||
| they output to by passing in an (optional) customization function: | ||||
| 
 | ||||
|     import ( | ||||
|         Dbg "github.com/robertkrimen/dbg" | ||||
|         "os" | ||||
|     ) | ||||
| 
 | ||||
|     # dbg to os.Stderr | ||||
|     dbg, dbgf := Dbg.New(func(dbgr *Dbgr) { | ||||
|         dbgr.SetOutput(os.Stderr) | ||||
|     }) | ||||
| 
 | ||||
| */ | ||||
| func New(options ...interface{}) (dbg DbgFunction, dbgf DbgFunction) { | ||||
| 	dbgr := NewDbgr() | ||||
| 	if len(options) > 0 { | ||||
| 		if fn, ok := options[0].(func(*Dbgr)); ok { | ||||
| 			fn(dbgr) | ||||
| 		} | ||||
| 	} | ||||
| 	return dbgr.DbgDbgf() | ||||
| } | ||||
| 
 | ||||
| func (self Dbgr) Dbg(values ...interface{}) { | ||||
| 	self.getEmit().emit(_frmt{}, "", values...) | ||||
| } | ||||
| 
 | ||||
| func (self Dbgr) Dbgf(values ...interface{}) { | ||||
| 	self.dbgf(values...) | ||||
| } | ||||
| 
 | ||||
| func (self Dbgr) DbgDbgf() (dbg DbgFunction, dbgf DbgFunction) { | ||||
| 	dbg = func(vl ...interface{}) { | ||||
| 		self.Dbg(vl...) | ||||
| 	} | ||||
| 	dbgf = func(vl ...interface{}) { | ||||
| 		self.dbgf(vl...) | ||||
| 	} | ||||
| 	return dbg, dbgf // Redundant, but...
 | ||||
| } | ||||
| 
 | ||||
| func (self Dbgr) dbgf(values ...interface{}) { | ||||
| 
 | ||||
| 	var frmt _frmt | ||||
| 	if len(values) > 0 { | ||||
| 		tmp := fmt.Sprint(values[0]) | ||||
| 		frmt = parseFormat(tmp) | ||||
| 		values = values[1:] | ||||
| 	} | ||||
| 
 | ||||
| 	buffer_f := bytes.Buffer{} | ||||
| 	format := frmt.format | ||||
| 	end := len(format) | ||||
| 	for at := 0; at < end; { | ||||
| 		last := at | ||||
| 		for at < end && format[at] != '%' { | ||||
| 			at++ | ||||
| 		} | ||||
| 		if at > last { | ||||
| 			buffer_f.WriteString(format[last:at]) | ||||
| 		} | ||||
| 		if at >= end { | ||||
| 			break | ||||
| 		} | ||||
| 		// format[at] == '%'
 | ||||
| 		at++ | ||||
| 		// format[at] == ?
 | ||||
| 		if format[at] == '@' { | ||||
| 			depth := 2 | ||||
| 			pc, _, _, _ := runtime.Caller(depth) | ||||
| 			name := runtime.FuncForPC(pc).Name() | ||||
| 			buffer_f.WriteString(name) | ||||
| 		} else { | ||||
| 			buffer_f.WriteString(format[at-1 : at+1]) | ||||
| 		} | ||||
| 		at++ | ||||
| 	} | ||||
| 
 | ||||
| 	//values_f := append([]interface{}{}, values[0:frmt.operandCount]...)
 | ||||
| 	values_f := values[0:frmt.operandCount] | ||||
| 	values_dbg := values[frmt.operandCount:] | ||||
| 	if len(values_dbg) > 0 { | ||||
| 		// Adjust frmt.format:
 | ||||
| 		// (%v instead of %s because: frmt.check)
 | ||||
| 		{ | ||||
| 			tmp := format | ||||
| 			if len(tmp) > 0 { | ||||
| 				if unicode.IsSpace(rune(tmp[len(tmp)-1])) { | ||||
| 					buffer_f.WriteString("%v") | ||||
| 				} else { | ||||
| 					buffer_f.WriteString(" %v") | ||||
| 				} | ||||
| 			} else if frmt.check { | ||||
| 				// Performing a check, so no output
 | ||||
| 			} else { | ||||
| 				buffer_f.WriteString("%v") | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Adjust values_f:
 | ||||
| 		if !frmt.check { | ||||
| 			tmp := []string{} | ||||
| 			for _, value := range values_dbg { | ||||
| 				tmp = append(tmp, fmt.Sprintf("%v", value)) | ||||
| 			} | ||||
| 			// First, make a copy of values_f, so we avoid overwriting values_dbg when appending
 | ||||
| 			values_f = append([]interface{}{}, values_f...) | ||||
| 			values_f = append(values_f, strings.Join(tmp, " ")) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	format = buffer_f.String() | ||||
| 	if frmt.check { | ||||
| 		// We do not actually emit to the log, but panic if
 | ||||
| 		// a non-nil value is detected (e.g. a non-nil error)
 | ||||
| 		for _, value := range values_dbg { | ||||
| 			if value != nil { | ||||
| 				if format == "" { | ||||
| 					panic(value) | ||||
| 				} else { | ||||
| 					panic(fmt.Sprintf(format, append(values_f, value)...)) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		self.getEmit().emit(frmt, format, values_f...) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Idiot-proof &Dbgr{}, etc.
 | ||||
| func (self *Dbgr) getEmit() _emit { | ||||
| 	if self.emit == nil { | ||||
| 		self.emit = standardEmit() | ||||
| 	} | ||||
| 	return self.emit | ||||
| } | ||||
| 
 | ||||
| // SetOutput will accept the following as a destination for output:
 | ||||
| //
 | ||||
| //      *log.Logger         Print*/Panic*/Fatal* of the logger
 | ||||
| //      io.Writer           - 
 | ||||
| //      nil                 Reset to the default output (os.Stderr)
 | ||||
| //      "log"               Print*/Panic*/Fatal* via the "log" package
 | ||||
| //
 | ||||
| func (self *Dbgr) SetOutput(output interface{}) { | ||||
| 	if output == nil { | ||||
| 		self.emit = standardEmit() | ||||
| 		return | ||||
| 	} | ||||
| 	switch output := output.(type) { | ||||
| 	case *log.Logger: | ||||
| 		self.emit = _emitLogger{ | ||||
| 			logger: output, | ||||
| 		} | ||||
| 		return | ||||
| 	case io.Writer: | ||||
| 		self.emit = _emitWriter{ | ||||
| 			writer: output, | ||||
| 		} | ||||
| 		return | ||||
| 	case string: | ||||
| 		if output == "log" { | ||||
| 			self.emit = _emitLog{} | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	panic(output) | ||||
| } | ||||
| 
 | ||||
| // ======== //
 | ||||
| // = emit = //
 | ||||
| // ======== //
 | ||||
| 
 | ||||
| func standardEmit() _emit { | ||||
| 	return _emitWriter{ | ||||
| 		writer: os.Stderr, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func ln(tmp string) string { | ||||
| 	length := len(tmp) | ||||
| 	if length > 0 && tmp[length-1] != '\n' { | ||||
| 		return tmp + "\n" | ||||
| 	} | ||||
| 	return tmp | ||||
| } | ||||
| 
 | ||||
| type _emit interface { | ||||
| 	emit(_frmt, string, ...interface{}) | ||||
| } | ||||
| 
 | ||||
| type _emitWriter struct { | ||||
| 	writer io.Writer | ||||
| } | ||||
| 
 | ||||
| func (self _emitWriter) emit(frmt _frmt, format string, values ...interface{}) { | ||||
| 	if format == "" { | ||||
| 		fmt.Fprintln(self.writer, values...) | ||||
| 	} else { | ||||
| 		if frmt.panic { | ||||
| 			panic(fmt.Sprintf(format, values...)) | ||||
| 		} | ||||
| 		fmt.Fprintf(self.writer, ln(format), values...) | ||||
| 		if frmt.fatal { | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type _emitLogger struct { | ||||
| 	logger *log.Logger | ||||
| } | ||||
| 
 | ||||
| func (self _emitLogger) emit(frmt _frmt, format string, values ...interface{}) { | ||||
| 	if format == "" { | ||||
| 		self.logger.Println(values...) | ||||
| 	} else { | ||||
| 		if frmt.panic { | ||||
| 			self.logger.Panicf(format, values...) | ||||
| 		} else if frmt.fatal { | ||||
| 			self.logger.Fatalf(format, values...) | ||||
| 		} else { | ||||
| 			self.logger.Printf(format, values...) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type _emitLog struct { | ||||
| } | ||||
| 
 | ||||
| func (self _emitLog) emit(frmt _frmt, format string, values ...interface{}) { | ||||
| 	if format == "" { | ||||
| 		log.Println(values...) | ||||
| 	} else { | ||||
| 		if frmt.panic { | ||||
| 			log.Panicf(format, values...) | ||||
| 		} else if frmt.fatal { | ||||
| 			log.Fatalf(format, values...) | ||||
| 		} else { | ||||
| 			log.Printf(format, values...) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										280
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/environment.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										280
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/environment.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,280 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| // _environment
 | ||||
| 
 | ||||
| type _environment interface { | ||||
| 	HasBinding(string) bool | ||||
| 
 | ||||
| 	CreateMutableBinding(string, bool) | ||||
| 	SetMutableBinding(string, Value, bool) | ||||
| 	// SetMutableBinding with Lazy CreateMutableBinding(..., true)
 | ||||
| 	SetValue(string, Value, bool) | ||||
| 
 | ||||
| 	GetBindingValue(string, bool) Value | ||||
| 	GetValue(string, bool) Value // GetBindingValue
 | ||||
| 	DeleteBinding(string) bool | ||||
| 	ImplicitThisValue() *_object | ||||
| 
 | ||||
| 	Outer() _environment | ||||
| 
 | ||||
| 	newReference(string, bool) _reference | ||||
| 	clone(clone *_clone) _environment | ||||
| 	runtimeOf() *_runtime | ||||
| } | ||||
| 
 | ||||
| // _functionEnvironment
 | ||||
| 
 | ||||
| type _functionEnvironment struct { | ||||
| 	_declarativeEnvironment | ||||
| 	arguments           *_object | ||||
| 	indexOfArgumentName map[string]string | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newFunctionEnvironment(outer _environment) *_functionEnvironment { | ||||
| 	return &_functionEnvironment{ | ||||
| 		_declarativeEnvironment: _declarativeEnvironment{ | ||||
| 			runtime:  runtime, | ||||
| 			outer:    outer, | ||||
| 			property: map[string]_declarativeProperty{}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self0 _functionEnvironment) clone(clone *_clone) _environment { | ||||
| 	return &_functionEnvironment{ | ||||
| 		*(self0._declarativeEnvironment.clone(clone).(*_declarativeEnvironment)), | ||||
| 		clone.object(self0.arguments), | ||||
| 		self0.indexOfArgumentName, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self _functionEnvironment) runtimeOf() *_runtime { | ||||
| 	return self._declarativeEnvironment.runtimeOf() | ||||
| } | ||||
| 
 | ||||
| // _objectEnvironment
 | ||||
| 
 | ||||
| type _objectEnvironment struct { | ||||
| 	runtime     *_runtime | ||||
| 	outer       _environment | ||||
| 	Object      *_object | ||||
| 	ProvideThis bool | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) runtimeOf() *_runtime { | ||||
| 	return self.runtime | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newObjectEnvironment(object *_object, outer _environment) *_objectEnvironment { | ||||
| 	if object == nil { | ||||
| 		object = runtime.newBaseObject() | ||||
| 		object.class = "environment" | ||||
| 	} | ||||
| 	return &_objectEnvironment{ | ||||
| 		runtime: runtime, | ||||
| 		outer:   outer, | ||||
| 		Object:  object, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self0 *_objectEnvironment) clone(clone *_clone) _environment { | ||||
| 	self1, exists := clone.objectEnvironment(self0) | ||||
| 	if exists { | ||||
| 		return self1 | ||||
| 	} | ||||
| 	*self1 = _objectEnvironment{ | ||||
| 		clone.runtime, | ||||
| 		clone.environment(self0.outer), | ||||
| 		clone.object(self0.Object), | ||||
| 		self0.ProvideThis, | ||||
| 	} | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) HasBinding(name string) bool { | ||||
| 	return self.Object.hasProperty(name) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) CreateMutableBinding(name string, deletable bool) { | ||||
| 	if self.Object.hasProperty(name) { | ||||
| 		panic(hereBeDragons()) | ||||
| 	} | ||||
| 	mode := _propertyMode(0111) | ||||
| 	if !deletable { | ||||
| 		mode = _propertyMode(0110) | ||||
| 	} | ||||
| 	// TODO False?
 | ||||
| 	self.Object.defineProperty(name, UndefinedValue(), mode, false) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) SetMutableBinding(name string, value Value, strict bool) { | ||||
| 	self.Object.put(name, value, strict) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) SetValue(name string, value Value, throw bool) { | ||||
| 	if !self.HasBinding(name) { | ||||
| 		self.CreateMutableBinding(name, true) // Configurable by default
 | ||||
| 	} | ||||
| 	self.SetMutableBinding(name, value, throw) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value { | ||||
| 	if self.Object.hasProperty(name) { | ||||
| 		return self.Object.get(name) | ||||
| 	} | ||||
| 	if strict { | ||||
| 		panic(newReferenceError("Not Defined", name)) | ||||
| 	} | ||||
| 	return UndefinedValue() | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) GetValue(name string, throw bool) Value { | ||||
| 	return self.GetBindingValue(name, throw) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) DeleteBinding(name string) bool { | ||||
| 	return self.Object.delete(name, false) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) ImplicitThisValue() *_object { | ||||
| 	if self.ProvideThis { | ||||
| 		return self.Object | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) Outer() _environment { | ||||
| 	return self.outer | ||||
| } | ||||
| 
 | ||||
| func (self *_objectEnvironment) newReference(name string, strict bool) _reference { | ||||
| 	return newPropertyReference(self.Object, name, strict) | ||||
| } | ||||
| 
 | ||||
| // _declarativeEnvironment
 | ||||
| 
 | ||||
| func (runtime *_runtime) newDeclarativeEnvironment(outer _environment) *_declarativeEnvironment { | ||||
| 	return &_declarativeEnvironment{ | ||||
| 		runtime:  runtime, | ||||
| 		outer:    outer, | ||||
| 		property: map[string]_declarativeProperty{}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self0 *_declarativeEnvironment) clone(clone *_clone) _environment { | ||||
| 	self1, exists := clone.declarativeEnvironment(self0) | ||||
| 	if exists { | ||||
| 		return self1 | ||||
| 	} | ||||
| 	property := make(map[string]_declarativeProperty, len(self0.property)) | ||||
| 	for index, value := range self0.property { | ||||
| 		property[index] = clone.declarativeProperty(value) | ||||
| 	} | ||||
| 	*self1 = _declarativeEnvironment{ | ||||
| 		clone.runtime, | ||||
| 		clone.environment(self0.outer), | ||||
| 		property, | ||||
| 	} | ||||
| 	return self1 | ||||
| } | ||||
| 
 | ||||
| type _declarativeProperty struct { | ||||
| 	value     Value | ||||
| 	mutable   bool | ||||
| 	deletable bool | ||||
| 	readable  bool | ||||
| } | ||||
| 
 | ||||
| type _declarativeEnvironment struct { | ||||
| 	runtime  *_runtime | ||||
| 	outer    _environment | ||||
| 	property map[string]_declarativeProperty | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) HasBinding(name string) bool { | ||||
| 	_, exists := self.property[name] | ||||
| 	return exists | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) runtimeOf() *_runtime { | ||||
| 	return self.runtime | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) CreateMutableBinding(name string, deletable bool) { | ||||
| 	_, exists := self.property[name] | ||||
| 	if exists { | ||||
| 		panic(fmt.Errorf("CreateMutableBinding: %s: already exists", name)) | ||||
| 	} | ||||
| 	self.property[name] = _declarativeProperty{ | ||||
| 		value:     UndefinedValue(), | ||||
| 		mutable:   true, | ||||
| 		deletable: deletable, | ||||
| 		readable:  false, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) SetMutableBinding(name string, value Value, strict bool) { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		panic(fmt.Errorf("SetMutableBinding: %s: missing", name)) | ||||
| 	} | ||||
| 	if property.mutable { | ||||
| 		property.value = value | ||||
| 		self.property[name] = property | ||||
| 	} else { | ||||
| 		typeErrorResult(strict) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) SetValue(name string, value Value, throw bool) { | ||||
| 	if !self.HasBinding(name) { | ||||
| 		self.CreateMutableBinding(name, false) // NOT deletable by default
 | ||||
| 	} | ||||
| 	self.SetMutableBinding(name, value, throw) | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) GetBindingValue(name string, strict bool) Value { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		panic(fmt.Errorf("GetBindingValue: %s: missing", name)) | ||||
| 	} | ||||
| 	if !property.mutable && !property.readable { | ||||
| 		if strict { | ||||
| 			panic(newTypeError()) | ||||
| 		} | ||||
| 		return UndefinedValue() | ||||
| 	} | ||||
| 	return property.value | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) GetValue(name string, throw bool) Value { | ||||
| 	return self.GetBindingValue(name, throw) | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) DeleteBinding(name string) bool { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		return true | ||||
| 	} | ||||
| 	if !property.deletable { | ||||
| 		return false | ||||
| 	} | ||||
| 	delete(self.property, name) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) ImplicitThisValue() *_object { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) Outer() _environment { | ||||
| 	return self.outer | ||||
| } | ||||
| 
 | ||||
| func (self *_declarativeEnvironment) newReference(name string, strict bool) _reference { | ||||
| 	return newEnvironmentReference(self, name, strict, nil) | ||||
| } | ||||
							
								
								
									
										152
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										152
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,152 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| ) | ||||
| 
 | ||||
| type _exception struct { | ||||
| 	value interface{} | ||||
| } | ||||
| 
 | ||||
| func newException(value interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: value, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_exception) eject() interface{} { | ||||
| 	value := self.value | ||||
| 	self.value = nil // Prevent Go from holding on to the value, whatever it is
 | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| type _error struct { | ||||
| 	Name    string | ||||
| 	Message string | ||||
| 
 | ||||
| 	Line int // Hackish -- line where the error/exception occurred
 | ||||
| } | ||||
| 
 | ||||
| var messageDetail map[string]string = map[string]string{ | ||||
| 	"notDefined": "%v is not defined", | ||||
| } | ||||
| 
 | ||||
| func messageFromDescription(description string, argumentList ...interface{}) string { | ||||
| 	message := messageDetail[description] | ||||
| 	if message == "" { | ||||
| 		message = description | ||||
| 	} | ||||
| 	message = fmt.Sprintf(message, argumentList...) | ||||
| 	return message | ||||
| } | ||||
| 
 | ||||
| func (self _error) MessageValue() Value { | ||||
| 	if self.Message == "" { | ||||
| 		return UndefinedValue() | ||||
| 	} | ||||
| 	return toValue_string(self.Message) | ||||
| } | ||||
| 
 | ||||
| func (self _error) String() string { | ||||
| 	if len(self.Name) == 0 { | ||||
| 		return self.Message | ||||
| 	} | ||||
| 	if len(self.Message) == 0 { | ||||
| 		return self.Name | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s: %s", self.Name, self.Message) | ||||
| } | ||||
| 
 | ||||
| func newError(name string, argumentList ...interface{}) _error { | ||||
| 	description := "" | ||||
| 	var node ast.Node = nil | ||||
| 	length := len(argumentList) | ||||
| 	if length > 0 { | ||||
| 		if node, _ = argumentList[length-1].(ast.Node); node != nil || argumentList[length-1] == nil { | ||||
| 			argumentList = argumentList[0 : length-1] | ||||
| 			length -= 1 | ||||
| 		} | ||||
| 		if length > 0 { | ||||
| 			description, argumentList = argumentList[0].(string), argumentList[1:] | ||||
| 		} | ||||
| 	} | ||||
| 	return _error{ | ||||
| 		Name:    name, | ||||
| 		Message: messageFromDescription(description, argumentList...), | ||||
| 		Line:    -1, | ||||
| 	} | ||||
| 	//error := _error{
 | ||||
| 	//    Name:    name,
 | ||||
| 	//    Message: messageFromDescription(description, argumentList...),
 | ||||
| 	//    Line:    -1,
 | ||||
| 	//}
 | ||||
| 	//if node != nil {
 | ||||
| 	//    error.Line = ast.position()
 | ||||
| 	//}
 | ||||
| 	//return error
 | ||||
| } | ||||
| 
 | ||||
| func newReferenceError(argumentList ...interface{}) _error { | ||||
| 	return newError("ReferenceError", argumentList...) | ||||
| } | ||||
| 
 | ||||
| func newTypeError(argumentList ...interface{}) _error { | ||||
| 	return newError("TypeError", argumentList...) | ||||
| } | ||||
| 
 | ||||
| func newRangeError(argumentList ...interface{}) _error { | ||||
| 	return newError("RangeError", argumentList...) | ||||
| } | ||||
| 
 | ||||
| func newSyntaxError(argumentList ...interface{}) _error { | ||||
| 	return newError("SyntaxError", argumentList...) | ||||
| } | ||||
| 
 | ||||
| func newURIError(argumentList ...interface{}) _error { | ||||
| 	return newError("URIError", argumentList...) | ||||
| } | ||||
| 
 | ||||
| func typeErrorResult(throw bool) bool { | ||||
| 	if throw { | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func catchPanic(function func()) (err error) { | ||||
| 	// FIXME
 | ||||
| 	defer func() { | ||||
| 		if caught := recover(); caught != nil { | ||||
| 			if exception, ok := caught.(*_exception); ok { | ||||
| 				caught = exception.eject() | ||||
| 			} | ||||
| 			switch caught := caught.(type) { | ||||
| 			//case *_syntaxError:
 | ||||
| 			//    err = errors.New(fmt.Sprintf("%s (line %d)", caught.String(), caught.Line+0))
 | ||||
| 			//    return
 | ||||
| 			case _error: | ||||
| 				if caught.Line == -1 { | ||||
| 					err = errors.New(caught.String()) | ||||
| 				} else { | ||||
| 					// We're 0-based (for now), hence the + 1
 | ||||
| 					err = errors.New(fmt.Sprintf("%s (line %d)", caught.String(), caught.Line+1)) | ||||
| 				} | ||||
| 				return | ||||
| 			case Value: | ||||
| 				err = errors.New(toString(caught)) | ||||
| 				return | ||||
| 				//case string:
 | ||||
| 				//    if strings.HasPrefix(caught, "SyntaxError:") {
 | ||||
| 				//        err = errors.New(caught)
 | ||||
| 				//        return
 | ||||
| 				//    }
 | ||||
| 			} | ||||
| 			panic(caught) | ||||
| 		} | ||||
| 	}() | ||||
| 	function() | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										62
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/error_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/error_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,62 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestError(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		test(` | ||||
|             [ Error.prototype.name, Error.prototype.message, Error.prototype.hasOwnProperty("message") ]; | ||||
|         `, "Error,,true") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestError_instanceof(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		test(`(new TypeError()) instanceof Error`, true) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestPanicValue(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		vm.Set("abc", func(call FunctionCall) Value { | ||||
| 			value, err := call.Otto.Run(`({ def: 3.14159 })`) | ||||
| 			is(err, nil) | ||||
| 			panic(value) | ||||
| 		}) | ||||
| 
 | ||||
| 		test(` | ||||
|             try { | ||||
|                 abc(); | ||||
|             } | ||||
|             catch (err) { | ||||
|                 error = err; | ||||
|             } | ||||
|             [ error instanceof Error, error.message, error.def ]; | ||||
|         `, "false,,3.14159") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_catchPanic(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		vm := New() | ||||
| 
 | ||||
| 		_, err := vm.Run(` | ||||
|             A syntax error that | ||||
|             does not define | ||||
|             var; | ||||
|                 abc; | ||||
|         `) | ||||
| 		is(err, "!=", nil) | ||||
| 
 | ||||
| 		_, err = vm.Call(`abc.def`, nil) | ||||
| 		is(err, "!=", nil) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										40
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/execution_context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/execution_context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,40 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| type _executionContext struct { | ||||
| 	LexicalEnvironment  _environment | ||||
| 	VariableEnvironment _environment | ||||
| 	this                *_object | ||||
| 	eval                bool // Replace this with kind?
 | ||||
| } | ||||
| 
 | ||||
| func newExecutionContext(lexical _environment, variable _environment, this *_object) *_executionContext { | ||||
| 	return &_executionContext{ | ||||
| 		LexicalEnvironment:  lexical, | ||||
| 		VariableEnvironment: variable, | ||||
| 		this:                this, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_executionContext) getValue(name string) Value { | ||||
| 	strict := false | ||||
| 	return self.LexicalEnvironment.GetValue(name, strict) | ||||
| } | ||||
| 
 | ||||
| func (self *_executionContext) setValue(name string, value Value, throw bool) { | ||||
| 	self.LexicalEnvironment.SetValue(name, value, throw) | ||||
| } | ||||
| 
 | ||||
| func (self *_executionContext) newLexicalEnvironment(object *_object) (_environment, *_objectEnvironment) { | ||||
| 	// Get runtime from the object (for now)
 | ||||
| 	runtime := object.runtime | ||||
| 	previousLexical := self.LexicalEnvironment | ||||
| 	newLexical := runtime.newObjectEnvironment(object, self.LexicalEnvironment) | ||||
| 	self.LexicalEnvironment = newLexical | ||||
| 	return previousLexical, newLexical | ||||
| } | ||||
| 
 | ||||
| func (self *_executionContext) newDeclarativeEnvironment(runtime *_runtime) _environment { | ||||
| 	previousLexical := self.LexicalEnvironment | ||||
| 	self.LexicalEnvironment = runtime.newDeclarativeEnvironment(self.LexicalEnvironment) | ||||
| 	return previousLexical | ||||
| } | ||||
							
								
								
									
										72
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/file/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/file/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,72 +0,0 @@ | ||||
| # file | ||||
| -- | ||||
|     import "github.com/robertkrimen/otto/file" | ||||
| 
 | ||||
| Package file encapsulates the file abstractions used by the ast & parser. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| #### type FileSet | ||||
| 
 | ||||
| ```go | ||||
| type FileSet struct { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| A FileSet represents a set of source files. | ||||
| 
 | ||||
| #### func (*FileSet) AddFile | ||||
| 
 | ||||
| ```go | ||||
| func (self *FileSet) AddFile(filename, src string) int | ||||
| ``` | ||||
| AddFile adds a new file with the given filename and src. | ||||
| 
 | ||||
| This an internal method, but exported for cross-package use. | ||||
| 
 | ||||
| #### func (*FileSet) Position | ||||
| 
 | ||||
| ```go | ||||
| func (self *FileSet) Position(idx Idx) *Position | ||||
| ``` | ||||
| Position converts an Idx in the FileSet into a Position. | ||||
| 
 | ||||
| #### type Idx | ||||
| 
 | ||||
| ```go | ||||
| type Idx int | ||||
| ``` | ||||
| 
 | ||||
| Idx is a compact encoding of a source position within a file set. It can be | ||||
| converted into a Position for a more convenient, but much larger, | ||||
| representation. | ||||
| 
 | ||||
| #### type Position | ||||
| 
 | ||||
| ```go | ||||
| type Position struct { | ||||
| 	Filename string // The filename where the error occurred, if any | ||||
| 	Offset   int    // The src offset | ||||
| 	Line     int    // The line number, starting at 1 | ||||
| 	Column   int    // The column number, starting at 1 (The character count) | ||||
| 
 | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Position describes an arbitrary source position including the filename, line, | ||||
| and column location. | ||||
| 
 | ||||
| #### func (*Position) String | ||||
| 
 | ||||
| ```go | ||||
| func (self *Position) String() string | ||||
| ``` | ||||
| String returns a string in one of several forms: | ||||
| 
 | ||||
|     file:line:column    A valid position with filename | ||||
|     line:column         A valid position without filename | ||||
|     file                An invalid position with filename | ||||
|     -                   An invalid position without filename | ||||
| 
 | ||||
| -- | ||||
| **godocdown** http://github.com/robertkrimen/godocdown | ||||
							
								
								
									
										106
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/file/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/file/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,106 +0,0 @@ | ||||
| // Package file encapsulates the file abstractions used by the ast & parser.
 | ||||
| //
 | ||||
| package file | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Idx is a compact encoding of a source position within a file set.
 | ||||
| // It can be converted into a Position for a more convenient, but much
 | ||||
| // larger, representation.
 | ||||
| type Idx int | ||||
| 
 | ||||
| // Position describes an arbitrary source position
 | ||||
| // including the filename, line, and column location.
 | ||||
| type Position struct { | ||||
| 	Filename string // The filename where the error occurred, if any
 | ||||
| 	Offset   int    // The src offset
 | ||||
| 	Line     int    // The line number, starting at 1
 | ||||
| 	Column   int    // The column number, starting at 1 (The character count)
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // A Position is valid if the line number is > 0.
 | ||||
| 
 | ||||
| func (self *Position) isValid() bool { | ||||
| 	return self.Line > 0 | ||||
| } | ||||
| 
 | ||||
| // String returns a string in one of several forms:
 | ||||
| //
 | ||||
| //	file:line:column    A valid position with filename
 | ||||
| //	line:column         A valid position without filename
 | ||||
| //	file                An invalid position with filename
 | ||||
| //	-                   An invalid position without filename
 | ||||
| //
 | ||||
| func (self *Position) String() string { | ||||
| 	str := self.Filename | ||||
| 	if self.isValid() { | ||||
| 		if str != "" { | ||||
| 			str += ":" | ||||
| 		} | ||||
| 		str += fmt.Sprintf("%d:%d", self.Line, self.Column) | ||||
| 	} | ||||
| 	if str == "" { | ||||
| 		str = "-" | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
| 
 | ||||
| // FileSet
 | ||||
| 
 | ||||
| // A FileSet represents a set of source files.
 | ||||
| type FileSet struct { | ||||
| 	files []*_file | ||||
| 	last  *_file | ||||
| } | ||||
| 
 | ||||
| // AddFile adds a new file with the given filename and src.
 | ||||
| //
 | ||||
| // This an internal method, but exported for cross-package use.
 | ||||
| func (self *FileSet) AddFile(filename, src string) int { | ||||
| 	base := self.nextBase() | ||||
| 	file := &_file{ | ||||
| 		filename: filename, | ||||
| 		src:      src, | ||||
| 		base:     base, | ||||
| 	} | ||||
| 	self.files = append(self.files, file) | ||||
| 	self.last = file | ||||
| 	return base | ||||
| } | ||||
| 
 | ||||
| func (self *FileSet) nextBase() int { | ||||
| 	if self.last == nil { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return self.last.base + len(self.last.src) + 1 | ||||
| } | ||||
| 
 | ||||
| // Position converts an Idx in the FileSet into a Position.
 | ||||
| func (self *FileSet) Position(idx Idx) *Position { | ||||
| 	position := &Position{} | ||||
| 	for _, file := range self.files { | ||||
| 		if idx <= Idx(file.base+len(file.src)) { | ||||
| 			offset := int(idx) - file.base | ||||
| 			src := file.src[:offset] | ||||
| 			position.Filename = file.filename | ||||
| 			position.Offset = offset | ||||
| 			position.Line = 1 + strings.Count(src, "\n") | ||||
| 			if index := strings.LastIndex(src, "\n"); index >= 0 { | ||||
| 				position.Column = offset - index | ||||
| 			} else { | ||||
| 				position.Column = 1 + len(src) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return position | ||||
| } | ||||
| 
 | ||||
| type _file struct { | ||||
| 	filename string | ||||
| 	src      string | ||||
| 	base     int // This will always be 1 or greater
 | ||||
| } | ||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,4 +0,0 @@ | ||||
| .PHONY: test | ||||
| 
 | ||||
| test: | ||||
| 	go test | ||||
							
								
								
									
										190
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										190
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,190 +0,0 @@ | ||||
| # parser | ||||
| -- | ||||
|     import "github.com/robertkrimen/otto/parser" | ||||
| 
 | ||||
| Package parser implements a parser for JavaScript. | ||||
| 
 | ||||
|     import ( | ||||
|         "github.com/robertkrimen/otto/parser" | ||||
|     ) | ||||
| 
 | ||||
| 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) | ||||
| 
 | ||||
| 
 | ||||
| ### Warning | ||||
| 
 | ||||
| The parser and AST interfaces are still works-in-progress (particularly where | ||||
| node types are concerned) and may change in the future. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| #### func  ParseFile | ||||
| 
 | ||||
| ```go | ||||
| func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error) | ||||
| ``` | ||||
| ParseFile parses the source code of a single JavaScript/ECMAScript source file | ||||
| and returns the corresponding ast.Program node. | ||||
| 
 | ||||
| If fileSet == nil, ParseFile parses source without a FileSet. If fileSet != nil, | ||||
| ParseFile first adds filename and src to fileSet. | ||||
| 
 | ||||
| The filename argument is optional and is used for labelling errors, etc. | ||||
| 
 | ||||
| src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST | ||||
| always be in UTF-8. | ||||
| 
 | ||||
|     // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList | ||||
|     program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0) | ||||
| 
 | ||||
| #### func  ParseFunction | ||||
| 
 | ||||
| ```go | ||||
| func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error) | ||||
| ``` | ||||
| ParseFunction parses a given parameter list and body as a function and returns | ||||
| the corresponding ast.FunctionLiteral 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 | ||||
| func TransformRegExp(pattern string) (string, error) | ||||
| ``` | ||||
| TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern. | ||||
| 
 | ||||
| re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or | ||||
| backreference (\1, \2, ...) will cause an error. | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| If the pattern is invalid (not valid even in JavaScript), then this function | ||||
| returns the empty string and an error. | ||||
| 
 | ||||
| If the pattern is valid, but incompatible (contains a lookahead or | ||||
| backreference), then this function returns the transformation (a non-empty | ||||
| string) AND an error. | ||||
| 
 | ||||
| #### type Error | ||||
| 
 | ||||
| ```go | ||||
| type Error struct { | ||||
| 	Position file.Position | ||||
| 	Message  string | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| An Error represents a parsing error. It includes the position where the error | ||||
| occurred and a message/description. | ||||
| 
 | ||||
| #### func (Error) Error | ||||
| 
 | ||||
| ```go | ||||
| func (self Error) Error() string | ||||
| ``` | ||||
| 
 | ||||
| #### type ErrorList | ||||
| 
 | ||||
| ```go | ||||
| type ErrorList []*Error | ||||
| ``` | ||||
| 
 | ||||
| ErrorList is a list of *Errors. | ||||
| 
 | ||||
| #### func (*ErrorList) Add | ||||
| 
 | ||||
| ```go | ||||
| func (self *ErrorList) Add(position file.Position, msg string) | ||||
| ``` | ||||
| Add adds an Error with given position and message to an ErrorList. | ||||
| 
 | ||||
| #### func (ErrorList) Err | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Err() error | ||||
| ``` | ||||
| Err returns an error equivalent to this ErrorList. If the list is empty, Err | ||||
| returns nil. | ||||
| 
 | ||||
| #### func (ErrorList) Error | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Error() string | ||||
| ``` | ||||
| Error implements the Error interface. | ||||
| 
 | ||||
| #### func (ErrorList) Len | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Len() int | ||||
| ``` | ||||
| 
 | ||||
| #### func (ErrorList) Less | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Less(i, j int) bool | ||||
| ``` | ||||
| 
 | ||||
| #### func (*ErrorList) Reset | ||||
| 
 | ||||
| ```go | ||||
| func (self *ErrorList) Reset() | ||||
| ``` | ||||
| Reset resets an ErrorList to no errors. | ||||
| 
 | ||||
| #### func (ErrorList) Sort | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Sort() | ||||
| ``` | ||||
| 
 | ||||
| #### func (ErrorList) Swap | ||||
| 
 | ||||
| ```go | ||||
| func (self ErrorList) Swap(i, j int) | ||||
| ``` | ||||
| 
 | ||||
| #### type Mode | ||||
| 
 | ||||
| ```go | ||||
| type Mode uint | ||||
| ``` | ||||
| 
 | ||||
| A Mode value is a set of flags (or 0). They control optional parser | ||||
| functionality. | ||||
| 
 | ||||
| ```go | ||||
| const ( | ||||
| 	IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking) | ||||
| ) | ||||
| ``` | ||||
| 
 | ||||
| -- | ||||
| **godocdown** http://github.com/robertkrimen/godocdown | ||||
							
								
								
									
										9
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/dbg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/dbg.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,9 +0,0 @@ | ||||
| // This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg
 | ||||
| 
 | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	Dbg "github.com/robertkrimen/otto/dbg" | ||||
| ) | ||||
| 
 | ||||
| var dbg, dbgf = Dbg.New() | ||||
							
								
								
									
										175
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										175
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,175 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	err_UnexpectedToken      = "Unexpected token %v" | ||||
| 	err_UnexpectedEndOfInput = "Unexpected end of input" | ||||
| 	err_UnexpectedEscape     = "Unexpected escape" | ||||
| ) | ||||
| 
 | ||||
| //    UnexpectedNumber:  'Unexpected number',
 | ||||
| //    UnexpectedString:  'Unexpected string',
 | ||||
| //    UnexpectedIdentifier:  'Unexpected identifier',
 | ||||
| //    UnexpectedReserved:  'Unexpected reserved word',
 | ||||
| //    NewlineAfterThrow:  'Illegal newline after throw',
 | ||||
| //    InvalidRegExp: 'Invalid regular expression',
 | ||||
| //    UnterminatedRegExp:  'Invalid regular expression: missing /',
 | ||||
| //    InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
 | ||||
| //    InvalidLHSInForIn:  'Invalid left-hand side in for-in',
 | ||||
| //    MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
 | ||||
| //    NoCatchOrFinally:  'Missing catch or finally after try',
 | ||||
| //    UnknownLabel: 'Undefined label \'%0\'',
 | ||||
| //    Redeclaration: '%0 \'%1\' has already been declared',
 | ||||
| //    IllegalContinue: 'Illegal continue statement',
 | ||||
| //    IllegalBreak: 'Illegal break statement',
 | ||||
| //    IllegalReturn: 'Illegal return statement',
 | ||||
| //    StrictModeWith:  'Strict mode code may not include a with statement',
 | ||||
| //    StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
 | ||||
| //    StrictVarName:  'Variable name may not be eval or arguments in strict mode',
 | ||||
| //    StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
 | ||||
| //    StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
 | ||||
| //    StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
 | ||||
| //    StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
 | ||||
| //    StrictDelete:  'Delete of an unqualified identifier in strict mode.',
 | ||||
| //    StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
 | ||||
| //    AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
 | ||||
| //    AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
 | ||||
| //    StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
 | ||||
| //    StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
 | ||||
| //    StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
 | ||||
| //    StrictReservedWord:  'Use of future reserved word in strict mode'
 | ||||
| 
 | ||||
| // A SyntaxError is a description of an ECMAScript syntax error.
 | ||||
| 
 | ||||
| // An Error represents a parsing error. It includes the position where the error occurred and a message/description.
 | ||||
| type Error struct { | ||||
| 	Position file.Position | ||||
| 	Message  string | ||||
| } | ||||
| 
 | ||||
| // FXIME Should this be "SyntaxError"?
 | ||||
| 
 | ||||
| func (self Error) Error() string { | ||||
| 	filename := self.Position.Filename | ||||
| 	if filename == "" { | ||||
| 		filename = "(anonymous)" | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s: Line %d:%d %s", | ||||
| 		filename, | ||||
| 		self.Position.Line, | ||||
| 		self.Position.Column, | ||||
| 		self.Message, | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) error(place interface{}, msg string, msgValues ...interface{}) *Error { | ||||
| 	idx := file.Idx(0) | ||||
| 	switch place := place.(type) { | ||||
| 	case int: | ||||
| 		idx = self.idxOf(place) | ||||
| 	case file.Idx: | ||||
| 		if place == 0 { | ||||
| 			idx = self.idxOf(self.chrOffset) | ||||
| 		} else { | ||||
| 			idx = place | ||||
| 		} | ||||
| 	default: | ||||
| 		panic(fmt.Errorf("error(%T, ...)", place)) | ||||
| 	} | ||||
| 
 | ||||
| 	position := self.position(idx) | ||||
| 	msg = fmt.Sprintf(msg, msgValues...) | ||||
| 	self.errors.Add(position, msg) | ||||
| 	return self.errors[len(self.errors)-1] | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) errorUnexpected(idx file.Idx, chr rune) error { | ||||
| 	if chr == -1 { | ||||
| 		return self.error(idx, err_UnexpectedEndOfInput) | ||||
| 	} | ||||
| 	return self.error(idx, err_UnexpectedToken, token.ILLEGAL) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) errorUnexpectedToken(tkn token.Token) error { | ||||
| 	switch tkn { | ||||
| 	case token.EOF: | ||||
| 		return self.error(file.Idx(0), err_UnexpectedEndOfInput) | ||||
| 	} | ||||
| 	value := tkn.String() | ||||
| 	switch tkn { | ||||
| 	case token.BOOLEAN, token.NULL: | ||||
| 		value = self.literal | ||||
| 	case token.IDENTIFIER: | ||||
| 		return self.error(self.idx, "Unexpected identifier") | ||||
| 	case token.KEYWORD: | ||||
| 		// TODO Might be a future reserved word
 | ||||
| 		return self.error(self.idx, "Unexpected reserved word") | ||||
| 	case token.NUMBER: | ||||
| 		return self.error(self.idx, "Unexpected number") | ||||
| 	case token.STRING: | ||||
| 		return self.error(self.idx, "Unexpected string") | ||||
| 	} | ||||
| 	return self.error(self.idx, err_UnexpectedToken, value) | ||||
| } | ||||
| 
 | ||||
| // ErrorList is a list of *Errors.
 | ||||
| //
 | ||||
| type ErrorList []*Error | ||||
| 
 | ||||
| // Add adds an Error with given position and message to an ErrorList.
 | ||||
| func (self *ErrorList) Add(position file.Position, msg string) { | ||||
| 	*self = append(*self, &Error{position, msg}) | ||||
| } | ||||
| 
 | ||||
| // Reset resets an ErrorList to no errors.
 | ||||
| func (self *ErrorList) Reset() { *self = (*self)[0:0] } | ||||
| 
 | ||||
| func (self ErrorList) Len() int      { return len(self) } | ||||
| func (self ErrorList) Swap(i, j int) { self[i], self[j] = self[j], self[i] } | ||||
| func (self ErrorList) Less(i, j int) bool { | ||||
| 	x := &self[i].Position | ||||
| 	y := &self[j].Position | ||||
| 	if x.Filename < y.Filename { | ||||
| 		return true | ||||
| 	} | ||||
| 	if x.Filename == y.Filename { | ||||
| 		if x.Line < y.Line { | ||||
| 			return true | ||||
| 		} | ||||
| 		if x.Line == y.Line { | ||||
| 			return x.Column < y.Column | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (self ErrorList) Sort() { | ||||
| 	sort.Sort(self) | ||||
| } | ||||
| 
 | ||||
| // Error implements the Error interface.
 | ||||
| func (self ErrorList) Error() string { | ||||
| 	switch len(self) { | ||||
| 	case 0: | ||||
| 		return "no errors" | ||||
| 	case 1: | ||||
| 		return self[0].Error() | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s (and %d more errors)", self[0].Error(), len(self)-1) | ||||
| } | ||||
| 
 | ||||
| // Err returns an error equivalent to this ErrorList.
 | ||||
| // If the list is empty, Err returns nil.
 | ||||
| func (self ErrorList) Err() error { | ||||
| 	if len(self) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return self | ||||
| } | ||||
							
								
								
									
										815
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/expression.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										815
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/expression.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,815 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"regexp" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| func (self *_parser) parseIdentifier() *ast.Identifier { | ||||
| 	literal := self.literal | ||||
| 	idx := self.idx | ||||
| 	self.next() | ||||
| 	return &ast.Identifier{ | ||||
| 		Name: literal, | ||||
| 		Idx:  idx, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parsePrimaryExpression() ast.Expression { | ||||
| 	literal := self.literal | ||||
| 	idx := self.idx | ||||
| 	switch self.token { | ||||
| 	case token.IDENTIFIER: | ||||
| 		self.next() | ||||
| 		if len(literal) > 1 { | ||||
| 			tkn, strict := token.IsKeyword(literal) | ||||
| 			if tkn == token.KEYWORD { | ||||
| 				if !strict { | ||||
| 					self.error(idx, "Unexpected reserved word") | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return &ast.Identifier{ | ||||
| 			Name: literal, | ||||
| 			Idx:  idx, | ||||
| 		} | ||||
| 	case token.NULL: | ||||
| 		self.next() | ||||
| 		return &ast.NullLiteral{ | ||||
| 			Idx:     idx, | ||||
| 			Literal: literal, | ||||
| 		} | ||||
| 	case token.BOOLEAN: | ||||
| 		self.next() | ||||
| 		value := false | ||||
| 		switch literal { | ||||
| 		case "true": | ||||
| 			value = true | ||||
| 		case "false": | ||||
| 			value = false | ||||
| 		default: | ||||
| 			self.error(idx, "Illegal boolean literal") | ||||
| 		} | ||||
| 		return &ast.BooleanLiteral{ | ||||
| 			Idx:     idx, | ||||
| 			Literal: literal, | ||||
| 			Value:   value, | ||||
| 		} | ||||
| 	case token.STRING: | ||||
| 		self.next() | ||||
| 		value, err := parseStringLiteral(literal[1 : len(literal)-1]) | ||||
| 		if err != nil { | ||||
| 			self.error(idx, err.Error()) | ||||
| 		} | ||||
| 		return &ast.StringLiteral{ | ||||
| 			Idx:     idx, | ||||
| 			Literal: literal, | ||||
| 			Value:   value, | ||||
| 		} | ||||
| 	case token.NUMBER: | ||||
| 		self.next() | ||||
| 		value, err := parseNumberLiteral(literal) | ||||
| 		if err != nil { | ||||
| 			self.error(idx, err.Error()) | ||||
| 			value = 0 | ||||
| 		} | ||||
| 		return &ast.NumberLiteral{ | ||||
| 			Idx:     idx, | ||||
| 			Literal: literal, | ||||
| 			Value:   value, | ||||
| 		} | ||||
| 	case token.SLASH, token.QUOTIENT_ASSIGN: | ||||
| 		return self.parseRegExpLiteral() | ||||
| 	case token.LEFT_BRACE: | ||||
| 		return self.parseObjectLiteral() | ||||
| 	case token.LEFT_BRACKET: | ||||
| 		return self.parseArrayLiteral() | ||||
| 	case token.LEFT_PARENTHESIS: | ||||
| 		self.expect(token.LEFT_PARENTHESIS) | ||||
| 		expression := self.parseExpression() | ||||
| 		self.expect(token.RIGHT_PARENTHESIS) | ||||
| 		return expression | ||||
| 	case token.THIS: | ||||
| 		self.next() | ||||
| 		return &ast.ThisExpression{ | ||||
| 			Idx: idx, | ||||
| 		} | ||||
| 	case token.FUNCTION: | ||||
| 		return self.parseFunction(false) | ||||
| 	} | ||||
| 
 | ||||
| 	self.errorUnexpectedToken(self.token) | ||||
| 	self.nextStatement() | ||||
| 	return &ast.BadExpression{From: idx, To: self.idx} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseRegExpLiteral() *ast.RegExpLiteral { | ||||
| 
 | ||||
| 	offset := self.chrOffset - 1 // Opening slash already gotten
 | ||||
| 	if self.token == token.QUOTIENT_ASSIGN { | ||||
| 		offset -= 1 // =
 | ||||
| 	} | ||||
| 	idx := self.idxOf(offset) | ||||
| 
 | ||||
| 	pattern, err := self.scanString(offset) | ||||
| 	endOffset := self.chrOffset | ||||
| 
 | ||||
| 	self.next() | ||||
| 	if err == nil { | ||||
| 		pattern = pattern[1 : len(pattern)-1] | ||||
| 	} | ||||
| 
 | ||||
| 	flags := "" | ||||
| 	if self.token == token.IDENTIFIER { // gim
 | ||||
| 
 | ||||
| 		flags = self.literal | ||||
| 		self.next() | ||||
| 		endOffset = self.chrOffset - 1 | ||||
| 	} | ||||
| 
 | ||||
| 	var value string | ||||
| 	// TODO 15.10
 | ||||
| 	{ | ||||
| 		// Test during parsing that this is a valid regular expression
 | ||||
| 		// Sorry, (?=) and (?!) are invalid (for now)
 | ||||
| 		pattern, err := TransformRegExp(pattern) | ||||
| 		if err != nil { | ||||
| 			if pattern == "" || self.mode&IgnoreRegExpErrors == 0 { | ||||
| 				self.error(idx, "Invalid regular expression: %s", err.Error()) | ||||
| 			} | ||||
| 		} else { | ||||
| 			_, err = regexp.Compile(pattern) | ||||
| 			if err != nil { | ||||
| 				// We should not get here, ParseRegExp should catch any errors
 | ||||
| 				self.error(idx, "Invalid regular expression: %s", err.Error()[22:]) // Skip redundant "parse regexp error"
 | ||||
| 			} else { | ||||
| 				value = pattern | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	literal := self.str[offset:endOffset] | ||||
| 
 | ||||
| 	return &ast.RegExpLiteral{ | ||||
| 		Idx:     idx, | ||||
| 		Literal: literal, | ||||
| 		Pattern: pattern, | ||||
| 		Flags:   flags, | ||||
| 		Value:   value, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.VariableExpression) ast.Expression { | ||||
| 
 | ||||
| 	if self.token != token.IDENTIFIER { | ||||
| 		idx := self.expect(token.IDENTIFIER) | ||||
| 		self.nextStatement() | ||||
| 		return &ast.BadExpression{From: idx, To: self.idx} | ||||
| 	} | ||||
| 
 | ||||
| 	literal := self.literal | ||||
| 	idx := self.idx | ||||
| 	self.next() | ||||
| 	node := &ast.VariableExpression{ | ||||
| 		Name: literal, | ||||
| 		Idx:  idx, | ||||
| 	} | ||||
| 
 | ||||
| 	if declarationList != nil { | ||||
| 		*declarationList = append(*declarationList, node) | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.ASSIGN { | ||||
| 		self.next() | ||||
| 		node.Initializer = self.parseAssignmentExpression() | ||||
| 	} | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expression { | ||||
| 
 | ||||
| 	var declarationList []*ast.VariableExpression // Avoid bad expressions
 | ||||
| 	var list []ast.Expression | ||||
| 
 | ||||
| 	for { | ||||
| 		list = append(list, self.parseVariableDeclaration(&declarationList)) | ||||
| 		if self.token != token.COMMA { | ||||
| 			break | ||||
| 		} | ||||
| 		self.next() | ||||
| 	} | ||||
| 
 | ||||
| 	self.scope.declare(&ast.VariableDeclaration{ | ||||
| 		Var:  var_, | ||||
| 		List: declarationList, | ||||
| 	}) | ||||
| 
 | ||||
| 	return list | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseObjectPropertyKey() (string, string) { | ||||
| 	idx, tkn, literal := self.idx, self.token, self.literal | ||||
| 	value := "" | ||||
| 	self.next() | ||||
| 	switch tkn { | ||||
| 	case token.IDENTIFIER: | ||||
| 		value = literal | ||||
| 	case token.NUMBER: | ||||
| 		var err error | ||||
| 		_, err = parseNumberLiteral(literal) | ||||
| 		if err != nil { | ||||
| 			self.error(idx, err.Error()) | ||||
| 		} else { | ||||
| 			value = literal | ||||
| 		} | ||||
| 	case token.STRING: | ||||
| 		var err error | ||||
| 		value, err = parseStringLiteral(literal[1 : len(literal)-1]) | ||||
| 		if err != nil { | ||||
| 			self.error(idx, err.Error()) | ||||
| 		} | ||||
| 	default: | ||||
| 		// null, false, class, etc.
 | ||||
| 		if matchIdentifier.MatchString(literal) { | ||||
| 			value = literal | ||||
| 		} | ||||
| 	} | ||||
| 	return literal, value | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseObjectProperty() ast.Property { | ||||
| 
 | ||||
| 	literal, value := self.parseObjectPropertyKey() | ||||
| 	if literal == "get" && self.token != token.COLON { | ||||
| 		idx := self.idx | ||||
| 		_, value := self.parseObjectPropertyKey() | ||||
| 		parameterList := self.parseFunctionParameterList() | ||||
| 
 | ||||
| 		node := &ast.FunctionLiteral{ | ||||
| 			Function:      idx, | ||||
| 			ParameterList: parameterList, | ||||
| 		} | ||||
| 		self.parseFunctionBlock(node) | ||||
| 		return ast.Property{ | ||||
| 			Key:   value, | ||||
| 			Kind:  "get", | ||||
| 			Value: node, | ||||
| 		} | ||||
| 	} else if literal == "set" && self.token != token.COLON { | ||||
| 		idx := self.idx | ||||
| 		_, value := self.parseObjectPropertyKey() | ||||
| 		parameterList := self.parseFunctionParameterList() | ||||
| 
 | ||||
| 		node := &ast.FunctionLiteral{ | ||||
| 			Function:      idx, | ||||
| 			ParameterList: parameterList, | ||||
| 		} | ||||
| 		self.parseFunctionBlock(node) | ||||
| 		return ast.Property{ | ||||
| 			Key:   value, | ||||
| 			Kind:  "set", | ||||
| 			Value: node, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.expect(token.COLON) | ||||
| 
 | ||||
| 	return ast.Property{ | ||||
| 		Key:   value, | ||||
| 		Kind:  "value", | ||||
| 		Value: self.parseAssignmentExpression(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseObjectLiteral() ast.Expression { | ||||
| 	var value []ast.Property | ||||
| 	idx0 := self.expect(token.LEFT_BRACE) | ||||
| 	for self.token != token.RIGHT_BRACE && self.token != token.EOF { | ||||
| 		property := self.parseObjectProperty() | ||||
| 		value = append(value, property) | ||||
| 		if self.token == token.COMMA { | ||||
| 			self.next() | ||||
| 			continue | ||||
| 		} | ||||
| 	} | ||||
| 	idx1 := self.expect(token.RIGHT_BRACE) | ||||
| 
 | ||||
| 	return &ast.ObjectLiteral{ | ||||
| 		LeftBrace:  idx0, | ||||
| 		RightBrace: idx1, | ||||
| 		Value:      value, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseArrayLiteral() ast.Expression { | ||||
| 
 | ||||
| 	idx0 := self.expect(token.LEFT_BRACKET) | ||||
| 	var value []ast.Expression | ||||
| 	for self.token != token.RIGHT_BRACKET && self.token != token.EOF { | ||||
| 		if self.token == token.COMMA { | ||||
| 			self.next() | ||||
| 			value = append(value, nil) | ||||
| 			continue | ||||
| 		} | ||||
| 		value = append(value, self.parseAssignmentExpression()) | ||||
| 		if self.token != token.RIGHT_BRACKET { | ||||
| 			self.expect(token.COMMA) | ||||
| 		} | ||||
| 	} | ||||
| 	idx1 := self.expect(token.RIGHT_BRACKET) | ||||
| 
 | ||||
| 	return &ast.ArrayLiteral{ | ||||
| 		LeftBracket:  idx0, | ||||
| 		RightBracket: idx1, | ||||
| 		Value:        value, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) { | ||||
| 	idx0 = self.expect(token.LEFT_PARENTHESIS) | ||||
| 	if self.token != token.RIGHT_PARENTHESIS { | ||||
| 		for { | ||||
| 			argumentList = append(argumentList, self.parseAssignmentExpression()) | ||||
| 			if self.token != token.COMMA { | ||||
| 				break | ||||
| 			} | ||||
| 			self.next() | ||||
| 		} | ||||
| 	} | ||||
| 	idx1 = self.expect(token.RIGHT_PARENTHESIS) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression { | ||||
| 	argumentList, idx0, idx1 := self.parseArgumentList() | ||||
| 	return &ast.CallExpression{ | ||||
| 		Callee:           left, | ||||
| 		LeftParenthesis:  idx0, | ||||
| 		ArgumentList:     argumentList, | ||||
| 		RightParenthesis: idx1, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseDotMember(left ast.Expression) ast.Expression { | ||||
| 	period := self.expect(token.PERIOD) | ||||
| 
 | ||||
| 	literal := self.literal | ||||
| 	idx := self.idx | ||||
| 
 | ||||
| 	if !matchIdentifier.MatchString(literal) { | ||||
| 		self.expect(token.IDENTIFIER) | ||||
| 		self.nextStatement() | ||||
| 		return &ast.BadExpression{From: period, To: self.idx} | ||||
| 	} | ||||
| 
 | ||||
| 	self.next() | ||||
| 
 | ||||
| 	return &ast.DotExpression{ | ||||
| 		Left: left, | ||||
| 		Identifier: ast.Identifier{ | ||||
| 			Idx:  idx, | ||||
| 			Name: literal, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseBracketMember(left ast.Expression) ast.Expression { | ||||
| 	idx0 := self.expect(token.LEFT_BRACKET) | ||||
| 	member := self.parseExpression() | ||||
| 	idx1 := self.expect(token.RIGHT_BRACKET) | ||||
| 	return &ast.BracketExpression{ | ||||
| 		LeftBracket:  idx0, | ||||
| 		Left:         left, | ||||
| 		Member:       member, | ||||
| 		RightBracket: idx1, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseNewExpression() ast.Expression { | ||||
| 	idx := self.expect(token.NEW) | ||||
| 	callee := self.parseLeftHandSideExpression() | ||||
| 	node := &ast.NewExpression{ | ||||
| 		New:    idx, | ||||
| 		Callee: callee, | ||||
| 	} | ||||
| 	if self.token == token.LEFT_PARENTHESIS { | ||||
| 		argumentList, idx0, idx1 := self.parseArgumentList() | ||||
| 		node.ArgumentList = argumentList | ||||
| 		node.LeftParenthesis = idx0 | ||||
| 		node.RightParenthesis = idx1 | ||||
| 	} | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseLeftHandSideExpression() ast.Expression { | ||||
| 
 | ||||
| 	var left ast.Expression | ||||
| 	if self.token == token.NEW { | ||||
| 		left = self.parseNewExpression() | ||||
| 	} else { | ||||
| 		left = self.parsePrimaryExpression() | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		if self.token == token.PERIOD { | ||||
| 			left = self.parseDotMember(left) | ||||
| 		} else if self.token == token.LEFT_BRACE { | ||||
| 			left = self.parseBracketMember(left) | ||||
| 		} else { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression { | ||||
| 
 | ||||
| 	allowIn := self.scope.allowIn | ||||
| 	self.scope.allowIn = true | ||||
| 	defer func() { | ||||
| 		self.scope.allowIn = allowIn | ||||
| 	}() | ||||
| 
 | ||||
| 	var left ast.Expression | ||||
| 	if self.token == token.NEW { | ||||
| 		left = self.parseNewExpression() | ||||
| 	} else { | ||||
| 		left = self.parsePrimaryExpression() | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		if self.token == token.PERIOD { | ||||
| 			left = self.parseDotMember(left) | ||||
| 		} else if self.token == token.LEFT_BRACKET { | ||||
| 			left = self.parseBracketMember(left) | ||||
| 		} else if self.token == token.LEFT_PARENTHESIS { | ||||
| 			left = self.parseCallExpression(left) | ||||
| 		} else { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parsePostfixExpression() ast.Expression { | ||||
| 	operand := self.parseLeftHandSideExpressionAllowCall() | ||||
| 
 | ||||
| 	switch self.token { | ||||
| 	case token.INCREMENT, token.DECREMENT: | ||||
| 		// Make sure there is no line terminator here
 | ||||
| 		if self.implicitSemicolon { | ||||
| 			break | ||||
| 		} | ||||
| 		tkn := self.token | ||||
| 		idx := self.idx | ||||
| 		self.next() | ||||
| 		switch operand.(type) { | ||||
| 		case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: | ||||
| 		default: | ||||
| 			self.error(idx, "Invalid left-hand side in assignment") | ||||
| 			self.nextStatement() | ||||
| 			return &ast.BadExpression{From: idx, To: self.idx} | ||||
| 		} | ||||
| 		return &ast.UnaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Idx:      idx, | ||||
| 			Operand:  operand, | ||||
| 			Postfix:  true, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return operand | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseUnaryExpression() ast.Expression { | ||||
| 
 | ||||
| 	switch self.token { | ||||
| 	case token.PLUS, token.MINUS, token.NOT, token.BITWISE_NOT: | ||||
| 		fallthrough | ||||
| 	case token.DELETE, token.VOID, token.TYPEOF: | ||||
| 		tkn := self.token | ||||
| 		idx := self.idx | ||||
| 		self.next() | ||||
| 		return &ast.UnaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Idx:      idx, | ||||
| 			Operand:  self.parseUnaryExpression(), | ||||
| 		} | ||||
| 	case token.INCREMENT, token.DECREMENT: | ||||
| 		tkn := self.token | ||||
| 		idx := self.idx | ||||
| 		self.next() | ||||
| 		operand := self.parseUnaryExpression() | ||||
| 		switch operand.(type) { | ||||
| 		case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: | ||||
| 		default: | ||||
| 			self.error(idx, "Invalid left-hand side in assignment") | ||||
| 			self.nextStatement() | ||||
| 			return &ast.BadExpression{From: idx, To: self.idx} | ||||
| 		} | ||||
| 		return &ast.UnaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Idx:      idx, | ||||
| 			Operand:  operand, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return self.parsePostfixExpression() | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseMultiplicativeExpression() ast.Expression { | ||||
| 	next := self.parseUnaryExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.MULTIPLY || self.token == token.SLASH || | ||||
| 		self.token == token.REMAINDER { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseAdditiveExpression() ast.Expression { | ||||
| 	next := self.parseMultiplicativeExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.PLUS || self.token == token.MINUS { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseShiftExpression() ast.Expression { | ||||
| 	next := self.parseAdditiveExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.SHIFT_LEFT || self.token == token.SHIFT_RIGHT || | ||||
| 		self.token == token.UNSIGNED_SHIFT_RIGHT { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseRelationalExpression() ast.Expression { | ||||
| 	next := self.parseShiftExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	allowIn := self.scope.allowIn | ||||
| 	self.scope.allowIn = true | ||||
| 	defer func() { | ||||
| 		self.scope.allowIn = allowIn | ||||
| 	}() | ||||
| 
 | ||||
| 	switch self.token { | ||||
| 	case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL: | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		return &ast.BinaryExpression{ | ||||
| 			Operator:   tkn, | ||||
| 			Left:       left, | ||||
| 			Right:      self.parseRelationalExpression(), | ||||
| 			Comparison: true, | ||||
| 		} | ||||
| 	case token.INSTANCEOF: | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		return &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    self.parseRelationalExpression(), | ||||
| 		} | ||||
| 	case token.IN: | ||||
| 		if !allowIn { | ||||
| 			return left | ||||
| 		} | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		return &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    self.parseRelationalExpression(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseEqualityExpression() ast.Expression { | ||||
| 	next := self.parseRelationalExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.EQUAL || self.token == token.NOT_EQUAL || | ||||
| 		self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator:   tkn, | ||||
| 			Left:       left, | ||||
| 			Right:      next(), | ||||
| 			Comparison: true, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseBitwiseAndExpression() ast.Expression { | ||||
| 	next := self.parseEqualityExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.AND { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression { | ||||
| 	next := self.parseBitwiseAndExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.EXCLUSIVE_OR { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseBitwiseOrExpression() ast.Expression { | ||||
| 	next := self.parseBitwiseExclusiveOrExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.OR { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseLogicalAndExpression() ast.Expression { | ||||
| 	next := self.parseBitwiseOrExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.LOGICAL_AND { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseLogicalOrExpression() ast.Expression { | ||||
| 	next := self.parseLogicalAndExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	for self.token == token.LOGICAL_OR { | ||||
| 		tkn := self.token | ||||
| 		self.next() | ||||
| 		left = &ast.BinaryExpression{ | ||||
| 			Operator: tkn, | ||||
| 			Left:     left, | ||||
| 			Right:    next(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseConditionlExpression() ast.Expression { | ||||
| 	left := self.parseLogicalOrExpression() | ||||
| 
 | ||||
| 	if self.token == token.QUESTION_MARK { | ||||
| 		self.next() | ||||
| 		consequent := self.parseAssignmentExpression() | ||||
| 		self.expect(token.COLON) | ||||
| 		return &ast.ConditionalExpression{ | ||||
| 			Test:       left, | ||||
| 			Consequent: consequent, | ||||
| 			Alternate:  self.parseAssignmentExpression(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseAssignmentExpression() ast.Expression { | ||||
| 	left := self.parseConditionlExpression() | ||||
| 	var operator token.Token | ||||
| 	switch self.token { | ||||
| 	case token.ASSIGN: | ||||
| 		operator = self.token | ||||
| 	case token.ADD_ASSIGN: | ||||
| 		operator = token.PLUS | ||||
| 	case token.SUBTRACT_ASSIGN: | ||||
| 		operator = token.MINUS | ||||
| 	case token.MULTIPLY_ASSIGN: | ||||
| 		operator = token.MULTIPLY | ||||
| 	case token.QUOTIENT_ASSIGN: | ||||
| 		operator = token.SLASH | ||||
| 	case token.REMAINDER_ASSIGN: | ||||
| 		operator = token.REMAINDER | ||||
| 	case token.AND_ASSIGN: | ||||
| 		operator = token.AND | ||||
| 	case token.AND_NOT_ASSIGN: | ||||
| 		operator = token.AND_NOT | ||||
| 	case token.OR_ASSIGN: | ||||
| 		operator = token.OR | ||||
| 	case token.EXCLUSIVE_OR_ASSIGN: | ||||
| 		operator = token.EXCLUSIVE_OR | ||||
| 	case token.SHIFT_LEFT_ASSIGN: | ||||
| 		operator = token.SHIFT_LEFT | ||||
| 	case token.SHIFT_RIGHT_ASSIGN: | ||||
| 		operator = token.SHIFT_RIGHT | ||||
| 	case token.UNSIGNED_SHIFT_RIGHT_ASSIGN: | ||||
| 		operator = token.UNSIGNED_SHIFT_RIGHT | ||||
| 	} | ||||
| 
 | ||||
| 	if operator != 0 { | ||||
| 		idx := self.idx | ||||
| 		self.next() | ||||
| 		switch left.(type) { | ||||
| 		case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression: | ||||
| 		default: | ||||
| 			self.error(left.Idx0(), "Invalid left-hand side in assignment") | ||||
| 			self.nextStatement() | ||||
| 			return &ast.BadExpression{From: idx, To: self.idx} | ||||
| 		} | ||||
| 		return &ast.AssignExpression{ | ||||
| 			Left:     left, | ||||
| 			Operator: operator, | ||||
| 			Right:    self.parseAssignmentExpression(), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseExpression() ast.Expression { | ||||
| 	next := self.parseAssignmentExpression | ||||
| 	left := next() | ||||
| 
 | ||||
| 	if self.token == token.COMMA { | ||||
| 		sequence := []ast.Expression{left} | ||||
| 		for { | ||||
| 			if self.token != token.COMMA { | ||||
| 				break | ||||
| 			} | ||||
| 			self.next() | ||||
| 			sequence = append(sequence, next()) | ||||
| 		} | ||||
| 		return &ast.SequenceExpression{ | ||||
| 			Sequence: sequence, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return left | ||||
| } | ||||
							
								
								
									
										819
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/lexer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										819
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/lexer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,819 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| type _chr struct { | ||||
| 	value rune | ||||
| 	width int | ||||
| } | ||||
| 
 | ||||
| var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`) | ||||
| 
 | ||||
| func isDecimalDigit(chr rune) bool { | ||||
| 	return '0' <= chr && chr <= '9' | ||||
| } | ||||
| 
 | ||||
| func digitValue(chr rune) int { | ||||
| 	switch { | ||||
| 	case '0' <= chr && chr <= '9': | ||||
| 		return int(chr - '0') | ||||
| 	case 'a' <= chr && chr <= 'f': | ||||
| 		return int(chr - 'a' + 10) | ||||
| 	case 'A' <= chr && chr <= 'F': | ||||
| 		return int(chr - 'A' + 10) | ||||
| 	} | ||||
| 	return 16 // Larger than any legal digit value
 | ||||
| } | ||||
| 
 | ||||
| func isDigit(chr rune, base int) bool { | ||||
| 	return digitValue(chr) < base | ||||
| } | ||||
| 
 | ||||
| func isIdentifierStart(chr rune) bool { | ||||
| 	return chr == '$' || chr == '_' || chr == '\\' || | ||||
| 		'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' || | ||||
| 		chr >= utf8.RuneSelf && unicode.IsLetter(chr) | ||||
| } | ||||
| 
 | ||||
| func isIdentifierPart(chr rune) bool { | ||||
| 	return chr == '$' || chr == '_' || chr == '\\' || | ||||
| 		'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' || | ||||
| 		'0' <= chr && chr <= '9' || | ||||
| 		chr >= utf8.RuneSelf && (unicode.IsLetter(chr) || unicode.IsDigit(chr)) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanIdentifier() (string, error) { | ||||
| 	offset := self.chrOffset | ||||
| 	parse := false | ||||
| 	for isIdentifierPart(self.chr) { | ||||
| 		if self.chr == '\\' { | ||||
| 			distance := self.chrOffset - offset | ||||
| 			self.read() | ||||
| 			if self.chr != 'u' { | ||||
| 				return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr)) | ||||
| 			} | ||||
| 			parse = true | ||||
| 			var value rune | ||||
| 			for j := 0; j < 4; j++ { | ||||
| 				self.read() | ||||
| 				decimal, ok := hex2decimal(byte(self.chr)) | ||||
| 				if !ok { | ||||
| 					return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr)) | ||||
| 				} | ||||
| 				value = value<<4 | decimal | ||||
| 			} | ||||
| 			if value == '\\' { | ||||
| 				return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) | ||||
| 			} else if distance == 0 { | ||||
| 				if !isIdentifierStart(value) { | ||||
| 					return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) | ||||
| 				} | ||||
| 			} else if distance > 0 { | ||||
| 				if !isIdentifierPart(value) { | ||||
| 					return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value)) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		self.read() | ||||
| 	} | ||||
| 	literal := string(self.str[offset:self.chrOffset]) | ||||
| 	if parse { | ||||
| 		return parseStringLiteral(literal) | ||||
| 	} | ||||
| 	return literal, nil | ||||
| } | ||||
| 
 | ||||
| // 7.2
 | ||||
| func isLineWhiteSpace(chr rune) bool { | ||||
| 	switch chr { | ||||
| 	case '\u0009', '\u000b', '\u000c', '\u0020', '\u00a0', '\ufeff': | ||||
| 		return true | ||||
| 	case '\u000a', '\u000d', '\u2028', '\u2029': | ||||
| 		return false | ||||
| 	case '\u0085': | ||||
| 		return false | ||||
| 	} | ||||
| 	return unicode.IsSpace(chr) | ||||
| } | ||||
| 
 | ||||
| // 7.3
 | ||||
| func isLineTerminator(chr rune) bool { | ||||
| 	switch chr { | ||||
| 	case '\u000a', '\u000d', '\u2028', '\u2029': | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) { | ||||
| 
 | ||||
| 	self.implicitSemicolon = false | ||||
| 
 | ||||
| 	for { | ||||
| 		self.skipWhiteSpace() | ||||
| 
 | ||||
| 		idx = self.idxOf(self.chrOffset) | ||||
| 		insertSemicolon := false | ||||
| 
 | ||||
| 		switch chr := self.chr; { | ||||
| 		case isIdentifierStart(chr): | ||||
| 			var err error | ||||
| 			literal, err = self.scanIdentifier() | ||||
| 			if err != nil { | ||||
| 				tkn = token.ILLEGAL | ||||
| 				break | ||||
| 			} | ||||
| 			if len(literal) > 1 { | ||||
| 				// Keywords are longer than 1 character, avoid lookup otherwise
 | ||||
| 				var strict bool | ||||
| 				tkn, strict = token.IsKeyword(literal) | ||||
| 
 | ||||
| 				switch tkn { | ||||
| 
 | ||||
| 				case 0: // Not a keyword
 | ||||
| 					if literal == "true" || literal == "false" { | ||||
| 						self.insertSemicolon = true | ||||
| 						tkn = token.BOOLEAN | ||||
| 						return | ||||
| 					} else if literal == "null" { | ||||
| 						self.insertSemicolon = true | ||||
| 						tkn = token.NULL | ||||
| 						return | ||||
| 					} | ||||
| 
 | ||||
| 				case token.KEYWORD: | ||||
| 					tkn = token.KEYWORD | ||||
| 					if strict { | ||||
| 						// TODO If strict and in strict mode, then this is not a break
 | ||||
| 						break | ||||
| 					} | ||||
| 					return | ||||
| 
 | ||||
| 				case | ||||
| 					token.THIS, | ||||
| 					token.BREAK, | ||||
| 					token.THROW, // A newline after a throw is not allowed, but we need to detect it
 | ||||
| 					token.RETURN, | ||||
| 					token.CONTINUE, | ||||
| 					token.DEBUGGER: | ||||
| 					self.insertSemicolon = true | ||||
| 					return | ||||
| 
 | ||||
| 				default: | ||||
| 					return | ||||
| 
 | ||||
| 				} | ||||
| 			} | ||||
| 			self.insertSemicolon = true | ||||
| 			tkn = token.IDENTIFIER | ||||
| 			return | ||||
| 		case '0' <= chr && chr <= '9': | ||||
| 			self.insertSemicolon = true | ||||
| 			tkn, literal = self.scanNumericLiteral(false) | ||||
| 			return | ||||
| 		default: | ||||
| 			self.read() | ||||
| 			switch chr { | ||||
| 			case -1: | ||||
| 				if self.insertSemicolon { | ||||
| 					self.insertSemicolon = false | ||||
| 					self.implicitSemicolon = true | ||||
| 				} | ||||
| 				tkn = token.EOF | ||||
| 			case '\r', '\n', '\u2028', '\u2029': | ||||
| 				self.insertSemicolon = false | ||||
| 				self.implicitSemicolon = true | ||||
| 				continue | ||||
| 			case ':': | ||||
| 				tkn = token.COLON | ||||
| 			case '.': | ||||
| 				if digitValue(self.chr) < 10 { | ||||
| 					insertSemicolon = true | ||||
| 					tkn, literal = self.scanNumericLiteral(true) | ||||
| 				} else { | ||||
| 					tkn = token.PERIOD | ||||
| 				} | ||||
| 			case ',': | ||||
| 				tkn = token.COMMA | ||||
| 			case ';': | ||||
| 				tkn = token.SEMICOLON | ||||
| 			case '(': | ||||
| 				tkn = token.LEFT_PARENTHESIS | ||||
| 			case ')': | ||||
| 				tkn = token.RIGHT_PARENTHESIS | ||||
| 				insertSemicolon = true | ||||
| 			case '[': | ||||
| 				tkn = token.LEFT_BRACKET | ||||
| 			case ']': | ||||
| 				tkn = token.RIGHT_BRACKET | ||||
| 				insertSemicolon = true | ||||
| 			case '{': | ||||
| 				tkn = token.LEFT_BRACE | ||||
| 			case '}': | ||||
| 				tkn = token.RIGHT_BRACE | ||||
| 				insertSemicolon = true | ||||
| 			case '+': | ||||
| 				tkn = self.switch3(token.PLUS, token.ADD_ASSIGN, '+', token.INCREMENT) | ||||
| 				if tkn == token.INCREMENT { | ||||
| 					insertSemicolon = true | ||||
| 				} | ||||
| 			case '-': | ||||
| 				tkn = self.switch3(token.MINUS, token.SUBTRACT_ASSIGN, '-', token.DECREMENT) | ||||
| 				if tkn == token.DECREMENT { | ||||
| 					insertSemicolon = true | ||||
| 				} | ||||
| 			case '*': | ||||
| 				tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN) | ||||
| 			case '/': | ||||
| 				if self.chr == '/' { | ||||
| 					self.skipSingleLineComment() | ||||
| 					continue | ||||
| 				} else if self.chr == '*' { | ||||
| 					self.skipMultiLineComment() | ||||
| 					continue | ||||
| 				} else { | ||||
| 					// Could be division, could be RegExp literal
 | ||||
| 					tkn = self.switch2(token.SLASH, token.QUOTIENT_ASSIGN) | ||||
| 					insertSemicolon = true | ||||
| 				} | ||||
| 			case '%': | ||||
| 				tkn = self.switch2(token.REMAINDER, token.REMAINDER_ASSIGN) | ||||
| 			case '^': | ||||
| 				tkn = self.switch2(token.EXCLUSIVE_OR, token.EXCLUSIVE_OR_ASSIGN) | ||||
| 			case '<': | ||||
| 				tkn = self.switch4(token.LESS, token.LESS_OR_EQUAL, '<', token.SHIFT_LEFT, token.SHIFT_LEFT_ASSIGN) | ||||
| 			case '>': | ||||
| 				tkn = self.switch6(token.GREATER, token.GREATER_OR_EQUAL, '>', token.SHIFT_RIGHT, token.SHIFT_RIGHT_ASSIGN, '>', token.UNSIGNED_SHIFT_RIGHT, token.UNSIGNED_SHIFT_RIGHT_ASSIGN) | ||||
| 			case '=': | ||||
| 				tkn = self.switch2(token.ASSIGN, token.EQUAL) | ||||
| 				if tkn == token.EQUAL && self.chr == '=' { | ||||
| 					self.read() | ||||
| 					tkn = token.STRICT_EQUAL | ||||
| 				} | ||||
| 			case '!': | ||||
| 				tkn = self.switch2(token.NOT, token.NOT_EQUAL) | ||||
| 				if tkn == token.NOT_EQUAL && self.chr == '=' { | ||||
| 					self.read() | ||||
| 					tkn = token.STRICT_NOT_EQUAL | ||||
| 				} | ||||
| 			case '&': | ||||
| 				if self.chr == '^' { | ||||
| 					self.read() | ||||
| 					tkn = self.switch2(token.AND_NOT, token.AND_NOT_ASSIGN) | ||||
| 				} else { | ||||
| 					tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND) | ||||
| 				} | ||||
| 			case '|': | ||||
| 				tkn = self.switch3(token.OR, token.OR_ASSIGN, '|', token.LOGICAL_OR) | ||||
| 			case '~': | ||||
| 				tkn = token.BITWISE_NOT | ||||
| 			case '?': | ||||
| 				tkn = token.QUESTION_MARK | ||||
| 			case '"', '\'': | ||||
| 				insertSemicolon = true | ||||
| 				tkn = token.STRING | ||||
| 				var err error | ||||
| 				literal, err = self.scanString(self.chrOffset - 1) | ||||
| 				if err != nil { | ||||
| 					tkn = token.ILLEGAL | ||||
| 				} | ||||
| 			default: | ||||
| 				self.errorUnexpected(idx, chr) | ||||
| 				tkn = token.ILLEGAL | ||||
| 			} | ||||
| 		} | ||||
| 		self.insertSemicolon = insertSemicolon | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) switch2(tkn0, tkn1 token.Token) token.Token { | ||||
| 	if self.chr == '=' { | ||||
| 		self.read() | ||||
| 		return tkn1 | ||||
| 	} | ||||
| 	return tkn0 | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) switch3(tkn0, tkn1 token.Token, chr2 rune, tkn2 token.Token) token.Token { | ||||
| 	if self.chr == '=' { | ||||
| 		self.read() | ||||
| 		return tkn1 | ||||
| 	} | ||||
| 	if self.chr == chr2 { | ||||
| 		self.read() | ||||
| 		return tkn2 | ||||
| 	} | ||||
| 	return tkn0 | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) switch4(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token) token.Token { | ||||
| 	if self.chr == '=' { | ||||
| 		self.read() | ||||
| 		return tkn1 | ||||
| 	} | ||||
| 	if self.chr == chr2 { | ||||
| 		self.read() | ||||
| 		if self.chr == '=' { | ||||
| 			self.read() | ||||
| 			return tkn3 | ||||
| 		} | ||||
| 		return tkn2 | ||||
| 	} | ||||
| 	return tkn0 | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) switch6(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token, chr3 rune, tkn4, tkn5 token.Token) token.Token { | ||||
| 	if self.chr == '=' { | ||||
| 		self.read() | ||||
| 		return tkn1 | ||||
| 	} | ||||
| 	if self.chr == chr2 { | ||||
| 		self.read() | ||||
| 		if self.chr == '=' { | ||||
| 			self.read() | ||||
| 			return tkn3 | ||||
| 		} | ||||
| 		if self.chr == chr3 { | ||||
| 			self.read() | ||||
| 			if self.chr == '=' { | ||||
| 				self.read() | ||||
| 				return tkn5 | ||||
| 			} | ||||
| 			return tkn4 | ||||
| 		} | ||||
| 		return tkn2 | ||||
| 	} | ||||
| 	return tkn0 | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) chrAt(index int) _chr { | ||||
| 	value, width := utf8.DecodeRuneInString(self.str[index:]) | ||||
| 	return _chr{ | ||||
| 		value: value, | ||||
| 		width: width, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) _peek() rune { | ||||
| 	if self.offset+1 < self.length { | ||||
| 		return rune(self.str[self.offset+1]) | ||||
| 	} | ||||
| 	return -1 | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) read() { | ||||
| 	if self.offset < self.length { | ||||
| 		self.chrOffset = self.offset | ||||
| 		chr, width := rune(self.str[self.offset]), 1 | ||||
| 		if chr >= utf8.RuneSelf { // !ASCII
 | ||||
| 			chr, width = utf8.DecodeRuneInString(self.str[self.offset:]) | ||||
| 			if chr == utf8.RuneError && width == 1 { | ||||
| 				self.error(self.chrOffset, "Invalid UTF-8 character") | ||||
| 			} | ||||
| 		} | ||||
| 		self.offset += width | ||||
| 		self.chr = chr | ||||
| 	} else { | ||||
| 		self.chrOffset = self.length | ||||
| 		self.chr = -1 // EOF
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // This is here since the functions are so similar
 | ||||
| func (self *_RegExp_parser) read() { | ||||
| 	if self.offset < self.length { | ||||
| 		self.chrOffset = self.offset | ||||
| 		chr, width := rune(self.str[self.offset]), 1 | ||||
| 		if chr >= utf8.RuneSelf { // !ASCII
 | ||||
| 			chr, width = utf8.DecodeRuneInString(self.str[self.offset:]) | ||||
| 			if chr == utf8.RuneError && width == 1 { | ||||
| 				self.error(self.chrOffset, "Invalid UTF-8 character") | ||||
| 			} | ||||
| 		} | ||||
| 		self.offset += width | ||||
| 		self.chr = chr | ||||
| 	} else { | ||||
| 		self.chrOffset = self.length | ||||
| 		self.chr = -1 // EOF
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) skipSingleLineComment() { | ||||
| 	for self.chr != -1 { | ||||
| 		self.read() | ||||
| 		if isLineTerminator(self.chr) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) skipMultiLineComment() { | ||||
| 	self.read() | ||||
| 	for self.chr >= 0 { | ||||
| 		chr := self.chr | ||||
| 		self.read() | ||||
| 		if chr == '*' && self.chr == '/' { | ||||
| 			self.read() | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.errorUnexpected(0, self.chr) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) skipWhiteSpace() { | ||||
| 	for { | ||||
| 		switch self.chr { | ||||
| 		case ' ', '\t', '\f', '\v', '\u00a0', '\ufeff': | ||||
| 			self.read() | ||||
| 			continue | ||||
| 		case '\r': | ||||
| 			if self._peek() == '\n' { | ||||
| 				self.read() | ||||
| 			} | ||||
| 			fallthrough | ||||
| 		case '\u2028', '\u2029', '\n': | ||||
| 			if self.insertSemicolon { | ||||
| 				return | ||||
| 			} | ||||
| 			self.read() | ||||
| 			continue | ||||
| 		} | ||||
| 		if self.chr >= utf8.RuneSelf { | ||||
| 			if unicode.IsSpace(self.chr) { | ||||
| 				self.read() | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 		break | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) skipLineWhiteSpace() { | ||||
| 	for isLineWhiteSpace(self.chr) { | ||||
| 		self.read() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanMantissa(base int) { | ||||
| 	for digitValue(self.chr) < base { | ||||
| 		self.read() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanEscape(quote rune) { | ||||
| 
 | ||||
| 	var length, base uint32 | ||||
| 	switch self.chr { | ||||
| 	//case '0', '1', '2', '3', '4', '5', '6', '7':
 | ||||
| 	//    Octal:
 | ||||
| 	//    length, base, limit = 3, 8, 255
 | ||||
| 	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"', '\'', '0': | ||||
| 		self.read() | ||||
| 		return | ||||
| 	case '\r', '\n', '\u2028', '\u2029': | ||||
| 		self.scanNewline() | ||||
| 		return | ||||
| 	case 'x': | ||||
| 		self.read() | ||||
| 		length, base = 2, 16 | ||||
| 	case 'u': | ||||
| 		self.read() | ||||
| 		length, base = 4, 16 | ||||
| 	default: | ||||
| 		self.read() // Always make progress
 | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var value uint32 | ||||
| 	for ; length > 0 && self.chr != quote && self.chr >= 0; length-- { | ||||
| 		digit := uint32(digitValue(self.chr)) | ||||
| 		if digit >= base { | ||||
| 			break | ||||
| 		} | ||||
| 		value = value*base + digit | ||||
| 		self.read() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanString(offset int) (string, error) { | ||||
| 	// " ' /
 | ||||
| 	quote := rune(self.str[offset]) | ||||
| 
 | ||||
| 	for self.chr != quote { | ||||
| 		chr := self.chr | ||||
| 		if chr == '\n' || chr == '\r' || chr == '\u2028' || chr == '\u2029' || chr < 0 { | ||||
| 			goto newline | ||||
| 		} | ||||
| 		self.read() | ||||
| 		if chr == '\\' { | ||||
| 			if quote == '/' { | ||||
| 				if self.chr == '\n' || self.chr == '\r' || self.chr == '\u2028' || self.chr == '\u2029' || self.chr < 0 { | ||||
| 					goto newline | ||||
| 				} | ||||
| 				self.read() | ||||
| 			} else { | ||||
| 				self.scanEscape(quote) | ||||
| 			} | ||||
| 		} else if chr == '[' && quote == '/' { | ||||
| 			// Allow a slash (/) in a bracket character class ([...])
 | ||||
| 			// TODO Fix this, this is hacky...
 | ||||
| 			quote = -1 | ||||
| 		} else if chr == ']' && quote == -1 { | ||||
| 			quote = '/' | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// " ' /
 | ||||
| 	self.read() | ||||
| 
 | ||||
| 	return string(self.str[offset:self.chrOffset]), nil | ||||
| 
 | ||||
| newline: | ||||
| 	self.scanNewline() | ||||
| 	err := "String not terminated" | ||||
| 	if quote == '/' { | ||||
| 		err = "Invalid regular expression: missing /" | ||||
| 		self.error(self.idxOf(offset), err) | ||||
| 	} | ||||
| 	return "", errors.New(err) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanNewline() { | ||||
| 	if self.chr == '\r' { | ||||
| 		self.read() | ||||
| 		if self.chr != '\n' { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	self.read() | ||||
| } | ||||
| 
 | ||||
| func hex2decimal(chr byte) (value rune, ok bool) { | ||||
| 	{ | ||||
| 		chr := rune(chr) | ||||
| 		switch { | ||||
| 		case '0' <= chr && chr <= '9': | ||||
| 			return chr - '0', true | ||||
| 		case 'a' <= chr && chr <= 'f': | ||||
| 			return chr - 'a' + 10, true | ||||
| 		case 'A' <= chr && chr <= 'F': | ||||
| 			return chr - 'A' + 10, true | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func parseNumberLiteral(literal string) (value interface{}, err error) { | ||||
| 	// TODO Is Uint okay? What about -MAX_UINT
 | ||||
| 	value, err = strconv.ParseInt(literal, 0, 64) | ||||
| 	if err == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	parseIntErr := err // Save this first error, just in case
 | ||||
| 
 | ||||
| 	value, err = strconv.ParseFloat(literal, 64) | ||||
| 	if err == nil { | ||||
| 		return | ||||
| 	} else if err.(*strconv.NumError).Err == strconv.ErrRange { | ||||
| 		// Infinity, etc.
 | ||||
| 		return value, nil | ||||
| 	} | ||||
| 
 | ||||
| 	err = parseIntErr | ||||
| 
 | ||||
| 	if err.(*strconv.NumError).Err == strconv.ErrRange { | ||||
| 		if len(literal) > 2 && literal[0] == '0' && (literal[1] == 'X' || literal[1] == 'x') { | ||||
| 			// Could just be a very large number (e.g. 0x8000000000000000)
 | ||||
| 			var value float64 | ||||
| 			literal = literal[2:] | ||||
| 			for _, chr := range literal { | ||||
| 				digit := digitValue(chr) | ||||
| 				if digit >= 16 { | ||||
| 					goto error | ||||
| 				} | ||||
| 				value = value*16 + float64(digit) | ||||
| 			} | ||||
| 			return value, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| error: | ||||
| 	return nil, errors.New("Illegal numeric literal") | ||||
| } | ||||
| 
 | ||||
| func parseStringLiteral(literal string) (string, error) { | ||||
| 	// Best case scenario...
 | ||||
| 	if literal == "" { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Slightly less-best case scenario...
 | ||||
| 	if !strings.ContainsRune(literal, '\\') { | ||||
| 		return literal, nil | ||||
| 	} | ||||
| 
 | ||||
| 	str := literal | ||||
| 	buffer := bytes.NewBuffer(make([]byte, 0, 3*len(literal)/2)) | ||||
| 
 | ||||
| 	for len(str) > 0 { | ||||
| 		switch chr := str[0]; { | ||||
| 		// We do not explicitly handle the case of the quote
 | ||||
| 		// value, which can be: " ' /
 | ||||
| 		// This assumes we're already passed a partially well-formed literal
 | ||||
| 		case chr >= utf8.RuneSelf: | ||||
| 			chr, size := utf8.DecodeRuneInString(str) | ||||
| 			buffer.WriteRune(chr) | ||||
| 			str = str[size:] | ||||
| 			continue | ||||
| 		case chr != '\\': | ||||
| 			buffer.WriteByte(chr) | ||||
| 			str = str[1:] | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		if len(str) <= 1 { | ||||
| 			panic("len(str) <= 1") | ||||
| 		} | ||||
| 		chr := str[1] | ||||
| 		var value rune | ||||
| 		if chr >= utf8.RuneSelf { | ||||
| 			str = str[1:] | ||||
| 			var size int | ||||
| 			value, size = utf8.DecodeRuneInString(str) | ||||
| 			str = str[size:] // \ + <character>
 | ||||
| 		} else { | ||||
| 			str = str[2:] // \<character>
 | ||||
| 			switch chr { | ||||
| 			case 'b': | ||||
| 				value = '\b' | ||||
| 			case 'f': | ||||
| 				value = '\f' | ||||
| 			case 'n': | ||||
| 				value = '\n' | ||||
| 			case 'r': | ||||
| 				value = '\r' | ||||
| 			case 't': | ||||
| 				value = '\t' | ||||
| 			case 'v': | ||||
| 				value = '\v' | ||||
| 			case 'x', 'u': | ||||
| 				size := 0 | ||||
| 				switch chr { | ||||
| 				case 'x': | ||||
| 					size = 2 | ||||
| 				case 'u': | ||||
| 					size = 4 | ||||
| 				} | ||||
| 				if len(str) < size { | ||||
| 					return "", fmt.Errorf("invalid escape: \\%s: len(%q) != %d", string(chr), str, size) | ||||
| 				} | ||||
| 				for j := 0; j < size; j++ { | ||||
| 					decimal, ok := hex2decimal(str[j]) | ||||
| 					if !ok { | ||||
| 						return "", fmt.Errorf("invalid escape: \\%s: %q", string(chr), str[:size]) | ||||
| 					} | ||||
| 					value = value<<4 | decimal | ||||
| 				} | ||||
| 				str = str[size:] | ||||
| 				if chr == 'x' { | ||||
| 					break | ||||
| 				} | ||||
| 				if value > utf8.MaxRune { | ||||
| 					panic("value > utf8.MaxRune") | ||||
| 				} | ||||
| 			case '0': | ||||
| 				if len(str) == 0 || '0' > str[0] || str[0] > '7' { | ||||
| 					value = 0 | ||||
| 					break | ||||
| 				} | ||||
| 				fallthrough | ||||
| 			case '1', '2', '3', '4', '5', '6', '7': | ||||
| 				// TODO strict
 | ||||
| 				value = rune(chr) - '0' | ||||
| 				j := 0 | ||||
| 				for ; j < 2; j++ { | ||||
| 					if len(str) < j+1 { | ||||
| 						break | ||||
| 					} | ||||
| 					chr := str[j] | ||||
| 					if '0' > chr || chr > '7' { | ||||
| 						break | ||||
| 					} | ||||
| 					decimal := rune(str[j]) - '0' | ||||
| 					value = (value << 3) | decimal | ||||
| 				} | ||||
| 				str = str[j:] | ||||
| 			case '\\': | ||||
| 				value = '\\' | ||||
| 			case '\'', '"': | ||||
| 				value = rune(chr) | ||||
| 			case '\r': | ||||
| 				if len(str) > 0 { | ||||
| 					if str[0] == '\n' { | ||||
| 						str = str[1:] | ||||
| 					} | ||||
| 				} | ||||
| 				fallthrough | ||||
| 			case '\n': | ||||
| 				continue | ||||
| 			default: | ||||
| 				value = rune(chr) | ||||
| 			} | ||||
| 		} | ||||
| 		buffer.WriteRune(value) | ||||
| 	} | ||||
| 
 | ||||
| 	return buffer.String(), nil | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) { | ||||
| 
 | ||||
| 	offset := self.chrOffset | ||||
| 	tkn := token.NUMBER | ||||
| 
 | ||||
| 	if decimalPoint { | ||||
| 		offset-- | ||||
| 		self.scanMantissa(10) | ||||
| 		goto exponent | ||||
| 	} | ||||
| 
 | ||||
| 	if self.chr == '0' { | ||||
| 		offset := self.chrOffset | ||||
| 		self.read() | ||||
| 		if self.chr == 'x' || self.chr == 'X' { | ||||
| 			// Hexadecimal
 | ||||
| 			self.read() | ||||
| 			if isDigit(self.chr, 16) { | ||||
| 				self.read() | ||||
| 			} else { | ||||
| 				return token.ILLEGAL, self.str[offset:self.chrOffset] | ||||
| 			} | ||||
| 			self.scanMantissa(16) | ||||
| 
 | ||||
| 			if self.chrOffset-offset <= 2 { | ||||
| 				// Only "0x" or "0X"
 | ||||
| 				self.error(0, "Illegal hexadecimal number") | ||||
| 			} | ||||
| 
 | ||||
| 			goto hexadecimal | ||||
| 		} else if self.chr == '.' { | ||||
| 			// Float
 | ||||
| 			goto float | ||||
| 		} else { | ||||
| 			// Octal, Float
 | ||||
| 			if self.chr == 'e' || self.chr == 'E' { | ||||
| 				goto exponent | ||||
| 			} | ||||
| 			self.scanMantissa(8) | ||||
| 			if self.chr == '8' || self.chr == '9' { | ||||
| 				return token.ILLEGAL, self.str[offset:self.chrOffset] | ||||
| 			} | ||||
| 			goto octal | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.scanMantissa(10) | ||||
| 
 | ||||
| float: | ||||
| 	if self.chr == '.' { | ||||
| 		self.read() | ||||
| 		self.scanMantissa(10) | ||||
| 	} | ||||
| 
 | ||||
| exponent: | ||||
| 	if self.chr == 'e' || self.chr == 'E' { | ||||
| 		self.read() | ||||
| 		if self.chr == '-' || self.chr == '+' { | ||||
| 			self.read() | ||||
| 		} | ||||
| 		if isDecimalDigit(self.chr) { | ||||
| 			self.read() | ||||
| 			self.scanMantissa(10) | ||||
| 		} else { | ||||
| 			return token.ILLEGAL, self.str[offset:self.chrOffset] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| hexadecimal: | ||||
| octal: | ||||
| 	if isIdentifierStart(self.chr) || isDecimalDigit(self.chr) { | ||||
| 		return token.ILLEGAL, self.str[offset:self.chrOffset] | ||||
| 	} | ||||
| 
 | ||||
| 	return tkn, self.str[offset:self.chrOffset] | ||||
| } | ||||
							
								
								
									
										380
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/lexer_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										380
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/lexer_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,380 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"../terst" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| var tt = terst.Terst | ||||
| var is = terst.Is | ||||
| 
 | ||||
| func TestLexer(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		setup := func(src string) *_parser { | ||||
| 			parser := newParser("", src) | ||||
| 			return parser | ||||
| 		} | ||||
| 
 | ||||
| 		test := func(src string, test ...interface{}) { | ||||
| 			parser := setup(src) | ||||
| 			for len(test) > 0 { | ||||
| 				tkn, literal, idx := parser.scan() | ||||
| 				if len(test) > 0 { | ||||
| 					is(tkn, test[0].(token.Token)) | ||||
| 					test = test[1:] | ||||
| 				} | ||||
| 				if len(test) > 0 { | ||||
| 					is(literal, test[0].(string)) | ||||
| 					test = test[1:] | ||||
| 				} | ||||
| 				if len(test) > 0 { | ||||
| 					// FIXME terst, Fix this so that cast to file.Idx is not necessary?
 | ||||
| 					is(idx, file.Idx(test[0].(int))) | ||||
| 					test = test[1:] | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		test("", | ||||
| 			token.EOF, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.EOF, "", 2, | ||||
| 		) | ||||
| 
 | ||||
| 		test(".0", | ||||
| 			token.NUMBER, ".0", 1, | ||||
| 			token.EOF, "", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.EOF, "", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc(1)", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.LEFT_PARENTHESIS, "", 4, | ||||
| 			token.NUMBER, "1", 5, | ||||
| 			token.RIGHT_PARENTHESIS, "", 6, | ||||
| 			token.EOF, "", 7, | ||||
| 		) | ||||
| 
 | ||||
| 		test(".", | ||||
| 			token.PERIOD, "", 1, | ||||
| 			token.EOF, "", 2, | ||||
| 		) | ||||
| 
 | ||||
| 		test("===.", | ||||
| 			token.STRICT_EQUAL, "", 1, | ||||
| 			token.PERIOD, "", 4, | ||||
| 			token.EOF, "", 5, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>>=.0", | ||||
| 			token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, | ||||
| 			token.NUMBER, ".0", 5, | ||||
| 			token.EOF, "", 7, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>>=0.0.", | ||||
| 			token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, | ||||
| 			token.NUMBER, "0.0", 5, | ||||
| 			token.PERIOD, "", 8, | ||||
| 			token.EOF, "", 9, | ||||
| 		) | ||||
| 
 | ||||
| 		test("\"abc\"", | ||||
| 			token.STRING, "\"abc\"", 1, | ||||
| 			token.EOF, "", 6, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc = //", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.ASSIGN, "", 5, | ||||
| 			token.EOF, "", 9, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc = 1 / 2", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.ASSIGN, "", 5, | ||||
| 			token.NUMBER, "1", 7, | ||||
| 			token.SLASH, "", 9, | ||||
| 			token.NUMBER, "2", 11, | ||||
| 			token.EOF, "", 12, | ||||
| 		) | ||||
| 
 | ||||
| 		test("xyzzy = 'Nothing happens.'", | ||||
| 			token.IDENTIFIER, "xyzzy", 1, | ||||
| 			token.ASSIGN, "", 7, | ||||
| 			token.STRING, "'Nothing happens.'", 9, | ||||
| 			token.EOF, "", 27, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc = !false", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.ASSIGN, "", 5, | ||||
| 			token.NOT, "", 7, | ||||
| 			token.BOOLEAN, "false", 8, | ||||
| 			token.EOF, "", 13, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc = !!true", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.ASSIGN, "", 5, | ||||
| 			token.NOT, "", 7, | ||||
| 			token.NOT, "", 8, | ||||
| 			token.BOOLEAN, "true", 9, | ||||
| 			token.EOF, "", 13, | ||||
| 		) | ||||
| 
 | ||||
| 		test("abc *= 1", | ||||
| 			token.IDENTIFIER, "abc", 1, | ||||
| 			token.MULTIPLY_ASSIGN, "", 5, | ||||
| 			token.NUMBER, "1", 8, | ||||
| 			token.EOF, "", 9, | ||||
| 		) | ||||
| 
 | ||||
| 		test("if 1 else", | ||||
| 			token.IF, "if", 1, | ||||
| 			token.NUMBER, "1", 4, | ||||
| 			token.ELSE, "else", 6, | ||||
| 			token.EOF, "", 10, | ||||
| 		) | ||||
| 
 | ||||
| 		test("null", | ||||
| 			token.NULL, "null", 1, | ||||
| 			token.EOF, "", 5, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`"\u007a\x79\u000a\x78"`, | ||||
| 			token.STRING, "\"\\u007a\\x79\\u000a\\x78\"", 1, | ||||
| 			token.EOF, "", 23, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`"[First line \ | ||||
| Second line \ | ||||
|  Third line\ | ||||
| .     ]" | ||||
| 	`, | ||||
| 			token.STRING, "\"[First line \\\nSecond line \\\n Third line\\\n.     ]\"", 1, | ||||
| 			token.EOF, "", 53, | ||||
| 		) | ||||
| 
 | ||||
| 		test("/", | ||||
| 			token.SLASH, "", 1, | ||||
| 			token.EOF, "", 2, | ||||
| 		) | ||||
| 
 | ||||
| 		test("var abc = \"abc\uFFFFabc\"", | ||||
| 			token.VAR, "var", 1, | ||||
| 			token.IDENTIFIER, "abc", 5, | ||||
| 			token.ASSIGN, "", 9, | ||||
| 			token.STRING, "\"abc\uFFFFabc\"", 11, | ||||
| 			token.EOF, "", 22, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`'\t' === '\r'`, | ||||
| 			token.STRING, "'\\t'", 1, | ||||
| 			token.STRICT_EQUAL, "", 6, | ||||
| 			token.STRING, "'\\r'", 10, | ||||
| 			token.EOF, "", 14, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`var \u0024 = 1`, | ||||
| 			token.VAR, "var", 1, | ||||
| 			token.IDENTIFIER, "$", 5, | ||||
| 			token.ASSIGN, "", 12, | ||||
| 			token.NUMBER, "1", 14, | ||||
| 			token.EOF, "", 15, | ||||
| 		) | ||||
| 
 | ||||
| 		test("10e10000", | ||||
| 			token.NUMBER, "10e10000", 1, | ||||
| 			token.EOF, "", 9, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`var if var class`, | ||||
| 			token.VAR, "var", 1, | ||||
| 			token.IF, "if", 5, | ||||
| 			token.VAR, "var", 8, | ||||
| 			token.KEYWORD, "class", 12, | ||||
| 			token.EOF, "", 17, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`-0`, | ||||
| 			token.MINUS, "", 1, | ||||
| 			token.NUMBER, "0", 2, | ||||
| 			token.EOF, "", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`.01`, | ||||
| 			token.NUMBER, ".01", 1, | ||||
| 			token.EOF, "", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`.01e+2`, | ||||
| 			token.NUMBER, ".01e+2", 1, | ||||
| 			token.EOF, "", 7, | ||||
| 		) | ||||
| 
 | ||||
| 		test(";", | ||||
| 			token.SEMICOLON, "", 1, | ||||
| 			token.EOF, "", 2, | ||||
| 		) | ||||
| 
 | ||||
| 		test(";;", | ||||
| 			token.SEMICOLON, "", 1, | ||||
| 			token.SEMICOLON, "", 2, | ||||
| 			token.EOF, "", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test("//", | ||||
| 			token.EOF, "", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test(";;//", | ||||
| 			token.SEMICOLON, "", 1, | ||||
| 			token.SEMICOLON, "", 2, | ||||
| 			token.EOF, "", 5, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test("12 123", | ||||
| 			token.NUMBER, "12", 1, | ||||
| 			token.NUMBER, "123", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1.2 12.3", | ||||
| 			token.NUMBER, "1.2", 1, | ||||
| 			token.NUMBER, "12.3", 5, | ||||
| 		) | ||||
| 
 | ||||
| 		test("/ /=", | ||||
| 			token.SLASH, "", 1, | ||||
| 			token.QUOTIENT_ASSIGN, "", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`"abc"`, | ||||
| 			token.STRING, `"abc"`, 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`'abc'`, | ||||
| 			token.STRING, `'abc'`, 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test("++", | ||||
| 			token.INCREMENT, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">", | ||||
| 			token.GREATER, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">=", | ||||
| 			token.GREATER_OR_EQUAL, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>", | ||||
| 			token.SHIFT_RIGHT, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>=", | ||||
| 			token.SHIFT_RIGHT_ASSIGN, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>>", | ||||
| 			token.UNSIGNED_SHIFT_RIGHT, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test(">>>=", | ||||
| 			token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1 \"abc\"", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.STRING, "\"abc\"", 3, | ||||
| 		) | ||||
| 
 | ||||
| 		test(",", | ||||
| 			token.COMMA, "", 1, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1, \"abc\"", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.COMMA, "", 2, | ||||
| 			token.STRING, "\"abc\"", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test("new abc(1, 3.14159);", | ||||
| 			token.NEW, "new", 1, | ||||
| 			token.IDENTIFIER, "abc", 5, | ||||
| 			token.LEFT_PARENTHESIS, "", 8, | ||||
| 			token.NUMBER, "1", 9, | ||||
| 			token.COMMA, "", 10, | ||||
| 			token.NUMBER, "3.14159", 12, | ||||
| 			token.RIGHT_PARENTHESIS, "", 19, | ||||
| 			token.SEMICOLON, "", 20, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1 == \"1\"", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.EQUAL, "", 3, | ||||
| 			token.STRING, "\"1\"", 6, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1\n[]\n", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.LEFT_BRACKET, "", 3, | ||||
| 			token.RIGHT_BRACKET, "", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test("1\ufeff[]\ufeff", | ||||
| 			token.NUMBER, "1", 1, | ||||
| 			token.LEFT_BRACKET, "", 5, | ||||
| 			token.RIGHT_BRACKET, "", 6, | ||||
| 		) | ||||
| 
 | ||||
| 		// ILLEGAL
 | ||||
| 
 | ||||
| 		test(`3ea`, | ||||
| 			token.ILLEGAL, "3e", 1, | ||||
| 			token.IDENTIFIER, "a", 3, | ||||
| 			token.EOF, "", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`3in`, | ||||
| 			token.ILLEGAL, "3", 1, | ||||
| 			token.IN, "in", 2, | ||||
| 			token.EOF, "", 4, | ||||
| 		) | ||||
| 
 | ||||
| 		test("\"Hello\nWorld\"", | ||||
| 			token.ILLEGAL, "", 1, | ||||
| 			token.IDENTIFIER, "World", 8, | ||||
| 			token.ILLEGAL, "", 13, | ||||
| 			token.EOF, "", 14, | ||||
| 		) | ||||
| 
 | ||||
| 		test("\u203f = 10", | ||||
| 			token.ILLEGAL, "", 1, | ||||
| 			token.ASSIGN, "", 5, | ||||
| 			token.NUMBER, "10", 7, | ||||
| 			token.EOF, "", 9, | ||||
| 		) | ||||
| 
 | ||||
| 		test(`"\x0G"`, | ||||
| 			token.STRING, "\"\\x0G\"", 1, | ||||
| 			token.EOF, "", 7, | ||||
| 		) | ||||
| 
 | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										930
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/marshal_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										930
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/marshal_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,930 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| ) | ||||
| 
 | ||||
| func marshal(name string, children ...interface{}) interface{} { | ||||
| 	if len(children) == 1 { | ||||
| 		if name == "" { | ||||
| 			return testMarshalNode(children[0]) | ||||
| 		} | ||||
| 		return map[string]interface{}{ | ||||
| 			name: children[0], | ||||
| 		} | ||||
| 	} | ||||
| 	map_ := map[string]interface{}{} | ||||
| 	length := len(children) / 2 | ||||
| 	for i := 0; i < length; i++ { | ||||
| 		name := children[i*2].(string) | ||||
| 		value := children[i*2+1] | ||||
| 		map_[name] = value | ||||
| 	} | ||||
| 	if name == "" { | ||||
| 		return map_ | ||||
| 	} | ||||
| 	return map[string]interface{}{ | ||||
| 		name: map_, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func testMarshalNode(node interface{}) interface{} { | ||||
| 	switch node := node.(type) { | ||||
| 
 | ||||
| 	// Expression
 | ||||
| 
 | ||||
| 	case *ast.ArrayLiteral: | ||||
| 		return marshal("Array", testMarshalNode(node.Value)) | ||||
| 
 | ||||
| 	case *ast.AssignExpression: | ||||
| 		return marshal("Assign", | ||||
| 			"Left", testMarshalNode(node.Left), | ||||
| 			"Right", testMarshalNode(node.Right), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.BinaryExpression: | ||||
| 		return marshal("BinaryExpression", | ||||
| 			"Operator", node.Operator.String(), | ||||
| 			"Left", testMarshalNode(node.Left), | ||||
| 			"Right", testMarshalNode(node.Right), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.BooleanLiteral: | ||||
| 		return marshal("Literal", node.Value) | ||||
| 
 | ||||
| 	case *ast.CallExpression: | ||||
| 		return marshal("Call", | ||||
| 			"Callee", testMarshalNode(node.Callee), | ||||
| 			"ArgumentList", testMarshalNode(node.ArgumentList), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.ConditionalExpression: | ||||
| 		return marshal("Conditional", | ||||
| 			"Test", testMarshalNode(node.Test), | ||||
| 			"Consequent", testMarshalNode(node.Consequent), | ||||
| 			"Alternate", testMarshalNode(node.Alternate), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.DotExpression: | ||||
| 		return marshal("Dot", | ||||
| 			"Left", testMarshalNode(node.Left), | ||||
| 			"Member", node.Identifier.Name, | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.NewExpression: | ||||
| 		return marshal("New", | ||||
| 			"Callee", testMarshalNode(node.Callee), | ||||
| 			"ArgumentList", testMarshalNode(node.ArgumentList), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.NullLiteral: | ||||
| 		return marshal("Literal", nil) | ||||
| 
 | ||||
| 	case *ast.NumberLiteral: | ||||
| 		return marshal("Literal", node.Value) | ||||
| 
 | ||||
| 	case *ast.ObjectLiteral: | ||||
| 		return marshal("Object", testMarshalNode(node.Value)) | ||||
| 
 | ||||
| 	case *ast.RegExpLiteral: | ||||
| 		return marshal("Literal", node.Literal) | ||||
| 
 | ||||
| 	case *ast.StringLiteral: | ||||
| 		return marshal("Literal", node.Literal) | ||||
| 
 | ||||
| 	case *ast.VariableExpression: | ||||
| 		return []interface{}{node.Name, testMarshalNode(node.Initializer)} | ||||
| 
 | ||||
| 	// Statement
 | ||||
| 
 | ||||
| 	case *ast.Program: | ||||
| 		return testMarshalNode(node.Body) | ||||
| 
 | ||||
| 	case *ast.BlockStatement: | ||||
| 		return marshal("BlockStatement", testMarshalNode(node.List)) | ||||
| 
 | ||||
| 	case *ast.EmptyStatement: | ||||
| 		return "EmptyStatement" | ||||
| 
 | ||||
| 	case *ast.ExpressionStatement: | ||||
| 		return testMarshalNode(node.Expression) | ||||
| 
 | ||||
| 	case *ast.ForInStatement: | ||||
| 		return marshal("ForIn", | ||||
| 			"Into", marshal("", node.Into), | ||||
| 			"Source", marshal("", node.Source), | ||||
| 			"Body", marshal("", node.Body), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.FunctionLiteral: | ||||
| 		return marshal("Function", testMarshalNode(node.Body)) | ||||
| 
 | ||||
| 	case *ast.Identifier: | ||||
| 		return marshal("Identifier", node.Name) | ||||
| 
 | ||||
| 	case *ast.IfStatement: | ||||
| 		if_ := marshal("", | ||||
| 			"Test", testMarshalNode(node.Test), | ||||
| 			"Consequent", testMarshalNode(node.Consequent), | ||||
| 		).(map[string]interface{}) | ||||
| 		if node.Alternate != nil { | ||||
| 			if_["Alternate"] = testMarshalNode(node.Alternate) | ||||
| 		} | ||||
| 		return marshal("If", if_) | ||||
| 
 | ||||
| 	case *ast.LabelledStatement: | ||||
| 		return marshal("Label", | ||||
| 			"Name", node.Label.Name, | ||||
| 			"Statement", testMarshalNode(node.Statement), | ||||
| 		) | ||||
| 	case ast.Property: | ||||
| 		return marshal("", | ||||
| 			"Key", node.Key, | ||||
| 			"Value", testMarshalNode(node.Value), | ||||
| 		) | ||||
| 
 | ||||
| 	case *ast.ReturnStatement: | ||||
| 		return marshal("Return", testMarshalNode(node.Argument)) | ||||
| 
 | ||||
| 	case *ast.SequenceExpression: | ||||
| 		return marshal("Sequence", testMarshalNode(node.Sequence)) | ||||
| 
 | ||||
| 	case *ast.ThrowStatement: | ||||
| 		return marshal("Throw", testMarshalNode(node.Argument)) | ||||
| 
 | ||||
| 	case *ast.VariableStatement: | ||||
| 		return marshal("Var", testMarshalNode(node.List)) | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		value := reflect.ValueOf(node) | ||||
| 		if value.Kind() == reflect.Slice { | ||||
| 			tmp0 := []interface{}{} | ||||
| 			for index := 0; index < value.Len(); index++ { | ||||
| 				tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface())) | ||||
| 			} | ||||
| 			return tmp0 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if node != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func testMarshal(node interface{}) string { | ||||
| 	value, err := json.Marshal(testMarshalNode(node)) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return string(value) | ||||
| } | ||||
| 
 | ||||
| func TestParserAST(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 
 | ||||
| 		test := func(inputOutput string) { | ||||
| 			match := matchBeforeAfterSeparator.FindStringIndex(inputOutput) | ||||
| 			input := strings.TrimSpace(inputOutput[0:match[0]]) | ||||
| 			wantOutput := strings.TrimSpace(inputOutput[match[1]:]) | ||||
| 			_, program, err := testParse(input) | ||||
| 			is(err, nil) | ||||
| 			haveOutput := testMarshal(program) | ||||
| 			tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{} | ||||
| 			json.Indent(&tmp0, []byte(haveOutput), "\t\t", "   ") | ||||
| 			json.Indent(&tmp1, []byte(wantOutput), "\t\t", "   ") | ||||
| 			is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String()) | ||||
| 		} | ||||
| 
 | ||||
| 		test(` | ||||
|         --- | ||||
| [] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         ; | ||||
|         --- | ||||
| [ | ||||
|   "EmptyStatement" | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         ;;; | ||||
|         --- | ||||
| [ | ||||
|   "EmptyStatement", | ||||
|   "EmptyStatement", | ||||
|   "EmptyStatement" | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         1; true; abc; "abc"; null; | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Literal": 1 | ||||
|   }, | ||||
|   { | ||||
|     "Literal": true | ||||
|   }, | ||||
|   { | ||||
|     "Identifier": "abc" | ||||
|   }, | ||||
|   { | ||||
|     "Literal": "\"abc\"" | ||||
|   }, | ||||
|   { | ||||
|     "Literal": null | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         { 1; null; 3.14159; ; } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BlockStatement": [ | ||||
|       { | ||||
|         "Literal": 1 | ||||
|       }, | ||||
|       { | ||||
|         "Literal": null | ||||
|       }, | ||||
|       { | ||||
|         "Literal": 3.14159 | ||||
|       }, | ||||
|       "EmptyStatement" | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         new abc(); | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "New": { | ||||
|       "ArgumentList": [], | ||||
|       "Callee": { | ||||
|         "Identifier": "abc" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         new abc(1, 3.14159) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "New": { | ||||
|       "ArgumentList": [ | ||||
|         { | ||||
|           "Literal": 1 | ||||
|         }, | ||||
|         { | ||||
|           "Literal": 3.14159 | ||||
|         } | ||||
|       ], | ||||
|       "Callee": { | ||||
|         "Identifier": "abc" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         true ? false : true | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Conditional": { | ||||
|       "Alternate": { | ||||
|         "Literal": true | ||||
|       }, | ||||
|       "Consequent": { | ||||
|         "Literal": false | ||||
|       }, | ||||
|       "Test": { | ||||
|         "Literal": true | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         true || false | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BinaryExpression": { | ||||
|       "Left": { | ||||
|         "Literal": true | ||||
|       }, | ||||
|       "Operator": "||", | ||||
|       "Right": { | ||||
|         "Literal": false | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         0 + { abc: true } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BinaryExpression": { | ||||
|       "Left": { | ||||
|         "Literal": 0 | ||||
|       }, | ||||
|       "Operator": "+", | ||||
|       "Right": { | ||||
|         "Object": [ | ||||
|           { | ||||
|             "Key": "abc", | ||||
|             "Value": { | ||||
|               "Literal": true | ||||
|             } | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         1 == "1" | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BinaryExpression": { | ||||
|       "Left": { | ||||
|         "Literal": 1 | ||||
|       }, | ||||
|       "Operator": "==", | ||||
|       "Right": { | ||||
|         "Literal": "\"1\"" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         abc(1) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Call": { | ||||
|       "ArgumentList": [ | ||||
|         { | ||||
|           "Literal": 1 | ||||
|         } | ||||
|       ], | ||||
|       "Callee": { | ||||
|         "Identifier": "abc" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         Math.pow(3, 2) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Call": { | ||||
|       "ArgumentList": [ | ||||
|         { | ||||
|           "Literal": 3 | ||||
|         }, | ||||
|         { | ||||
|           "Literal": 2 | ||||
|         } | ||||
|       ], | ||||
|       "Callee": { | ||||
|         "Dot": { | ||||
|           "Left": { | ||||
|             "Identifier": "Math" | ||||
|           }, | ||||
|           "Member": "pow" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         1, 2, 3 | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Sequence": [ | ||||
|       { | ||||
|         "Literal": 1 | ||||
|       }, | ||||
|       { | ||||
|         "Literal": 2 | ||||
|       }, | ||||
|       { | ||||
|         "Literal": 3 | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         / abc /   gim; | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Literal": "/ abc /   gim" | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         if (0) | ||||
|             1; | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "If": { | ||||
|       "Consequent": { | ||||
|         "Literal": 1 | ||||
|       }, | ||||
|       "Test": { | ||||
|         "Literal": 0 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         0+function(){ | ||||
|             return; | ||||
|         } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BinaryExpression": { | ||||
|       "Left": { | ||||
|         "Literal": 0 | ||||
|       }, | ||||
|       "Operator": "+", | ||||
|       "Right": { | ||||
|         "Function": { | ||||
|           "BlockStatement": [ | ||||
|             { | ||||
|               "Return": null | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         xyzzy // Ignore it
 | ||||
|         // Ignore this
 | ||||
|         // And this
 | ||||
|         /* And all.. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         ... of this! | ||||
|         */ | ||||
|         "Nothing happens." | ||||
|         // And finally this
 | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Identifier": "xyzzy" | ||||
|   }, | ||||
|   { | ||||
|     "Literal": "\"Nothing happens.\"" | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         ((x & (x = 1)) !== 0) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BinaryExpression": { | ||||
|       "Left": { | ||||
|         "BinaryExpression": { | ||||
|           "Left": { | ||||
|             "Identifier": "x" | ||||
|           }, | ||||
|           "Operator": "\u0026", | ||||
|           "Right": { | ||||
|             "Assign": { | ||||
|               "Left": { | ||||
|                 "Identifier": "x" | ||||
|               }, | ||||
|               "Right": { | ||||
|                 "Literal": 1 | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "Operator": "!==", | ||||
|       "Right": { | ||||
|         "Literal": 0 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         { abc: 'def' } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "BlockStatement": [ | ||||
|       { | ||||
|         "Label": { | ||||
|           "Name": "abc", | ||||
|           "Statement": { | ||||
|             "Literal": "'def'" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         // This is not an object, this is a string literal with a label!
 | ||||
|         ({ abc: 'def' }) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Object": [ | ||||
|       { | ||||
|         "Key": "abc", | ||||
|         "Value": { | ||||
|           "Literal": "'def'" | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         [,] | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Array": [ | ||||
|       null | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         [,,] | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Array": [ | ||||
|       null, | ||||
|       null | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         ({ get abc() {} }) | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Object": [ | ||||
|       { | ||||
|         "Key": "abc", | ||||
|         "Value": { | ||||
|           "Function": { | ||||
|             "BlockStatement": [] | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         /abc/.source | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Dot": { | ||||
|       "Left": { | ||||
|         "Literal": "/abc/" | ||||
|       }, | ||||
|       "Member": "source" | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|                 xyzzy | ||||
| 
 | ||||
|         throw new TypeError("Nothing happens.") | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Identifier": "xyzzy" | ||||
|   }, | ||||
|   { | ||||
|     "Throw": { | ||||
|       "New": { | ||||
|         "ArgumentList": [ | ||||
|           { | ||||
|             "Literal": "\"Nothing happens.\"" | ||||
|           } | ||||
|         ], | ||||
|         "Callee": { | ||||
|           "Identifier": "TypeError" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
| 	`) | ||||
| 
 | ||||
| 		// When run, this will call a type error to be thrown
 | ||||
| 		// This is essentially the same as:
 | ||||
| 		//
 | ||||
| 		// var abc = 1(function(){})()
 | ||||
| 		//
 | ||||
| 		test(` | ||||
|         var abc = 1 | ||||
|         (function(){ | ||||
|         })() | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Var": [ | ||||
|       [ | ||||
|         "abc", | ||||
|         { | ||||
|           "Call": { | ||||
|             "ArgumentList": [], | ||||
|             "Callee": { | ||||
|               "Call": { | ||||
|                 "ArgumentList": [ | ||||
|                   { | ||||
|                     "Function": { | ||||
|                       "BlockStatement": [] | ||||
|                     } | ||||
|                   } | ||||
|                 ], | ||||
|                 "Callee": { | ||||
|                   "Literal": 1 | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       ] | ||||
|     ] | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         "use strict" | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Literal": "\"use strict\"" | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         "use strict" | ||||
|         abc = 1 + 2 + 11 | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Literal": "\"use strict\"" | ||||
|   }, | ||||
|   { | ||||
|     "Assign": { | ||||
|       "Left": { | ||||
|         "Identifier": "abc" | ||||
|       }, | ||||
|       "Right": { | ||||
|         "BinaryExpression": { | ||||
|           "Left": { | ||||
|             "BinaryExpression": { | ||||
|               "Left": { | ||||
|                 "Literal": 1 | ||||
|               }, | ||||
|               "Operator": "+", | ||||
|               "Right": { | ||||
|                 "Literal": 2 | ||||
|               } | ||||
|             } | ||||
|           }, | ||||
|           "Operator": "+", | ||||
|           "Right": { | ||||
|             "Literal": 11 | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         abc = function() { 'use strict' } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Assign": { | ||||
|       "Left": { | ||||
|         "Identifier": "abc" | ||||
|       }, | ||||
|       "Right": { | ||||
|         "Function": { | ||||
|           "BlockStatement": [ | ||||
|             { | ||||
|               "Literal": "'use strict'" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         for (var abc in def) { | ||||
|         } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "ForIn": { | ||||
|       "Body": { | ||||
|         "BlockStatement": [] | ||||
|       }, | ||||
|       "Into": [ | ||||
|         "abc", | ||||
|         null | ||||
|       ], | ||||
|       "Source": { | ||||
|         "Identifier": "def" | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 
 | ||||
| 		test(` | ||||
|         abc = { | ||||
|             '"': "'", | ||||
|             "'": '"', | ||||
|         } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "Assign": { | ||||
|       "Left": { | ||||
|         "Identifier": "abc" | ||||
|       }, | ||||
|       "Right": { | ||||
|         "Object": [ | ||||
|           { | ||||
|             "Key": "\"", | ||||
|             "Value": { | ||||
|               "Literal": "\"'\"" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "Key": "'", | ||||
|             "Value": { | ||||
|               "Literal": "'\"'" | ||||
|             } | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|             `) | ||||
| 
 | ||||
| 		return | ||||
| 
 | ||||
| 		test(` | ||||
|         if (!abc && abc.jkl(def) && abc[0] === +abc[0] && abc.length < ghi) { | ||||
|         } | ||||
|         --- | ||||
| [ | ||||
|   { | ||||
|     "If": { | ||||
|       "Consequent": { | ||||
|         "BlockStatement": [] | ||||
|       }, | ||||
|       "Test": { | ||||
|         "BinaryExpression": { | ||||
|           "Left": { | ||||
|             "BinaryExpression": { | ||||
|               "Left": { | ||||
|                 "BinaryExpression": { | ||||
|                   "Left": null, | ||||
|                   "Operator": "\u0026\u0026", | ||||
|                   "Right": { | ||||
|                     "Call": { | ||||
|                       "ArgumentList": [ | ||||
|                         { | ||||
|                           "Identifier": "def" | ||||
|                         } | ||||
|                       ], | ||||
|                       "Callee": { | ||||
|                         "Dot": { | ||||
|                           "Left": { | ||||
|                             "Identifier": "abc" | ||||
|                           }, | ||||
|                           "Member": "jkl" | ||||
|                         } | ||||
|                       } | ||||
|                     } | ||||
|                   } | ||||
|                 } | ||||
|               }, | ||||
|               "Operator": "\u0026\u0026", | ||||
|               "Right": { | ||||
|                 "BinaryExpression": { | ||||
|                   "Left": null, | ||||
|                   "Operator": "===", | ||||
|                   "Right": null | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           }, | ||||
|           "Operator": "\u0026\u0026", | ||||
|           "Right": { | ||||
|             "BinaryExpression": { | ||||
|               "Left": { | ||||
|                 "Dot": { | ||||
|                   "Left": { | ||||
|                     "Identifier": "abc" | ||||
|                   }, | ||||
|                   "Member": "length" | ||||
|                 } | ||||
|               }, | ||||
|               "Operator": "\u003c", | ||||
|               "Right": { | ||||
|                 "Identifier": "ghi" | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| ] | ||||
|         `) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										270
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										270
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,270 +0,0 @@ | ||||
| /* | ||||
| Package parser implements a parser for JavaScript. | ||||
| 
 | ||||
|     import ( | ||||
|         "github.com/robertkrimen/otto/parser" | ||||
|     ) | ||||
| 
 | ||||
| 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) | ||||
| 
 | ||||
| Warning | ||||
| 
 | ||||
| The parser and AST interfaces are still works-in-progress (particularly where | ||||
| node types are concerned) and may change in the future. | ||||
| 
 | ||||
| */ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| // A Mode value is a set of flags (or 0). They control optional parser functionality.
 | ||||
| type Mode uint | ||||
| 
 | ||||
| const ( | ||||
| 	IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
 | ||||
| ) | ||||
| 
 | ||||
| type _parser struct { | ||||
| 	filename string | ||||
| 	str      string | ||||
| 	length   int | ||||
| 	base     int | ||||
| 
 | ||||
| 	chr       rune // The current character
 | ||||
| 	chrOffset int  // The offset of current character
 | ||||
| 	offset    int  // The offset after current character (may be greater than 1)
 | ||||
| 
 | ||||
| 	idx     file.Idx    // The index of token
 | ||||
| 	token   token.Token // The token
 | ||||
| 	literal string      // The literal of the token, if any
 | ||||
| 
 | ||||
| 	scope             *_scope | ||||
| 	insertSemicolon   bool // If we see a newline, then insert an implicit semicolon
 | ||||
| 	implicitSemicolon bool // An implicit semicolon exists
 | ||||
| 
 | ||||
| 	errors ErrorList | ||||
| 
 | ||||
| 	recover struct { | ||||
| 		// Scratch when trying to seek to the next statement, etc.
 | ||||
| 		idx   file.Idx | ||||
| 		count int | ||||
| 	} | ||||
| 
 | ||||
| 	mode Mode | ||||
| } | ||||
| 
 | ||||
| func _newParser(filename, src string, base int) *_parser { | ||||
| 	return &_parser{ | ||||
| 		chr:    ' ', // This is set so we can start scanning by skipping whitespace
 | ||||
| 		str:    src, | ||||
| 		length: len(src), | ||||
| 		base:   base, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func newParser(filename, src string) *_parser { | ||||
| 	return _newParser(filename, src, 1) | ||||
| } | ||||
| 
 | ||||
| func ReadSource(filename string, src interface{}) ([]byte, error) { | ||||
| 	if src != nil { | ||||
| 		switch src := src.(type) { | ||||
| 		case string: | ||||
| 			return []byte(src), nil | ||||
| 		case []byte: | ||||
| 			return src, nil | ||||
| 		case *bytes.Buffer: | ||||
| 			if src != nil { | ||||
| 				return src.Bytes(), nil | ||||
| 			} | ||||
| 		case io.Reader: | ||||
| 			var bfr bytes.Buffer | ||||
| 			if _, err := io.Copy(&bfr, src); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			return bfr.Bytes(), nil | ||||
| 		} | ||||
| 		return nil, errors.New("invalid source") | ||||
| 	} | ||||
| 	return ioutil.ReadFile(filename) | ||||
| } | ||||
| 
 | ||||
| // ParseFile parses the source code of a single JavaScript/ECMAScript source file and returns
 | ||||
| // the corresponding ast.Program node.
 | ||||
| //
 | ||||
| // If fileSet == nil, ParseFile parses source without a FileSet.
 | ||||
| // If fileSet != nil, ParseFile first adds filename and src to fileSet.
 | ||||
| //
 | ||||
| // The filename argument is optional and is used for labelling errors, etc.
 | ||||
| //
 | ||||
| // src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.
 | ||||
| //
 | ||||
| //      // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
 | ||||
| //      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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	{ | ||||
| 		str := string(str) | ||||
| 
 | ||||
| 		base := 1 | ||||
| 		if fileSet != nil { | ||||
| 			base = fileSet.AddFile(filename, str) | ||||
| 		} | ||||
| 
 | ||||
| 		parser := _newParser(filename, str, base) | ||||
| 		parser.mode = mode | ||||
| 		return parser.parse() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ParseFunction parses a given parameter list and body as a function and returns the
 | ||||
| // corresponding ast.FunctionLiteral node.
 | ||||
| //
 | ||||
| // The parameter list, if any, should be a comma-separated list of identifiers.
 | ||||
| //
 | ||||
| func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error) { | ||||
| 
 | ||||
| 	src := "(function(" + parameterList + ") {\n" + body + "\n})" | ||||
| 
 | ||||
| 	parser := _newParser("", src, 1) | ||||
| 	program, err := parser.parse() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral), nil | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) slice(idx0, idx1 file.Idx) string { | ||||
| 	from := int(idx0) - self.base | ||||
| 	to := int(idx1) - self.base | ||||
| 	if from >= 0 && to <= len(self.str) { | ||||
| 		return self.str[from:to] | ||||
| 	} | ||||
| 
 | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parse() (*ast.Program, error) { | ||||
| 	self.next() | ||||
| 	program := self.parseProgram() | ||||
| 	if false { | ||||
| 		self.errors.Sort() | ||||
| 	} | ||||
| 	return program, self.errors.Err() | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) next() { | ||||
| 	self.token, self.literal, self.idx = self.scan() | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) optionalSemicolon() { | ||||
| 	if self.token == token.SEMICOLON { | ||||
| 		self.next() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if self.implicitSemicolon { | ||||
| 		self.implicitSemicolon = false | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token != token.EOF && self.token != token.RIGHT_BRACE { | ||||
| 		self.expect(token.SEMICOLON) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) semicolon() { | ||||
| 	if self.token != token.RIGHT_PARENTHESIS && self.token != token.RIGHT_BRACE { | ||||
| 		if self.implicitSemicolon { | ||||
| 			self.implicitSemicolon = false | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		self.expect(token.SEMICOLON) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) idxOf(offset int) file.Idx { | ||||
| 	return file.Idx(self.base + offset) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) expect(value token.Token) file.Idx { | ||||
| 	idx := self.idx | ||||
| 	if self.token != value { | ||||
| 		self.errorUnexpectedToken(self.token) | ||||
| 	} | ||||
| 	self.next() | ||||
| 	return idx | ||||
| } | ||||
| 
 | ||||
| func lineCount(str string) (int, int) { | ||||
| 	line, last := 0, -1 | ||||
| 	pair := false | ||||
| 	for index, chr := range str { | ||||
| 		switch chr { | ||||
| 		case '\r': | ||||
| 			line += 1 | ||||
| 			last = index | ||||
| 			pair = true | ||||
| 			continue | ||||
| 		case '\n': | ||||
| 			if !pair { | ||||
| 				line += 1 | ||||
| 			} | ||||
| 			last = index | ||||
| 		case '\u2028', '\u2029': | ||||
| 			line += 1 | ||||
| 			last = index + 2 | ||||
| 		} | ||||
| 		pair = false | ||||
| 	} | ||||
| 	return line, last | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) position(idx file.Idx) file.Position { | ||||
| 	position := file.Position{} | ||||
| 	offset := int(idx) - self.base | ||||
| 	str := self.str[:offset] | ||||
| 	position.Filename = self.filename | ||||
| 	line, last := lineCount(str) | ||||
| 	position.Line = 1 + line | ||||
| 	if last >= 0 { | ||||
| 		position.Column = offset - last | ||||
| 	} else { | ||||
| 		position.Column = 1 + len(str) | ||||
| 	} | ||||
| 
 | ||||
| 	return position | ||||
| } | ||||
							
								
								
									
										1004
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/parser_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1004
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/parser_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										358
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										358
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,358 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| type _RegExp_parser struct { | ||||
| 	str    string | ||||
| 	length int | ||||
| 
 | ||||
| 	chr       rune // The current character
 | ||||
| 	chrOffset int  // The offset of current character
 | ||||
| 	offset    int  // The offset after current character (may be greater than 1)
 | ||||
| 
 | ||||
| 	errors  []error | ||||
| 	invalid bool // The input is an invalid JavaScript RegExp
 | ||||
| 
 | ||||
| 	goRegexp *bytes.Buffer | ||||
| } | ||||
| 
 | ||||
| // TransformRegExp transforms a JavaScript pattern into  a Go "regexp" pattern.
 | ||||
| //
 | ||||
| // re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or
 | ||||
| // backreference (\1, \2, ...) will cause an error.
 | ||||
| //
 | ||||
| // 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.
 | ||||
| //
 | ||||
| // If the pattern is invalid (not valid even in JavaScript), then this function
 | ||||
| // returns the empty string and an error.
 | ||||
| //
 | ||||
| // If the pattern is valid, but incompatible (contains a lookahead or backreference),
 | ||||
| // then this function returns the transformation (a non-empty string) AND an error.
 | ||||
| func TransformRegExp(pattern string) (string, error) { | ||||
| 
 | ||||
| 	if pattern == "" { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO If without \, if without (?=, (?!, then another shortcut
 | ||||
| 
 | ||||
| 	parser := _RegExp_parser{ | ||||
| 		str:      pattern, | ||||
| 		length:   len(pattern), | ||||
| 		goRegexp: bytes.NewBuffer(make([]byte, 0, 3*len(pattern)/2)), | ||||
| 	} | ||||
| 	parser.read() // Pull in the first character
 | ||||
| 	parser.scan() | ||||
| 	var err error | ||||
| 	if len(parser.errors) > 0 { | ||||
| 		err = parser.errors[0] | ||||
| 	} | ||||
| 	if parser.invalid { | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	// Might not be re2 compatible, but is still a valid JavaScript RegExp
 | ||||
| 	return parser.goRegexp.String(), err | ||||
| } | ||||
| 
 | ||||
| func (self *_RegExp_parser) scan() { | ||||
| 	for self.chr != -1 { | ||||
| 		switch self.chr { | ||||
| 		case '\\': | ||||
| 			self.read() | ||||
| 			self.scanEscape(false) | ||||
| 		case '(': | ||||
| 			self.pass() | ||||
| 			self.scanGroup() | ||||
| 		case '[': | ||||
| 			self.pass() | ||||
| 			self.scanBracket() | ||||
| 		case ')': | ||||
| 			self.error(-1, "Unmatched ')'") | ||||
| 			self.invalid = true | ||||
| 			self.pass() | ||||
| 		default: | ||||
| 			self.pass() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // (...)
 | ||||
| func (self *_RegExp_parser) scanGroup() { | ||||
| 	str := self.str[self.chrOffset:] | ||||
| 	if len(str) > 1 { // A possibility of (?= or (?!
 | ||||
| 		if str[0] == '?' { | ||||
| 			if str[1] == '=' || str[1] == '!' { | ||||
| 				self.error(-1, "re2: Invalid (%s) <lookahead>", self.str[self.chrOffset:self.chrOffset+2]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for self.chr != -1 && self.chr != ')' { | ||||
| 		switch self.chr { | ||||
| 		case '\\': | ||||
| 			self.read() | ||||
| 			self.scanEscape(false) | ||||
| 		case '(': | ||||
| 			self.pass() | ||||
| 			self.scanGroup() | ||||
| 		case '[': | ||||
| 			self.pass() | ||||
| 			self.scanBracket() | ||||
| 		default: | ||||
| 			self.pass() | ||||
| 			continue | ||||
| 		} | ||||
| 	} | ||||
| 	if self.chr != ')' { | ||||
| 		self.error(-1, "Unterminated group") | ||||
| 		self.invalid = true | ||||
| 		return | ||||
| 	} | ||||
| 	self.pass() | ||||
| } | ||||
| 
 | ||||
| // [...]
 | ||||
| func (self *_RegExp_parser) scanBracket() { | ||||
| 	for self.chr != -1 { | ||||
| 		if self.chr == ']' { | ||||
| 			break | ||||
| 		} else if self.chr == '\\' { | ||||
| 			self.read() | ||||
| 			self.scanEscape(true) | ||||
| 			continue | ||||
| 		} | ||||
| 		self.pass() | ||||
| 	} | ||||
| 	if self.chr != ']' { | ||||
| 		self.error(-1, "Unterminated character class") | ||||
| 		self.invalid = true | ||||
| 		return | ||||
| 	} | ||||
| 	self.pass() | ||||
| } | ||||
| 
 | ||||
| // \...
 | ||||
| func (self *_RegExp_parser) scanEscape(inClass bool) { | ||||
| 	offset := self.chrOffset | ||||
| 
 | ||||
| 	var length, base uint32 | ||||
| 	switch self.chr { | ||||
| 
 | ||||
| 	case '0', '1', '2', '3', '4', '5', '6', '7': | ||||
| 		var value int64 | ||||
| 		size := 0 | ||||
| 		for { | ||||
| 			digit := int64(digitValue(self.chr)) | ||||
| 			if digit >= 8 { | ||||
| 				// Not a valid digit
 | ||||
| 				break | ||||
| 			} | ||||
| 			value = value*8 + digit | ||||
| 			self.read() | ||||
| 			size += 1 | ||||
| 		} | ||||
| 		if size == 1 { // The number of characters read
 | ||||
| 			_, err := self.goRegexp.Write([]byte{'\\', byte(value) + '0'}) | ||||
| 			if err != nil { | ||||
| 				self.errors = append(self.errors, err) | ||||
| 			} | ||||
| 			if value != 0 { | ||||
| 				// An invalid backreference
 | ||||
| 				self.error(-1, "re2: Invalid \\%d <backreference>", value) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		tmp := []byte{'\\', 'x', '0', 0} | ||||
| 		if value >= 16 { | ||||
| 			tmp = tmp[0:2] | ||||
| 		} else { | ||||
| 			tmp = tmp[0:3] | ||||
| 		} | ||||
| 		tmp = strconv.AppendInt(tmp, value, 16) | ||||
| 		_, err := self.goRegexp.Write(tmp) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 		return | ||||
| 
 | ||||
| 	case '8', '9': | ||||
| 		size := 0 | ||||
| 		for { | ||||
| 			digit := digitValue(self.chr) | ||||
| 			if digit >= 10 { | ||||
| 				// Not a valid digit
 | ||||
| 				break | ||||
| 			} | ||||
| 			self.read() | ||||
| 			size += 1 | ||||
| 		} | ||||
| 		err := self.goRegexp.WriteByte('\\') | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 		_, err = self.goRegexp.WriteString(self.str[offset:self.chrOffset]) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 		self.error(-1, "re2: Invalid \\%s <backreference>", self.str[offset:self.chrOffset]) | ||||
| 		return | ||||
| 
 | ||||
| 	case 'x': | ||||
| 		self.read() | ||||
| 		length, base = 2, 16 | ||||
| 
 | ||||
| 	case 'u': | ||||
| 		self.read() | ||||
| 		length, base = 4, 16 | ||||
| 
 | ||||
| 	case 'b': | ||||
| 		if inClass { | ||||
| 			_, err := self.goRegexp.Write([]byte{'\\', 'x', '0', '8'}) | ||||
| 			if err != nil { | ||||
| 				self.errors = append(self.errors, err) | ||||
| 			} | ||||
| 			self.read() | ||||
| 			return | ||||
| 		} | ||||
| 		fallthrough | ||||
| 
 | ||||
| 	case 'B': | ||||
| 		fallthrough | ||||
| 
 | ||||
| 	case 'd', 'D', 's', 'S', 'w', 'W': | ||||
| 		// This is slightly broken, because ECMAScript
 | ||||
| 		// includes \v in \s, \S, while re2 does not
 | ||||
| 		fallthrough | ||||
| 
 | ||||
| 	case '\\': | ||||
| 		fallthrough | ||||
| 
 | ||||
| 	case 'f', 'n', 'r', 't', 'v': | ||||
| 		err := self.goRegexp.WriteByte('\\') | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 		self.pass() | ||||
| 		return | ||||
| 
 | ||||
| 	case 'c': | ||||
| 		self.read() | ||||
| 		var value int64 | ||||
| 		if 'a' <= self.chr && self.chr <= 'z' { | ||||
| 			value = int64(self.chr) - 'a' + 1 | ||||
| 		} else if 'A' <= self.chr && self.chr <= 'Z' { | ||||
| 			value = int64(self.chr) - 'A' + 1 | ||||
| 		} else { | ||||
| 			err := self.goRegexp.WriteByte('c') | ||||
| 			if err != nil { | ||||
| 				self.errors = append(self.errors, err) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 		tmp := []byte{'\\', 'x', '0', 0} | ||||
| 		if value >= 16 { | ||||
| 			tmp = tmp[0:2] | ||||
| 		} else { | ||||
| 			tmp = tmp[0:3] | ||||
| 		} | ||||
| 		tmp = strconv.AppendInt(tmp, value, 16) | ||||
| 		_, err := self.goRegexp.Write(tmp) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 		self.read() | ||||
| 		return | ||||
| 
 | ||||
| 	default: | ||||
| 		// $ is an identifier character, so we have to have
 | ||||
| 		// a special case for it here
 | ||||
| 		if self.chr == '$' || !isIdentifierPart(self.chr) { | ||||
| 			// A non-identifier character needs escaping
 | ||||
| 			err := self.goRegexp.WriteByte('\\') | ||||
| 			if err != nil { | ||||
| 				self.errors = append(self.errors, err) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// Unescape the character for re2
 | ||||
| 		} | ||||
| 		self.pass() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Otherwise, we're a \u.... or \x...
 | ||||
| 	valueOffset := self.chrOffset | ||||
| 
 | ||||
| 	var value uint32 | ||||
| 	{ | ||||
| 		length := length | ||||
| 		for ; length > 0; length-- { | ||||
| 			digit := uint32(digitValue(self.chr)) | ||||
| 			if digit >= base { | ||||
| 				// Not a valid digit
 | ||||
| 				goto skip | ||||
| 			} | ||||
| 			value = value*base + digit | ||||
| 			self.read() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if length == 4 { | ||||
| 		_, err := self.goRegexp.Write([]byte{ | ||||
| 			'\\', | ||||
| 			'x', | ||||
| 			'{', | ||||
| 			self.str[valueOffset+0], | ||||
| 			self.str[valueOffset+1], | ||||
| 			self.str[valueOffset+2], | ||||
| 			self.str[valueOffset+3], | ||||
| 			'}', | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 	} else if length == 2 { | ||||
| 		_, err := self.goRegexp.Write([]byte{ | ||||
| 			'\\', | ||||
| 			'x', | ||||
| 			self.str[valueOffset+0], | ||||
| 			self.str[valueOffset+1], | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		// Should never, ever get here...
 | ||||
| 		self.error(-1, "re2: Illegal branch in scanEscape") | ||||
| 		goto skip | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| 
 | ||||
| skip: | ||||
| 	_, err := self.goRegexp.WriteString(self.str[offset:self.chrOffset]) | ||||
| 	if err != nil { | ||||
| 		self.errors = append(self.errors, err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_RegExp_parser) pass() { | ||||
| 	if self.chr != -1 { | ||||
| 		_, err := self.goRegexp.WriteRune(self.chr) | ||||
| 		if err != nil { | ||||
| 			self.errors = append(self.errors, err) | ||||
| 		} | ||||
| 	} | ||||
| 	self.read() | ||||
| } | ||||
| 
 | ||||
| // TODO Better error reporting, use the offset, etc.
 | ||||
| func (self *_RegExp_parser) error(offset int, msg string, msgValues ...interface{}) error { | ||||
| 	err := fmt.Errorf(msg, msgValues...) | ||||
| 	self.errors = append(self.errors, err) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										149
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/regexp_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										149
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/regexp_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,149 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"regexp" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestRegExp(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		{ | ||||
| 			// err
 | ||||
| 			test := func(input string, expect interface{}) { | ||||
| 				_, err := TransformRegExp(input) | ||||
| 				is(err, expect) | ||||
| 			} | ||||
| 
 | ||||
| 			test("[", "Unterminated character class") | ||||
| 
 | ||||
| 			test("(", "Unterminated group") | ||||
| 
 | ||||
| 			test("(?=)", "re2: Invalid (?=) <lookahead>") | ||||
| 
 | ||||
| 			test("(?=)", "re2: Invalid (?=) <lookahead>") | ||||
| 
 | ||||
| 			test("(?!)", "re2: Invalid (?!) <lookahead>") | ||||
| 
 | ||||
| 			// An error anyway
 | ||||
| 			test("(?=", "re2: Invalid (?=) <lookahead>") | ||||
| 
 | ||||
| 			test("\\1", "re2: Invalid \\1 <backreference>") | ||||
| 
 | ||||
| 			test("\\90", "re2: Invalid \\90 <backreference>") | ||||
| 
 | ||||
| 			test("\\9123456789", "re2: Invalid \\9123456789 <backreference>") | ||||
| 
 | ||||
| 			test("\\(?=)", "Unmatched ')'") | ||||
| 
 | ||||
| 			test(")", "Unmatched ')'") | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			// err
 | ||||
| 			test := func(input, expect string, expectErr interface{}) { | ||||
| 				output, err := TransformRegExp(input) | ||||
| 				is(output, expect) | ||||
| 				is(err, expectErr) | ||||
| 			} | ||||
| 
 | ||||
| 			test("(?!)", "(?!)", "re2: Invalid (?!) <lookahead>") | ||||
| 
 | ||||
| 			test(")", "", "Unmatched ')'") | ||||
| 
 | ||||
| 			test("(?!))", "", "re2: Invalid (?!) <lookahead>") | ||||
| 
 | ||||
| 			test("\\0", "\\0", nil) | ||||
| 
 | ||||
| 			test("\\1", "\\1", "re2: Invalid \\1 <backreference>") | ||||
| 
 | ||||
| 			test("\\9123456789", "\\9123456789", "re2: Invalid \\9123456789 <backreference>") | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			// err
 | ||||
| 			test := func(input string, expect string) { | ||||
| 				result, err := TransformRegExp(input) | ||||
| 				is(err, nil) | ||||
| 				if is(result, expect) { | ||||
| 					_, err := regexp.Compile(result) | ||||
| 					if !is(err, nil) { | ||||
| 						t.Log(result) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			test("", "") | ||||
| 
 | ||||
| 			test("abc", "abc") | ||||
| 
 | ||||
| 			test(`\abc`, `abc`) | ||||
| 
 | ||||
| 			test(`\a\b\c`, `a\bc`) | ||||
| 
 | ||||
| 			test(`\x`, `x`) | ||||
| 
 | ||||
| 			test(`\c`, `c`) | ||||
| 
 | ||||
| 			test(`\cA`, `\x01`) | ||||
| 
 | ||||
| 			test(`\cz`, `\x1a`) | ||||
| 
 | ||||
| 			test(`\ca`, `\x01`) | ||||
| 
 | ||||
| 			test(`\cj`, `\x0a`) | ||||
| 
 | ||||
| 			test(`\ck`, `\x0b`) | ||||
| 
 | ||||
| 			test(`\+`, `\+`) | ||||
| 
 | ||||
| 			test(`[\b]`, `[\x08]`) | ||||
| 
 | ||||
| 			test(`\u0z01\x\undefined`, `u0z01xundefined`) | ||||
| 
 | ||||
| 			test(`\\|'|\r|\n|\t|\u2028|\u2029`, `\\|'|\r|\n|\t|\x{2028}|\x{2029}`) | ||||
| 
 | ||||
| 			test("]", "]") | ||||
| 
 | ||||
| 			test("}", "}") | ||||
| 
 | ||||
| 			test("%", "%") | ||||
| 
 | ||||
| 			test("(%)", "(%)") | ||||
| 
 | ||||
| 			test("(?:[%\\s])", "(?:[%\\s])") | ||||
| 
 | ||||
| 			test("[[]", "[[]") | ||||
| 
 | ||||
| 			test("\\101", "\\x41") | ||||
| 
 | ||||
| 			test("\\51", "\\x29") | ||||
| 
 | ||||
| 			test("\\051", "\\x29") | ||||
| 
 | ||||
| 			test("\\175", "\\x7d") | ||||
| 
 | ||||
| 			test("\\04", "\\x04") | ||||
| 
 | ||||
| 			test(`<%([\s\S]+?)%>`, `<%([\s\S]+?)%>`) | ||||
| 
 | ||||
| 			test(`(.)^`, "(.)^") | ||||
| 
 | ||||
| 			test(`<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`, `<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`) | ||||
| 
 | ||||
| 			test(`\$`, `\$`) | ||||
| 
 | ||||
| 			test(`[G-b]`, `[G-b]`) | ||||
| 
 | ||||
| 			test(`[G-b\0]`, `[G-b\0]`) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestTransformRegExp(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		pattern, err := TransformRegExp(`\s+abc\s+`) | ||||
| 		is(err, nil) | ||||
| 		is(pattern, `\s+abc\s+`) | ||||
| 		is(regexp.MustCompile(pattern).MatchString("\t abc def"), true) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										44
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/scope.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/scope.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,44 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| ) | ||||
| 
 | ||||
| type _scope struct { | ||||
| 	outer           *_scope | ||||
| 	allowIn         bool | ||||
| 	inIteration     bool | ||||
| 	inSwitch        bool | ||||
| 	inFunction      bool | ||||
| 	declarationList []ast.Declaration | ||||
| 
 | ||||
| 	labels []string | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) openScope() { | ||||
| 	self.scope = &_scope{ | ||||
| 		outer:   self.scope, | ||||
| 		allowIn: true, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) closeScope() { | ||||
| 	self.scope = self.scope.outer | ||||
| } | ||||
| 
 | ||||
| func (self *_scope) declare(declaration ast.Declaration) { | ||||
| 	self.declarationList = append(self.declarationList, declaration) | ||||
| } | ||||
| 
 | ||||
| func (self *_scope) hasLabel(name string) bool { | ||||
| 	for _, label := range self.labels { | ||||
| 		if label == name { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	if self.outer != nil && !self.inFunction { | ||||
| 		// Crossing a function boundary to look for a label is verboten
 | ||||
| 		return self.outer.hasLabel(name) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										662
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/statement.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										662
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/parser/statement.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,662 +0,0 @@ | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| func (self *_parser) parseBlockStatement() *ast.BlockStatement { | ||||
| 	node := &ast.BlockStatement{} | ||||
| 	node.LeftBrace = self.expect(token.LEFT_BRACE) | ||||
| 	node.List = self.parseStatementList() | ||||
| 	node.RightBrace = self.expect(token.RIGHT_BRACE) | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseEmptyStatement() ast.Statement { | ||||
| 	idx := self.expect(token.SEMICOLON) | ||||
| 	return &ast.EmptyStatement{Semicolon: idx} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseStatementList() (list []ast.Statement) { | ||||
| 	for self.token != token.RIGHT_BRACE && self.token != token.EOF { | ||||
| 		list = append(list, self.parseStatement()) | ||||
| 	} | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseStatement() ast.Statement { | ||||
| 
 | ||||
| 	if self.token == token.EOF { | ||||
| 		self.errorUnexpectedToken(self.token) | ||||
| 		return &ast.BadStatement{From: self.idx, To: self.idx + 1} | ||||
| 	} | ||||
| 
 | ||||
| 	switch self.token { | ||||
| 	case token.SEMICOLON: | ||||
| 		return self.parseEmptyStatement() | ||||
| 	case token.LEFT_BRACE: | ||||
| 		return self.parseBlockStatement() | ||||
| 	case token.IF: | ||||
| 		return self.parseIfStatement() | ||||
| 	case token.DO: | ||||
| 		return self.parseDoWhileStatement() | ||||
| 	case token.WHILE: | ||||
| 		return self.parseWhileStatement() | ||||
| 	case token.FOR: | ||||
| 		return self.parseForOrForInStatement() | ||||
| 	case token.BREAK: | ||||
| 		return self.parseBreakStatement() | ||||
| 	case token.CONTINUE: | ||||
| 		return self.parseContinueStatement() | ||||
| 	case token.DEBUGGER: | ||||
| 		return self.parseDebuggerStatement() | ||||
| 	case token.WITH: | ||||
| 		return self.parseWithStatement() | ||||
| 	case token.VAR: | ||||
| 		return self.parseVariableStatement() | ||||
| 	case token.FUNCTION: | ||||
| 		self.parseFunction(true) | ||||
| 		// FIXME
 | ||||
| 		return &ast.EmptyStatement{} | ||||
| 	case token.SWITCH: | ||||
| 		return self.parseSwitchStatement() | ||||
| 	case token.RETURN: | ||||
| 		return self.parseReturnStatement() | ||||
| 	case token.THROW: | ||||
| 		return self.parseThrowStatement() | ||||
| 	case token.TRY: | ||||
| 		return self.parseTryStatement() | ||||
| 	} | ||||
| 
 | ||||
| 	expression := self.parseExpression() | ||||
| 
 | ||||
| 	if identifier, isIdentifier := expression.(*ast.Identifier); isIdentifier && self.token == token.COLON { | ||||
| 		// LabelledStatement
 | ||||
| 		colon := self.idx | ||||
| 		self.next() // :
 | ||||
| 		label := identifier.Name | ||||
| 		for _, value := range self.scope.labels { | ||||
| 			if label == value { | ||||
| 				self.error(identifier.Idx0(), "Label '%s' already exists", label) | ||||
| 			} | ||||
| 		} | ||||
| 		self.scope.labels = append(self.scope.labels, label) // Push the label
 | ||||
| 		statement := self.parseStatement() | ||||
| 		self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
 | ||||
| 		return &ast.LabelledStatement{ | ||||
| 			Label:     identifier, | ||||
| 			Colon:     colon, | ||||
| 			Statement: statement, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.optionalSemicolon() | ||||
| 
 | ||||
| 	return &ast.ExpressionStatement{ | ||||
| 		Expression: expression, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseTryStatement() ast.Statement { | ||||
| 
 | ||||
| 	node := &ast.TryStatement{ | ||||
| 		Try:  self.expect(token.TRY), | ||||
| 		Body: self.parseBlockStatement(), | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.CATCH { | ||||
| 		catch := self.idx | ||||
| 		self.next() | ||||
| 		self.expect(token.LEFT_PARENTHESIS) | ||||
| 		if self.token != token.IDENTIFIER { | ||||
| 			self.expect(token.IDENTIFIER) | ||||
| 			self.nextStatement() | ||||
| 			return &ast.BadStatement{From: catch, To: self.idx} | ||||
| 		} else { | ||||
| 			identifier := self.parseIdentifier() | ||||
| 			self.expect(token.RIGHT_PARENTHESIS) | ||||
| 			node.Catch = &ast.CatchStatement{ | ||||
| 				Catch:     catch, | ||||
| 				Parameter: identifier, | ||||
| 				Body:      self.parseBlockStatement(), | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.FINALLY { | ||||
| 		self.next() | ||||
| 		node.Finally = self.parseBlockStatement() | ||||
| 	} | ||||
| 
 | ||||
| 	if node.Catch == nil && node.Finally == nil { | ||||
| 		self.error(node.Try, "Missing catch or finally after try") | ||||
| 		return &ast.BadStatement{From: node.Try, To: node.Body.Idx1()} | ||||
| 	} | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseFunctionParameterList() *ast.ParameterList { | ||||
| 	opening := self.expect(token.LEFT_PARENTHESIS) | ||||
| 	var list []*ast.Identifier | ||||
| 	for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF { | ||||
| 		if self.token != token.IDENTIFIER { | ||||
| 			self.expect(token.IDENTIFIER) | ||||
| 		} else { | ||||
| 			list = append(list, self.parseIdentifier()) | ||||
| 		} | ||||
| 		if self.token != token.RIGHT_PARENTHESIS { | ||||
| 			self.expect(token.COMMA) | ||||
| 		} | ||||
| 	} | ||||
| 	closing := self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	return &ast.ParameterList{ | ||||
| 		Opening: opening, | ||||
| 		List:    list, | ||||
| 		Closing: closing, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseParameterList() (list []string) { | ||||
| 	for self.token != token.EOF { | ||||
| 		if self.token != token.IDENTIFIER { | ||||
| 			self.expect(token.IDENTIFIER) | ||||
| 		} | ||||
| 		list = append(list, self.literal) | ||||
| 		self.next() | ||||
| 		if self.token != token.EOF { | ||||
| 			self.expect(token.COMMA) | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseFunction(declaration bool) *ast.FunctionLiteral { | ||||
| 
 | ||||
| 	node := &ast.FunctionLiteral{ | ||||
| 		Function: self.expect(token.FUNCTION), | ||||
| 	} | ||||
| 
 | ||||
| 	var name *ast.Identifier | ||||
| 	if self.token == token.IDENTIFIER { | ||||
| 		name = self.parseIdentifier() | ||||
| 		if declaration { | ||||
| 			self.scope.declare(&ast.FunctionDeclaration{ | ||||
| 				Function: node, | ||||
| 			}) | ||||
| 		} | ||||
| 	} else if declaration { | ||||
| 		// Use expect error handling
 | ||||
| 		self.expect(token.IDENTIFIER) | ||||
| 	} | ||||
| 	node.Name = name | ||||
| 	node.ParameterList = self.parseFunctionParameterList() | ||||
| 	self.parseFunctionBlock(node) | ||||
| 	node.Source = self.slice(node.Idx0(), node.Idx1()) | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) { | ||||
| 	{ | ||||
| 		self.openScope() | ||||
| 		inFunction := self.scope.inFunction | ||||
| 		self.scope.inFunction = true | ||||
| 		defer func() { | ||||
| 			self.scope.inFunction = inFunction | ||||
| 			self.closeScope() | ||||
| 		}() | ||||
| 		node.Body = self.parseBlockStatement() | ||||
| 		node.DeclarationList = self.scope.declarationList | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseDebuggerStatement() ast.Statement { | ||||
| 	idx := self.expect(token.DEBUGGER) | ||||
| 
 | ||||
| 	node := &ast.DebuggerStatement{ | ||||
| 		Debugger: idx, | ||||
| 	} | ||||
| 
 | ||||
| 	self.semicolon() | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseReturnStatement() ast.Statement { | ||||
| 	idx := self.expect(token.RETURN) | ||||
| 
 | ||||
| 	if !self.scope.inFunction { | ||||
| 		self.error(idx, "Illegal return statement") | ||||
| 		self.nextStatement() | ||||
| 		return &ast.BadStatement{From: idx, To: self.idx} | ||||
| 	} | ||||
| 
 | ||||
| 	node := &ast.ReturnStatement{ | ||||
| 		Return: idx, | ||||
| 	} | ||||
| 
 | ||||
| 	if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE && self.token != token.EOF { | ||||
| 		node.Argument = self.parseExpression() | ||||
| 	} | ||||
| 
 | ||||
| 	self.semicolon() | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseThrowStatement() ast.Statement { | ||||
| 	idx := self.expect(token.THROW) | ||||
| 
 | ||||
| 	if self.implicitSemicolon { | ||||
| 		if self.chr == -1 { // Hackish
 | ||||
| 			self.error(idx, "Unexpected end of input") | ||||
| 		} else { | ||||
| 			self.error(idx, "Illegal newline after throw") | ||||
| 		} | ||||
| 		self.nextStatement() | ||||
| 		return &ast.BadStatement{From: idx, To: self.idx} | ||||
| 	} | ||||
| 
 | ||||
| 	node := &ast.ThrowStatement{ | ||||
| 		Argument: self.parseExpression(), | ||||
| 	} | ||||
| 
 | ||||
| 	self.semicolon() | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseSwitchStatement() ast.Statement { | ||||
| 	self.expect(token.SWITCH) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 	node := &ast.SwitchStatement{ | ||||
| 		Discriminant: self.parseExpression(), | ||||
| 		Default:      -1, | ||||
| 	} | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	self.expect(token.LEFT_BRACE) | ||||
| 
 | ||||
| 	inSwitch := self.scope.inSwitch | ||||
| 	self.scope.inSwitch = true | ||||
| 	defer func() { | ||||
| 		self.scope.inSwitch = inSwitch | ||||
| 	}() | ||||
| 
 | ||||
| 	for index := 0; self.token != token.EOF; index++ { | ||||
| 		if self.token == token.RIGHT_BRACE { | ||||
| 			self.next() | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		clause := self.parseCaseStatement() | ||||
| 		if clause.Test == nil { | ||||
| 			if node.Default != -1 { | ||||
| 				self.error(clause.Case, "Already saw a default in switch") | ||||
| 			} | ||||
| 			node.Default = index | ||||
| 		} | ||||
| 		node.Body = append(node.Body, clause) | ||||
| 	} | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseWithStatement() ast.Statement { | ||||
| 	self.expect(token.WITH) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 	node := &ast.WithStatement{ | ||||
| 		Object: self.parseExpression(), | ||||
| 	} | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	node.Body = self.parseStatement() | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseCaseStatement() *ast.CaseStatement { | ||||
| 
 | ||||
| 	node := &ast.CaseStatement{ | ||||
| 		Case: self.idx, | ||||
| 	} | ||||
| 	if self.token == token.DEFAULT { | ||||
| 		self.next() | ||||
| 	} else { | ||||
| 		self.expect(token.CASE) | ||||
| 		node.Test = self.parseExpression() | ||||
| 	} | ||||
| 	self.expect(token.COLON) | ||||
| 
 | ||||
| 	for { | ||||
| 		if self.token == token.EOF || | ||||
| 			self.token == token.RIGHT_BRACE || | ||||
| 			self.token == token.CASE || | ||||
| 			self.token == token.DEFAULT { | ||||
| 			break | ||||
| 		} | ||||
| 		node.Consequent = append(node.Consequent, self.parseStatement()) | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseIterationStatement() ast.Statement { | ||||
| 	inIteration := self.scope.inIteration | ||||
| 	self.scope.inIteration = true | ||||
| 	defer func() { | ||||
| 		self.scope.inIteration = inIteration | ||||
| 	}() | ||||
| 	return self.parseStatement() | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement { | ||||
| 
 | ||||
| 	// Already have consumed "<into> in"
 | ||||
| 
 | ||||
| 	source := self.parseExpression() | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	return &ast.ForInStatement{ | ||||
| 		Into:   into, | ||||
| 		Source: source, | ||||
| 		Body:   self.parseIterationStatement(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement { | ||||
| 
 | ||||
| 	// Already have consumed "<initializer> ;"
 | ||||
| 
 | ||||
| 	var test, update ast.Expression | ||||
| 
 | ||||
| 	if self.token != token.SEMICOLON { | ||||
| 		test = self.parseExpression() | ||||
| 	} | ||||
| 	self.expect(token.SEMICOLON) | ||||
| 
 | ||||
| 	if self.token != token.RIGHT_PARENTHESIS { | ||||
| 		update = self.parseExpression() | ||||
| 	} | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	return &ast.ForStatement{ | ||||
| 		Initializer: initializer, | ||||
| 		Test:        test, | ||||
| 		Update:      update, | ||||
| 		Body:        self.parseIterationStatement(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseForOrForInStatement() ast.Statement { | ||||
| 	idx := self.expect(token.FOR) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 
 | ||||
| 	var left []ast.Expression | ||||
| 
 | ||||
| 	forIn := false | ||||
| 	if self.token != token.SEMICOLON { | ||||
| 
 | ||||
| 		allowIn := self.scope.allowIn | ||||
| 		self.scope.allowIn = false | ||||
| 		if self.token == token.VAR { | ||||
| 			var_ := self.idx | ||||
| 			self.next() | ||||
| 			list := self.parseVariableDeclarationList(var_) | ||||
| 			if len(list) == 1 && self.token == token.IN { | ||||
| 				self.next() // in
 | ||||
| 				forIn = true | ||||
| 				left = []ast.Expression{list[0]} // There is only one declaration
 | ||||
| 			} else { | ||||
| 				left = list | ||||
| 			} | ||||
| 		} else { | ||||
| 			left = append(left, self.parseExpression()) | ||||
| 			if self.token == token.IN { | ||||
| 				self.next() | ||||
| 				forIn = true | ||||
| 			} | ||||
| 		} | ||||
| 		self.scope.allowIn = allowIn | ||||
| 	} | ||||
| 
 | ||||
| 	if forIn { | ||||
| 		switch left[0].(type) { | ||||
| 		case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression, *ast.VariableExpression: | ||||
| 			// These are all acceptable
 | ||||
| 		default: | ||||
| 			self.error(idx, "Invalid left-hand side in for-in") | ||||
| 			self.nextStatement() | ||||
| 			return &ast.BadStatement{From: idx, To: self.idx} | ||||
| 		} | ||||
| 		return self.parseForIn(left[0]) | ||||
| 	} | ||||
| 
 | ||||
| 	self.expect(token.SEMICOLON) | ||||
| 	return self.parseFor(&ast.SequenceExpression{Sequence: left}) | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseVariableStatement() *ast.VariableStatement { | ||||
| 
 | ||||
| 	idx := self.expect(token.VAR) | ||||
| 
 | ||||
| 	list := self.parseVariableDeclarationList(idx) | ||||
| 	self.semicolon() | ||||
| 
 | ||||
| 	return &ast.VariableStatement{ | ||||
| 		Var:  idx, | ||||
| 		List: list, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseDoWhileStatement() ast.Statement { | ||||
| 	inIteration := self.scope.inIteration | ||||
| 	self.scope.inIteration = true | ||||
| 	defer func() { | ||||
| 		self.scope.inIteration = inIteration | ||||
| 	}() | ||||
| 
 | ||||
| 	self.expect(token.DO) | ||||
| 	node := &ast.DoWhileStatement{} | ||||
| 	if self.token == token.LEFT_BRACE { | ||||
| 		node.Body = self.parseBlockStatement() | ||||
| 	} else { | ||||
| 		node.Body = self.parseStatement() | ||||
| 	} | ||||
| 
 | ||||
| 	self.expect(token.WHILE) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 	node.Test = self.parseExpression() | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseWhileStatement() ast.Statement { | ||||
| 	self.expect(token.WHILE) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 	node := &ast.WhileStatement{ | ||||
| 		Test: self.parseExpression(), | ||||
| 	} | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 	node.Body = self.parseIterationStatement() | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseIfStatement() ast.Statement { | ||||
| 	self.expect(token.IF) | ||||
| 	self.expect(token.LEFT_PARENTHESIS) | ||||
| 	node := &ast.IfStatement{ | ||||
| 		Test: self.parseExpression(), | ||||
| 	} | ||||
| 	self.expect(token.RIGHT_PARENTHESIS) | ||||
| 
 | ||||
| 	if self.token == token.LEFT_BRACE { | ||||
| 		node.Consequent = self.parseBlockStatement() | ||||
| 	} else { | ||||
| 		node.Consequent = self.parseStatement() | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.ELSE { | ||||
| 		self.next() | ||||
| 		node.Alternate = self.parseStatement() | ||||
| 	} | ||||
| 
 | ||||
| 	return node | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseSourceElement() ast.Statement { | ||||
| 	return self.parseStatement() | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseSourceElements() []ast.Statement { | ||||
| 	body := []ast.Statement(nil) | ||||
| 
 | ||||
| 	for { | ||||
| 		if self.token != token.STRING { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		body = append(body, self.parseSourceElement()) | ||||
| 	} | ||||
| 
 | ||||
| 	for self.token != token.EOF { | ||||
| 		body = append(body, self.parseSourceElement()) | ||||
| 	} | ||||
| 
 | ||||
| 	return body | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseProgram() *ast.Program { | ||||
| 	self.openScope() | ||||
| 	defer self.closeScope() | ||||
| 	return &ast.Program{ | ||||
| 		Body:            self.parseSourceElements(), | ||||
| 		DeclarationList: self.scope.declarationList, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseBreakStatement() ast.Statement { | ||||
| 	idx := self.expect(token.BREAK) | ||||
| 	semicolon := self.implicitSemicolon | ||||
| 	if self.token == token.SEMICOLON { | ||||
| 		semicolon = true | ||||
| 		self.next() | ||||
| 	} | ||||
| 
 | ||||
| 	if semicolon || self.token == token.RIGHT_BRACE { | ||||
| 		self.implicitSemicolon = false | ||||
| 		if !self.scope.inIteration && !self.scope.inSwitch { | ||||
| 			goto illegal | ||||
| 		} | ||||
| 		return &ast.BranchStatement{ | ||||
| 			Idx:   idx, | ||||
| 			Token: token.BREAK, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.IDENTIFIER { | ||||
| 		identifier := self.parseIdentifier() | ||||
| 		if !self.scope.hasLabel(identifier.Name) { | ||||
| 			self.error(idx, "Undefined label '%s'", identifier.Name) | ||||
| 			return &ast.BadStatement{From: idx, To: identifier.Idx1()} | ||||
| 		} | ||||
| 		self.semicolon() | ||||
| 		return &ast.BranchStatement{ | ||||
| 			Idx:   idx, | ||||
| 			Token: token.BREAK, | ||||
| 			Label: identifier, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.expect(token.IDENTIFIER) | ||||
| 
 | ||||
| illegal: | ||||
| 	self.error(idx, "Illegal break statement") | ||||
| 	self.nextStatement() | ||||
| 	return &ast.BadStatement{From: idx, To: self.idx} | ||||
| } | ||||
| 
 | ||||
| func (self *_parser) parseContinueStatement() ast.Statement { | ||||
| 	idx := self.expect(token.CONTINUE) | ||||
| 	semicolon := self.implicitSemicolon | ||||
| 	if self.token == token.SEMICOLON { | ||||
| 		semicolon = true | ||||
| 		self.next() | ||||
| 	} | ||||
| 
 | ||||
| 	if semicolon || self.token == token.RIGHT_BRACE { | ||||
| 		self.implicitSemicolon = false | ||||
| 		if !self.scope.inIteration { | ||||
| 			goto illegal | ||||
| 		} | ||||
| 		return &ast.BranchStatement{ | ||||
| 			Idx:   idx, | ||||
| 			Token: token.CONTINUE, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if self.token == token.IDENTIFIER { | ||||
| 		identifier := self.parseIdentifier() | ||||
| 		if !self.scope.hasLabel(identifier.Name) { | ||||
| 			self.error(idx, "Undefined label '%s'", identifier.Name) | ||||
| 			return &ast.BadStatement{From: idx, To: identifier.Idx1()} | ||||
| 		} | ||||
| 		if !self.scope.inIteration { | ||||
| 			goto illegal | ||||
| 		} | ||||
| 		self.semicolon() | ||||
| 		return &ast.BranchStatement{ | ||||
| 			Idx:   idx, | ||||
| 			Token: token.CONTINUE, | ||||
| 			Label: identifier, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self.expect(token.IDENTIFIER) | ||||
| 
 | ||||
| illegal: | ||||
| 	self.error(idx, "Illegal continue statement") | ||||
| 	self.nextStatement() | ||||
| 	return &ast.BadStatement{From: idx, To: self.idx} | ||||
| } | ||||
| 
 | ||||
| // Find the next statement after an error (recover)
 | ||||
| func (self *_parser) nextStatement() { | ||||
| 	for { | ||||
| 		switch self.token { | ||||
| 		case token.BREAK, token.CONTINUE, | ||||
| 			token.FOR, token.IF, token.RETURN, token.SWITCH, | ||||
| 			token.VAR, token.DO, token.TRY, token.WITH, | ||||
| 			token.WHILE, token.THROW, token.CATCH, token.FINALLY: | ||||
| 			// Return only if parser made some progress since last
 | ||||
| 			// sync or if it has not reached 10 next calls without
 | ||||
| 			// progress. Otherwise consume at least one token to
 | ||||
| 			// avoid an endless parser loop
 | ||||
| 			if self.idx == self.recover.idx && self.recover.count < 10 { | ||||
| 				self.recover.count++ | ||||
| 				return | ||||
| 			} | ||||
| 			if self.idx > self.recover.idx { | ||||
| 				self.recover.idx = self.idx | ||||
| 				self.recover.count = 0 | ||||
| 				return | ||||
| 			} | ||||
| 			// Reaching here indicates a parser bug, likely an
 | ||||
| 			// incorrect token list in this function, but it only
 | ||||
| 			// leads to skipping of possibly correct code if a
 | ||||
| 			// previous error is present, and thus is preferred
 | ||||
| 			// over a non-terminating parse.
 | ||||
| 		case token.EOF: | ||||
| 			return | ||||
| 		} | ||||
| 		self.next() | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										51
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/registry/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/registry/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,51 +0,0 @@ | ||||
| # registry | ||||
| -- | ||||
|     import "github.com/robertkrimen/otto/registry" | ||||
| 
 | ||||
| Package registry is an expirmental package to facillitate altering the otto | ||||
| runtime via import. | ||||
| 
 | ||||
| This interface can change at any time. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| #### func  Apply | ||||
| 
 | ||||
| ```go | ||||
| func Apply(callback func(Entry)) | ||||
| ``` | ||||
| 
 | ||||
| #### type Entry | ||||
| 
 | ||||
| ```go | ||||
| type Entry struct { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| #### func  Register | ||||
| 
 | ||||
| ```go | ||||
| func Register(source func() string) *Entry | ||||
| ``` | ||||
| 
 | ||||
| #### func (*Entry) Disable | ||||
| 
 | ||||
| ```go | ||||
| func (self *Entry) Disable() | ||||
| ``` | ||||
| 
 | ||||
| #### func (*Entry) Enable | ||||
| 
 | ||||
| ```go | ||||
| func (self *Entry) Enable() | ||||
| ``` | ||||
| 
 | ||||
| #### func (Entry) Source | ||||
| 
 | ||||
| ```go | ||||
| func (self Entry) Source() string | ||||
| ``` | ||||
| 
 | ||||
| -- | ||||
| **godocdown** http://github.com/robertkrimen/godocdown | ||||
							
								
								
									
										47
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,47 +0,0 @@ | ||||
| /* | ||||
| Package registry is an expirmental package to facillitate altering the otto runtime via import. | ||||
| 
 | ||||
| This interface can change at any time. | ||||
| */ | ||||
| package registry | ||||
| 
 | ||||
| var registry []*Entry = make([]*Entry, 0) | ||||
| 
 | ||||
| type Entry struct { | ||||
| 	active bool | ||||
| 	source func() string | ||||
| } | ||||
| 
 | ||||
| func newEntry(source func() string) *Entry { | ||||
| 	return &Entry{ | ||||
| 		active: true, | ||||
| 		source: source, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *Entry) Enable() { | ||||
| 	self.active = true | ||||
| } | ||||
| 
 | ||||
| func (self *Entry) Disable() { | ||||
| 	self.active = false | ||||
| } | ||||
| 
 | ||||
| func (self Entry) Source() string { | ||||
| 	return self.source() | ||||
| } | ||||
| 
 | ||||
| func Apply(callback func(Entry)) { | ||||
| 	for _, entry := range registry { | ||||
| 		if !entry.active { | ||||
| 			continue | ||||
| 		} | ||||
| 		callback(*entry) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func Register(source func() string) *Entry { | ||||
| 	entry := newEntry(source) | ||||
| 	registry = append(registry, entry) | ||||
| 	return entry | ||||
| } | ||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,2 +0,0 @@ | ||||
| token_const.go: tokenfmt | ||||
| 	./$^ | gofmt > $@ | ||||
							
								
								
									
										171
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										171
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/README.markdown
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,171 +0,0 @@ | ||||
| # token | ||||
| -- | ||||
|     import "github.com/robertkrimen/otto/token" | ||||
| 
 | ||||
| Package token defines constants representing the lexical tokens of JavaScript | ||||
| (ECMA5). | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| ```go | ||||
| const ( | ||||
| 	ILLEGAL | ||||
| 	EOF | ||||
| 	COMMENT | ||||
| 	KEYWORD | ||||
| 
 | ||||
| 	STRING | ||||
| 	BOOLEAN | ||||
| 	NULL | ||||
| 	NUMBER | ||||
| 	IDENTIFIER | ||||
| 
 | ||||
| 	PLUS      // + | ||||
| 	MINUS     // - | ||||
| 	MULTIPLY  // * | ||||
| 	SLASH     // / | ||||
| 	REMAINDER // % | ||||
| 
 | ||||
| 	AND                  // & | ||||
| 	OR                   // | | ||||
| 	EXCLUSIVE_OR         // ^ | ||||
| 	SHIFT_LEFT           // << | ||||
| 	SHIFT_RIGHT          // >> | ||||
| 	UNSIGNED_SHIFT_RIGHT // >>> | ||||
| 	AND_NOT              // &^ | ||||
| 
 | ||||
| 	ADD_ASSIGN       // += | ||||
| 	SUBTRACT_ASSIGN  // -= | ||||
| 	MULTIPLY_ASSIGN  // *= | ||||
| 	QUOTIENT_ASSIGN  // /= | ||||
| 	REMAINDER_ASSIGN // %= | ||||
| 
 | ||||
| 	AND_ASSIGN                  // &= | ||||
| 	OR_ASSIGN                   // |= | ||||
| 	EXCLUSIVE_OR_ASSIGN         // ^= | ||||
| 	SHIFT_LEFT_ASSIGN           // <<= | ||||
| 	SHIFT_RIGHT_ASSIGN          // >>= | ||||
| 	UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>= | ||||
| 	AND_NOT_ASSIGN              // &^= | ||||
| 
 | ||||
| 	LOGICAL_AND // && | ||||
| 	LOGICAL_OR  // || | ||||
| 	INCREMENT   // ++ | ||||
| 	DECREMENT   // -- | ||||
| 
 | ||||
| 	EQUAL        // == | ||||
| 	STRICT_EQUAL // === | ||||
| 	LESS         // < | ||||
| 	GREATER      // > | ||||
| 	ASSIGN       // = | ||||
| 	NOT          // ! | ||||
| 
 | ||||
| 	BITWISE_NOT // ~ | ||||
| 
 | ||||
| 	NOT_EQUAL        // != | ||||
| 	STRICT_NOT_EQUAL // !== | ||||
| 	LESS_OR_EQUAL    // <= | ||||
| 	GREATER_OR_EQUAL // <= | ||||
| 
 | ||||
| 	LEFT_PARENTHESIS // ( | ||||
| 	LEFT_BRACKET     // [ | ||||
| 	LEFT_BRACE       // { | ||||
| 	COMMA            // , | ||||
| 	PERIOD           // . | ||||
| 
 | ||||
| 	RIGHT_PARENTHESIS // ) | ||||
| 	RIGHT_BRACKET     // ] | ||||
| 	RIGHT_BRACE       // } | ||||
| 	SEMICOLON         // ; | ||||
| 	COLON             // : | ||||
| 	QUESTION_MARK     // ? | ||||
| 
 | ||||
| 	IF | ||||
| 	IN | ||||
| 	DO | ||||
| 
 | ||||
| 	VAR | ||||
| 	FOR | ||||
| 	NEW | ||||
| 	TRY | ||||
| 
 | ||||
| 	THIS | ||||
| 	ELSE | ||||
| 	CASE | ||||
| 	VOID | ||||
| 	WITH | ||||
| 
 | ||||
| 	WHILE | ||||
| 	BREAK | ||||
| 	CATCH | ||||
| 	THROW | ||||
| 
 | ||||
| 	RETURN | ||||
| 	TYPEOF | ||||
| 	DELETE | ||||
| 	SWITCH | ||||
| 
 | ||||
| 	DEFAULT | ||||
| 	FINALLY | ||||
| 
 | ||||
| 	FUNCTION | ||||
| 	CONTINUE | ||||
| 	DEBUGGER | ||||
| 
 | ||||
| 	INSTANCEOF | ||||
| ) | ||||
| ``` | ||||
| 
 | ||||
| #### type Token | ||||
| 
 | ||||
| ```go | ||||
| type Token int | ||||
| ``` | ||||
| 
 | ||||
| Token is the set of lexical tokens in JavaScript (ECMA5). | ||||
| 
 | ||||
| #### func  IsKeyword | ||||
| 
 | ||||
| ```go | ||||
| func IsKeyword(literal string) (Token, bool) | ||||
| ``` | ||||
| IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token if | ||||
| the literal is a future keyword (const, let, class, super, ...), or 0 if the | ||||
| literal is not a keyword. | ||||
| 
 | ||||
| If the literal is a keyword, IsKeyword returns a second value indicating if the | ||||
| literal is considered a future keyword in strict-mode only. | ||||
| 
 | ||||
| 7.6.1.2 Future Reserved Words: | ||||
| 
 | ||||
|     const | ||||
|     class | ||||
|     enum | ||||
|     export | ||||
|     extends | ||||
|     import | ||||
|     super | ||||
| 
 | ||||
| 7.6.1.2 Future Reserved Words (strict): | ||||
| 
 | ||||
|     implements | ||||
|     interface | ||||
|     let | ||||
|     package | ||||
|     private | ||||
|     protected | ||||
|     public | ||||
|     static | ||||
| 
 | ||||
| #### func (Token) String | ||||
| 
 | ||||
| ```go | ||||
| func (tkn Token) String() string | ||||
| ``` | ||||
| String returns the string corresponding to the token. For operators, delimiters, | ||||
| and keywords the string is the actual token string (e.g., for the token PLUS, | ||||
| the String() is "+"). For all other tokens the string corresponds to the token | ||||
| name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER"). | ||||
| 
 | ||||
| -- | ||||
| **godocdown** http://github.com/robertkrimen/godocdown | ||||
							
								
								
									
										116
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/token.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,116 +0,0 @@ | ||||
| // Package token defines constants representing the lexical tokens of JavaScript (ECMA5).
 | ||||
| package token | ||||
| 
 | ||||
| import ( | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // Token is the set of lexical tokens in JavaScript (ECMA5).
 | ||||
| type Token int | ||||
| 
 | ||||
| // String returns the string corresponding to the token.
 | ||||
| // For operators, delimiters, and keywords the string is the actual
 | ||||
| // token string (e.g., for the token PLUS, the String() is
 | ||||
| // "+"). For all other tokens the string corresponds to the token
 | ||||
| // name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER").
 | ||||
| //
 | ||||
| func (tkn Token) String() string { | ||||
| 	if 0 == tkn { | ||||
| 		return "UNKNOWN" | ||||
| 	} | ||||
| 	if tkn < Token(len(token2string)) { | ||||
| 		return token2string[tkn] | ||||
| 	} | ||||
| 	return "token(" + strconv.Itoa(int(tkn)) + ")" | ||||
| } | ||||
| 
 | ||||
| // This is not used for anything
 | ||||
| func (tkn Token) precedence(in bool) int { | ||||
| 
 | ||||
| 	switch tkn { | ||||
| 	case LOGICAL_OR: | ||||
| 		return 1 | ||||
| 
 | ||||
| 	case LOGICAL_AND: | ||||
| 		return 2 | ||||
| 
 | ||||
| 	case OR, OR_ASSIGN: | ||||
| 		return 3 | ||||
| 
 | ||||
| 	case EXCLUSIVE_OR: | ||||
| 		return 4 | ||||
| 
 | ||||
| 	case AND, AND_ASSIGN, AND_NOT, AND_NOT_ASSIGN: | ||||
| 		return 5 | ||||
| 
 | ||||
| 	case EQUAL, | ||||
| 		NOT_EQUAL, | ||||
| 		STRICT_EQUAL, | ||||
| 		STRICT_NOT_EQUAL: | ||||
| 		return 6 | ||||
| 
 | ||||
| 	case LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL, INSTANCEOF: | ||||
| 		return 7 | ||||
| 
 | ||||
| 	case IN: | ||||
| 		if in { | ||||
| 			return 7 | ||||
| 		} | ||||
| 		return 0 | ||||
| 
 | ||||
| 	case SHIFT_LEFT, SHIFT_RIGHT, UNSIGNED_SHIFT_RIGHT: | ||||
| 		fallthrough | ||||
| 	case SHIFT_LEFT_ASSIGN, SHIFT_RIGHT_ASSIGN, UNSIGNED_SHIFT_RIGHT_ASSIGN: | ||||
| 		return 8 | ||||
| 
 | ||||
| 	case PLUS, MINUS, ADD_ASSIGN, SUBTRACT_ASSIGN: | ||||
| 		return 9 | ||||
| 
 | ||||
| 	case MULTIPLY, SLASH, REMAINDER, MULTIPLY_ASSIGN, QUOTIENT_ASSIGN, REMAINDER_ASSIGN: | ||||
| 		return 11 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| type _keyword struct { | ||||
| 	token         Token | ||||
| 	futureKeyword bool | ||||
| 	strict        bool | ||||
| } | ||||
| 
 | ||||
| // IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token
 | ||||
| // if the literal is a future keyword (const, let, class, super, ...), or 0 if the literal is not a keyword.
 | ||||
| //
 | ||||
| // If the literal is a keyword, IsKeyword returns a second value indicating if the literal
 | ||||
| // is considered a future keyword in strict-mode only.
 | ||||
| //
 | ||||
| // 7.6.1.2 Future Reserved Words:
 | ||||
| //
 | ||||
| //       const
 | ||||
| //       class
 | ||||
| //       enum
 | ||||
| //       export
 | ||||
| //       extends
 | ||||
| //       import
 | ||||
| //       super
 | ||||
| //
 | ||||
| // 7.6.1.2 Future Reserved Words (strict):
 | ||||
| //
 | ||||
| //       implements
 | ||||
| //       interface
 | ||||
| //       let
 | ||||
| //       package
 | ||||
| //       private
 | ||||
| //       protected
 | ||||
| //       public
 | ||||
| //       static
 | ||||
| //
 | ||||
| func IsKeyword(literal string) (Token, bool) { | ||||
| 	if keyword, exists := keywordTable[literal]; exists { | ||||
| 		if keyword.futureKeyword { | ||||
| 			return KEYWORD, keyword.strict | ||||
| 		} | ||||
| 		return keyword.token, false | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
							
								
								
									
										349
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/token_const.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										349
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/token_const.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,349 +0,0 @@ | ||||
| package token | ||||
| 
 | ||||
| const ( | ||||
| 	_ Token = iota | ||||
| 
 | ||||
| 	ILLEGAL | ||||
| 	EOF | ||||
| 	COMMENT | ||||
| 	KEYWORD | ||||
| 
 | ||||
| 	STRING | ||||
| 	BOOLEAN | ||||
| 	NULL | ||||
| 	NUMBER | ||||
| 	IDENTIFIER | ||||
| 
 | ||||
| 	PLUS      // +
 | ||||
| 	MINUS     // -
 | ||||
| 	MULTIPLY  // *
 | ||||
| 	SLASH     // /
 | ||||
| 	REMAINDER // %
 | ||||
| 
 | ||||
| 	AND                  // &
 | ||||
| 	OR                   // |
 | ||||
| 	EXCLUSIVE_OR         // ^
 | ||||
| 	SHIFT_LEFT           // <<
 | ||||
| 	SHIFT_RIGHT          // >>
 | ||||
| 	UNSIGNED_SHIFT_RIGHT // >>>
 | ||||
| 	AND_NOT              // &^
 | ||||
| 
 | ||||
| 	ADD_ASSIGN       // +=
 | ||||
| 	SUBTRACT_ASSIGN  // -=
 | ||||
| 	MULTIPLY_ASSIGN  // *=
 | ||||
| 	QUOTIENT_ASSIGN  // /=
 | ||||
| 	REMAINDER_ASSIGN // %=
 | ||||
| 
 | ||||
| 	AND_ASSIGN                  // &=
 | ||||
| 	OR_ASSIGN                   // |=
 | ||||
| 	EXCLUSIVE_OR_ASSIGN         // ^=
 | ||||
| 	SHIFT_LEFT_ASSIGN           // <<=
 | ||||
| 	SHIFT_RIGHT_ASSIGN          // >>=
 | ||||
| 	UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
 | ||||
| 	AND_NOT_ASSIGN              // &^=
 | ||||
| 
 | ||||
| 	LOGICAL_AND // &&
 | ||||
| 	LOGICAL_OR  // ||
 | ||||
| 	INCREMENT   // ++
 | ||||
| 	DECREMENT   // --
 | ||||
| 
 | ||||
| 	EQUAL        // ==
 | ||||
| 	STRICT_EQUAL // ===
 | ||||
| 	LESS         // <
 | ||||
| 	GREATER      // >
 | ||||
| 	ASSIGN       // =
 | ||||
| 	NOT          // !
 | ||||
| 
 | ||||
| 	BITWISE_NOT // ~
 | ||||
| 
 | ||||
| 	NOT_EQUAL        // !=
 | ||||
| 	STRICT_NOT_EQUAL // !==
 | ||||
| 	LESS_OR_EQUAL    // <=
 | ||||
| 	GREATER_OR_EQUAL // <=
 | ||||
| 
 | ||||
| 	LEFT_PARENTHESIS // (
 | ||||
| 	LEFT_BRACKET     // [
 | ||||
| 	LEFT_BRACE       // {
 | ||||
| 	COMMA            // ,
 | ||||
| 	PERIOD           // .
 | ||||
| 
 | ||||
| 	RIGHT_PARENTHESIS // )
 | ||||
| 	RIGHT_BRACKET     // ]
 | ||||
| 	RIGHT_BRACE       // }
 | ||||
| 	SEMICOLON         // ;
 | ||||
| 	COLON             // :
 | ||||
| 	QUESTION_MARK     // ?
 | ||||
| 
 | ||||
| 	firstKeyword | ||||
| 	IF | ||||
| 	IN | ||||
| 	DO | ||||
| 
 | ||||
| 	VAR | ||||
| 	FOR | ||||
| 	NEW | ||||
| 	TRY | ||||
| 
 | ||||
| 	THIS | ||||
| 	ELSE | ||||
| 	CASE | ||||
| 	VOID | ||||
| 	WITH | ||||
| 
 | ||||
| 	WHILE | ||||
| 	BREAK | ||||
| 	CATCH | ||||
| 	THROW | ||||
| 
 | ||||
| 	RETURN | ||||
| 	TYPEOF | ||||
| 	DELETE | ||||
| 	SWITCH | ||||
| 
 | ||||
| 	DEFAULT | ||||
| 	FINALLY | ||||
| 
 | ||||
| 	FUNCTION | ||||
| 	CONTINUE | ||||
| 	DEBUGGER | ||||
| 
 | ||||
| 	INSTANCEOF | ||||
| 	lastKeyword | ||||
| ) | ||||
| 
 | ||||
| var token2string = [...]string{ | ||||
| 	ILLEGAL:                     "ILLEGAL", | ||||
| 	EOF:                         "EOF", | ||||
| 	COMMENT:                     "COMMENT", | ||||
| 	KEYWORD:                     "KEYWORD", | ||||
| 	STRING:                      "STRING", | ||||
| 	BOOLEAN:                     "BOOLEAN", | ||||
| 	NULL:                        "NULL", | ||||
| 	NUMBER:                      "NUMBER", | ||||
| 	IDENTIFIER:                  "IDENTIFIER", | ||||
| 	PLUS:                        "+", | ||||
| 	MINUS:                       "-", | ||||
| 	MULTIPLY:                    "*", | ||||
| 	SLASH:                       "/", | ||||
| 	REMAINDER:                   "%", | ||||
| 	AND:                         "&", | ||||
| 	OR:                          "|", | ||||
| 	EXCLUSIVE_OR:                "^", | ||||
| 	SHIFT_LEFT:                  "<<", | ||||
| 	SHIFT_RIGHT:                 ">>", | ||||
| 	UNSIGNED_SHIFT_RIGHT:        ">>>", | ||||
| 	AND_NOT:                     "&^", | ||||
| 	ADD_ASSIGN:                  "+=", | ||||
| 	SUBTRACT_ASSIGN:             "-=", | ||||
| 	MULTIPLY_ASSIGN:             "*=", | ||||
| 	QUOTIENT_ASSIGN:             "/=", | ||||
| 	REMAINDER_ASSIGN:            "%=", | ||||
| 	AND_ASSIGN:                  "&=", | ||||
| 	OR_ASSIGN:                   "|=", | ||||
| 	EXCLUSIVE_OR_ASSIGN:         "^=", | ||||
| 	SHIFT_LEFT_ASSIGN:           "<<=", | ||||
| 	SHIFT_RIGHT_ASSIGN:          ">>=", | ||||
| 	UNSIGNED_SHIFT_RIGHT_ASSIGN: ">>>=", | ||||
| 	AND_NOT_ASSIGN:              "&^=", | ||||
| 	LOGICAL_AND:                 "&&", | ||||
| 	LOGICAL_OR:                  "||", | ||||
| 	INCREMENT:                   "++", | ||||
| 	DECREMENT:                   "--", | ||||
| 	EQUAL:                       "==", | ||||
| 	STRICT_EQUAL:                "===", | ||||
| 	LESS:                        "<", | ||||
| 	GREATER:                     ">", | ||||
| 	ASSIGN:                      "=", | ||||
| 	NOT:                         "!", | ||||
| 	BITWISE_NOT:                 "~", | ||||
| 	NOT_EQUAL:                   "!=", | ||||
| 	STRICT_NOT_EQUAL:            "!==", | ||||
| 	LESS_OR_EQUAL:               "<=", | ||||
| 	GREATER_OR_EQUAL:            "<=", | ||||
| 	LEFT_PARENTHESIS:            "(", | ||||
| 	LEFT_BRACKET:                "[", | ||||
| 	LEFT_BRACE:                  "{", | ||||
| 	COMMA:                       ",", | ||||
| 	PERIOD:                      ".", | ||||
| 	RIGHT_PARENTHESIS:           ")", | ||||
| 	RIGHT_BRACKET:               "]", | ||||
| 	RIGHT_BRACE:                 "}", | ||||
| 	SEMICOLON:                   ";", | ||||
| 	COLON:                       ":", | ||||
| 	QUESTION_MARK:               "?", | ||||
| 	IF:                          "if", | ||||
| 	IN:                          "in", | ||||
| 	DO:                          "do", | ||||
| 	VAR:                         "var", | ||||
| 	FOR:                         "for", | ||||
| 	NEW:                         "new", | ||||
| 	TRY:                         "try", | ||||
| 	THIS:                        "this", | ||||
| 	ELSE:                        "else", | ||||
| 	CASE:                        "case", | ||||
| 	VOID:                        "void", | ||||
| 	WITH:                        "with", | ||||
| 	WHILE:                       "while", | ||||
| 	BREAK:                       "break", | ||||
| 	CATCH:                       "catch", | ||||
| 	THROW:                       "throw", | ||||
| 	RETURN:                      "return", | ||||
| 	TYPEOF:                      "typeof", | ||||
| 	DELETE:                      "delete", | ||||
| 	SWITCH:                      "switch", | ||||
| 	DEFAULT:                     "default", | ||||
| 	FINALLY:                     "finally", | ||||
| 	FUNCTION:                    "function", | ||||
| 	CONTINUE:                    "continue", | ||||
| 	DEBUGGER:                    "debugger", | ||||
| 	INSTANCEOF:                  "instanceof", | ||||
| } | ||||
| 
 | ||||
| var keywordTable = map[string]_keyword{ | ||||
| 	"if": _keyword{ | ||||
| 		token: IF, | ||||
| 	}, | ||||
| 	"in": _keyword{ | ||||
| 		token: IN, | ||||
| 	}, | ||||
| 	"do": _keyword{ | ||||
| 		token: DO, | ||||
| 	}, | ||||
| 	"var": _keyword{ | ||||
| 		token: VAR, | ||||
| 	}, | ||||
| 	"for": _keyword{ | ||||
| 		token: FOR, | ||||
| 	}, | ||||
| 	"new": _keyword{ | ||||
| 		token: NEW, | ||||
| 	}, | ||||
| 	"try": _keyword{ | ||||
| 		token: TRY, | ||||
| 	}, | ||||
| 	"this": _keyword{ | ||||
| 		token: THIS, | ||||
| 	}, | ||||
| 	"else": _keyword{ | ||||
| 		token: ELSE, | ||||
| 	}, | ||||
| 	"case": _keyword{ | ||||
| 		token: CASE, | ||||
| 	}, | ||||
| 	"void": _keyword{ | ||||
| 		token: VOID, | ||||
| 	}, | ||||
| 	"with": _keyword{ | ||||
| 		token: WITH, | ||||
| 	}, | ||||
| 	"while": _keyword{ | ||||
| 		token: WHILE, | ||||
| 	}, | ||||
| 	"break": _keyword{ | ||||
| 		token: BREAK, | ||||
| 	}, | ||||
| 	"catch": _keyword{ | ||||
| 		token: CATCH, | ||||
| 	}, | ||||
| 	"throw": _keyword{ | ||||
| 		token: THROW, | ||||
| 	}, | ||||
| 	"return": _keyword{ | ||||
| 		token: RETURN, | ||||
| 	}, | ||||
| 	"typeof": _keyword{ | ||||
| 		token: TYPEOF, | ||||
| 	}, | ||||
| 	"delete": _keyword{ | ||||
| 		token: DELETE, | ||||
| 	}, | ||||
| 	"switch": _keyword{ | ||||
| 		token: SWITCH, | ||||
| 	}, | ||||
| 	"default": _keyword{ | ||||
| 		token: DEFAULT, | ||||
| 	}, | ||||
| 	"finally": _keyword{ | ||||
| 		token: FINALLY, | ||||
| 	}, | ||||
| 	"function": _keyword{ | ||||
| 		token: FUNCTION, | ||||
| 	}, | ||||
| 	"continue": _keyword{ | ||||
| 		token: CONTINUE, | ||||
| 	}, | ||||
| 	"debugger": _keyword{ | ||||
| 		token: DEBUGGER, | ||||
| 	}, | ||||
| 	"instanceof": _keyword{ | ||||
| 		token: INSTANCEOF, | ||||
| 	}, | ||||
| 	"const": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"class": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"enum": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"export": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"extends": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"import": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"super": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 	}, | ||||
| 	"implements": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"interface": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"let": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"package": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"private": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"protected": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"public": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| 	"static": _keyword{ | ||||
| 		token:         KEYWORD, | ||||
| 		futureKeyword: true, | ||||
| 		strict:        true, | ||||
| 	}, | ||||
| } | ||||
							
								
								
									
										222
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/tokenfmt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										222
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/token/tokenfmt
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,222 +0,0 @@ | ||||
| #!/usr/bin/env perl | ||||
| 
 | ||||
| use strict; | ||||
| use warnings; | ||||
| 
 | ||||
| my (%token, @order, @keywords); | ||||
| 
 | ||||
| { | ||||
|     my $keywords; | ||||
|     my @const; | ||||
|     push @const, <<_END_; | ||||
| package token | ||||
| 
 | ||||
| const( | ||||
|     _ Token = iota | ||||
| _END_ | ||||
| 
 | ||||
|     for (split m/\n/, <<_END_) { | ||||
| ILLEGAL | ||||
| EOF | ||||
| COMMENT | ||||
| KEYWORD | ||||
| 
 | ||||
| STRING | ||||
| BOOLEAN | ||||
| NULL | ||||
| NUMBER | ||||
| IDENTIFIER | ||||
| 
 | ||||
| PLUS                            + | ||||
| MINUS                           - | ||||
| MULTIPLY                        * | ||||
| SLASH                           / | ||||
| REMAINDER                       % | ||||
| 
 | ||||
| AND                             & | ||||
| OR                              | | ||||
| EXCLUSIVE_OR                    ^ | ||||
| SHIFT_LEFT                      << | ||||
| SHIFT_RIGHT                     >> | ||||
| UNSIGNED_SHIFT_RIGHT            >>> | ||||
| AND_NOT                         &^ | ||||
| 
 | ||||
| ADD_ASSIGN                     += | ||||
| SUBTRACT_ASSIGN                -= | ||||
| MULTIPLY_ASSIGN                *= | ||||
| QUOTIENT_ASSIGN                /= | ||||
| REMAINDER_ASSIGN               %= | ||||
| 
 | ||||
| AND_ASSIGN                     &= | ||||
| OR_ASSIGN                      |= | ||||
| EXCLUSIVE_OR_ASSIGN            ^= | ||||
| SHIFT_LEFT_ASSIGN              <<= | ||||
| SHIFT_RIGHT_ASSIGN             >>= | ||||
| UNSIGNED_SHIFT_RIGHT_ASSIGN    >>>= | ||||
| AND_NOT_ASSIGN                 &^= | ||||
| 
 | ||||
| LOGICAL_AND                    && | ||||
| LOGICAL_OR                     || | ||||
| INCREMENT                      ++ | ||||
| DECREMENT                      -- | ||||
| 
 | ||||
| EQUAL                          == | ||||
| STRICT_EQUAL                   === | ||||
| LESS                           < | ||||
| GREATER                        > | ||||
| ASSIGN                         = | ||||
| NOT                            ! | ||||
| 
 | ||||
| BITWISE_NOT                    ~ | ||||
| 
 | ||||
| NOT_EQUAL                      != | ||||
| STRICT_NOT_EQUAL               !== | ||||
| LESS_OR_EQUAL                  <= | ||||
| GREATER_OR_EQUAL               <= | ||||
| 
 | ||||
| LEFT_PARENTHESIS               ( | ||||
| LEFT_BRACKET                   [ | ||||
| LEFT_BRACE                     { | ||||
| COMMA                          , | ||||
| PERIOD                         . | ||||
| 
 | ||||
| RIGHT_PARENTHESIS              ) | ||||
| RIGHT_BRACKET                  ] | ||||
| RIGHT_BRACE                    } | ||||
| SEMICOLON                      ; | ||||
| COLON                          : | ||||
| QUESTION_MARK                  ? | ||||
| 
 | ||||
| firstKeyword | ||||
| IF | ||||
| IN | ||||
| DO | ||||
| 
 | ||||
| VAR | ||||
| FOR | ||||
| NEW | ||||
| TRY | ||||
| 
 | ||||
| THIS | ||||
| ELSE | ||||
| CASE | ||||
| VOID | ||||
| WITH | ||||
| 
 | ||||
| WHILE | ||||
| BREAK | ||||
| CATCH | ||||
| THROW | ||||
| 
 | ||||
| RETURN | ||||
| TYPEOF | ||||
| DELETE | ||||
| SWITCH | ||||
| 
 | ||||
| DEFAULT | ||||
| FINALLY | ||||
| 
 | ||||
| FUNCTION | ||||
| CONTINUE | ||||
| DEBUGGER | ||||
| 
 | ||||
| INSTANCEOF | ||||
| lastKeyword | ||||
| _END_ | ||||
|         chomp; | ||||
| 
 | ||||
|         next if m/^\s*#/; | ||||
| 
 | ||||
|         my ($name, $symbol) = m/(\w+)\s*(\S+)?/; | ||||
| 
 | ||||
|         if (defined $symbol) { | ||||
|             push @order, $name; | ||||
|             push @const, "$name // $symbol"; | ||||
|             $token{$name} = $symbol; | ||||
|         } elsif (defined $name) { | ||||
|             $keywords ||= $name eq 'firstKeyword'; | ||||
| 
 | ||||
|             push @const, $name; | ||||
|             #$const[-1] .= " Token = iota" if 2 == @const; | ||||
|             if ($name =~ m/^([A-Z]+)/) { | ||||
|                 push @keywords, $name if $keywords; | ||||
|                 push @order, $name; | ||||
|                 if ($token{SEMICOLON}) { | ||||
|                     $token{$name} = lc $1; | ||||
|                 } else { | ||||
|                     $token{$name} = $name; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             push @const, ""; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|     push @const, ")"; | ||||
|     print join "\n", @const, ""; | ||||
| } | ||||
| 
 | ||||
| { | ||||
|     print <<_END_; | ||||
| 
 | ||||
| var token2string = [...]string{ | ||||
| _END_ | ||||
|     for my $name (@order) { | ||||
|         print "$name: \"$token{$name}\",\n"; | ||||
|     } | ||||
|     print <<_END_; | ||||
| } | ||||
| _END_ | ||||
| 
 | ||||
|     print <<_END_; | ||||
| 
 | ||||
| var keywordTable = map[string]_keyword{ | ||||
| _END_ | ||||
|     for my $name (@keywords) { | ||||
|         print <<_END_ | ||||
| 			"@{[ lc $name ]}": _keyword{ | ||||
| 				token: $name, | ||||
| 			}, | ||||
| _END_ | ||||
|     } | ||||
| 
 | ||||
|     for my $name (qw/ | ||||
|         const | ||||
|         class | ||||
|         enum | ||||
|         export | ||||
|         extends | ||||
|         import | ||||
|         super | ||||
|         /) { | ||||
|         print <<_END_ | ||||
| 			"$name": _keyword{ | ||||
| 				token: KEYWORD, | ||||
|                 futureKeyword: true, | ||||
| 			}, | ||||
| _END_ | ||||
|     } | ||||
| 
 | ||||
|     for my $name (qw/ | ||||
|         implements | ||||
|         interface | ||||
|         let | ||||
|         package | ||||
|         private | ||||
|         protected | ||||
|         public | ||||
|         static | ||||
|         /) { | ||||
|         print <<_END_ | ||||
| 			"$name": _keyword{ | ||||
| 				token: KEYWORD, | ||||
|                 futureKeyword: true, | ||||
|                 strict: true, | ||||
| 			}, | ||||
| _END_ | ||||
|     } | ||||
| 
 | ||||
|     print <<_END_; | ||||
| } | ||||
| _END_ | ||||
| } | ||||
							
								
								
									
										9
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,9 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| func (runtime *_runtime) newErrorObject(message Value) *_object { | ||||
| 	self := runtime.newClassObject("Error") | ||||
| 	if message.IsDefined() { | ||||
| 		self.defineProperty("message", toValue_string(toString(message)), 0111, false) | ||||
| 	} | ||||
| 	return self | ||||
| } | ||||
							
								
								
									
										276
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_function.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										276
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_function.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,276 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| type _functionObject struct { | ||||
| 	call      _callFunction | ||||
| 	construct _constructFunction | ||||
| } | ||||
| 
 | ||||
| func (self _functionObject) source(object *_object) string { | ||||
| 	return self.call.Source(object) | ||||
| } | ||||
| 
 | ||||
| func (self0 _functionObject) clone(clone *_clone) _functionObject { | ||||
| 	return _functionObject{ | ||||
| 		clone.callFunction(self0.call), | ||||
| 		self0.construct, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newNativeFunctionObject(name string, native _nativeFunction, length int) *_object { | ||||
| 	self := runtime.newClassObject("Function") | ||||
| 	self.value = _functionObject{ | ||||
| 		call:      newNativeCallFunction(native), | ||||
| 		construct: defaultConstructFunction, | ||||
| 	} | ||||
| 	self.defineProperty("length", toValue_int(length), 0000, false) | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newBoundFunctionObject(target *_object, this Value, argumentList []Value) *_object { | ||||
| 	self := runtime.newClassObject("Function") | ||||
| 	self.value = _functionObject{ | ||||
| 		call:      newBoundCallFunction(target, this, argumentList), | ||||
| 		construct: newBoundConstructFunction(target), | ||||
| 	} | ||||
| 	length := int(toInt32(target.get("length"))) | ||||
| 	length -= len(argumentList) | ||||
| 	if length < 0 { | ||||
| 		length = 0 | ||||
| 	} | ||||
| 	self.defineProperty("length", toValue_int(length), 0000, false) | ||||
| 	self.defineProperty("caller", UndefinedValue(), 0000, false)    // TODO Should throw a TypeError
 | ||||
| 	self.defineProperty("arguments", UndefinedValue(), 0000, false) // TODO Should throw a TypeError
 | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newBoundFunction(target *_object, this Value, argumentList []Value) *_object { | ||||
| 	self := runtime.newBoundFunctionObject(target, this, argumentList) | ||||
| 	self.prototype = runtime.Global.FunctionPrototype | ||||
| 	prototype := runtime.newObject() | ||||
| 	self.defineProperty("prototype", toValue_object(prototype), 0100, false) | ||||
| 	prototype.defineProperty("constructor", toValue_object(self), 0100, false) | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (self *_object) functionValue() _functionObject { | ||||
| 	value, _ := self.value.(_functionObject) | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| func (self *_object) Call(this Value, argumentList ...interface{}) Value { | ||||
| 	if self.functionValue().call == nil { | ||||
| 		panic(newTypeError("%v is not a function", toValue_object(self))) | ||||
| 	} | ||||
| 	return self.runtime.Call(self, this, self.runtime.toValueArray(argumentList...), false) | ||||
| 	// ... -> runtime -> self.Function.Call.Dispatch -> ...
 | ||||
| } | ||||
| 
 | ||||
| func (self *_object) Construct(this Value, argumentList ...interface{}) Value { | ||||
| 	function := self.functionValue() | ||||
| 	if function.call == nil { | ||||
| 		panic(newTypeError("%v is not a function", toValue_object(self))) | ||||
| 	} | ||||
| 	if function.construct == nil { | ||||
| 		panic(newTypeError("%v is not a constructor", toValue_object(self))) | ||||
| 	} | ||||
| 	return function.construct(self, this, self.runtime.toValueArray(argumentList...)) | ||||
| } | ||||
| 
 | ||||
| func defaultConstructFunction(self *_object, this Value, argumentList []Value) Value { | ||||
| 	newObject := self.runtime.newObject() | ||||
| 	newObject.class = "Object" | ||||
| 	prototypeValue := self.get("prototype") | ||||
| 	if !prototypeValue.IsObject() { | ||||
| 		prototypeValue = toValue_object(self.runtime.Global.ObjectPrototype) | ||||
| 	} | ||||
| 	newObject.prototype = prototypeValue._object() | ||||
| 	newObjectValue := toValue_object(newObject) | ||||
| 	result := self.Call(newObjectValue, argumentList) | ||||
| 	if result.IsObject() { | ||||
| 		return result | ||||
| 	} | ||||
| 	return newObjectValue | ||||
| } | ||||
| 
 | ||||
| func (self *_object) callGet(this Value) Value { | ||||
| 	return self.runtime.Call(self, this, []Value(nil), false) | ||||
| } | ||||
| 
 | ||||
| func (self *_object) callSet(this Value, value Value) { | ||||
| 	self.runtime.Call(self, this, []Value{value}, false) | ||||
| } | ||||
| 
 | ||||
| // 15.3.5.3
 | ||||
| func (self *_object) HasInstance(of Value) bool { | ||||
| 	if self.functionValue().call == nil { | ||||
| 		// We should not have a HasInstance method
 | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| 	if !of.IsObject() { | ||||
| 		return false | ||||
| 	} | ||||
| 	prototype := self.get("prototype") | ||||
| 	if !prototype.IsObject() { | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| 	prototypeObject := prototype._object() | ||||
| 
 | ||||
| 	value := of._object().prototype | ||||
| 	for value != nil { | ||||
| 		if value == prototypeObject { | ||||
| 			return true | ||||
| 		} | ||||
| 		value = value.prototype | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| type _nativeFunction func(FunctionCall) Value | ||||
| 
 | ||||
| // _constructFunction
 | ||||
| type _constructFunction func(*_object, Value, []Value) Value | ||||
| 
 | ||||
| // _callFunction
 | ||||
| type _callFunction interface { | ||||
| 	Dispatch(*_object, *_functionEnvironment, *_runtime, Value, []Value, bool) Value | ||||
| 	Source(*_object) string | ||||
| 	ScopeEnvironment() _environment | ||||
| 	clone(clone *_clone) _callFunction | ||||
| } | ||||
| 
 | ||||
| // _nativeCallFunction
 | ||||
| type _nativeCallFunction struct { | ||||
| 	name     string | ||||
| 	function _nativeFunction | ||||
| } | ||||
| 
 | ||||
| func newNativeCallFunction(native _nativeFunction) _nativeCallFunction { | ||||
| 	return _nativeCallFunction{"", native} | ||||
| } | ||||
| 
 | ||||
| func (self _nativeCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, evalHint bool) Value { | ||||
| 	return self.function(FunctionCall{ | ||||
| 		runtime:  runtime, | ||||
| 		evalHint: evalHint, | ||||
| 
 | ||||
| 		This:         this, | ||||
| 		ArgumentList: argumentList, | ||||
| 		Otto:         runtime.Otto, | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (self _nativeCallFunction) ScopeEnvironment() _environment { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (self _nativeCallFunction) Source(*_object) string { | ||||
| 	return fmt.Sprintf("function %s() { [native code] }", self.name) | ||||
| } | ||||
| 
 | ||||
| func (self0 _nativeCallFunction) clone(clone *_clone) _callFunction { | ||||
| 	return self0 | ||||
| } | ||||
| 
 | ||||
| // _boundCallFunction
 | ||||
| type _boundCallFunction struct { | ||||
| 	target       *_object | ||||
| 	this         Value | ||||
| 	argumentList []Value | ||||
| } | ||||
| 
 | ||||
| func newBoundCallFunction(target *_object, this Value, argumentList []Value) *_boundCallFunction { | ||||
| 	self := &_boundCallFunction{ | ||||
| 		target:       target, | ||||
| 		this:         this, | ||||
| 		argumentList: argumentList, | ||||
| 	} | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (self _boundCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value { | ||||
| 	argumentList = append(self.argumentList, argumentList...) | ||||
| 	return runtime.Call(self.target, self.this, argumentList, false) | ||||
| } | ||||
| 
 | ||||
| func (self _boundCallFunction) ScopeEnvironment() _environment { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (self _boundCallFunction) Source(*_object) string { | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| func (self0 _boundCallFunction) clone(clone *_clone) _callFunction { | ||||
| 	return _boundCallFunction{ | ||||
| 		target:       clone.object(self0.target), | ||||
| 		this:         clone.value(self0.this), | ||||
| 		argumentList: clone.valueArray(self0.argumentList), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func newBoundConstructFunction(target *_object) _constructFunction { | ||||
| 	// This is not exactly as described in 15.3.4.5.2, we let [[Call]] supply the
 | ||||
| 	// bound arguments, etc.
 | ||||
| 	return func(self *_object, this Value, argumentList []Value) Value { | ||||
| 		switch value := target.value.(type) { | ||||
| 		case _functionObject: | ||||
| 			return value.construct(self, this, argumentList) | ||||
| 		} | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // FunctionCall{}
 | ||||
| 
 | ||||
| // FunctionCall is an encapsulation of a JavaScript function call.
 | ||||
| type FunctionCall struct { | ||||
| 	runtime     *_runtime | ||||
| 	_thisObject *_object | ||||
| 	evalHint    bool | ||||
| 
 | ||||
| 	This         Value | ||||
| 	ArgumentList []Value | ||||
| 	Otto         *Otto | ||||
| } | ||||
| 
 | ||||
| // Argument will return the value of the argument at the given index.
 | ||||
| //
 | ||||
| // If no such argument exists, undefined is returned.
 | ||||
| func (self FunctionCall) Argument(index int) Value { | ||||
| 	return valueOfArrayIndex(self.ArgumentList, index) | ||||
| } | ||||
| 
 | ||||
| func (self FunctionCall) getArgument(index int) (Value, bool) { | ||||
| 	return getValueOfArrayIndex(self.ArgumentList, index) | ||||
| } | ||||
| 
 | ||||
| func (self FunctionCall) slice(index int) []Value { | ||||
| 	if index < len(self.ArgumentList) { | ||||
| 		return self.ArgumentList[index:] | ||||
| 	} | ||||
| 	return []Value{} | ||||
| } | ||||
| 
 | ||||
| func (self *FunctionCall) thisObject() *_object { | ||||
| 	if self._thisObject == nil { | ||||
| 		this := self.runtime.GetValue(self.This) // FIXME Is this right?
 | ||||
| 		self._thisObject = self.runtime.toObject(this) | ||||
| 	} | ||||
| 	return self._thisObject | ||||
| } | ||||
| 
 | ||||
| func (self *FunctionCall) thisClassObject(class string) *_object { | ||||
| 	thisObject := self.thisObject() | ||||
| 	if thisObject.class != class { | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| 	return self._thisObject | ||||
| } | ||||
| 
 | ||||
| func (self FunctionCall) toObject(value Value) *_object { | ||||
| 	return self.runtime.toObject(value) | ||||
| } | ||||
							
								
								
									
										157
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										157
									
								
								Godeps/_workspace/src/github.com/obscuren/otto/type_reference.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,157 +0,0 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| ) | ||||
| 
 | ||||
| type _reference interface { | ||||
| 	GetBase() interface{}      // GetBase
 | ||||
| 	GetName() string           // GetReferencedName
 | ||||
| 	IsStrict() bool            // IsStrictReference
 | ||||
| 	IsUnresolvable() bool      // IsUnresolvableReference
 | ||||
| 	IsPropertyReference() bool // IsPropertyReference
 | ||||
| 	GetValue() Value           // GetValue
 | ||||
| 	PutValue(Value) bool       // PutValue
 | ||||
| 	Delete() bool | ||||
| } | ||||
| 
 | ||||
| // Reference
 | ||||
| 
 | ||||
| type _referenceDefault struct { | ||||
| 	name   string | ||||
| 	strict bool | ||||
| } | ||||
| 
 | ||||
| func (self _referenceDefault) GetName() string { | ||||
| 	return self.name | ||||
| } | ||||
| 
 | ||||
| func (self _referenceDefault) IsStrict() bool { | ||||
| 	return self.strict | ||||
| } | ||||
| 
 | ||||
| // PropertyReference
 | ||||
| 
 | ||||
| type _propertyReference struct { | ||||
| 	_referenceDefault | ||||
| 	Base *_object | ||||
| } | ||||
| 
 | ||||
| func newPropertyReference(base *_object, name string, strict bool) *_propertyReference { | ||||
| 	return &_propertyReference{ | ||||
| 		Base: base, | ||||
| 		_referenceDefault: _referenceDefault{ | ||||
| 			name:   name, | ||||
| 			strict: strict, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) GetBase() interface{} { | ||||
| 	return self.Base | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) IsUnresolvable() bool { | ||||
| 	return self.Base == nil | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) IsPropertyReference() bool { | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) GetValue() Value { | ||||
| 	if self.Base == nil { | ||||
| 		panic(newReferenceError("notDefined", self.name)) | ||||
| 	} | ||||
| 	return self.Base.get(self.name) | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) PutValue(value Value) bool { | ||||
| 	if self.Base == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	self.Base.put(self.name, value, self.IsStrict()) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (self *_propertyReference) Delete() bool { | ||||
| 	if self.Base == nil { | ||||
| 		// TODO Throw an error if strict
 | ||||
| 		return true | ||||
| 	} | ||||
| 	return self.Base.delete(self.name, self.IsStrict()) | ||||
| } | ||||
| 
 | ||||
| // ArgumentReference
 | ||||
| 
 | ||||
| func newArgumentReference(base *_object, name string, strict bool) *_propertyReference { | ||||
| 	if base == nil { | ||||
| 		panic(hereBeDragons()) | ||||
| 	} | ||||
| 	return newPropertyReference(base, name, strict) | ||||
| } | ||||
| 
 | ||||
| type _environmentReference struct { | ||||
| 	_referenceDefault | ||||
| 	Base _environment | ||||
| 	node ast.Node | ||||
| } | ||||
| 
 | ||||
| func newEnvironmentReference(base _environment, name string, strict bool, node ast.Node) *_environmentReference { | ||||
| 	return &_environmentReference{ | ||||
| 		Base: base, | ||||
| 		_referenceDefault: _referenceDefault{ | ||||
| 			name:   name, | ||||
| 			strict: strict, | ||||
| 		}, | ||||
| 		node: node, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) GetBase() interface{} { | ||||
| 	return self.Base | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) IsUnresolvable() bool { | ||||
| 	return self.Base == nil // The base (an environment) will never be nil
 | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) IsPropertyReference() bool { | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) GetValue() Value { | ||||
| 	if self.Base == nil { | ||||
| 		// This should never be reached, but just in case
 | ||||
| 	} | ||||
| 	return self.Base.GetValue(self.name, self.IsStrict()) | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) PutValue(value Value) bool { | ||||
| 	if self.Base == nil { | ||||
| 		// This should never be reached, but just in case
 | ||||
| 		return false | ||||
| 	} | ||||
| 	self.Base.SetValue(self.name, value, self.IsStrict()) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (self *_environmentReference) Delete() bool { | ||||
| 	if self.Base == nil { | ||||
| 		// This should never be reached, but just in case
 | ||||
| 		return false | ||||
| 	} | ||||
| 	return self.Base.DeleteBinding(self.name) | ||||
| } | ||||
| 
 | ||||
| // getIdentifierReference
 | ||||
| 
 | ||||
| func getIdentifierReference(environment _environment, name string, strict bool) _reference { | ||||
| 	if environment == nil { | ||||
| 		return newPropertyReference(nil, name, strict) | ||||
| 	} | ||||
| 	if environment.HasBinding(name) { | ||||
| 		return environment.newReference(name, strict) | ||||
| 	} | ||||
| 	return getIdentifierReference(environment.Outer(), name, strict) | ||||
| } | ||||
| @ -6,8 +6,8 @@ TESTS := \ | ||||
| 	~ | ||||
| 
 | ||||
| TEST := -v --run | ||||
| TEST := -v --run Test\($(subst $(eval) ,\|,$(TESTS))\) | ||||
| TEST := -v | ||||
| TEST := -v --run Test\($(subst $(eval) ,\|,$(TESTS))\) | ||||
| TEST := . | ||||
| 
 | ||||
| test: parser inline.go | ||||
| @ -60,7 +60,7 @@ Set a Go function | ||||
| 
 | ||||
|     vm.Set("sayHello", func(call otto.FunctionCall) otto.Value { | ||||
|         fmt.Printf("Hello, %s.\n", call.Argument(0).String()) | ||||
|         return otto.UndefinedValue() | ||||
|         return otto.Value{} | ||||
|     }) | ||||
| 
 | ||||
| Set a Go function that returns something useful | ||||
| @ -139,7 +139,6 @@ For more information: http://github.com/robertkrimen/otto/tree/master/underscore | ||||
| The following are some limitations with otto: | ||||
| 
 | ||||
|     * "use strict" will parse, but does nothing. | ||||
|     * Error reporting needs to be improved. | ||||
|     * The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification. | ||||
| 
 | ||||
| 
 | ||||
| @ -205,16 +204,18 @@ the interrupt channel to do this: | ||||
|             } | ||||
|             fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration) | ||||
|         }() | ||||
| 
 | ||||
|         vm := otto.New() | ||||
|         vm.Interrupt = make(chan func()) | ||||
|         vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking | ||||
| 
 | ||||
|         go func() { | ||||
|             time.Sleep(2 * time.Second) // Stop after two seconds | ||||
|             vm.Interrupt <- func() { | ||||
|                 panic(halt) | ||||
|             } | ||||
|         }() | ||||
| 
 | ||||
|         vm.Run(unsafe) // Here be dragons (risky code) | ||||
|         vm.Interrupt = nil | ||||
|     } | ||||
| 
 | ||||
| Where is setTimeout/setInterval? | ||||
| @ -242,6 +243,36 @@ Here is some more discussion of the issue: | ||||
| var ErrVersion = errors.New("version mismatch") | ||||
| ``` | ||||
| 
 | ||||
| #### type Error | ||||
| 
 | ||||
| ```go | ||||
| type Error struct { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc. | ||||
| 
 | ||||
| #### func (Error) Error | ||||
| 
 | ||||
| ```go | ||||
| func (err Error) Error() string | ||||
| ``` | ||||
| Error returns a description of the error | ||||
| 
 | ||||
|     TypeError: 'def' is not a function | ||||
| 
 | ||||
| #### func (Error) String | ||||
| 
 | ||||
| ```go | ||||
| 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 | ||||
| 
 | ||||
| ```go | ||||
| @ -416,16 +447,16 @@ error if there was a problem during compilation. | ||||
| #### func (*Otto) Copy | ||||
| 
 | ||||
| ```go | ||||
| func (self *Otto) Copy() *Otto | ||||
| func (in *Otto) Copy() *Otto | ||||
| ``` | ||||
| Copy will create a copy/clone of the runtime. | ||||
| 
 | ||||
| Copy is useful for saving some processing time when creating many similar | ||||
| runtimes. | ||||
| Copy is useful for saving some time when creating many similar runtimes. | ||||
| 
 | ||||
| This implementation is alpha-ish, and works by introspecting every part of the | ||||
| runtime and reallocating and then relinking everything back together. Please | ||||
| report if you notice any inadvertent sharing of data between copies. | ||||
| 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 | ||||
| 
 | ||||
| @ -562,12 +593,10 @@ NullValue will return a Value representing null. | ||||
| func ToValue(value interface{}) (Value, error) | ||||
| ``` | ||||
| ToValue will convert an interface{} value to a value digestible by | ||||
| otto/JavaScript This function will not work for advanced types (struct, map, | ||||
| slice/array, etc.) and you probably should not use it. | ||||
| otto/JavaScript | ||||
| 
 | ||||
| ToValue may be deprecated and removed in the near future. | ||||
| 
 | ||||
| Try Otto.ToValue for a replacement. | ||||
| This function will not work for advanced types (struct, map, slice/array, etc.) | ||||
| and you should use Otto.ToValue instead. | ||||
| 
 | ||||
| #### func  TrueValue | ||||
| 
 | ||||
| @ -630,15 +659,13 @@ func (self Value) Export() (interface{}, error) | ||||
| Export will attempt to convert the value to a Go representation and return it | ||||
| via an interface{} kind. | ||||
| 
 | ||||
| WARNING: The interface function will be changing soon to: | ||||
| Export returns an error, but it will always be nil. It is present for backwards | ||||
| compatibility. | ||||
| 
 | ||||
|     Export() interface{} | ||||
| If a reasonable conversion is not possible, then the original value is returned. | ||||
| 
 | ||||
| If a reasonable conversion is not possible, then the original result is | ||||
| returned. | ||||
| 
 | ||||
|     undefined   -> otto.Value (UndefinedValue()) | ||||
|     null        -> interface{}(nil) | ||||
|     undefined   -> nil (FIXME?: Should be Value{}) | ||||
|     null        -> nil | ||||
|     boolean     -> bool | ||||
|     number      -> A number type (int, float32, uint64, ...) | ||||
|     string      -> string | ||||
| @ -55,7 +55,7 @@ func Test_issue13(t *testing.T) { | ||||
| 			t.Error(err) | ||||
| 			t.FailNow() | ||||
| 		} | ||||
| 		is(result.toString(), "Xyzzy,42,def,ghi") | ||||
| 		is(result.string(), "Xyzzy,42,def,ghi") | ||||
| 
 | ||||
| 		anything := struct { | ||||
| 			Abc interface{} | ||||
| @ -231,12 +231,12 @@ func Test_issue24(t *testing.T) { | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			vm.Set("abc", testStruct{Abc: true, Ghi: "Nothing happens."}) | ||||
| 			vm.Set("abc", _abcStruct{Abc: true, Ghi: "Nothing happens."}) | ||||
| 			value, err := vm.Get("abc") | ||||
| 			is(err, nil) | ||||
| 			export, _ := value.Export() | ||||
| 			{ | ||||
| 				value, valid := export.(testStruct) | ||||
| 				value, valid := export.(_abcStruct) | ||||
| 				is(valid, true) | ||||
| 
 | ||||
| 				is(value.Abc, true) | ||||
| @ -245,12 +245,12 @@ func Test_issue24(t *testing.T) { | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			vm.Set("abc", &testStruct{Abc: true, Ghi: "Nothing happens."}) | ||||
| 			vm.Set("abc", &_abcStruct{Abc: true, Ghi: "Nothing happens."}) | ||||
| 			value, err := vm.Get("abc") | ||||
| 			is(err, nil) | ||||
| 			export, _ := value.Export() | ||||
| 			{ | ||||
| 				value, valid := export.(*testStruct) | ||||
| 				value, valid := export.(*_abcStruct) | ||||
| 				is(valid, true) | ||||
| 
 | ||||
| 				is(value.Abc, true) | ||||
| @ -313,10 +313,22 @@ func Test_issue64(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_issue73(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		vm.Set("abc", [4]int{3, 2, 1, 0}) | ||||
| 
 | ||||
| 		test(` | ||||
|             var def = [ 0, 1, 2, 3 ]; | ||||
|             JSON.stringify(def) + JSON.stringify(abc); | ||||
|         `, "[0,1,2,3][3,2,1,0]") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_7_3_1(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test(` | ||||
| 
 | ||||
|             eval("var test7_3_1\u2028abc = 66;"); | ||||
|             [ abc, typeof test7_3_1 ]; | ||||
|         `, "66,undefined") | ||||
| @ -430,13 +442,13 @@ def" | ||||
| 		test(` | ||||
|             var abc = 0; | ||||
|             do { | ||||
|             if(typeof(def) === "function"){ | ||||
|                 abc = -1; | ||||
|                 break; | ||||
|             } else { | ||||
|                 abc = 1; | ||||
|                 break; | ||||
|             } | ||||
|                 if(typeof(def) === "function"){ | ||||
|                     abc = -1; | ||||
|                     break; | ||||
|                 } else { | ||||
|                     abc = 1; | ||||
|                     break; | ||||
|                 } | ||||
|             } while(function def(){}); | ||||
|             abc; | ||||
|         `, 1) | ||||
| @ -502,3 +514,104 @@ def" | ||||
|         `, "1,0,\t abc def,\t abc ") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_issue79(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		vm.Set("abc", []_abcStruct{ | ||||
| 			{ | ||||
| 				Ghi: "一", | ||||
| 				Def: 1, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Def: 3, | ||||
| 				Ghi: "三", | ||||
| 			}, | ||||
| 			{ | ||||
| 				Def: 2, | ||||
| 				Ghi: "二", | ||||
| 			}, | ||||
| 			{ | ||||
| 				Def: 4, | ||||
| 				Ghi: "四", | ||||
| 			}, | ||||
| 		}) | ||||
| 
 | ||||
| 		test(` | ||||
|             abc.sort(function(a,b){ return b.Def-a.Def }); | ||||
|             def = []; | ||||
|             for (i = 0; i < abc.length; i++) { | ||||
|                 def.push(abc[i].String()) | ||||
|             } | ||||
|             def; | ||||
|         `, "四,三,二,一") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_issue80(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		test(` | ||||
|             JSON.stringify([ | ||||
|                 1401868959, | ||||
|                 14018689591, | ||||
|                 140186895901, | ||||
|                 1401868959001, | ||||
|                 14018689590001, | ||||
|                 140186895900001, | ||||
|                 1401868959000001, | ||||
|                 1401868959000001.5, | ||||
|                 14018689590000001, | ||||
|                 140186895900000001, | ||||
|                 1401868959000000001, | ||||
|                 14018689590000000001, | ||||
|                 140186895900000000001, | ||||
|                 140186895900000000001.5 | ||||
|             ]); | ||||
|         `, "[1401868959,14018689591,140186895901,1401868959001,14018689590001,140186895900001,1401868959000001,1.4018689590000015e+15,14018689590000001,140186895900000001,1401868959000000001,1.401868959e+19,1.401868959e+20,1.401868959e+20]") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_issue87(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		test(` | ||||
|             var def = 0; | ||||
|             abc: { | ||||
|                 for (;;) { | ||||
|                     def = !1; | ||||
|                     break abc; | ||||
|                 } | ||||
|                 def = !0; | ||||
|             } | ||||
|             def; | ||||
|         `, false) | ||||
| 
 | ||||
| 		_, err := vm.Run(` | ||||
| /* | ||||
| CryptoJS v3.1.2 | ||||
| code.google.com/p/crypto-js | ||||
| (c) 2009-2013 by Jeff Mott. All rights reserved. | ||||
| code.google.com/p/crypto-js/wiki/License | ||||
| */ | ||||
| var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, | ||||
| r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< | ||||
| 32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b, | ||||
| 2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}}, | ||||
| u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this); | ||||
| a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a, | ||||
| d)).finalize(c)}}});var t=f.algo={};return f}(Math); | ||||
| (function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]= | ||||
| c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes; | ||||
| d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math); | ||||
| (function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g= | ||||
| this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})(); | ||||
|         `) | ||||
| 		is(err, nil) | ||||
| 
 | ||||
| 		test(`CryptoJS.HmacSHA256("Message", "secret");`, "aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597") | ||||
| 	}) | ||||
| } | ||||
| @ -2,7 +2,6 @@ package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| @ -19,25 +18,26 @@ func builtinGlobal_eval(call FunctionCall) Value { | ||||
| 		return src | ||||
| 	} | ||||
| 	runtime := call.runtime | ||||
| 	program := runtime.cmpl_parseOrThrow(toString(src)) | ||||
| 	if call.evalHint { | ||||
| 		runtime.EnterEvalExecutionContext(call) | ||||
| 		defer runtime.LeaveExecutionContext() | ||||
| 	program := runtime.cmpl_parseOrThrow(src.string()) | ||||
| 	if !call.eval { | ||||
| 		// Not a direct call to eval, so we enter the global ExecutionContext
 | ||||
| 		runtime.enterGlobalScope() | ||||
| 		defer runtime.leaveScope() | ||||
| 	} | ||||
| 	returnValue := runtime.cmpl_evaluate_nodeProgram(program) | ||||
| 	returnValue := runtime.cmpl_evaluate_nodeProgram(program, true) | ||||
| 	if returnValue.isEmpty() { | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	return returnValue | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_isNaN(call FunctionCall) Value { | ||||
| 	value := toFloat(call.Argument(0)) | ||||
| 	value := call.Argument(0).float64() | ||||
| 	return toValue_bool(math.IsNaN(value)) | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_isFinite(call FunctionCall) Value { | ||||
| 	value := toFloat(call.Argument(0)) | ||||
| 	value := call.Argument(0).float64() | ||||
| 	return toValue_bool(!math.IsNaN(value) && !math.IsInf(value, 0)) | ||||
| } | ||||
| 
 | ||||
| @ -70,7 +70,7 @@ func digitValue(chr rune) int { | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_parseInt(call FunctionCall) Value { | ||||
| 	input := strings.TrimSpace(toString(call.Argument(0))) | ||||
| 	input := strings.TrimSpace(call.Argument(0).string()) | ||||
| 	if len(input) == 0 { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -153,7 +153,7 @@ var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`) | ||||
| 
 | ||||
| func builtinGlobal_parseFloat(call FunctionCall) Value { | ||||
| 	// Caveat emptor: This implementation does NOT match the specification
 | ||||
| 	input := strings.TrimSpace(toString(call.Argument(0))) | ||||
| 	input := strings.TrimSpace(call.Argument(0).string()) | ||||
| 	if parseFloat_matchBadSpecial.MatchString(input) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -185,7 +185,7 @@ func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value { | ||||
| 	case []uint16: | ||||
| 		input = vl | ||||
| 	default: | ||||
| 		input = utf16.Encode([]rune(toString(value))) | ||||
| 		input = utf16.Encode([]rune(value.string())) | ||||
| 	} | ||||
| 	if len(input) == 0 { | ||||
| 		return toValue_string("") | ||||
| @ -197,18 +197,17 @@ func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value { | ||||
| 		value := input[index] | ||||
| 		decode := utf16.Decode(input[index : index+1]) | ||||
| 		if value >= 0xDC00 && value <= 0xDFFF { | ||||
| 			panic(newURIError("URI malformed")) | ||||
| 			panic(call.runtime.panicURIError("URI malformed")) | ||||
| 		} | ||||
| 		if value >= 0xD800 && value <= 0xDBFF { | ||||
| 			index += 1 | ||||
| 			if index >= length { | ||||
| 				panic(newURIError("URI malformed")) | ||||
| 				panic(call.runtime.panicURIError("URI malformed")) | ||||
| 			} | ||||
| 			// input = ..., value, value1, ...
 | ||||
| 			value = value | ||||
| 			value1 := input[index] | ||||
| 			if value1 < 0xDC00 || value1 > 0xDFFF { | ||||
| 				panic(newURIError("URI malformed")) | ||||
| 				panic(call.runtime.panicURIError("URI malformed")) | ||||
| 			} | ||||
| 			decode = []rune{((rune(value) - 0xD800) * 0x400) + (rune(value1) - 0xDC00) + 0x10000} | ||||
| 		} | ||||
| @ -257,17 +256,17 @@ func _decodeURI(input string, reserve bool) (string, bool) { | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_decodeURI(call FunctionCall) Value { | ||||
| 	output, err := _decodeURI(toString(call.Argument(0)), true) | ||||
| 	output, err := _decodeURI(call.Argument(0).string(), true) | ||||
| 	if err { | ||||
| 		panic(newURIError("URI malformed")) | ||||
| 		panic(call.runtime.panicURIError("URI malformed")) | ||||
| 	} | ||||
| 	return toValue_string(output) | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_decodeURIComponent(call FunctionCall) Value { | ||||
| 	output, err := _decodeURI(toString(call.Argument(0)), false) | ||||
| 	output, err := _decodeURI(call.Argument(0).string(), false) | ||||
| 	if err { | ||||
| 		panic(newURIError("URI malformed")) | ||||
| 		panic(call.runtime.panicURIError("URI malformed")) | ||||
| 	} | ||||
| 	return toValue_string(output) | ||||
| } | ||||
| @ -346,48 +345,9 @@ func builtin_unescape(input string) string { | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_escape(call FunctionCall) Value { | ||||
| 	return toValue_string(builtin_escape(toString(call.Argument(0)))) | ||||
| 	return toValue_string(builtin_escape(call.Argument(0).string())) | ||||
| } | ||||
| 
 | ||||
| func builtinGlobal_unescape(call FunctionCall) Value { | ||||
| 	return toValue_string(builtin_unescape(toString(call.Argument(0)))) | ||||
| } | ||||
| 
 | ||||
| // Error
 | ||||
| 
 | ||||
| func builtinError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newError("", call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewError(self *_object, _ Value, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newError("", valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func builtinError_toString(call FunctionCall) Value { | ||||
| 	thisObject := call.thisObject() | ||||
| 	if thisObject == nil { | ||||
| 		panic(newTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	name := "Error" | ||||
| 	nameValue := thisObject.get("name") | ||||
| 	if nameValue.IsDefined() { | ||||
| 		name = toString(nameValue) | ||||
| 	} | ||||
| 
 | ||||
| 	message := "" | ||||
| 	messageValue := thisObject.get("message") | ||||
| 	if messageValue.IsDefined() { | ||||
| 		message = toString(messageValue) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(name) == 0 { | ||||
| 		return toValue_string(message) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(message) == 0 { | ||||
| 		return toValue_string(name) | ||||
| 	} | ||||
| 
 | ||||
| 	return toValue_string(fmt.Sprintf("%s: %s", name, message)) | ||||
| 	return toValue_string(builtin_unescape(call.Argument(0).string())) | ||||
| } | ||||
| @ -11,7 +11,7 @@ func builtinArray(call FunctionCall) Value { | ||||
| 	return toValue_object(builtinNewArrayNative(call.runtime, call.ArgumentList)) | ||||
| } | ||||
| 
 | ||||
| func builtinNewArray(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewArray(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(builtinNewArrayNative(self.runtime, argumentList)) | ||||
| } | ||||
| 
 | ||||
| @ -19,7 +19,7 @@ func builtinNewArrayNative(runtime *_runtime, argumentList []Value) *_object { | ||||
| 	if len(argumentList) == 1 { | ||||
| 		firstArgument := argumentList[0] | ||||
| 		if firstArgument.IsNumber() { | ||||
| 			return runtime.newArray(arrayUint32(firstArgument)) | ||||
| 			return runtime.newArray(arrayUint32(runtime, firstArgument)) | ||||
| 		} | ||||
| 	} | ||||
| 	return runtime.newArrayOf(argumentList) | ||||
| @ -30,7 +30,7 @@ func builtinArray_toString(call FunctionCall) Value { | ||||
| 	join := thisObject.get("join") | ||||
| 	if join.isCallable() { | ||||
| 		join := join._object() | ||||
| 		return join.Call(call.This, call.ArgumentList) | ||||
| 		return join.call(call.This, call.ArgumentList, false, nativeFrame) | ||||
| 	} | ||||
| 	return builtinObject_toString(call) | ||||
| } | ||||
| @ -46,15 +46,15 @@ func builtinArray_toLocaleString(call FunctionCall) Value { | ||||
| 	for index := int64(0); index < length; index += 1 { | ||||
| 		value := thisObject.get(arrayIndexToString(index)) | ||||
| 		stringValue := "" | ||||
| 		switch value._valueType { | ||||
| 		switch value.kind { | ||||
| 		case valueEmpty, valueUndefined, valueNull: | ||||
| 		default: | ||||
| 			object := call.runtime.toObject(value) | ||||
| 			toLocaleString := object.get("toLocaleString") | ||||
| 			if !toLocaleString.isCallable() { | ||||
| 				panic(newTypeError()) | ||||
| 				panic(call.runtime.panicTypeError()) | ||||
| 			} | ||||
| 			stringValue = toLocaleString.call(toValue_object(object)).toString() | ||||
| 			stringValue = toLocaleString.call(call.runtime, toValue_object(object)).string() | ||||
| 		} | ||||
| 		stringList = append(stringList, stringValue) | ||||
| 	} | ||||
| @ -66,11 +66,11 @@ func builtinArray_concat(call FunctionCall) Value { | ||||
| 	valueArray := []Value{} | ||||
| 	source := append([]Value{toValue_object(thisObject)}, call.ArgumentList...) | ||||
| 	for _, item := range source { | ||||
| 		switch item._valueType { | ||||
| 		switch item.kind { | ||||
| 		case valueObject: | ||||
| 			object := item._object() | ||||
| 			if isArray(object) { | ||||
| 				length := toInteger(object.get("length")).value | ||||
| 				length := object.get("length").number().int64 | ||||
| 				for index := int64(0); index < length; index += 1 { | ||||
| 					name := strconv.FormatInt(index, 10) | ||||
| 					if object.hasProperty(name) { | ||||
| @ -94,7 +94,7 @@ func builtinArray_shift(call FunctionCall) Value { | ||||
| 	length := int64(toUint32(thisObject.get("length"))) | ||||
| 	if 0 == length { | ||||
| 		thisObject.put("length", toValue_int64(0), true) | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	first := thisObject.get("0") | ||||
| 	for index := int64(1); index < length; index++ { | ||||
| @ -130,7 +130,7 @@ func builtinArray_pop(call FunctionCall) Value { | ||||
| 	length := int64(toUint32(thisObject.get("length"))) | ||||
| 	if 0 == length { | ||||
| 		thisObject.put("length", toValue_uint32(0), true) | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	last := thisObject.get(arrayIndexToString(length - 1)) | ||||
| 	thisObject.delete(arrayIndexToString(length-1), true) | ||||
| @ -143,7 +143,7 @@ func builtinArray_join(call FunctionCall) Value { | ||||
| 	{ | ||||
| 		argument := call.Argument(0) | ||||
| 		if argument.IsDefined() { | ||||
| 			separator = toString(argument) | ||||
| 			separator = argument.string() | ||||
| 		} | ||||
| 	} | ||||
| 	thisObject := call.thisObject() | ||||
| @ -155,10 +155,10 @@ func builtinArray_join(call FunctionCall) Value { | ||||
| 	for index := int64(0); index < length; index += 1 { | ||||
| 		value := thisObject.get(arrayIndexToString(index)) | ||||
| 		stringValue := "" | ||||
| 		switch value._valueType { | ||||
| 		switch value.kind { | ||||
| 		case valueEmpty, valueUndefined, valueNull: | ||||
| 		default: | ||||
| 			stringValue = toString(value) | ||||
| 			stringValue = value.string() | ||||
| 		} | ||||
| 		stringList = append(stringList, stringValue) | ||||
| 	} | ||||
| @ -370,8 +370,8 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int | ||||
| 	} | ||||
| 
 | ||||
| 	if compare == nil { | ||||
| 		j.value = toString(x) | ||||
| 		k.value = toString(y) | ||||
| 		j.value = x.string() | ||||
| 		k.value = y.string() | ||||
| 
 | ||||
| 		if j.value == k.value { | ||||
| 			return 0 | ||||
| @ -382,7 +382,7 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int | ||||
| 		return 1 | ||||
| 	} | ||||
| 
 | ||||
| 	return int(toInt32(compare.Call(UndefinedValue(), []Value{x, y}))) | ||||
| 	return int(toInt32(compare.call(Value{}, []Value{x, y}, false, nativeFrame))) | ||||
| } | ||||
| 
 | ||||
| func arraySortSwap(thisObject *_object, index0, index1 uint) { | ||||
| @ -447,7 +447,7 @@ func builtinArray_sort(call FunctionCall) Value { | ||||
| 	compare := compareValue._object() | ||||
| 	if compareValue.IsUndefined() { | ||||
| 	} else if !compareValue.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	if length > 1 { | ||||
| 		arraySortQuickSort(thisObject, 0, length-1, compare) | ||||
| @ -464,7 +464,7 @@ func builtinArray_indexOf(call FunctionCall) Value { | ||||
| 	if length := int64(toUint32(thisObject.get("length"))); length > 0 { | ||||
| 		index := int64(0) | ||||
| 		if len(call.ArgumentList) > 1 { | ||||
| 			index = toInteger(call.Argument(1)).value | ||||
| 			index = call.Argument(1).number().int64 | ||||
| 		} | ||||
| 		if index < 0 { | ||||
| 			if index += length; index < 0 { | ||||
| @ -492,7 +492,7 @@ func builtinArray_lastIndexOf(call FunctionCall) Value { | ||||
| 	length := int64(toUint32(thisObject.get("length"))) | ||||
| 	index := length - 1 | ||||
| 	if len(call.ArgumentList) > 1 { | ||||
| 		index = toInteger(call.Argument(1)).value | ||||
| 		index = call.Argument(1).number().int64 | ||||
| 	} | ||||
| 	if 0 > index { | ||||
| 		index += length | ||||
| @ -523,15 +523,15 @@ func builtinArray_every(call FunctionCall) Value { | ||||
| 		callThis := call.Argument(1) | ||||
| 		for index := int64(0); index < length; index++ { | ||||
| 			if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 				if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() { | ||||
| 				if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() { | ||||
| 					continue | ||||
| 				} | ||||
| 				return FalseValue() | ||||
| 				return falseValue | ||||
| 			} | ||||
| 		} | ||||
| 		return TrueValue() | ||||
| 		return trueValue | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_some(call FunctionCall) Value { | ||||
| @ -542,14 +542,14 @@ func builtinArray_some(call FunctionCall) Value { | ||||
| 		callThis := call.Argument(1) | ||||
| 		for index := int64(0); index < length; index++ { | ||||
| 			if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 				if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() { | ||||
| 					return TrueValue() | ||||
| 				if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() { | ||||
| 					return trueValue | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return FalseValue() | ||||
| 		return falseValue | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_forEach(call FunctionCall) Value { | ||||
| @ -560,12 +560,12 @@ func builtinArray_forEach(call FunctionCall) Value { | ||||
| 		callThis := call.Argument(1) | ||||
| 		for index := int64(0); index < length; index++ { | ||||
| 			if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 				iterator.call(callThis, thisObject.get(key), toValue_int64(index), this) | ||||
| 				iterator.call(call.runtime, callThis, thisObject.get(key), toValue_int64(index), this) | ||||
| 			} | ||||
| 		} | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_map(call FunctionCall) Value { | ||||
| @ -577,14 +577,14 @@ func builtinArray_map(call FunctionCall) Value { | ||||
| 		values := make([]Value, length) | ||||
| 		for index := int64(0); index < length; index++ { | ||||
| 			if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 				values[index] = iterator.call(callThis, thisObject.get(key), index, this) | ||||
| 				values[index] = iterator.call(call.runtime, callThis, thisObject.get(key), index, this) | ||||
| 			} else { | ||||
| 				values[index] = UndefinedValue() | ||||
| 				values[index] = Value{} | ||||
| 			} | ||||
| 		} | ||||
| 		return toValue_object(call.runtime.newArrayOf(values)) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_filter(call FunctionCall) Value { | ||||
| @ -597,14 +597,14 @@ func builtinArray_filter(call FunctionCall) Value { | ||||
| 		for index := int64(0); index < length; index++ { | ||||
| 			if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 				value := thisObject.get(key) | ||||
| 				if iterator.call(callThis, value, index, this).isTrue() { | ||||
| 				if iterator.call(call.runtime, callThis, value, index, this).bool() { | ||||
| 					values = append(values, value) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return toValue_object(call.runtime.newArrayOf(values)) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_reduce(call FunctionCall) Value { | ||||
| @ -630,13 +630,13 @@ func builtinArray_reduce(call FunctionCall) Value { | ||||
| 			} | ||||
| 			for ; index < length; index++ { | ||||
| 				if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 					accumulator = iterator.call(UndefinedValue(), accumulator, thisObject.get(key), key, this) | ||||
| 					accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this) | ||||
| 				} | ||||
| 			} | ||||
| 			return accumulator | ||||
| 		} | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinArray_reduceRight(call FunctionCall) Value { | ||||
| @ -662,11 +662,11 @@ func builtinArray_reduceRight(call FunctionCall) Value { | ||||
| 			} | ||||
| 			for ; index >= 0; index-- { | ||||
| 				if key := arrayIndexToString(index); thisObject.hasProperty(key) { | ||||
| 					accumulator = iterator.call(UndefinedValue(), accumulator, thisObject.get(key), key, this) | ||||
| 					accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this) | ||||
| 				} | ||||
| 			} | ||||
| 			return accumulator | ||||
| 		} | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| @ -3,10 +3,10 @@ package otto | ||||
| // Boolean
 | ||||
| 
 | ||||
| func builtinBoolean(call FunctionCall) Value { | ||||
| 	return toValue_bool(toBoolean(call.Argument(0))) | ||||
| 	return toValue_bool(call.Argument(0).bool()) | ||||
| } | ||||
| 
 | ||||
| func builtinNewBoolean(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewBoolean(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newBoolean(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| @ -16,7 +16,7 @@ func builtinBoolean_toString(call FunctionCall) Value { | ||||
| 		// Will throw a TypeError if ThisObject is not a Boolean
 | ||||
| 		value = call.thisClassObject("Boolean").primitiveValue() | ||||
| 	} | ||||
| 	return toValue_string(toString(value)) | ||||
| 	return toValue_string(value.string()) | ||||
| } | ||||
| 
 | ||||
| func builtinBoolean_valueOf(call FunctionCall) Value { | ||||
| @ -21,12 +21,12 @@ func builtinDate(call FunctionCall) Value { | ||||
| 	return toValue_string(date.Time().Format(builtinDate_goDateTimeLayout)) | ||||
| } | ||||
| 
 | ||||
| func builtinNewDate(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewDate(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newDate(newDateTime(argumentList, Time.Local))) | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -34,7 +34,7 @@ func builtinDate_toString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toDateString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -42,7 +42,7 @@ func builtinDate_toDateString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toTimeString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -50,7 +50,7 @@ func builtinDate_toTimeString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toUTCString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -58,7 +58,7 @@ func builtinDate_toUTCString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toISOString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -69,20 +69,21 @@ func builtinDate_toJSON(call FunctionCall) Value { | ||||
| 	object := call.thisObject() | ||||
| 	value := object.DefaultValue(defaultValueHintNumber) // FIXME object.primitiveNumberValue
 | ||||
| 	{                                                    // FIXME value.isFinite
 | ||||
| 		value := toFloat(value) | ||||
| 		value := value.float64() | ||||
| 		if math.IsNaN(value) || math.IsInf(value, 0) { | ||||
| 			return NullValue() | ||||
| 			return nullValue | ||||
| 		} | ||||
| 	} | ||||
| 	toISOString := object.get("toISOString") | ||||
| 	if !toISOString.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		// FIXME
 | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return toISOString.call(toValue_object(object), []Value{}) | ||||
| 	return toISOString.call(call.runtime, toValue_object(object), []Value{}) | ||||
| } | ||||
| 
 | ||||
| func builtinDate_toGMTString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -90,7 +91,7 @@ func builtinDate_toGMTString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getTime(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -101,15 +102,15 @@ func builtinDate_getTime(call FunctionCall) Value { | ||||
| 
 | ||||
| func builtinDate_setTime(call FunctionCall) Value { | ||||
| 	object := call.thisObject() | ||||
| 	date := dateObjectOf(object) | ||||
| 	date.Set(toFloat(call.Argument(0))) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	date.Set(call.Argument(0).float64()) | ||||
| 	object.value = date | ||||
| 	return date.Value() | ||||
| } | ||||
| 
 | ||||
| func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool) (*_object, *_dateObject, *_ecmaTime, []int) { | ||||
| 	object := call.thisObject() | ||||
| 	date := dateObjectOf(object) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return nil, nil, nil, nil | ||||
| 	} | ||||
| @ -126,16 +127,14 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool | ||||
| 	valueList := make([]int, argumentLimit) | ||||
| 	for index := 0; index < argumentLimit; index++ { | ||||
| 		value := call.ArgumentList[index] | ||||
| 		if value.IsNaN() { | ||||
| 		nm := value.number() | ||||
| 		switch nm.kind { | ||||
| 		case numberInteger, numberFloat: | ||||
| 		default: | ||||
| 			object.value = invalidDateObject | ||||
| 			return nil, nil, nil, nil | ||||
| 		} | ||||
| 		integer := toInteger(value) | ||||
| 		if !integer.valid() { | ||||
| 			object.value = invalidDateObject | ||||
| 			return nil, nil, nil, nil | ||||
| 		} | ||||
| 		valueList[index] = int(integer.value) | ||||
| 		valueList[index] = int(nm.int64) | ||||
| 	} | ||||
| 	baseTime := date.Time() | ||||
| 	if timeLocal { | ||||
| @ -146,7 +145,7 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool | ||||
| } | ||||
| 
 | ||||
| func builtinDate_parse(call FunctionCall) Value { | ||||
| 	date := toString(call.Argument(0)) | ||||
| 	date := call.Argument(0).string() | ||||
| 	return toValue_float64(dateParse(date)) | ||||
| } | ||||
| 
 | ||||
| @ -161,7 +160,7 @@ func builtinDate_now(call FunctionCall) Value { | ||||
| 
 | ||||
| // This is a placeholder
 | ||||
| func builtinDate_toLocaleString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -170,7 +169,7 @@ func builtinDate_toLocaleString(call FunctionCall) Value { | ||||
| 
 | ||||
| // This is a placeholder
 | ||||
| func builtinDate_toLocaleDateString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -179,7 +178,7 @@ func builtinDate_toLocaleDateString(call FunctionCall) Value { | ||||
| 
 | ||||
| // This is a placeholder
 | ||||
| func builtinDate_toLocaleTimeString(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return toValue_string("Invalid Date") | ||||
| 	} | ||||
| @ -187,7 +186,7 @@ func builtinDate_toLocaleTimeString(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_valueOf(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -197,7 +196,7 @@ func builtinDate_valueOf(call FunctionCall) Value { | ||||
| func builtinDate_getYear(call FunctionCall) Value { | ||||
| 	// Will throw a TypeError is ThisObject is nil or
 | ||||
| 	// does not have Class of "Date"
 | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -207,7 +206,7 @@ func builtinDate_getYear(call FunctionCall) Value { | ||||
| func builtinDate_getFullYear(call FunctionCall) Value { | ||||
| 	// Will throw a TypeError is ThisObject is nil or
 | ||||
| 	// does not have Class of "Date"
 | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -215,7 +214,7 @@ func builtinDate_getFullYear(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCFullYear(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -223,7 +222,7 @@ func builtinDate_getUTCFullYear(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getMonth(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -231,7 +230,7 @@ func builtinDate_getMonth(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCMonth(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -239,7 +238,7 @@ func builtinDate_getUTCMonth(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getDate(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -247,7 +246,7 @@ func builtinDate_getDate(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCDate(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -256,7 +255,7 @@ func builtinDate_getUTCDate(call FunctionCall) Value { | ||||
| 
 | ||||
| func builtinDate_getDay(call FunctionCall) Value { | ||||
| 	// Actually day of the week
 | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -264,7 +263,7 @@ func builtinDate_getDay(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCDay(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -272,7 +271,7 @@ func builtinDate_getUTCDay(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getHours(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -280,7 +279,7 @@ func builtinDate_getHours(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCHours(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -288,7 +287,7 @@ func builtinDate_getUTCHours(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getMinutes(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -296,7 +295,7 @@ func builtinDate_getMinutes(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCMinutes(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -304,7 +303,7 @@ func builtinDate_getUTCMinutes(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getSeconds(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -312,7 +311,7 @@ func builtinDate_getSeconds(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCSeconds(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -320,7 +319,7 @@ func builtinDate_getUTCSeconds(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getMilliseconds(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -328,7 +327,7 @@ func builtinDate_getMilliseconds(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getUTCMilliseconds(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -336,7 +335,7 @@ func builtinDate_getUTCMilliseconds(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinDate_getTimezoneOffset(call FunctionCall) Value { | ||||
| 	date := dateObjectOf(call.thisObject()) | ||||
| 	date := dateObjectOf(call.runtime, call.thisObject()) | ||||
| 	if date.isNaN { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
							
								
								
									
										126
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/builtin_error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| func builtinError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newError("", call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newError("", valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func builtinError_toString(call FunctionCall) Value { | ||||
| 	thisObject := call.thisObject() | ||||
| 	if thisObject == nil { | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	name := "Error" | ||||
| 	nameValue := thisObject.get("name") | ||||
| 	if nameValue.IsDefined() { | ||||
| 		name = nameValue.string() | ||||
| 	} | ||||
| 
 | ||||
| 	message := "" | ||||
| 	messageValue := thisObject.get("message") | ||||
| 	if messageValue.IsDefined() { | ||||
| 		message = messageValue.string() | ||||
| 	} | ||||
| 
 | ||||
| 	if len(name) == 0 { | ||||
| 		return toValue_string(message) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(message) == 0 { | ||||
| 		return toValue_string(name) | ||||
| 	} | ||||
| 
 | ||||
| 	return toValue_string(fmt.Sprintf("%s: %s", name, message)) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newEvalError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("EvalError", message) | ||||
| 	self.prototype = runtime.global.EvalErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinEvalError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newEvalError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewEvalError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newEvalError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newTypeError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("TypeError", message) | ||||
| 	self.prototype = runtime.global.TypeErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinTypeError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newTypeError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewTypeError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newTypeError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newRangeError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("RangeError", message) | ||||
| 	self.prototype = runtime.global.RangeErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinRangeError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newRangeError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewRangeError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newRangeError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newURIError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("URIError", message) | ||||
| 	self.prototype = runtime.global.URIErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newReferenceError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("ReferenceError", message) | ||||
| 	self.prototype = runtime.global.ReferenceErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinReferenceError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newReferenceError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewReferenceError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newReferenceError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newSyntaxError(message Value) *_object { | ||||
| 	self := runtime.newErrorObject("SyntaxError", message) | ||||
| 	self.prototype = runtime.global.SyntaxErrorPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func builtinSyntaxError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newSyntaxError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewSyntaxError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newSyntaxError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| 
 | ||||
| func builtinURIError(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newURIError(call.Argument(0))) | ||||
| } | ||||
| 
 | ||||
| func builtinNewURIError(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newURIError(valueOfArrayIndex(argumentList, 0))) | ||||
| } | ||||
| @ -1,6 +1,7 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| @ -14,14 +15,14 @@ func builtinFunction(call FunctionCall) Value { | ||||
| 	return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList)) | ||||
| } | ||||
| 
 | ||||
| func builtinNewFunction(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewFunction(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(builtinNewFunctionNative(self.runtime, argumentList)) | ||||
| } | ||||
| 
 | ||||
| func argumentList2parameterList(argumentList []Value) []string { | ||||
| 	parameterList := make([]string, 0, len(argumentList)) | ||||
| 	for _, value := range argumentList { | ||||
| 		tmp := strings.FieldsFunc(toString(value), func(chr rune) bool { | ||||
| 		tmp := strings.FieldsFunc(value.string(), func(chr rune) bool { | ||||
| 			return chr == ',' || unicode.IsSpace(chr) | ||||
| 		}) | ||||
| 		parameterList = append(parameterList, tmp...) | ||||
| @ -37,40 +38,51 @@ func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object | ||||
| 	if count > 0 { | ||||
| 		tmp := make([]string, 0, count-1) | ||||
| 		for _, value := range argumentList[0 : count-1] { | ||||
| 			tmp = append(tmp, toString(value)) | ||||
| 			tmp = append(tmp, value.string()) | ||||
| 		} | ||||
| 		parameterList = strings.Join(tmp, ",") | ||||
| 		body = toString(argumentList[count-1]) | ||||
| 		body = argumentList[count-1].string() | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME
 | ||||
| 	function, err := parser.ParseFunction(parameterList, body) | ||||
| 	runtime.parseThrow(err) // Will panic/throw appropriately
 | ||||
| 	cmpl_function := parseExpression(function) | ||||
| 	cmpl := _compiler{} | ||||
| 	cmpl_function := cmpl.parseExpression(function) | ||||
| 
 | ||||
| 	return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.GlobalEnvironment) | ||||
| 	return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash) | ||||
| } | ||||
| 
 | ||||
| func builtinFunction_toString(call FunctionCall) Value { | ||||
| 	object := call.thisClassObject("Function") // Should throw a TypeError unless Function
 | ||||
| 	return toValue_string(object.value.(_functionObject).source(object)) | ||||
| 	switch fn := object.value.(type) { | ||||
| 	case _nativeFunctionObject: | ||||
| 		return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name)) | ||||
| 	case _nodeFunctionObject: | ||||
| 		return toValue_string(fn.node.source) | ||||
| 	case _bindFunctionObject: | ||||
| 		return toValue_string("function () { [native code] }") | ||||
| 	} | ||||
| 
 | ||||
| 	panic(call.runtime.panicTypeError("Function.toString()")) | ||||
| } | ||||
| 
 | ||||
| func builtinFunction_apply(call FunctionCall) Value { | ||||
| 	if !call.This.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	this := call.Argument(0) | ||||
| 	if this.IsUndefined() { | ||||
| 		// FIXME Not ECMA5
 | ||||
| 		this = toValue_object(call.runtime.GlobalObject) | ||||
| 		this = toValue_object(call.runtime.globalObject) | ||||
| 	} | ||||
| 	argumentList := call.Argument(1) | ||||
| 	switch argumentList._valueType { | ||||
| 	switch argumentList.kind { | ||||
| 	case valueUndefined, valueNull: | ||||
| 		return call.thisObject().Call(this, []Value{}) | ||||
| 		return call.thisObject().call(this, nil, false, nativeFrame) | ||||
| 	case valueObject: | ||||
| 	default: | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	arrayObject := argumentList._object() | ||||
| @ -80,29 +92,29 @@ func builtinFunction_apply(call FunctionCall) Value { | ||||
| 	for index := int64(0); index < length; index++ { | ||||
| 		valueArray[index] = arrayObject.get(arrayIndexToString(index)) | ||||
| 	} | ||||
| 	return thisObject.Call(this, valueArray) | ||||
| 	return thisObject.call(this, valueArray, false, nativeFrame) | ||||
| } | ||||
| 
 | ||||
| func builtinFunction_call(call FunctionCall) Value { | ||||
| 	if !call.This.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	thisObject := call.thisObject() | ||||
| 	this := call.Argument(0) | ||||
| 	if this.IsUndefined() { | ||||
| 		// FIXME Not ECMA5
 | ||||
| 		this = toValue_object(call.runtime.GlobalObject) | ||||
| 		this = toValue_object(call.runtime.globalObject) | ||||
| 	} | ||||
| 	if len(call.ArgumentList) >= 1 { | ||||
| 		return thisObject.Call(this, call.ArgumentList[1:]) | ||||
| 		return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame) | ||||
| 	} | ||||
| 	return thisObject.Call(this, []Value{}) | ||||
| 	return thisObject.call(this, nil, false, nativeFrame) | ||||
| } | ||||
| 
 | ||||
| func builtinFunction_bind(call FunctionCall) Value { | ||||
| 	target := call.This | ||||
| 	if !target.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	targetObject := target._object() | ||||
| 
 | ||||
| @ -110,7 +122,7 @@ func builtinFunction_bind(call FunctionCall) Value { | ||||
| 	argumentList := call.slice(1) | ||||
| 	if this.IsUndefined() { | ||||
| 		// FIXME Do this elsewhere?
 | ||||
| 		this = toValue_object(call.runtime.GlobalObject) | ||||
| 		this = toValue_object(call.runtime.globalObject) | ||||
| 	} | ||||
| 
 | ||||
| 	return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList)) | ||||
| @ -3,7 +3,7 @@ package otto | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"math" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| @ -23,13 +23,13 @@ func builtinJSON_parse(call FunctionCall) Value { | ||||
| 	} | ||||
| 
 | ||||
| 	var root interface{} | ||||
| 	err := json.Unmarshal([]byte(toString(call.Argument(0))), &root) | ||||
| 	err := json.Unmarshal([]byte(call.Argument(0).string()), &root) | ||||
| 	if err != nil { | ||||
| 		panic(newSyntaxError(err.Error())) | ||||
| 		panic(call.runtime.panicSyntaxError(err.Error())) | ||||
| 	} | ||||
| 	value, exists := builtinJSON_parseWalk(ctx, root) | ||||
| 	if !exists { | ||||
| 		value = UndefinedValue() | ||||
| 		value = Value{} | ||||
| 	} | ||||
| 	if revive { | ||||
| 		root := ctx.call.runtime.newObject() | ||||
| @ -65,13 +65,13 @@ func builtinJSON_reviveWalk(ctx _builtinJSON_parseContext, holder *_object, name | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return ctx.reviver.call(toValue_object(holder), name, value) | ||||
| 	return ctx.reviver.call(ctx.call.runtime, toValue_object(holder), name, value) | ||||
| } | ||||
| 
 | ||||
| func builtinJSON_parseWalk(ctx _builtinJSON_parseContext, rawValue interface{}) (Value, bool) { | ||||
| 	switch value := rawValue.(type) { | ||||
| 	case nil: | ||||
| 		return NullValue(), true | ||||
| 		return nullValue, true | ||||
| 	case bool: | ||||
| 		return toValue_bool(value), true | ||||
| 	case string: | ||||
| @ -120,7 +120,7 @@ func builtinJSON_stringify(call FunctionCall) Value { | ||||
| 			length = 0 | ||||
| 			for index, _ := range propertyList { | ||||
| 				value := replacer.get(arrayIndexToString(int64(index))) | ||||
| 				switch value._valueType { | ||||
| 				switch value.kind { | ||||
| 				case valueObject: | ||||
| 					switch value.value.(*_object).class { | ||||
| 					case "String": | ||||
| @ -133,7 +133,7 @@ func builtinJSON_stringify(call FunctionCall) Value { | ||||
| 				default: | ||||
| 					continue | ||||
| 				} | ||||
| 				name := toString(value) | ||||
| 				name := value.string() | ||||
| 				if seen[name] { | ||||
| 					continue | ||||
| 				} | ||||
| @ -148,24 +148,24 @@ func builtinJSON_stringify(call FunctionCall) Value { | ||||
| 		} | ||||
| 	} | ||||
| 	if spaceValue, exists := call.getArgument(2); exists { | ||||
| 		if spaceValue._valueType == valueObject { | ||||
| 		if spaceValue.kind == valueObject { | ||||
| 			switch spaceValue.value.(*_object).class { | ||||
| 			case "String": | ||||
| 				spaceValue = toValue_string(toString(spaceValue)) | ||||
| 				spaceValue = toValue_string(spaceValue.string()) | ||||
| 			case "Number": | ||||
| 				spaceValue = toNumber(spaceValue) | ||||
| 				spaceValue = spaceValue.numberValue() | ||||
| 			} | ||||
| 		} | ||||
| 		switch spaceValue._valueType { | ||||
| 		switch spaceValue.kind { | ||||
| 		case valueString: | ||||
| 			value := toString(spaceValue) | ||||
| 			value := spaceValue.string() | ||||
| 			if len(value) > 10 { | ||||
| 				ctx.gap = value[0:10] | ||||
| 			} else { | ||||
| 				ctx.gap = value | ||||
| 			} | ||||
| 		case valueNumber: | ||||
| 			value := toInteger(spaceValue).value | ||||
| 			value := spaceValue.number().int64 | ||||
| 			if value > 10 { | ||||
| 				value = 10 | ||||
| 			} else if value < 0 { | ||||
| @ -178,11 +178,11 @@ func builtinJSON_stringify(call FunctionCall) Value { | ||||
| 	holder.put("", call.Argument(0), false) | ||||
| 	value, exists := builtinJSON_stringifyWalk(ctx, "", holder) | ||||
| 	if !exists { | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	valueJSON, err := json.Marshal(value) | ||||
| 	if err != nil { | ||||
| 		panic(newTypeError(err.Error())) | ||||
| 		panic(call.runtime.panicTypeError(err.Error())) | ||||
| 	} | ||||
| 	if ctx.gap != "" { | ||||
| 		valueJSON1 := bytes.Buffer{} | ||||
| @ -198,7 +198,7 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho | ||||
| 	if value.IsObject() { | ||||
| 		object := value._object() | ||||
| 		if toJSON := object.get("toJSON"); toJSON.IsFunction() { | ||||
| 			value = toJSON.call(value, key) | ||||
| 			value = toJSON.call(ctx.call.runtime, value, key) | ||||
| 		} else { | ||||
| 			// If the object is a GoStruct or something that implements json.Marshaler
 | ||||
| 			if object.objectClass.marshalJSON != nil { | ||||
| @ -211,31 +211,35 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.replacerFunction != nil { | ||||
| 		value = (*ctx.replacerFunction).call(toValue_object(holder), key, value) | ||||
| 		value = (*ctx.replacerFunction).call(ctx.call.runtime, toValue_object(holder), key, value) | ||||
| 	} | ||||
| 
 | ||||
| 	if value._valueType == valueObject { | ||||
| 	if value.kind == valueObject { | ||||
| 		switch value.value.(*_object).class { | ||||
| 		case "Boolean": | ||||
| 			value = value._object().value.(Value) | ||||
| 		case "String": | ||||
| 			value = toValue_string(toString(value)) | ||||
| 			value = toValue_string(value.string()) | ||||
| 		case "Number": | ||||
| 			value = toNumber(value) | ||||
| 			value = value.numberValue() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueBoolean: | ||||
| 		return toBoolean(value), true | ||||
| 		return value.bool(), true | ||||
| 	case valueString: | ||||
| 		return toString(value), true | ||||
| 		return value.string(), true | ||||
| 	case valueNumber: | ||||
| 		value := toFloat(value) | ||||
| 		if math.IsNaN(value) || math.IsInf(value, 0) { | ||||
| 		integer := value.number() | ||||
| 		switch integer.kind { | ||||
| 		case numberInteger: | ||||
| 			return integer.int64, true | ||||
| 		case numberFloat: | ||||
| 			return integer.float64, true | ||||
| 		default: | ||||
| 			return nil, true | ||||
| 		} | ||||
| 		return value, true | ||||
| 	case valueNull: | ||||
| 		return nil, true | ||||
| 	case valueObject: | ||||
| @ -243,14 +247,24 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho | ||||
| 		if value := value._object(); nil != value { | ||||
| 			for _, object := range ctx.stack { | ||||
| 				if holder == object { | ||||
| 					panic(newTypeError("Converting circular structure to JSON")) | ||||
| 					panic(ctx.call.runtime.panicTypeError("Converting circular structure to JSON")) | ||||
| 				} | ||||
| 			} | ||||
| 			ctx.stack = append(ctx.stack, value) | ||||
| 			defer func() { ctx.stack = ctx.stack[:len(ctx.stack)-1] }() | ||||
| 		} | ||||
| 		if isArray(holder) { | ||||
| 			length := holder.get("length").value.(uint32) | ||||
| 			var length uint32 | ||||
| 			switch value := holder.get("length").value.(type) { | ||||
| 			case uint32: | ||||
| 				length = value | ||||
| 			case int: | ||||
| 				if value >= 0 { | ||||
| 					length = uint32(value) | ||||
| 				} | ||||
| 			default: | ||||
| 				panic(ctx.call.runtime.panicTypeError(fmt.Sprintf("JSON.stringify: invalid length: %v (%[1]T)", value))) | ||||
| 			} | ||||
| 			array := make([]interface{}, length) | ||||
| 			for index, _ := range array { | ||||
| 				name := arrayIndexToString(int64(index)) | ||||
| @ -8,31 +8,31 @@ import ( | ||||
| // Math
 | ||||
| 
 | ||||
| func builtinMath_abs(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Abs(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_acos(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Acos(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_asin(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Asin(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_atan(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Atan(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_atan2(call FunctionCall) Value { | ||||
| 	y := toFloat(call.Argument(0)) | ||||
| 	y := call.Argument(0).float64() | ||||
| 	if math.IsNaN(y) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| 	x := toFloat(call.Argument(1)) | ||||
| 	x := call.Argument(1).float64() | ||||
| 	if math.IsNaN(x) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -40,27 +40,27 @@ func builtinMath_atan2(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinMath_cos(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Cos(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_ceil(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Ceil(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_exp(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Exp(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_floor(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Floor(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_log(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Log(number)) | ||||
| } | ||||
| 
 | ||||
| @ -69,14 +69,14 @@ func builtinMath_max(call FunctionCall) Value { | ||||
| 	case 0: | ||||
| 		return negativeInfinityValue() | ||||
| 	case 1: | ||||
| 		return toValue_float64(toFloat(call.ArgumentList[0])) | ||||
| 		return toValue_float64(call.ArgumentList[0].float64()) | ||||
| 	} | ||||
| 	result := toFloat(call.ArgumentList[0]) | ||||
| 	result := call.ArgumentList[0].float64() | ||||
| 	if math.IsNaN(result) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| 	for _, value := range call.ArgumentList[1:] { | ||||
| 		value := toFloat(value) | ||||
| 		value := value.float64() | ||||
| 		if math.IsNaN(value) { | ||||
| 			return NaNValue() | ||||
| 		} | ||||
| @ -90,14 +90,14 @@ func builtinMath_min(call FunctionCall) Value { | ||||
| 	case 0: | ||||
| 		return positiveInfinityValue() | ||||
| 	case 1: | ||||
| 		return toValue_float64(toFloat(call.ArgumentList[0])) | ||||
| 		return toValue_float64(call.ArgumentList[0].float64()) | ||||
| 	} | ||||
| 	result := toFloat(call.ArgumentList[0]) | ||||
| 	result := call.ArgumentList[0].float64() | ||||
| 	if math.IsNaN(result) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| 	for _, value := range call.ArgumentList[1:] { | ||||
| 		value := toFloat(value) | ||||
| 		value := value.float64() | ||||
| 		if math.IsNaN(value) { | ||||
| 			return NaNValue() | ||||
| 		} | ||||
| @ -108,8 +108,8 @@ func builtinMath_min(call FunctionCall) Value { | ||||
| 
 | ||||
| func builtinMath_pow(call FunctionCall) Value { | ||||
| 	// TODO Make sure this works according to the specification (15.8.2.13)
 | ||||
| 	x := toFloat(call.Argument(0)) | ||||
| 	y := toFloat(call.Argument(1)) | ||||
| 	x := call.Argument(0).float64() | ||||
| 	y := call.Argument(1).float64() | ||||
| 	if math.Abs(x) == 1 && math.IsInf(y, 0) { | ||||
| 		return NaNValue() | ||||
| 	} | ||||
| @ -121,7 +121,7 @@ func builtinMath_random(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinMath_round(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	value := math.Floor(number + 0.5) | ||||
| 	if value == 0 { | ||||
| 		value = math.Copysign(0, number) | ||||
| @ -130,16 +130,16 @@ func builtinMath_round(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinMath_sin(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Sin(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_sqrt(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Sqrt(number)) | ||||
| } | ||||
| 
 | ||||
| func builtinMath_tan(call FunctionCall) Value { | ||||
| 	number := toFloat(call.Argument(0)) | ||||
| 	number := call.Argument(0).float64() | ||||
| 	return toValue_float64(math.Tan(number)) | ||||
| } | ||||
| @ -9,7 +9,7 @@ import ( | ||||
| 
 | ||||
| func numberValueFromNumberArgumentList(argumentList []Value) Value { | ||||
| 	if len(argumentList) > 0 { | ||||
| 		return toNumber(argumentList[0]) | ||||
| 		return argumentList[0].numberValue() | ||||
| 	} | ||||
| 	return toValue_int(0) | ||||
| } | ||||
| @ -18,7 +18,7 @@ func builtinNumber(call FunctionCall) Value { | ||||
| 	return numberValueFromNumberArgumentList(call.ArgumentList) | ||||
| } | ||||
| 
 | ||||
| func builtinNewNumber(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewNumber(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newNumber(numberValueFromNumberArgumentList(argumentList))) | ||||
| } | ||||
| 
 | ||||
| @ -30,12 +30,12 @@ func builtinNumber_toString(call FunctionCall) Value { | ||||
| 	if radixArgument.IsDefined() { | ||||
| 		integer := toIntegerFloat(radixArgument) | ||||
| 		if integer < 2 || integer > 36 { | ||||
| 			panic(newRangeError("RangeError: toString() radix must be between 2 and 36")) | ||||
| 			panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36")) | ||||
| 		} | ||||
| 		radix = int(integer) | ||||
| 	} | ||||
| 	if radix == 10 { | ||||
| 		return toValue_string(toString(value)) | ||||
| 		return toValue_string(value.string()) | ||||
| 	} | ||||
| 	return toValue_string(numberToStringRadix(value, radix)) | ||||
| } | ||||
| @ -47,16 +47,16 @@ func builtinNumber_valueOf(call FunctionCall) Value { | ||||
| func builtinNumber_toFixed(call FunctionCall) Value { | ||||
| 	precision := toIntegerFloat(call.Argument(0)) | ||||
| 	if 20 < precision || 0 > precision { | ||||
| 		panic(newRangeError("toFixed() precision must be between 0 and 20")) | ||||
| 		panic(call.runtime.panicRangeError("toFixed() precision must be between 0 and 20")) | ||||
| 	} | ||||
| 	if call.This.IsNaN() { | ||||
| 		return toValue_string("NaN") | ||||
| 	} | ||||
| 	value := toFloat(call.This) | ||||
| 	value := call.This.float64() | ||||
| 	if math.Abs(value) >= 1e21 { | ||||
| 		return toValue_string(floatToString(value, 64)) | ||||
| 	} | ||||
| 	return toValue_string(strconv.FormatFloat(toFloat(call.This), 'f', int(precision), 64)) | ||||
| 	return toValue_string(strconv.FormatFloat(call.This.float64(), 'f', int(precision), 64)) | ||||
| } | ||||
| 
 | ||||
| func builtinNumber_toExponential(call FunctionCall) Value { | ||||
| @ -67,10 +67,10 @@ func builtinNumber_toExponential(call FunctionCall) Value { | ||||
| 	if value := call.Argument(0); value.IsDefined() { | ||||
| 		precision = toIntegerFloat(value) | ||||
| 		if 0 > precision { | ||||
| 			panic(newRangeError("RangeError: toExponential() precision must be greater than 0")) | ||||
| 			panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36")) | ||||
| 		} | ||||
| 	} | ||||
| 	return toValue_string(strconv.FormatFloat(toFloat(call.This), 'e', int(precision), 64)) | ||||
| 	return toValue_string(strconv.FormatFloat(call.This.float64(), 'e', int(precision), 64)) | ||||
| } | ||||
| 
 | ||||
| func builtinNumber_toPrecision(call FunctionCall) Value { | ||||
| @ -79,13 +79,13 @@ func builtinNumber_toPrecision(call FunctionCall) Value { | ||||
| 	} | ||||
| 	value := call.Argument(0) | ||||
| 	if value.IsUndefined() { | ||||
| 		return toValue_string(toString(call.This)) | ||||
| 		return toValue_string(call.This.string()) | ||||
| 	} | ||||
| 	precision := toIntegerFloat(value) | ||||
| 	if 1 > precision { | ||||
| 		panic(newRangeError("RangeError: toPrecision() precision must be greater than 1")) | ||||
| 		panic(call.runtime.panicRangeError("RangeError: toPrecision() precision must be greater than 1")) | ||||
| 	} | ||||
| 	return toValue_string(strconv.FormatFloat(toFloat(call.This), 'g', int(precision), 64)) | ||||
| 	return toValue_string(strconv.FormatFloat(call.This.float64(), 'g', int(precision), 64)) | ||||
| } | ||||
| 
 | ||||
| func builtinNumber_toLocaleString(call FunctionCall) Value { | ||||
| @ -8,7 +8,7 @@ import ( | ||||
| 
 | ||||
| func builtinObject(call FunctionCall) Value { | ||||
| 	value := call.Argument(0) | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueUndefined, valueNull: | ||||
| 		return toValue_object(call.runtime.newObject()) | ||||
| 	} | ||||
| @ -16,9 +16,9 @@ func builtinObject(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.toObject(value)) | ||||
| } | ||||
| 
 | ||||
| func builtinNewObject(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewObject(self *_object, argumentList []Value) Value { | ||||
| 	value := valueOfArrayIndex(argumentList, 0) | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueNull, valueUndefined: | ||||
| 	case valueNumber, valueString, valueBoolean: | ||||
| 		return toValue_object(self.runtime.toObject(value)) | ||||
| @ -34,7 +34,7 @@ func builtinObject_valueOf(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinObject_hasOwnProperty(call FunctionCall) Value { | ||||
| 	propertyName := toString(call.Argument(0)) | ||||
| 	propertyName := call.Argument(0).string() | ||||
| 	thisObject := call.thisObject() | ||||
| 	return toValue_bool(thisObject.hasOwnProperty(propertyName)) | ||||
| } | ||||
| @ -42,27 +42,27 @@ func builtinObject_hasOwnProperty(call FunctionCall) Value { | ||||
| func builtinObject_isPrototypeOf(call FunctionCall) Value { | ||||
| 	value := call.Argument(0) | ||||
| 	if !value.IsObject() { | ||||
| 		return FalseValue() | ||||
| 		return falseValue | ||||
| 	} | ||||
| 	prototype := call.toObject(value).prototype | ||||
| 	thisObject := call.thisObject() | ||||
| 	for prototype != nil { | ||||
| 		if thisObject == prototype { | ||||
| 			return TrueValue() | ||||
| 			return trueValue | ||||
| 		} | ||||
| 		prototype = prototype.prototype | ||||
| 	} | ||||
| 	return FalseValue() | ||||
| 	return falseValue | ||||
| } | ||||
| 
 | ||||
| func builtinObject_propertyIsEnumerable(call FunctionCall) Value { | ||||
| 	propertyName := toString(call.Argument(0)) | ||||
| 	propertyName := call.Argument(0).string() | ||||
| 	thisObject := call.thisObject() | ||||
| 	property := thisObject.getOwnProperty(propertyName) | ||||
| 	if property != nil && property.enumerable() { | ||||
| 		return TrueValue() | ||||
| 		return trueValue | ||||
| 	} | ||||
| 	return FalseValue() | ||||
| 	return falseValue | ||||
| } | ||||
| 
 | ||||
| func builtinObject_toString(call FunctionCall) Value { | ||||
| @ -80,20 +80,20 @@ func builtinObject_toString(call FunctionCall) Value { | ||||
| func builtinObject_toLocaleString(call FunctionCall) Value { | ||||
| 	toString := call.thisObject().get("toString") | ||||
| 	if !toString.isCallable() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return toString.call(call.This) | ||||
| 	return toString.call(call.runtime, call.This) | ||||
| } | ||||
| 
 | ||||
| func builtinObject_getPrototypeOf(call FunctionCall) Value { | ||||
| 	objectValue := call.Argument(0) | ||||
| 	object := objectValue._object() | ||||
| 	if object == nil { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	if object.prototype == nil { | ||||
| 		return NullValue() | ||||
| 		return nullValue | ||||
| 	} | ||||
| 
 | ||||
| 	return toValue_object(object.prototype) | ||||
| @ -103,13 +103,13 @@ func builtinObject_getOwnPropertyDescriptor(call FunctionCall) Value { | ||||
| 	objectValue := call.Argument(0) | ||||
| 	object := objectValue._object() | ||||
| 	if object == nil { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	name := toString(call.Argument(1)) | ||||
| 	name := call.Argument(1).string() | ||||
| 	descriptor := object.getOwnProperty(name) | ||||
| 	if descriptor == nil { | ||||
| 		return UndefinedValue() | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	return toValue_object(call.runtime.fromPropertyDescriptor(*descriptor)) | ||||
| } | ||||
| @ -118,10 +118,10 @@ func builtinObject_defineProperty(call FunctionCall) Value { | ||||
| 	objectValue := call.Argument(0) | ||||
| 	object := objectValue._object() | ||||
| 	if object == nil { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	name := toString(call.Argument(1)) | ||||
| 	descriptor := toPropertyDescriptor(call.Argument(2)) | ||||
| 	name := call.Argument(1).string() | ||||
| 	descriptor := toPropertyDescriptor(call.runtime, call.Argument(2)) | ||||
| 	object.defineOwnProperty(name, descriptor, true) | ||||
| 	return objectValue | ||||
| } | ||||
| @ -130,12 +130,12 @@ func builtinObject_defineProperties(call FunctionCall) Value { | ||||
| 	objectValue := call.Argument(0) | ||||
| 	object := objectValue._object() | ||||
| 	if object == nil { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	properties := call.runtime.toObject(call.Argument(1)) | ||||
| 	properties.enumerate(false, func(name string) bool { | ||||
| 		descriptor := toPropertyDescriptor(properties.get(name)) | ||||
| 		descriptor := toPropertyDescriptor(call.runtime, properties.get(name)) | ||||
| 		object.defineOwnProperty(name, descriptor, true) | ||||
| 		return true | ||||
| 	}) | ||||
| @ -146,7 +146,7 @@ func builtinObject_defineProperties(call FunctionCall) Value { | ||||
| func builtinObject_create(call FunctionCall) Value { | ||||
| 	prototypeValue := call.Argument(0) | ||||
| 	if !prototypeValue.IsNull() && !prototypeValue.IsObject() { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	object := call.runtime.newObject() | ||||
| @ -156,7 +156,7 @@ func builtinObject_create(call FunctionCall) Value { | ||||
| 	if propertiesValue.IsDefined() { | ||||
| 		properties := call.runtime.toObject(propertiesValue) | ||||
| 		properties.enumerate(false, func(name string) bool { | ||||
| 			descriptor := toPropertyDescriptor(properties.get(name)) | ||||
| 			descriptor := toPropertyDescriptor(call.runtime, properties.get(name)) | ||||
| 			object.defineOwnProperty(name, descriptor, true) | ||||
| 			return true | ||||
| 		}) | ||||
| @ -170,7 +170,7 @@ func builtinObject_isExtensible(call FunctionCall) Value { | ||||
| 	if object := object._object(); object != nil { | ||||
| 		return toValue_bool(object.extensible) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinObject_preventExtensions(call FunctionCall) Value { | ||||
| @ -178,7 +178,7 @@ func builtinObject_preventExtensions(call FunctionCall) Value { | ||||
| 	if object := object._object(); object != nil { | ||||
| 		object.extensible = false | ||||
| 	} else { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return object | ||||
| } | ||||
| @ -199,7 +199,7 @@ func builtinObject_isSealed(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		return toValue_bool(result) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinObject_seal(call FunctionCall) Value { | ||||
| @ -214,7 +214,7 @@ func builtinObject_seal(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		object.extensible = false | ||||
| 	} else { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return object | ||||
| } | ||||
| @ -235,7 +235,7 @@ func builtinObject_isFrozen(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		return toValue_bool(result) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinObject_freeze(call FunctionCall) Value { | ||||
| @ -259,7 +259,7 @@ func builtinObject_freeze(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		object.extensible = false | ||||
| 	} else { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(call.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return object | ||||
| } | ||||
| @ -272,7 +272,7 @@ func builtinObject_keys(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		return toValue_object(call.runtime.newArrayOf(keys)) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func builtinObject_getOwnPropertyNames(call FunctionCall) Value { | ||||
| @ -285,5 +285,5 @@ func builtinObject_getOwnPropertyNames(call FunctionCall) Value { | ||||
| 		}) | ||||
| 		return toValue_object(call.runtime.newArrayOf(propertyNames)) | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(call.runtime.panicTypeError()) | ||||
| } | ||||
| @ -17,7 +17,7 @@ func builtinRegExp(call FunctionCall) Value { | ||||
| 	return toValue_object(call.runtime.newRegExp(pattern, flags)) | ||||
| } | ||||
| 
 | ||||
| func builtinNewRegExp(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewRegExp(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newRegExp( | ||||
| 		valueOfArrayIndex(argumentList, 0), | ||||
| 		valueOfArrayIndex(argumentList, 1), | ||||
| @ -26,15 +26,15 @@ func builtinNewRegExp(self *_object, _ Value, argumentList []Value) Value { | ||||
| 
 | ||||
| func builtinRegExp_toString(call FunctionCall) Value { | ||||
| 	thisObject := call.thisObject() | ||||
| 	source := toString(thisObject.get("source")) | ||||
| 	source := thisObject.get("source").string() | ||||
| 	flags := []byte{} | ||||
| 	if toBoolean(thisObject.get("global")) { | ||||
| 	if thisObject.get("global").bool() { | ||||
| 		flags = append(flags, 'g') | ||||
| 	} | ||||
| 	if toBoolean(thisObject.get("ignoreCase")) { | ||||
| 	if thisObject.get("ignoreCase").bool() { | ||||
| 		flags = append(flags, 'i') | ||||
| 	} | ||||
| 	if toBoolean(thisObject.get("multiline")) { | ||||
| 	if thisObject.get("multiline").bool() { | ||||
| 		flags = append(flags, 'm') | ||||
| 	} | ||||
| 	return toValue_string(fmt.Sprintf("/%s/%s", source, flags)) | ||||
| @ -42,17 +42,17 @@ func builtinRegExp_toString(call FunctionCall) Value { | ||||
| 
 | ||||
| func builtinRegExp_exec(call FunctionCall) Value { | ||||
| 	thisObject := call.thisObject() | ||||
| 	target := toString(call.Argument(0)) | ||||
| 	target := call.Argument(0).string() | ||||
| 	match, result := execRegExp(thisObject, target) | ||||
| 	if !match { | ||||
| 		return NullValue() | ||||
| 		return nullValue | ||||
| 	} | ||||
| 	return toValue_object(execResultToArray(call.runtime, target, result)) | ||||
| } | ||||
| 
 | ||||
| func builtinRegExp_test(call FunctionCall) Value { | ||||
| 	thisObject := call.thisObject() | ||||
| 	target := toString(call.Argument(0)) | ||||
| 	target := call.Argument(0).string() | ||||
| 	match, _ := execRegExp(thisObject, target) | ||||
| 	return toValue_bool(match) | ||||
| } | ||||
| @ -61,5 +61,5 @@ func builtinRegExp_compile(call FunctionCall) Value { | ||||
| 	// This (useless) function is deprecated, but is here to provide some
 | ||||
| 	// semblance of compatibility.
 | ||||
| 	// Caveat emptor: it may not be around for long.
 | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| @ -12,7 +12,7 @@ import ( | ||||
| 
 | ||||
| func stringValueFromStringArgumentList(argumentList []Value) Value { | ||||
| 	if len(argumentList) > 0 { | ||||
| 		return toValue_string(toString(argumentList[0])) | ||||
| 		return toValue_string(argumentList[0].string()) | ||||
| 	} | ||||
| 	return toValue_string("") | ||||
| } | ||||
| @ -21,7 +21,7 @@ func builtinString(call FunctionCall) Value { | ||||
| 	return stringValueFromStringArgumentList(call.ArgumentList) | ||||
| } | ||||
| 
 | ||||
| func builtinNewString(self *_object, _ Value, argumentList []Value) Value { | ||||
| func builtinNewString(self *_object, argumentList []Value) Value { | ||||
| 	return toValue_object(self.runtime.newString(stringValueFromStringArgumentList(argumentList))) | ||||
| } | ||||
| 
 | ||||
| @ -41,8 +41,8 @@ func builtinString_fromCharCode(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_charAt(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	idx := int(toInteger(call.Argument(0)).value) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	idx := int(call.Argument(0).number().int64) | ||||
| 	chr := stringAt(call.This._object().stringValue(), idx) | ||||
| 	if chr == utf8.RuneError { | ||||
| 		return toValue_string("") | ||||
| @ -51,8 +51,8 @@ func builtinString_charAt(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_charCodeAt(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	idx := int(toInteger(call.Argument(0)).value) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	idx := int(call.Argument(0).number().int64) | ||||
| 	chr := stringAt(call.This._object().stringValue(), idx) | ||||
| 	if chr == utf8.RuneError { | ||||
| 		return NaNValue() | ||||
| @ -61,19 +61,19 @@ func builtinString_charCodeAt(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_concat(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	var value bytes.Buffer | ||||
| 	value.WriteString(toString(call.This)) | ||||
| 	value.WriteString(call.This.string()) | ||||
| 	for _, item := range call.ArgumentList { | ||||
| 		value.WriteString(toString(item)) | ||||
| 		value.WriteString(item.string()) | ||||
| 	} | ||||
| 	return toValue_string(value.String()) | ||||
| } | ||||
| 
 | ||||
| func builtinString_indexOf(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	value := toString(call.This) | ||||
| 	target := toString(call.Argument(0)) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	value := call.This.string() | ||||
| 	target := call.Argument(0).string() | ||||
| 	if 2 > len(call.ArgumentList) { | ||||
| 		return toValue_int(strings.Index(value, target)) | ||||
| 	} | ||||
| @ -94,9 +94,9 @@ func builtinString_indexOf(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_lastIndexOf(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	value := toString(call.This) | ||||
| 	target := toString(call.Argument(0)) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	value := call.This.string() | ||||
| 	target := call.Argument(0).string() | ||||
| 	if 2 > len(call.ArgumentList) || call.ArgumentList[1].IsUndefined() { | ||||
| 		return toValue_int(strings.LastIndex(value, target)) | ||||
| 	} | ||||
| @ -104,15 +104,15 @@ func builtinString_lastIndexOf(call FunctionCall) Value { | ||||
| 	if length == 0 { | ||||
| 		return toValue_int(strings.LastIndex(value, target)) | ||||
| 	} | ||||
| 	start := toInteger(call.ArgumentList[1]) | ||||
| 	if !start.valid() { | ||||
| 	start := call.ArgumentList[1].number() | ||||
| 	if start.kind == numberInfinity { // FIXME
 | ||||
| 		// startNumber is infinity, so start is the end of string (start = length)
 | ||||
| 		return toValue_int(strings.LastIndex(value, target)) | ||||
| 	} | ||||
| 	if 0 > start.value { | ||||
| 		start.value = 0 | ||||
| 	if 0 > start.int64 { | ||||
| 		start.int64 = 0 | ||||
| 	} | ||||
| 	end := int(start.value) + len(target) | ||||
| 	end := int(start.int64) + len(target) | ||||
| 	if end > length { | ||||
| 		end = length | ||||
| 	} | ||||
| @ -120,18 +120,18 @@ func builtinString_lastIndexOf(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_match(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := toString(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := call.This.string() | ||||
| 	matcherValue := call.Argument(0) | ||||
| 	matcher := matcherValue._object() | ||||
| 	if !matcherValue.IsObject() || matcher.class != "RegExp" { | ||||
| 		matcher = call.runtime.newRegExp(matcherValue, UndefinedValue()) | ||||
| 		matcher = call.runtime.newRegExp(matcherValue, Value{}) | ||||
| 	} | ||||
| 	global := toBoolean(matcher.get("global")) | ||||
| 	global := matcher.get("global").bool() | ||||
| 	if !global { | ||||
| 		match, result := execRegExp(matcher, target) | ||||
| 		if !match { | ||||
| 			return NullValue() | ||||
| 			return nullValue | ||||
| 		} | ||||
| 		return toValue_object(execResultToArray(call.runtime, target, result)) | ||||
| 	} | ||||
| @ -141,7 +141,7 @@ func builtinString_match(call FunctionCall) Value { | ||||
| 		matchCount := len(result) | ||||
| 		if result == nil { | ||||
| 			matcher.put("lastIndex", toValue_int(0), true) | ||||
| 			return UndefinedValue() // !match
 | ||||
| 			return Value{} // !match
 | ||||
| 		} | ||||
| 		matchCount = len(result) | ||||
| 		valueArray := make([]Value, matchCount) | ||||
| @ -189,8 +189,8 @@ func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int | ||||
| } | ||||
| 
 | ||||
| func builtinString_replace(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := []byte(toString(call.This)) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := []byte(call.This.string()) | ||||
| 	searchValue := call.Argument(0) | ||||
| 	searchObject := searchValue._object() | ||||
| 
 | ||||
| @ -205,7 +205,7 @@ func builtinString_replace(call FunctionCall) Value { | ||||
| 			find = -1 | ||||
| 		} | ||||
| 	} else { | ||||
| 		search = regexp.MustCompile(regexp.QuoteMeta(toString(searchValue))) | ||||
| 		search = regexp.MustCompile(regexp.QuoteMeta(searchValue.string())) | ||||
| 	} | ||||
| 
 | ||||
| 	found := search.FindAllSubmatchIndex(target, find) | ||||
| @ -232,18 +232,18 @@ func builtinString_replace(call FunctionCall) Value { | ||||
| 					if match[offset] != -1 { | ||||
| 						argumentList[index] = toValue_string(target[match[offset]:match[offset+1]]) | ||||
| 					} else { | ||||
| 						argumentList[index] = UndefinedValue() | ||||
| 						argumentList[index] = Value{} | ||||
| 					} | ||||
| 				} | ||||
| 				argumentList[matchCount+0] = toValue_int(match[0]) | ||||
| 				argumentList[matchCount+1] = toValue_string(target) | ||||
| 				replacement := toString(replace.Call(UndefinedValue(), argumentList)) | ||||
| 				replacement := replace.call(Value{}, argumentList, false, nativeFrame).string() | ||||
| 				result = append(result, []byte(replacement)...) | ||||
| 				lastIndex = match[1] | ||||
| 			} | ||||
| 
 | ||||
| 		} else { | ||||
| 			replace := []byte(toString(replaceValue)) | ||||
| 			replace := []byte(replaceValue.string()) | ||||
| 			for _, match := range found { | ||||
| 				result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace) | ||||
| 				lastIndex = match[1] | ||||
| @ -260,17 +260,15 @@ func builtinString_replace(call FunctionCall) Value { | ||||
| 
 | ||||
| 		return toValue_string(string(result)) | ||||
| 	} | ||||
| 
 | ||||
| 	return UndefinedValue() | ||||
| } | ||||
| 
 | ||||
| func builtinString_search(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := toString(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := call.This.string() | ||||
| 	searchValue := call.Argument(0) | ||||
| 	search := searchValue._object() | ||||
| 	if !searchValue.IsObject() || search.class != "RegExp" { | ||||
| 		search = call.runtime.newRegExp(searchValue, UndefinedValue()) | ||||
| 		search = call.runtime.newRegExp(searchValue, Value{}) | ||||
| 	} | ||||
| 	result := search.regExpValue().regularExpression.FindStringIndex(target) | ||||
| 	if result == nil { | ||||
| @ -291,8 +289,8 @@ func stringSplitMatch(target string, targetLength int64, index uint, search stri | ||||
| } | ||||
| 
 | ||||
| func builtinString_split(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := toString(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := call.This.string() | ||||
| 
 | ||||
| 	separatorValue := call.Argument(0) | ||||
| 	limitValue := call.Argument(1) | ||||
| @ -343,7 +341,7 @@ func builtinString_split(call FunctionCall) Value { | ||||
| 			captureCount := len(match) / 2 | ||||
| 			for index := 1; index < captureCount; index++ { | ||||
| 				offset := index * 2 | ||||
| 				value := UndefinedValue() | ||||
| 				value := Value{} | ||||
| 				if match[offset] != -1 { | ||||
| 					value = toValue_string(target[match[offset]:match[offset+1]]) | ||||
| 				} | ||||
| @ -367,7 +365,7 @@ func builtinString_split(call FunctionCall) Value { | ||||
| 		return toValue_object(call.runtime.newArrayOf(valueArray)) | ||||
| 
 | ||||
| 	} else { | ||||
| 		separator := toString(separatorValue) | ||||
| 		separator := separatorValue.string() | ||||
| 
 | ||||
| 		splitLimit := limit | ||||
| 		excess := false | ||||
| @ -389,13 +387,11 @@ func builtinString_split(call FunctionCall) Value { | ||||
| 
 | ||||
| 		return toValue_object(call.runtime.newArrayOf(valueArray)) | ||||
| 	} | ||||
| 
 | ||||
| 	return UndefinedValue() | ||||
| } | ||||
| 
 | ||||
| func builtinString_slice(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := toString(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := call.This.string() | ||||
| 
 | ||||
| 	length := int64(len(target)) | ||||
| 	start, end := rangeStartEnd(call.ArgumentList, length, false) | ||||
| @ -406,8 +402,8 @@ func builtinString_slice(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_substring(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	target := toString(call.This) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	target := call.This.string() | ||||
| 
 | ||||
| 	length := int64(len(target)) | ||||
| 	start, end := rangeStartEnd(call.ArgumentList, length, true) | ||||
| @ -418,7 +414,7 @@ func builtinString_substring(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_substr(call FunctionCall) Value { | ||||
| 	target := toString(call.This) | ||||
| 	target := call.This.string() | ||||
| 
 | ||||
| 	size := int64(len(target)) | ||||
| 	start, length := rangeStartLength(call.ArgumentList, size) | ||||
| @ -443,42 +439,42 @@ func builtinString_substr(call FunctionCall) Value { | ||||
| } | ||||
| 
 | ||||
| func builtinString_toLowerCase(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue_string(strings.ToLower(toString(call.This))) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	return toValue_string(strings.ToLower(call.This.string())) | ||||
| } | ||||
| 
 | ||||
| func builtinString_toUpperCase(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue_string(strings.ToUpper(toString(call.This))) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	return toValue_string(strings.ToUpper(call.This.string())) | ||||
| } | ||||
| 
 | ||||
| // 7.2 Table 2 — Whitespace Characters & 7.3 Table 3 - Line Terminator Characters
 | ||||
| const builtinString_trim_whitespace = "\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF" | ||||
| 
 | ||||
| func builtinString_trim(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue(strings.Trim(toString(call.This), | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	return toValue(strings.Trim(call.This.string(), | ||||
| 		builtinString_trim_whitespace)) | ||||
| } | ||||
| 
 | ||||
| // Mozilla extension, not ECMAScript 5
 | ||||
| func builtinString_trimLeft(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue(strings.TrimLeft(toString(call.This), | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	return toValue(strings.TrimLeft(call.This.string(), | ||||
| 		builtinString_trim_whitespace)) | ||||
| } | ||||
| 
 | ||||
| // Mozilla extension, not ECMAScript 5
 | ||||
| func builtinString_trimRight(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue(strings.TrimRight(toString(call.This), | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	return toValue(strings.TrimRight(call.This.string(), | ||||
| 		builtinString_trim_whitespace)) | ||||
| } | ||||
| 
 | ||||
| func builtinString_localeCompare(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	this := toString(call.This) | ||||
| 	that := toString(call.Argument(0)) | ||||
| 	checkObjectCoercible(call.runtime, call.This) | ||||
| 	this := call.This.string() | ||||
| 	that := call.Argument(0).string() | ||||
| 	if this < that { | ||||
| 		return toValue_int(-1) | ||||
| 	} else if this == that { | ||||
| @ -491,7 +487,7 @@ func builtinString_localeCompare(call FunctionCall) Value { | ||||
| An alternate version of String.trim | ||||
| func builtinString_trim(call FunctionCall) Value { | ||||
| 	checkObjectCoercible(call.This) | ||||
| 	return toValue_string(strings.TrimFunc(toString(call.This), isWhiteSpaceOrLineTerminator)) | ||||
| 	return toValue_string(strings.TrimFunc(call.string(.This), isWhiteSpaceOrLineTerminator)) | ||||
| } | ||||
| */ | ||||
| 
 | ||||
							
								
								
									
										155
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/clone.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,155 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| type _clone struct { | ||||
| 	runtime      *_runtime | ||||
| 	_object      map[*_object]*_object | ||||
| 	_objectStash map[*_objectStash]*_objectStash | ||||
| 	_dclStash    map[*_dclStash]*_dclStash | ||||
| 	_fnStash     map[*_fnStash]*_fnStash | ||||
| } | ||||
| 
 | ||||
| func (in *_runtime) clone() *_runtime { | ||||
| 
 | ||||
| 	in.lck.Lock() | ||||
| 	defer in.lck.Unlock() | ||||
| 
 | ||||
| 	out := &_runtime{} | ||||
| 	clone := _clone{ | ||||
| 		runtime:      out, | ||||
| 		_object:      make(map[*_object]*_object), | ||||
| 		_objectStash: make(map[*_objectStash]*_objectStash), | ||||
| 		_dclStash:    make(map[*_dclStash]*_dclStash), | ||||
| 		_fnStash:     make(map[*_fnStash]*_fnStash), | ||||
| 	} | ||||
| 
 | ||||
| 	globalObject := clone.object(in.globalObject) | ||||
| 	out.globalStash = out.newObjectStash(globalObject, nil) | ||||
| 	out.globalObject = globalObject | ||||
| 	out.global = _global{ | ||||
| 		clone.object(in.global.Object), | ||||
| 		clone.object(in.global.Function), | ||||
| 		clone.object(in.global.Array), | ||||
| 		clone.object(in.global.String), | ||||
| 		clone.object(in.global.Boolean), | ||||
| 		clone.object(in.global.Number), | ||||
| 		clone.object(in.global.Math), | ||||
| 		clone.object(in.global.Date), | ||||
| 		clone.object(in.global.RegExp), | ||||
| 		clone.object(in.global.Error), | ||||
| 		clone.object(in.global.EvalError), | ||||
| 		clone.object(in.global.TypeError), | ||||
| 		clone.object(in.global.RangeError), | ||||
| 		clone.object(in.global.ReferenceError), | ||||
| 		clone.object(in.global.SyntaxError), | ||||
| 		clone.object(in.global.URIError), | ||||
| 		clone.object(in.global.JSON), | ||||
| 
 | ||||
| 		clone.object(in.global.ObjectPrototype), | ||||
| 		clone.object(in.global.FunctionPrototype), | ||||
| 		clone.object(in.global.ArrayPrototype), | ||||
| 		clone.object(in.global.StringPrototype), | ||||
| 		clone.object(in.global.BooleanPrototype), | ||||
| 		clone.object(in.global.NumberPrototype), | ||||
| 		clone.object(in.global.DatePrototype), | ||||
| 		clone.object(in.global.RegExpPrototype), | ||||
| 		clone.object(in.global.ErrorPrototype), | ||||
| 		clone.object(in.global.EvalErrorPrototype), | ||||
| 		clone.object(in.global.TypeErrorPrototype), | ||||
| 		clone.object(in.global.RangeErrorPrototype), | ||||
| 		clone.object(in.global.ReferenceErrorPrototype), | ||||
| 		clone.object(in.global.SyntaxErrorPrototype), | ||||
| 		clone.object(in.global.URIErrorPrototype), | ||||
| 	} | ||||
| 
 | ||||
| 	out.eval = out.globalObject.property["eval"].value.(Value).value.(*_object) | ||||
| 	out.globalObject.prototype = out.global.ObjectPrototype | ||||
| 
 | ||||
| 	// Not sure if this is necessary, but give some help to the GC
 | ||||
| 	clone.runtime = nil | ||||
| 	clone._object = nil | ||||
| 	clone._objectStash = nil | ||||
| 	clone._dclStash = nil | ||||
| 	clone._fnStash = nil | ||||
| 
 | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) object(in *_object) *_object { | ||||
| 	if out, exists := clone._object[in]; exists { | ||||
| 		return out | ||||
| 	} | ||||
| 	out := &_object{} | ||||
| 	clone._object[in] = out | ||||
| 	return in.objectClass.clone(in, out, clone) | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) dclStash(in *_dclStash) (*_dclStash, bool) { | ||||
| 	if out, exists := clone._dclStash[in]; exists { | ||||
| 		return out, true | ||||
| 	} | ||||
| 	out := &_dclStash{} | ||||
| 	clone._dclStash[in] = out | ||||
| 	return out, false | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) objectStash(in *_objectStash) (*_objectStash, bool) { | ||||
| 	if out, exists := clone._objectStash[in]; exists { | ||||
| 		return out, true | ||||
| 	} | ||||
| 	out := &_objectStash{} | ||||
| 	clone._objectStash[in] = out | ||||
| 	return out, false | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) fnStash(in *_fnStash) (*_fnStash, bool) { | ||||
| 	if out, exists := clone._fnStash[in]; exists { | ||||
| 		return out, true | ||||
| 	} | ||||
| 	out := &_fnStash{} | ||||
| 	clone._fnStash[in] = out | ||||
| 	return out, false | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) value(in Value) Value { | ||||
| 	out := in | ||||
| 	switch value := in.value.(type) { | ||||
| 	case *_object: | ||||
| 		out.value = clone.object(value) | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) valueArray(in []Value) []Value { | ||||
| 	out := make([]Value, len(in)) | ||||
| 	for index, value := range in { | ||||
| 		out[index] = clone.value(value) | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) stash(in _stash) _stash { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return in.clone(clone) | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) property(in _property) _property { | ||||
| 	out := in | ||||
| 	if value, valid := in.value.(Value); valid { | ||||
| 		out.value = clone.value(value) | ||||
| 	} else { | ||||
| 		panic(fmt.Errorf("in.value.(Value) != true")) | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (clone *_clone) dclProperty(in _dclProperty) _dclProperty { | ||||
| 	out := in | ||||
| 	out.value = clone.value(in.value) | ||||
| 	return out | ||||
| } | ||||
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/cmpl.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| ) | ||||
| 
 | ||||
| type _file struct { | ||||
| 	name string | ||||
| 	src  string | ||||
| 	base int // This will always be 1 or greater
 | ||||
| } | ||||
| 
 | ||||
| type _compiler struct { | ||||
| 	file    *file.File | ||||
| 	program *ast.Program | ||||
| } | ||||
| 
 | ||||
| func (cmpl *_compiler) parse() *_nodeProgram { | ||||
| 	if cmpl.program != nil { | ||||
| 		cmpl.file = cmpl.program.File | ||||
| 	} | ||||
| 	return cmpl._parse(cmpl.program) | ||||
| } | ||||
| @ -4,13 +4,20 @@ import ( | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeProgram(node *_nodeProgram) Value { | ||||
| func (self *_runtime) cmpl_evaluate_nodeProgram(node *_nodeProgram, eval bool) Value { | ||||
| 	if !eval { | ||||
| 		self.enterGlobalScope() | ||||
| 		defer func() { | ||||
| 			self.leaveScope() | ||||
| 		}() | ||||
| 	} | ||||
| 	self.cmpl_functionDeclaration(node.functionList) | ||||
| 	self.cmpl_variableDeclaration(node.varList) | ||||
| 	self.scope.frame.file = node.file | ||||
| 	return self.cmpl_evaluate_nodeStatementList(node.body) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_functionEnvironment, node *_nodeFunctionLiteral, this Value, argumentList []Value) Value { | ||||
| func (self *_runtime) cmpl_call_nodeFunction(function *_object, stash *_fnStash, node *_nodeFunctionLiteral, this Value, argumentList []Value) Value { | ||||
| 
 | ||||
| 	indexOfParameterName := make([]string, len(argumentList)) | ||||
| 	// function(abc, def, ghi)
 | ||||
| @ -24,19 +31,21 @@ func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_fu | ||||
| 		if name == "arguments" { | ||||
| 			argumentsFound = true | ||||
| 		} | ||||
| 		value := UndefinedValue() | ||||
| 		value := Value{} | ||||
| 		if index < len(argumentList) { | ||||
| 			value = argumentList[index] | ||||
| 			indexOfParameterName[index] = name | ||||
| 		} | ||||
| 		self.localSet(name, value) | ||||
| 		// strict = false
 | ||||
| 		self.scope.lexical.setValue(name, value, false) | ||||
| 	} | ||||
| 
 | ||||
| 	if !argumentsFound { | ||||
| 		arguments := self.newArgumentsObject(indexOfParameterName, environment, len(argumentList)) | ||||
| 		arguments := self.newArgumentsObject(indexOfParameterName, stash, len(argumentList)) | ||||
| 		arguments.defineProperty("callee", toValue_object(function), 0101, false) | ||||
| 		environment.arguments = arguments | ||||
| 		self.localSet("arguments", toValue_object(arguments)) | ||||
| 		stash.arguments = arguments | ||||
| 		// strict = false
 | ||||
| 		self.scope.lexical.setValue("arguments", toValue_object(arguments), false) | ||||
| 		for index, _ := range argumentList { | ||||
| 			if index < len(node.parameterList) { | ||||
| 				continue | ||||
| @ -50,38 +59,38 @@ func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_fu | ||||
| 	self.cmpl_variableDeclaration(node.varList) | ||||
| 
 | ||||
| 	result := self.cmpl_evaluate_nodeStatement(node.body) | ||||
| 	if result.isResult() { | ||||
| 	if result.kind == valueResult { | ||||
| 		return result | ||||
| 	} | ||||
| 
 | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_functionDeclaration(list []*_nodeFunctionLiteral) { | ||||
| 	executionContext := self._executionContext(0) | ||||
| 	executionContext := self.scope | ||||
| 	eval := executionContext.eval | ||||
| 	environment := executionContext.VariableEnvironment | ||||
| 	stash := executionContext.variable | ||||
| 
 | ||||
| 	for _, function := range list { | ||||
| 		name := function.name | ||||
| 		value := self.cmpl_evaluate_nodeExpression(function) | ||||
| 		if !environment.HasBinding(name) { | ||||
| 			environment.CreateMutableBinding(name, eval == true) | ||||
| 		if !stash.hasBinding(name) { | ||||
| 			stash.createBinding(name, eval == true, value) | ||||
| 		} else { | ||||
| 			// TODO 10.5.5.e
 | ||||
| 			stash.setBinding(name, value, false) // TODO strict
 | ||||
| 		} | ||||
| 		// TODO 10.5.5.e
 | ||||
| 		environment.SetMutableBinding(name, value, false) // TODO strict
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_variableDeclaration(list []string) { | ||||
| 	executionContext := self._executionContext(0) | ||||
| 	executionContext := self.scope | ||||
| 	eval := executionContext.eval | ||||
| 	environment := executionContext.VariableEnvironment | ||||
| 	stash := executionContext.variable | ||||
| 
 | ||||
| 	for _, name := range list { | ||||
| 		if !environment.HasBinding(name) { | ||||
| 			environment.CreateMutableBinding(name, eval == true) | ||||
| 			environment.SetMutableBinding(name, UndefinedValue(), false) // TODO strict
 | ||||
| 		if !stash.hasBinding(name) { | ||||
| 			stash.createBinding(name, eval == true, Value{}) // TODO strict?
 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -13,10 +13,10 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value { | ||||
| 	// If the Interrupt channel is nil, then
 | ||||
| 	// we avoid runtime.Gosched() overhead (if any)
 | ||||
| 	// FIXME: Test this
 | ||||
| 	if self.Otto.Interrupt != nil { | ||||
| 	if self.otto.Interrupt != nil { | ||||
| 		runtime.Gosched() | ||||
| 		select { | ||||
| 		case value := <-self.Otto.Interrupt: | ||||
| 		case value := <-self.otto.Interrupt: | ||||
| 			value() | ||||
| 		default: | ||||
| 		} | ||||
| @ -50,15 +50,14 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value { | ||||
| 		return self.cmpl_evaluate_nodeDotExpression(node) | ||||
| 
 | ||||
| 	case *_nodeFunctionLiteral: | ||||
| 		var local = self.LexicalEnvironment() | ||||
| 		var local = self.scope.lexical | ||||
| 		if node.name != "" { | ||||
| 			local = self.newDeclarativeEnvironment(local) | ||||
| 			local = self.newDeclarationStash(local) | ||||
| 		} | ||||
| 
 | ||||
| 		value := toValue_object(self.newNodeFunction(node, local)) | ||||
| 		if node.name != "" { | ||||
| 			local.CreateMutableBinding(node.name, false) | ||||
| 			local.SetMutableBinding(node.name, value, false) | ||||
| 			local.createBinding(node.name, false, value) | ||||
| 		} | ||||
| 		return value | ||||
| 
 | ||||
| @ -67,7 +66,7 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value { | ||||
| 		// TODO Should be true or false (strictness) depending on context
 | ||||
| 		// getIdentifierReference should not return nil, but we check anyway and panic
 | ||||
| 		// so as not to propagate the nil into something else
 | ||||
| 		reference := getIdentifierReference(self.LexicalEnvironment(), name, false) | ||||
| 		reference := getIdentifierReference(self, self.scope.lexical, name, false, _at(node.idx)) | ||||
| 		if reference == nil { | ||||
| 			// Should never get here!
 | ||||
| 			panic(hereBeDragons("referenceError == nil: " + name)) | ||||
| @ -90,7 +89,7 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value { | ||||
| 		return self.cmpl_evaluate_nodeSequenceExpression(node) | ||||
| 
 | ||||
| 	case *_nodeThisExpression: | ||||
| 		return toValue_object(self._executionContext(0).this) | ||||
| 		return toValue_object(self.scope.this) | ||||
| 
 | ||||
| 	case *_nodeUnaryExpression: | ||||
| 		return self.cmpl_evaluate_nodeUnaryExpression(node) | ||||
| @ -108,9 +107,9 @@ func (self *_runtime) cmpl_evaluate_nodeArrayLiteral(node *_nodeArrayLiteral) Va | ||||
| 
 | ||||
| 	for _, node := range node.value { | ||||
| 		if node == nil { | ||||
| 			valueArray = append(valueArray, Value{}) | ||||
| 			valueArray = append(valueArray, emptyValue) | ||||
| 		} else { | ||||
| 			valueArray = append(valueArray, self.GetValue(self.cmpl_evaluate_nodeExpression(node))) | ||||
| 			valueArray = append(valueArray, self.cmpl_evaluate_nodeExpression(node).resolve()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -123,14 +122,14 @@ func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpres | ||||
| 
 | ||||
| 	left := self.cmpl_evaluate_nodeExpression(node.left) | ||||
| 	right := self.cmpl_evaluate_nodeExpression(node.right) | ||||
| 	rightValue := self.GetValue(right) | ||||
| 	rightValue := right.resolve() | ||||
| 
 | ||||
| 	result := rightValue | ||||
| 	if node.operator != token.ASSIGN { | ||||
| 		result = self.calculateBinaryExpression(node.operator, left, rightValue) | ||||
| 	} | ||||
| 
 | ||||
| 	self.PutValue(left.reference(), result) | ||||
| 	self.putValue(left.reference(), result) | ||||
| 
 | ||||
| 	return result | ||||
| } | ||||
| @ -138,22 +137,22 @@ func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpres | ||||
| func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpression) Value { | ||||
| 
 | ||||
| 	left := self.cmpl_evaluate_nodeExpression(node.left) | ||||
| 	leftValue := self.GetValue(left) | ||||
| 	leftValue := left.resolve() | ||||
| 
 | ||||
| 	switch node.operator { | ||||
| 	// Logical
 | ||||
| 	case token.LOGICAL_AND: | ||||
| 		if !toBoolean(leftValue) { | ||||
| 		if !leftValue.bool() { | ||||
| 			return leftValue | ||||
| 		} | ||||
| 		right := self.cmpl_evaluate_nodeExpression(node.right) | ||||
| 		return self.GetValue(right) | ||||
| 		return right.resolve() | ||||
| 	case token.LOGICAL_OR: | ||||
| 		if toBoolean(leftValue) { | ||||
| 		if leftValue.bool() { | ||||
| 			return leftValue | ||||
| 		} | ||||
| 		right := self.cmpl_evaluate_nodeExpression(node.right) | ||||
| 		return self.GetValue(right) | ||||
| 		return right.resolve() | ||||
| 	} | ||||
| 
 | ||||
| 	return self.calculateBinaryExpression(node.operator, leftValue, self.cmpl_evaluate_nodeExpression(node.right)) | ||||
| @ -161,57 +160,90 @@ func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpres | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeBinaryExpression_comparison(node *_nodeBinaryExpression) Value { | ||||
| 
 | ||||
| 	left := self.GetValue(self.cmpl_evaluate_nodeExpression(node.left)) | ||||
| 	right := self.GetValue(self.cmpl_evaluate_nodeExpression(node.right)) | ||||
| 	left := self.cmpl_evaluate_nodeExpression(node.left).resolve() | ||||
| 	right := self.cmpl_evaluate_nodeExpression(node.right).resolve() | ||||
| 
 | ||||
| 	return toValue_bool(self.calculateComparison(node.operator, left, right)) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpression) Value { | ||||
| 	target := self.cmpl_evaluate_nodeExpression(node.left) | ||||
| 	targetValue := self.GetValue(target) | ||||
| 	targetValue := target.resolve() | ||||
| 	member := self.cmpl_evaluate_nodeExpression(node.member) | ||||
| 	memberValue := self.GetValue(member) | ||||
| 	memberValue := member.resolve() | ||||
| 
 | ||||
| 	// TODO Pass in base value as-is, and defer toObject till later?
 | ||||
| 	return toValue(newPropertyReference(self.toObject(targetValue), toString(memberValue), false)) | ||||
| 	return toValue(newPropertyReference(self, self.toObject(targetValue), memberValue.string(), false, _at(node.idx))) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value { | ||||
| 	rt := self | ||||
| 	this := Value{} | ||||
| 	callee := self.cmpl_evaluate_nodeExpression(node.callee) | ||||
| 	calleeValue := self.GetValue(callee) | ||||
| 
 | ||||
| 	argumentList := []Value{} | ||||
| 	if withArgumentList != nil { | ||||
| 		argumentList = self.toValueArray(withArgumentList...) | ||||
| 	} else { | ||||
| 		for _, argumentNode := range node.argumentList { | ||||
| 			argumentList = append(argumentList, self.GetValue(self.cmpl_evaluate_nodeExpression(argumentNode))) | ||||
| 			argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve()) | ||||
| 		} | ||||
| 	} | ||||
| 	this := UndefinedValue() | ||||
| 	calleeReference := callee.reference() | ||||
| 	evalHint := false | ||||
| 	if calleeReference != nil { | ||||
| 		if calleeReference.IsPropertyReference() { | ||||
| 			calleeObject := calleeReference.GetBase().(*_object) | ||||
| 			this = toValue_object(calleeObject) | ||||
| 		} else { | ||||
| 			// TODO ImplictThisValue
 | ||||
| 		} | ||||
| 		if calleeReference.GetName() == "eval" { | ||||
| 			evalHint = true // Possible direct eval
 | ||||
| 
 | ||||
| 	rf := callee.reference() | ||||
| 	vl := callee.resolve() | ||||
| 
 | ||||
| 	eval := false // Whether this call is a (candidate for) direct call to eval
 | ||||
| 	name := "" | ||||
| 	if rf != nil { | ||||
| 		switch rf := rf.(type) { | ||||
| 		case *_propertyReference: | ||||
| 			name = rf.name | ||||
| 			object := rf.base | ||||
| 			this = toValue_object(object) | ||||
| 			eval = rf.name == "eval" // Possible direct eval
 | ||||
| 		case *_stashReference: | ||||
| 			// TODO ImplicitThisValue
 | ||||
| 			name = rf.name | ||||
| 			eval = rf.name == "eval" // Possible direct eval
 | ||||
| 		default: | ||||
| 			// FIXME?
 | ||||
| 			panic(rt.panicTypeError("Here be dragons")) | ||||
| 		} | ||||
| 	} | ||||
| 	if !calleeValue.IsFunction() { | ||||
| 		panic(newTypeError("%v is not a function", calleeValue)) | ||||
| 
 | ||||
| 	at := _at(-1) | ||||
| 	switch callee := node.callee.(type) { | ||||
| 	case *_nodeIdentifier: | ||||
| 		at = _at(callee.idx) | ||||
| 	case *_nodeDotExpression: | ||||
| 		at = _at(callee.idx) | ||||
| 	case *_nodeBracketExpression: | ||||
| 		at = _at(callee.idx) | ||||
| 	} | ||||
| 	return self.Call(calleeValue._object(), this, argumentList, evalHint) | ||||
| 
 | ||||
| 	frame := _frame{ | ||||
| 		callee: name, | ||||
| 		file:   self.scope.frame.file, | ||||
| 	} | ||||
| 
 | ||||
| 	if !vl.IsFunction() { | ||||
| 		if name == "" { | ||||
| 			// FIXME Maybe typeof?
 | ||||
| 			panic(rt.panicTypeError("%v is not a function", vl, at)) | ||||
| 		} | ||||
| 		panic(rt.panicTypeError("'%s' is not a function", name, at)) | ||||
| 	} | ||||
| 
 | ||||
| 	self.scope.frame.offset = int(at) | ||||
| 
 | ||||
| 	return vl._object().call(this, argumentList, eval, frame) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditionalExpression) Value { | ||||
| 	test := self.cmpl_evaluate_nodeExpression(node.test) | ||||
| 	testValue := self.GetValue(test) | ||||
| 	if toBoolean(testValue) { | ||||
| 	testValue := test.resolve() | ||||
| 	if testValue.bool() { | ||||
| 		return self.cmpl_evaluate_nodeExpression(node.consequent) | ||||
| 	} | ||||
| 	return self.cmpl_evaluate_nodeExpression(node.alternate) | ||||
| @ -219,27 +251,60 @@ func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditi | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeDotExpression(node *_nodeDotExpression) Value { | ||||
| 	target := self.cmpl_evaluate_nodeExpression(node.left) | ||||
| 	targetValue := self.GetValue(target) | ||||
| 	targetValue := target.resolve() | ||||
| 	// TODO Pass in base value as-is, and defer toObject till later?
 | ||||
| 	object, err := self.objectCoerce(targetValue) | ||||
| 	if err != nil { | ||||
| 		panic(newTypeError(fmt.Sprintf("Cannot access member '%s' of %s", node.identifier, err.Error()))) | ||||
| 		panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error())) | ||||
| 	} | ||||
| 	return toValue(newPropertyReference(object, node.identifier, false)) | ||||
| 	return toValue(newPropertyReference(self, object, node.identifier, false, _at(node.idx))) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeNewExpression(node *_nodeNewExpression) Value { | ||||
| 	rt := self | ||||
| 	callee := self.cmpl_evaluate_nodeExpression(node.callee) | ||||
| 	calleeValue := self.GetValue(callee) | ||||
| 
 | ||||
| 	argumentList := []Value{} | ||||
| 	for _, argumentNode := range node.argumentList { | ||||
| 		argumentList = append(argumentList, self.GetValue(self.cmpl_evaluate_nodeExpression(argumentNode))) | ||||
| 		argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve()) | ||||
| 	} | ||||
| 	this := UndefinedValue() | ||||
| 	if !calleeValue.IsFunction() { | ||||
| 		panic(newTypeError("%v is not a function", calleeValue)) | ||||
| 
 | ||||
| 	rf := callee.reference() | ||||
| 	vl := callee.resolve() | ||||
| 
 | ||||
| 	name := "" | ||||
| 	if rf != nil { | ||||
| 		switch rf := rf.(type) { | ||||
| 		case *_propertyReference: | ||||
| 			name = rf.name | ||||
| 		case *_stashReference: | ||||
| 			name = rf.name | ||||
| 		default: | ||||
| 			panic(rt.panicTypeError("Here be dragons")) | ||||
| 		} | ||||
| 	} | ||||
| 	return calleeValue._object().Construct(this, argumentList) | ||||
| 
 | ||||
| 	at := _at(-1) | ||||
| 	switch callee := node.callee.(type) { | ||||
| 	case *_nodeIdentifier: | ||||
| 		at = _at(callee.idx) | ||||
| 	case *_nodeDotExpression: | ||||
| 		at = _at(callee.idx) | ||||
| 	case *_nodeBracketExpression: | ||||
| 		at = _at(callee.idx) | ||||
| 	} | ||||
| 
 | ||||
| 	if !vl.IsFunction() { | ||||
| 		if name == "" { | ||||
| 			// FIXME Maybe typeof?
 | ||||
| 			panic(rt.panicTypeError("%v is not a function", vl, at)) | ||||
| 		} | ||||
| 		panic(rt.panicTypeError("'%s' is not a function", name, at)) | ||||
| 	} | ||||
| 
 | ||||
| 	self.scope.frame.offset = int(at) | ||||
| 
 | ||||
| 	return vl._object().construct(argumentList) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral) Value { | ||||
| @ -249,15 +314,15 @@ func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral) | ||||
| 	for _, property := range node.value { | ||||
| 		switch property.kind { | ||||
| 		case "value": | ||||
| 			result.defineProperty(property.key, self.GetValue(self.cmpl_evaluate_nodeExpression(property.value)), 0111, false) | ||||
| 			result.defineProperty(property.key, self.cmpl_evaluate_nodeExpression(property.value).resolve(), 0111, false) | ||||
| 		case "get": | ||||
| 			getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.LexicalEnvironment()) | ||||
| 			getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical) | ||||
| 			descriptor := _property{} | ||||
| 			descriptor.mode = 0211 | ||||
| 			descriptor.value = _propertyGetSet{getter, nil} | ||||
| 			result.defineOwnProperty(property.key, descriptor, false) | ||||
| 		case "set": | ||||
| 			setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.LexicalEnvironment()) | ||||
| 			setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical) | ||||
| 			descriptor := _property{} | ||||
| 			descriptor.mode = 0211 | ||||
| 			descriptor.value = _propertyGetSet{nil, setter} | ||||
| @ -274,7 +339,7 @@ func (self *_runtime) cmpl_evaluate_nodeSequenceExpression(node *_nodeSequenceEx | ||||
| 	var result Value | ||||
| 	for _, node := range node.sequence { | ||||
| 		result = self.cmpl_evaluate_nodeExpression(node) | ||||
| 		result = self.GetValue(result) | ||||
| 		result = result.resolve() | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
| @ -284,31 +349,31 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi | ||||
| 	target := self.cmpl_evaluate_nodeExpression(node.operand) | ||||
| 	switch node.operator { | ||||
| 	case token.TYPEOF, token.DELETE: | ||||
| 		if target._valueType == valueReference && target.reference().IsUnresolvable() { | ||||
| 		if target.kind == valueReference && target.reference().invalid() { | ||||
| 			if node.operator == token.TYPEOF { | ||||
| 				return toValue_string("undefined") | ||||
| 			} | ||||
| 			return TrueValue() | ||||
| 			return trueValue | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch node.operator { | ||||
| 	case token.NOT: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		if targetValue.toBoolean() { | ||||
| 			return FalseValue() | ||||
| 		targetValue := target.resolve() | ||||
| 		if targetValue.bool() { | ||||
| 			return falseValue | ||||
| 		} | ||||
| 		return TrueValue() | ||||
| 		return trueValue | ||||
| 	case token.BITWISE_NOT: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		targetValue := target.resolve() | ||||
| 		integerValue := toInt32(targetValue) | ||||
| 		return toValue_int32(^integerValue) | ||||
| 	case token.PLUS: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		return toValue_float64(targetValue.toFloat()) | ||||
| 		targetValue := target.resolve() | ||||
| 		return toValue_float64(targetValue.float64()) | ||||
| 	case token.MINUS: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		value := targetValue.toFloat() | ||||
| 		targetValue := target.resolve() | ||||
| 		value := targetValue.float64() | ||||
| 		// TODO Test this
 | ||||
| 		sign := float64(-1) | ||||
| 		if math.Signbit(value) { | ||||
| @ -316,45 +381,45 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi | ||||
| 		} | ||||
| 		return toValue_float64(math.Copysign(value, sign)) | ||||
| 	case token.INCREMENT: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		targetValue := target.resolve() | ||||
| 		if node.postfix { | ||||
| 			// Postfix++
 | ||||
| 			oldValue := targetValue.toFloat() | ||||
| 			oldValue := targetValue.float64() | ||||
| 			newValue := toValue_float64(+1 + oldValue) | ||||
| 			self.PutValue(target.reference(), newValue) | ||||
| 			self.putValue(target.reference(), newValue) | ||||
| 			return toValue_float64(oldValue) | ||||
| 		} else { | ||||
| 			// ++Prefix
 | ||||
| 			newValue := toValue_float64(+1 + targetValue.toFloat()) | ||||
| 			self.PutValue(target.reference(), newValue) | ||||
| 			newValue := toValue_float64(+1 + targetValue.float64()) | ||||
| 			self.putValue(target.reference(), newValue) | ||||
| 			return newValue | ||||
| 		} | ||||
| 	case token.DECREMENT: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		targetValue := target.resolve() | ||||
| 		if node.postfix { | ||||
| 			// Postfix--
 | ||||
| 			oldValue := targetValue.toFloat() | ||||
| 			oldValue := targetValue.float64() | ||||
| 			newValue := toValue_float64(-1 + oldValue) | ||||
| 			self.PutValue(target.reference(), newValue) | ||||
| 			self.putValue(target.reference(), newValue) | ||||
| 			return toValue_float64(oldValue) | ||||
| 		} else { | ||||
| 			// --Prefix
 | ||||
| 			newValue := toValue_float64(-1 + targetValue.toFloat()) | ||||
| 			self.PutValue(target.reference(), newValue) | ||||
| 			newValue := toValue_float64(-1 + targetValue.float64()) | ||||
| 			self.putValue(target.reference(), newValue) | ||||
| 			return newValue | ||||
| 		} | ||||
| 	case token.VOID: | ||||
| 		self.GetValue(target) // FIXME Side effect?
 | ||||
| 		return UndefinedValue() | ||||
| 		target.resolve() // FIXME Side effect?
 | ||||
| 		return Value{} | ||||
| 	case token.DELETE: | ||||
| 		reference := target.reference() | ||||
| 		if reference == nil { | ||||
| 			return TrueValue() | ||||
| 			return trueValue | ||||
| 		} | ||||
| 		return toValue_bool(target.reference().Delete()) | ||||
| 		return toValue_bool(target.reference().delete()) | ||||
| 	case token.TYPEOF: | ||||
| 		targetValue := self.GetValue(target) | ||||
| 		switch targetValue._valueType { | ||||
| 		targetValue := target.resolve() | ||||
| 		switch targetValue.kind { | ||||
| 		case valueUndefined: | ||||
| 			return toValue_string("undefined") | ||||
| 		case valueNull: | ||||
| @ -366,7 +431,7 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi | ||||
| 		case valueString: | ||||
| 			return toValue_string("string") | ||||
| 		case valueObject: | ||||
| 			if targetValue._object().functionValue().call != nil { | ||||
| 			if targetValue._object().isCall() { | ||||
| 				return toValue_string("function") | ||||
| 			} | ||||
| 			return toValue_string("object") | ||||
| @ -381,11 +446,11 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi | ||||
| func (self *_runtime) cmpl_evaluate_nodeVariableExpression(node *_nodeVariableExpression) Value { | ||||
| 	if node.initializer != nil { | ||||
| 		// FIXME If reference is nil
 | ||||
| 		left := getIdentifierReference(self.LexicalEnvironment(), node.name, false) | ||||
| 		left := getIdentifierReference(self, self.scope.lexical, node.name, false, _at(node.idx)) | ||||
| 		right := self.cmpl_evaluate_nodeExpression(node.initializer) | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 
 | ||||
| 		self.PutValue(left, rightValue) | ||||
| 		self.putValue(left, rightValue) | ||||
| 	} | ||||
| 	return toValue_string(node.name) | ||||
| } | ||||
| @ -12,10 +12,10 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { | ||||
| 	// If the Interrupt channel is nil, then
 | ||||
| 	// we avoid runtime.Gosched() overhead (if any)
 | ||||
| 	// FIXME: Test this
 | ||||
| 	if self.Otto.Interrupt != nil { | ||||
| 	if self.otto.Interrupt != nil { | ||||
| 		runtime.Gosched() | ||||
| 		select { | ||||
| 		case value := <-self.Otto.Interrupt: | ||||
| 		case value := <-self.otto.Interrupt: | ||||
| 			value() | ||||
| 		default: | ||||
| 		} | ||||
| @ -24,8 +24,18 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { | ||||
| 	switch node := node.(type) { | ||||
| 
 | ||||
| 	case *_nodeBlockStatement: | ||||
| 		// FIXME If result is break, then return the empty value?
 | ||||
| 		return self.cmpl_evaluate_nodeStatementList(node.list) | ||||
| 		labels := self.labels | ||||
| 		self.labels = nil | ||||
| 
 | ||||
| 		value := self.cmpl_evaluate_nodeStatementList(node.list) | ||||
| 		switch value.kind { | ||||
| 		case valueResult: | ||||
| 			switch value.evaluateBreak(labels) { | ||||
| 			case resultBreak: | ||||
| 				return emptyValue | ||||
| 			} | ||||
| 		} | ||||
| 		return value | ||||
| 
 | ||||
| 	case *_nodeBranchStatement: | ||||
| 		target := node.label | ||||
| @ -37,13 +47,13 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { | ||||
| 		} | ||||
| 
 | ||||
| 	case *_nodeDebuggerStatement: | ||||
| 		return Value{} // Nothing happens.
 | ||||
| 		return emptyValue // Nothing happens.
 | ||||
| 
 | ||||
| 	case *_nodeDoWhileStatement: | ||||
| 		return self.cmpl_evaluate_nodeDoWhileStatement(node) | ||||
| 
 | ||||
| 	case *_nodeEmptyStatement: | ||||
| 		return Value{} | ||||
| 		return emptyValue | ||||
| 
 | ||||
| 	case *_nodeExpressionStatement: | ||||
| 		return self.cmpl_evaluate_nodeExpression(node.expression) | ||||
| @ -70,15 +80,15 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { | ||||
| 
 | ||||
| 	case *_nodeReturnStatement: | ||||
| 		if node.argument != nil { | ||||
| 			return toValue(newReturnResult(self.GetValue(self.cmpl_evaluate_nodeExpression(node.argument)))) | ||||
| 			return toValue(newReturnResult(self.cmpl_evaluate_nodeExpression(node.argument).resolve())) | ||||
| 		} | ||||
| 		return toValue(newReturnResult(UndefinedValue())) | ||||
| 		return toValue(newReturnResult(Value{})) | ||||
| 
 | ||||
| 	case *_nodeSwitchStatement: | ||||
| 		return self.cmpl_evaluate_nodeSwitchStatement(node) | ||||
| 
 | ||||
| 	case *_nodeThrowStatement: | ||||
| 		value := self.GetValue(self.cmpl_evaluate_nodeExpression(node.argument)) | ||||
| 		value := self.cmpl_evaluate_nodeExpression(node.argument).resolve() | ||||
| 		panic(newException(value)) | ||||
| 
 | ||||
| 	case *_nodeTryStatement: | ||||
| @ -89,7 +99,7 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value { | ||||
| 		for _, variable := range node.list { | ||||
| 			self.cmpl_evaluate_nodeVariableExpression(variable.(*_nodeVariableExpression)) | ||||
| 		} | ||||
| 		return Value{} | ||||
| 		return emptyValue | ||||
| 
 | ||||
| 	case *_nodeWhileStatement: | ||||
| 		return self.cmpl_evaluate_nodeWhileStatement(node) | ||||
| @ -106,17 +116,17 @@ func (self *_runtime) cmpl_evaluate_nodeStatementList(list []_nodeStatement) Val | ||||
| 	var result Value | ||||
| 	for _, node := range list { | ||||
| 		value := self.cmpl_evaluate_nodeStatement(node) | ||||
| 		switch value._valueType { | ||||
| 		switch value.kind { | ||||
| 		case valueResult: | ||||
| 			return value | ||||
| 		case valueEmpty: | ||||
| 		default: | ||||
| 			// We have GetValue here to (for example) trigger a
 | ||||
| 			// We have getValue here to (for example) trigger a
 | ||||
| 			// ReferenceError (of the not defined variety)
 | ||||
| 			// Not sure if this is the best way to error out early
 | ||||
| 			// for such errors or if there is a better way
 | ||||
| 			// TODO Do we still need this?
 | ||||
| 			result = self.GetValue(value) | ||||
| 			result = value.resolve() | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| @ -129,12 +139,12 @@ func (self *_runtime) cmpl_evaluate_nodeDoWhileStatement(node *_nodeDoWhileState | ||||
| 
 | ||||
| 	test := node.test | ||||
| 
 | ||||
| 	result := Value{} | ||||
| 	result := emptyValue | ||||
| resultBreak: | ||||
| 	for { | ||||
| 		for _, node := range node.body { | ||||
| 			value := self.cmpl_evaluate_nodeStatement(node) | ||||
| 			switch value._valueType { | ||||
| 			switch value.kind { | ||||
| 			case valueResult: | ||||
| 				switch value.evaluateBreakContinue(labels) { | ||||
| 				case resultReturn: | ||||
| @ -150,7 +160,7 @@ resultBreak: | ||||
| 			} | ||||
| 		} | ||||
| 	resultContinue: | ||||
| 		if !self.GetValue(self.cmpl_evaluate_nodeExpression(test)).isTrue() { | ||||
| 		if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { | ||||
| 			// Stahp: do ... while (false)
 | ||||
| 			break | ||||
| 		} | ||||
| @ -164,11 +174,11 @@ func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement | ||||
| 	self.labels = nil | ||||
| 
 | ||||
| 	source := self.cmpl_evaluate_nodeExpression(node.source) | ||||
| 	sourceValue := self.GetValue(source) | ||||
| 	sourceValue := source.resolve() | ||||
| 
 | ||||
| 	switch sourceValue._valueType { | ||||
| 	switch sourceValue.kind { | ||||
| 	case valueUndefined, valueNull: | ||||
| 		return emptyValue() | ||||
| 		return emptyValue | ||||
| 	} | ||||
| 
 | ||||
| 	sourceObject := self.toObject(sourceValue) | ||||
| @ -176,22 +186,22 @@ func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement | ||||
| 	into := node.into | ||||
| 	body := node.body | ||||
| 
 | ||||
| 	result := Value{} | ||||
| 	result := emptyValue | ||||
| 	object := sourceObject | ||||
| 	for object != nil { | ||||
| 		enumerateValue := Value{} | ||||
| 		enumerateValue := emptyValue | ||||
| 		object.enumerate(false, func(name string) bool { | ||||
| 			into := self.cmpl_evaluate_nodeExpression(into) | ||||
| 			// In the case of: for (var abc in def) ...
 | ||||
| 			if into.reference() == nil { | ||||
| 				identifier := toString(into) | ||||
| 				identifier := into.string() | ||||
| 				// TODO Should be true or false (strictness) depending on context
 | ||||
| 				into = toValue(getIdentifierReference(self.LexicalEnvironment(), identifier, false)) | ||||
| 				into = toValue(getIdentifierReference(self, self.scope.lexical, identifier, false, -1)) | ||||
| 			} | ||||
| 			self.PutValue(into.reference(), toValue_string(name)) | ||||
| 			self.putValue(into.reference(), toValue_string(name)) | ||||
| 			for _, node := range body { | ||||
| 				value := self.cmpl_evaluate_nodeStatement(node) | ||||
| 				switch value._valueType { | ||||
| 				switch value.kind { | ||||
| 				case valueResult: | ||||
| 					switch value.evaluateBreakContinue(labels) { | ||||
| 					case resultReturn: | ||||
| @ -233,22 +243,22 @@ func (self *_runtime) cmpl_evaluate_nodeForStatement(node *_nodeForStatement) Va | ||||
| 
 | ||||
| 	if initializer != nil { | ||||
| 		initialResult := self.cmpl_evaluate_nodeExpression(initializer) | ||||
| 		self.GetValue(initialResult) // Side-effect trigger
 | ||||
| 		initialResult.resolve() // Side-effect trigger
 | ||||
| 	} | ||||
| 
 | ||||
| 	result := Value{} | ||||
| 	result := emptyValue | ||||
| resultBreak: | ||||
| 	for { | ||||
| 		if test != nil { | ||||
| 			testResult := self.cmpl_evaluate_nodeExpression(test) | ||||
| 			testResultValue := self.GetValue(testResult) | ||||
| 			if toBoolean(testResultValue) == false { | ||||
| 			testResultValue := testResult.resolve() | ||||
| 			if testResultValue.bool() == false { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		for _, node := range body { | ||||
| 			value := self.cmpl_evaluate_nodeStatement(node) | ||||
| 			switch value._valueType { | ||||
| 			switch value.kind { | ||||
| 			case valueResult: | ||||
| 				switch value.evaluateBreakContinue(labels) { | ||||
| 				case resultReturn: | ||||
| @ -266,7 +276,7 @@ resultBreak: | ||||
| 	resultContinue: | ||||
| 		if update != nil { | ||||
| 			updateResult := self.cmpl_evaluate_nodeExpression(update) | ||||
| 			self.GetValue(updateResult) // Side-effect trigger
 | ||||
| 			updateResult.resolve() // Side-effect trigger
 | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| @ -274,14 +284,14 @@ resultBreak: | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeIfStatement(node *_nodeIfStatement) Value { | ||||
| 	test := self.cmpl_evaluate_nodeExpression(node.test) | ||||
| 	testValue := self.GetValue(test) | ||||
| 	if toBoolean(testValue) { | ||||
| 	testValue := test.resolve() | ||||
| 	if testValue.bool() { | ||||
| 		return self.cmpl_evaluate_nodeStatement(node.consequent) | ||||
| 	} else if node.alternate != nil { | ||||
| 		return self.cmpl_evaluate_nodeStatement(node.alternate) | ||||
| 	} | ||||
| 
 | ||||
| 	return Value{} | ||||
| 	return emptyValue | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStatement) Value { | ||||
| @ -302,18 +312,18 @@ func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStateme | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	result := Value{} | ||||
| 	result := emptyValue | ||||
| 	if target != -1 { | ||||
| 		for _, clause := range node.body[target:] { | ||||
| 			for _, statement := range clause.consequent { | ||||
| 				value := self.cmpl_evaluate_nodeStatement(statement) | ||||
| 				switch value._valueType { | ||||
| 				switch value.kind { | ||||
| 				case valueResult: | ||||
| 					switch value.evaluateBreak(labels) { | ||||
| 					case resultReturn: | ||||
| 						return value | ||||
| 					case resultBreak: | ||||
| 						return Value{} | ||||
| 						return emptyValue | ||||
| 					} | ||||
| 				case valueEmpty: | ||||
| 				default: | ||||
| @ -332,14 +342,15 @@ func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Va | ||||
| 	}) | ||||
| 
 | ||||
| 	if exception && node.catch != nil { | ||||
| 
 | ||||
| 		lexicalEnvironment := self._executionContext(0).newDeclarativeEnvironment(self) | ||||
| 		outer := self.scope.lexical | ||||
| 		self.scope.lexical = self.newDeclarationStash(outer) | ||||
| 		defer func() { | ||||
| 			self._executionContext(0).LexicalEnvironment = lexicalEnvironment | ||||
| 			self.scope.lexical = outer | ||||
| 		}() | ||||
| 		// TODO If necessary, convert TypeError<runtime> => TypeError
 | ||||
| 		// That, is, such errors can be thrown despite not being JavaScript "native"
 | ||||
| 		self.localSet(node.catch.parameter, tryCatchValue) | ||||
| 		// strict = false
 | ||||
| 		self.scope.lexical.setValue(node.catch.parameter, tryCatchValue, false) | ||||
| 
 | ||||
| 		// FIXME node.CatchParameter
 | ||||
| 		// FIXME node.Catch
 | ||||
| @ -350,7 +361,7 @@ func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Va | ||||
| 
 | ||||
| 	if node.finally != nil { | ||||
| 		finallyValue := self.cmpl_evaluate_nodeStatement(node.finally) | ||||
| 		if finallyValue.isResult() { | ||||
| 		if finallyValue.kind == valueResult { | ||||
| 			return finallyValue | ||||
| 		} | ||||
| 	} | ||||
| @ -369,16 +380,16 @@ func (self *_runtime) cmpl_evaluate_nodeWhileStatement(node *_nodeWhileStatement | ||||
| 	labels := append(self.labels, "") | ||||
| 	self.labels = nil | ||||
| 
 | ||||
| 	result := Value{} | ||||
| 	result := emptyValue | ||||
| resultBreakContinue: | ||||
| 	for { | ||||
| 		if !self.GetValue(self.cmpl_evaluate_nodeExpression(test)).isTrue() { | ||||
| 		if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { | ||||
| 			// Stahp: while (false) ...
 | ||||
| 			break | ||||
| 		} | ||||
| 		for _, node := range body { | ||||
| 			value := self.cmpl_evaluate_nodeStatement(node) | ||||
| 			switch value._valueType { | ||||
| 			switch value.kind { | ||||
| 			case valueResult: | ||||
| 				switch value.evaluateBreakContinue(labels) { | ||||
| 				case resultReturn: | ||||
| @ -399,11 +410,11 @@ resultBreakContinue: | ||||
| 
 | ||||
| func (self *_runtime) cmpl_evaluate_nodeWithStatement(node *_nodeWithStatement) Value { | ||||
| 	object := self.cmpl_evaluate_nodeExpression(node.object) | ||||
| 	objectValue := self.GetValue(object) | ||||
| 	previousLexicalEnvironment, lexicalEnvironment := self._executionContext(0).newLexicalEnvironment(self.toObject(objectValue)) | ||||
| 	lexicalEnvironment.ProvideThis = true | ||||
| 	outer := self.scope.lexical | ||||
| 	lexical := self.newObjectStash(self.toObject(object.resolve()), outer) | ||||
| 	self.scope.lexical = lexical | ||||
| 	defer func() { | ||||
| 		self._executionContext(0).LexicalEnvironment = previousLexicalEnvironment | ||||
| 		self.scope.lexical = outer | ||||
| 	}() | ||||
| 
 | ||||
| 	return self.cmpl_evaluate_nodeStatement(node.body) | ||||
| @ -5,165 +5,170 @@ import ( | ||||
| 	"regexp" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| 	"github.com/robertkrimen/otto/token" | ||||
| ) | ||||
| 
 | ||||
| var trueLiteral = &_nodeLiteral{value: toValue_bool(true)} | ||||
| var falseLiteral = &_nodeLiteral{value: toValue_bool(false)} | ||||
| var nullLiteral = &_nodeLiteral{value: NullValue()} | ||||
| var nullLiteral = &_nodeLiteral{value: nullValue} | ||||
| var emptyStatement = &_nodeEmptyStatement{} | ||||
| 
 | ||||
| func parseExpression(x ast.Expression) _nodeExpression { | ||||
| 	if x == nil { | ||||
| func (cmpl *_compiler) parseExpression(in ast.Expression) _nodeExpression { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	switch x := x.(type) { | ||||
| 	switch in := in.(type) { | ||||
| 
 | ||||
| 	case *ast.ArrayLiteral: | ||||
| 		y := &_nodeArrayLiteral{ | ||||
| 			value: make([]_nodeExpression, len(x.Value)), | ||||
| 		out := &_nodeArrayLiteral{ | ||||
| 			value: make([]_nodeExpression, len(in.Value)), | ||||
| 		} | ||||
| 		for i, value := range x.Value { | ||||
| 			y.value[i] = parseExpression(value) | ||||
| 		for i, value := range in.Value { | ||||
| 			out.value[i] = cmpl.parseExpression(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.AssignExpression: | ||||
| 		return &_nodeAssignExpression{ | ||||
| 			operator: x.Operator, | ||||
| 			left:     parseExpression(x.Left), | ||||
| 			right:    parseExpression(x.Right), | ||||
| 			operator: in.Operator, | ||||
| 			left:     cmpl.parseExpression(in.Left), | ||||
| 			right:    cmpl.parseExpression(in.Right), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.BinaryExpression: | ||||
| 		return &_nodeBinaryExpression{ | ||||
| 			operator:   x.Operator, | ||||
| 			left:       parseExpression(x.Left), | ||||
| 			right:      parseExpression(x.Right), | ||||
| 			comparison: x.Comparison, | ||||
| 			operator:   in.Operator, | ||||
| 			left:       cmpl.parseExpression(in.Left), | ||||
| 			right:      cmpl.parseExpression(in.Right), | ||||
| 			comparison: in.Comparison, | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.BooleanLiteral: | ||||
| 		if x.Value { | ||||
| 		if in.Value { | ||||
| 			return trueLiteral | ||||
| 		} | ||||
| 		return falseLiteral | ||||
| 
 | ||||
| 	case *ast.BracketExpression: | ||||
| 		return &_nodeBracketExpression{ | ||||
| 			left:   parseExpression(x.Left), | ||||
| 			member: parseExpression(x.Member), | ||||
| 			idx:    in.Left.Idx0(), | ||||
| 			left:   cmpl.parseExpression(in.Left), | ||||
| 			member: cmpl.parseExpression(in.Member), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.CallExpression: | ||||
| 		y := &_nodeCallExpression{ | ||||
| 			callee:       parseExpression(x.Callee), | ||||
| 			argumentList: make([]_nodeExpression, len(x.ArgumentList)), | ||||
| 		out := &_nodeCallExpression{ | ||||
| 			callee:       cmpl.parseExpression(in.Callee), | ||||
| 			argumentList: make([]_nodeExpression, len(in.ArgumentList)), | ||||
| 		} | ||||
| 		for i, value := range x.ArgumentList { | ||||
| 			y.argumentList[i] = parseExpression(value) | ||||
| 		for i, value := range in.ArgumentList { | ||||
| 			out.argumentList[i] = cmpl.parseExpression(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.ConditionalExpression: | ||||
| 		return &_nodeConditionalExpression{ | ||||
| 			test:       parseExpression(x.Test), | ||||
| 			consequent: parseExpression(x.Consequent), | ||||
| 			alternate:  parseExpression(x.Alternate), | ||||
| 			test:       cmpl.parseExpression(in.Test), | ||||
| 			consequent: cmpl.parseExpression(in.Consequent), | ||||
| 			alternate:  cmpl.parseExpression(in.Alternate), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.DotExpression: | ||||
| 		return &_nodeDotExpression{ | ||||
| 			left:       parseExpression(x.Left), | ||||
| 			identifier: x.Identifier.Name, | ||||
| 			idx:        in.Left.Idx0(), | ||||
| 			left:       cmpl.parseExpression(in.Left), | ||||
| 			identifier: in.Identifier.Name, | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.FunctionLiteral: | ||||
| 		name := "" | ||||
| 		if x.Name != nil { | ||||
| 			name = x.Name.Name | ||||
| 		if in.Name != nil { | ||||
| 			name = in.Name.Name | ||||
| 		} | ||||
| 		y := &_nodeFunctionLiteral{ | ||||
| 		out := &_nodeFunctionLiteral{ | ||||
| 			name:   name, | ||||
| 			body:   parseStatement(x.Body), | ||||
| 			source: x.Source, | ||||
| 			body:   cmpl.parseStatement(in.Body), | ||||
| 			source: in.Source, | ||||
| 			file:   cmpl.file, | ||||
| 		} | ||||
| 		if x.ParameterList != nil { | ||||
| 			list := x.ParameterList.List | ||||
| 			y.parameterList = make([]string, len(list)) | ||||
| 		if in.ParameterList != nil { | ||||
| 			list := in.ParameterList.List | ||||
| 			out.parameterList = make([]string, len(list)) | ||||
| 			for i, value := range list { | ||||
| 				y.parameterList[i] = value.Name | ||||
| 				out.parameterList[i] = value.Name | ||||
| 			} | ||||
| 		} | ||||
| 		for _, value := range x.DeclarationList { | ||||
| 		for _, value := range in.DeclarationList { | ||||
| 			switch value := value.(type) { | ||||
| 			case *ast.FunctionDeclaration: | ||||
| 				y.functionList = append(y.functionList, parseExpression(value.Function).(*_nodeFunctionLiteral)) | ||||
| 				out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*_nodeFunctionLiteral)) | ||||
| 			case *ast.VariableDeclaration: | ||||
| 				for _, value := range value.List { | ||||
| 					y.varList = append(y.varList, value.Name) | ||||
| 					out.varList = append(out.varList, value.Name) | ||||
| 				} | ||||
| 			default: | ||||
| 				panic(fmt.Errorf("Here be dragons: parseProgram.declaration(%T)", value)) | ||||
| 			} | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.Identifier: | ||||
| 		return &_nodeIdentifier{ | ||||
| 			name: x.Name, | ||||
| 			idx:  in.Idx, | ||||
| 			name: in.Name, | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.NewExpression: | ||||
| 		y := &_nodeNewExpression{ | ||||
| 			callee:       parseExpression(x.Callee), | ||||
| 			argumentList: make([]_nodeExpression, len(x.ArgumentList)), | ||||
| 		out := &_nodeNewExpression{ | ||||
| 			callee:       cmpl.parseExpression(in.Callee), | ||||
| 			argumentList: make([]_nodeExpression, len(in.ArgumentList)), | ||||
| 		} | ||||
| 		for i, value := range x.ArgumentList { | ||||
| 			y.argumentList[i] = parseExpression(value) | ||||
| 		for i, value := range in.ArgumentList { | ||||
| 			out.argumentList[i] = cmpl.parseExpression(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.NullLiteral: | ||||
| 		return nullLiteral | ||||
| 
 | ||||
| 	case *ast.NumberLiteral: | ||||
| 		return &_nodeLiteral{ | ||||
| 			value: toValue(x.Value), | ||||
| 			value: toValue(in.Value), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.ObjectLiteral: | ||||
| 		y := &_nodeObjectLiteral{ | ||||
| 			value: make([]_nodeProperty, len(x.Value)), | ||||
| 		out := &_nodeObjectLiteral{ | ||||
| 			value: make([]_nodeProperty, len(in.Value)), | ||||
| 		} | ||||
| 		for i, value := range x.Value { | ||||
| 			y.value[i] = _nodeProperty{ | ||||
| 		for i, value := range in.Value { | ||||
| 			out.value[i] = _nodeProperty{ | ||||
| 				key:   value.Key, | ||||
| 				kind:  value.Kind, | ||||
| 				value: parseExpression(value.Value), | ||||
| 				value: cmpl.parseExpression(value.Value), | ||||
| 			} | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.RegExpLiteral: | ||||
| 		return &_nodeRegExpLiteral{ | ||||
| 			flags:   x.Flags, | ||||
| 			pattern: x.Pattern, | ||||
| 			flags:   in.Flags, | ||||
| 			pattern: in.Pattern, | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.SequenceExpression: | ||||
| 		y := &_nodeSequenceExpression{ | ||||
| 			sequence: make([]_nodeExpression, len(x.Sequence)), | ||||
| 		out := &_nodeSequenceExpression{ | ||||
| 			sequence: make([]_nodeExpression, len(in.Sequence)), | ||||
| 		} | ||||
| 		for i, value := range x.Sequence { | ||||
| 			y.sequence[i] = parseExpression(value) | ||||
| 		for i, value := range in.Sequence { | ||||
| 			out.sequence[i] = cmpl.parseExpression(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.StringLiteral: | ||||
| 		return &_nodeLiteral{ | ||||
| 			value: toValue_string(x.Value), | ||||
| 			value: toValue_string(in.Value), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.ThisExpression: | ||||
| @ -171,203 +176,211 @@ func parseExpression(x ast.Expression) _nodeExpression { | ||||
| 
 | ||||
| 	case *ast.UnaryExpression: | ||||
| 		return &_nodeUnaryExpression{ | ||||
| 			operator: x.Operator, | ||||
| 			operand:  parseExpression(x.Operand), | ||||
| 			postfix:  x.Postfix, | ||||
| 			operator: in.Operator, | ||||
| 			operand:  cmpl.parseExpression(in.Operand), | ||||
| 			postfix:  in.Postfix, | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.VariableExpression: | ||||
| 		return &_nodeVariableExpression{ | ||||
| 			name:        x.Name, | ||||
| 			initializer: parseExpression(x.Initializer), | ||||
| 			idx:         in.Idx0(), | ||||
| 			name:        in.Name, | ||||
| 			initializer: cmpl.parseExpression(in.Initializer), | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	panic(fmt.Errorf("Here be dragons: parseExpression(%T)", x)) | ||||
| 	panic(fmt.Errorf("Here be dragons: cmpl.parseExpression(%T)", in)) | ||||
| } | ||||
| 
 | ||||
| func parseStatement(x ast.Statement) _nodeStatement { | ||||
| 	if x == nil { | ||||
| func (cmpl *_compiler) parseStatement(in ast.Statement) _nodeStatement { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	switch x := x.(type) { | ||||
| 	switch in := in.(type) { | ||||
| 
 | ||||
| 	case *ast.BlockStatement: | ||||
| 		y := &_nodeBlockStatement{ | ||||
| 			list: make([]_nodeStatement, len(x.List)), | ||||
| 		out := &_nodeBlockStatement{ | ||||
| 			list: make([]_nodeStatement, len(in.List)), | ||||
| 		} | ||||
| 		for i, value := range x.List { | ||||
| 			y.list[i] = parseStatement(value) | ||||
| 		for i, value := range in.List { | ||||
| 			out.list[i] = cmpl.parseStatement(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.BranchStatement: | ||||
| 		y := &_nodeBranchStatement{ | ||||
| 			branch: x.Token, | ||||
| 		out := &_nodeBranchStatement{ | ||||
| 			branch: in.Token, | ||||
| 		} | ||||
| 		if x.Label != nil { | ||||
| 			y.label = x.Label.Name | ||||
| 		if in.Label != nil { | ||||
| 			out.label = in.Label.Name | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.DebuggerStatement: | ||||
| 		return &_nodeDebuggerStatement{} | ||||
| 
 | ||||
| 	case *ast.DoWhileStatement: | ||||
| 		y := &_nodeDoWhileStatement{ | ||||
| 			test: parseExpression(x.Test), | ||||
| 		out := &_nodeDoWhileStatement{ | ||||
| 			test: cmpl.parseExpression(in.Test), | ||||
| 		} | ||||
| 		body := parseStatement(x.Body) | ||||
| 		body := cmpl.parseStatement(in.Body) | ||||
| 		if block, ok := body.(*_nodeBlockStatement); ok { | ||||
| 			y.body = block.list | ||||
| 			out.body = block.list | ||||
| 		} else { | ||||
| 			y.body = append(y.body, body) | ||||
| 			out.body = append(out.body, body) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.EmptyStatement: | ||||
| 		return emptyStatement | ||||
| 
 | ||||
| 	case *ast.ExpressionStatement: | ||||
| 		return &_nodeExpressionStatement{ | ||||
| 			expression: parseExpression(x.Expression), | ||||
| 			expression: cmpl.parseExpression(in.Expression), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.ForInStatement: | ||||
| 		y := &_nodeForInStatement{ | ||||
| 			into:   parseExpression(x.Into), | ||||
| 			source: parseExpression(x.Source), | ||||
| 		out := &_nodeForInStatement{ | ||||
| 			into:   cmpl.parseExpression(in.Into), | ||||
| 			source: cmpl.parseExpression(in.Source), | ||||
| 		} | ||||
| 		body := parseStatement(x.Body) | ||||
| 		body := cmpl.parseStatement(in.Body) | ||||
| 		if block, ok := body.(*_nodeBlockStatement); ok { | ||||
| 			y.body = block.list | ||||
| 			out.body = block.list | ||||
| 		} else { | ||||
| 			y.body = append(y.body, body) | ||||
| 			out.body = append(out.body, body) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.ForStatement: | ||||
| 		y := &_nodeForStatement{ | ||||
| 			initializer: parseExpression(x.Initializer), | ||||
| 			update:      parseExpression(x.Update), | ||||
| 			test:        parseExpression(x.Test), | ||||
| 		out := &_nodeForStatement{ | ||||
| 			initializer: cmpl.parseExpression(in.Initializer), | ||||
| 			update:      cmpl.parseExpression(in.Update), | ||||
| 			test:        cmpl.parseExpression(in.Test), | ||||
| 		} | ||||
| 		body := parseStatement(x.Body) | ||||
| 		body := cmpl.parseStatement(in.Body) | ||||
| 		if block, ok := body.(*_nodeBlockStatement); ok { | ||||
| 			y.body = block.list | ||||
| 			out.body = block.list | ||||
| 		} else { | ||||
| 			y.body = append(y.body, body) | ||||
| 			out.body = append(out.body, body) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.IfStatement: | ||||
| 		return &_nodeIfStatement{ | ||||
| 			test:       parseExpression(x.Test), | ||||
| 			consequent: parseStatement(x.Consequent), | ||||
| 			alternate:  parseStatement(x.Alternate), | ||||
| 			test:       cmpl.parseExpression(in.Test), | ||||
| 			consequent: cmpl.parseStatement(in.Consequent), | ||||
| 			alternate:  cmpl.parseStatement(in.Alternate), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.LabelledStatement: | ||||
| 		return &_nodeLabelledStatement{ | ||||
| 			label:     x.Label.Name, | ||||
| 			statement: parseStatement(x.Statement), | ||||
| 			label:     in.Label.Name, | ||||
| 			statement: cmpl.parseStatement(in.Statement), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.ReturnStatement: | ||||
| 		return &_nodeReturnStatement{ | ||||
| 			argument: parseExpression(x.Argument), | ||||
| 			argument: cmpl.parseExpression(in.Argument), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.SwitchStatement: | ||||
| 		y := &_nodeSwitchStatement{ | ||||
| 			discriminant: parseExpression(x.Discriminant), | ||||
| 			default_:     x.Default, | ||||
| 			body:         make([]*_nodeCaseStatement, len(x.Body)), | ||||
| 		out := &_nodeSwitchStatement{ | ||||
| 			discriminant: cmpl.parseExpression(in.Discriminant), | ||||
| 			default_:     in.Default, | ||||
| 			body:         make([]*_nodeCaseStatement, len(in.Body)), | ||||
| 		} | ||||
| 		for i, p := range x.Body { | ||||
| 			q := &_nodeCaseStatement{ | ||||
| 				test:       parseExpression(p.Test), | ||||
| 				consequent: make([]_nodeStatement, len(p.Consequent)), | ||||
| 		for i, clause := range in.Body { | ||||
| 			out.body[i] = &_nodeCaseStatement{ | ||||
| 				test:       cmpl.parseExpression(clause.Test), | ||||
| 				consequent: make([]_nodeStatement, len(clause.Consequent)), | ||||
| 			} | ||||
| 			for j, value := range p.Consequent { | ||||
| 				q.consequent[j] = parseStatement(value) | ||||
| 			for j, value := range clause.Consequent { | ||||
| 				out.body[i].consequent[j] = cmpl.parseStatement(value) | ||||
| 			} | ||||
| 			y.body[i] = q | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.ThrowStatement: | ||||
| 		return &_nodeThrowStatement{ | ||||
| 			argument: parseExpression(x.Argument), | ||||
| 			argument: cmpl.parseExpression(in.Argument), | ||||
| 		} | ||||
| 
 | ||||
| 	case *ast.TryStatement: | ||||
| 		y := &_nodeTryStatement{ | ||||
| 			body:    parseStatement(x.Body), | ||||
| 			finally: parseStatement(x.Finally), | ||||
| 		out := &_nodeTryStatement{ | ||||
| 			body:    cmpl.parseStatement(in.Body), | ||||
| 			finally: cmpl.parseStatement(in.Finally), | ||||
| 		} | ||||
| 		if x.Catch != nil { | ||||
| 			y.catch = &_nodeCatchStatement{ | ||||
| 				parameter: x.Catch.Parameter.Name, | ||||
| 				body:      parseStatement(x.Catch.Body), | ||||
| 		if in.Catch != nil { | ||||
| 			out.catch = &_nodeCatchStatement{ | ||||
| 				parameter: in.Catch.Parameter.Name, | ||||
| 				body:      cmpl.parseStatement(in.Catch.Body), | ||||
| 			} | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.VariableStatement: | ||||
| 		y := &_nodeVariableStatement{ | ||||
| 			list: make([]_nodeExpression, len(x.List)), | ||||
| 		out := &_nodeVariableStatement{ | ||||
| 			list: make([]_nodeExpression, len(in.List)), | ||||
| 		} | ||||
| 		for i, value := range x.List { | ||||
| 			y.list[i] = parseExpression(value) | ||||
| 		for i, value := range in.List { | ||||
| 			out.list[i] = cmpl.parseExpression(value) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.WhileStatement: | ||||
| 		y := &_nodeWhileStatement{ | ||||
| 			test: parseExpression(x.Test), | ||||
| 		out := &_nodeWhileStatement{ | ||||
| 			test: cmpl.parseExpression(in.Test), | ||||
| 		} | ||||
| 		body := parseStatement(x.Body) | ||||
| 		body := cmpl.parseStatement(in.Body) | ||||
| 		if block, ok := body.(*_nodeBlockStatement); ok { | ||||
| 			y.body = block.list | ||||
| 			out.body = block.list | ||||
| 		} else { | ||||
| 			y.body = append(y.body, body) | ||||
| 			out.body = append(out.body, body) | ||||
| 		} | ||||
| 		return y | ||||
| 		return out | ||||
| 
 | ||||
| 	case *ast.WithStatement: | ||||
| 		return &_nodeWithStatement{ | ||||
| 			object: parseExpression(x.Object), | ||||
| 			body:   parseStatement(x.Body), | ||||
| 			object: cmpl.parseExpression(in.Object), | ||||
| 			body:   cmpl.parseStatement(in.Body), | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	panic(fmt.Errorf("Here be dragons: parseStatement(%T)", x)) | ||||
| 	panic(fmt.Errorf("Here be dragons: cmpl.parseStatement(%T)", in)) | ||||
| } | ||||
| 
 | ||||
| func cmpl_parse(x *ast.Program) *_nodeProgram { | ||||
| 	y := &_nodeProgram{ | ||||
| 		body: make([]_nodeStatement, len(x.Body)), | ||||
| func cmpl_parse(in *ast.Program) *_nodeProgram { | ||||
| 	cmpl := _compiler{ | ||||
| 		program: in, | ||||
| 	} | ||||
| 	for i, value := range x.Body { | ||||
| 		y.body[i] = parseStatement(value) | ||||
| 	return cmpl.parse() | ||||
| } | ||||
| 
 | ||||
| func (cmpl *_compiler) _parse(in *ast.Program) *_nodeProgram { | ||||
| 	out := &_nodeProgram{ | ||||
| 		body: make([]_nodeStatement, len(in.Body)), | ||||
| 		file: in.File, | ||||
| 	} | ||||
| 	for _, value := range x.DeclarationList { | ||||
| 	for i, value := range in.Body { | ||||
| 		out.body[i] = cmpl.parseStatement(value) | ||||
| 	} | ||||
| 	for _, value := range in.DeclarationList { | ||||
| 		switch value := value.(type) { | ||||
| 		case *ast.FunctionDeclaration: | ||||
| 			y.functionList = append(y.functionList, parseExpression(value.Function).(*_nodeFunctionLiteral)) | ||||
| 			out.functionList = append(out.functionList, cmpl.parseExpression(value.Function).(*_nodeFunctionLiteral)) | ||||
| 		case *ast.VariableDeclaration: | ||||
| 			for _, value := range value.List { | ||||
| 				y.varList = append(y.varList, value.Name) | ||||
| 				out.varList = append(out.varList, value.Name) | ||||
| 			} | ||||
| 		default: | ||||
| 			panic(fmt.Errorf("Here be dragons: parseProgram.DeclarationList(%T)", value)) | ||||
| 			panic(fmt.Errorf("Here be dragons: cmpl.parseProgram.DeclarationList(%T)", value)) | ||||
| 		} | ||||
| 	} | ||||
| 	return y | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| type _nodeProgram struct { | ||||
| @ -377,6 +390,8 @@ type _nodeProgram struct { | ||||
| 	functionList []*_nodeFunctionLiteral | ||||
| 
 | ||||
| 	variableList []_nodeDeclaration | ||||
| 
 | ||||
| 	file *file.File | ||||
| } | ||||
| 
 | ||||
| type _nodeDeclaration struct { | ||||
| @ -411,6 +426,7 @@ type ( | ||||
| 	} | ||||
| 
 | ||||
| 	_nodeBracketExpression struct { | ||||
| 		idx    file.Idx | ||||
| 		left   _nodeExpression | ||||
| 		member _nodeExpression | ||||
| 	} | ||||
| @ -427,6 +443,7 @@ type ( | ||||
| 	} | ||||
| 
 | ||||
| 	_nodeDotExpression struct { | ||||
| 		idx        file.Idx | ||||
| 		left       _nodeExpression | ||||
| 		identifier string | ||||
| 	} | ||||
| @ -438,9 +455,11 @@ type ( | ||||
| 		parameterList []string | ||||
| 		varList       []string | ||||
| 		functionList  []*_nodeFunctionLiteral | ||||
| 		file          *file.File | ||||
| 	} | ||||
| 
 | ||||
| 	_nodeIdentifier struct { | ||||
| 		idx  file.Idx | ||||
| 		name string | ||||
| 	} | ||||
| 
 | ||||
| @ -483,6 +502,7 @@ type ( | ||||
| 	} | ||||
| 
 | ||||
| 	_nodeVariableExpression struct { | ||||
| 		idx         file.Idx | ||||
| 		name        string | ||||
| 		initializer _nodeExpression | ||||
| 	} | ||||
| @ -15,7 +15,7 @@ func Test_cmpl(t *testing.T) { | ||||
| 			is(err, nil) | ||||
| 			{ | ||||
| 				program := cmpl_parse(program) | ||||
| 				value := vm.runtime.cmpl_evaluate_nodeProgram(program) | ||||
| 				value := vm.runtime.cmpl_evaluate_nodeProgram(program, false) | ||||
| 				if len(expect) > 0 { | ||||
| 					is(value, expect[0]) | ||||
| 				} | ||||
| @ -16,33 +16,33 @@ func formatForConsole(argumentList []Value) string { | ||||
| 
 | ||||
| func builtinConsole_log(call FunctionCall) Value { | ||||
| 	fmt.Fprintln(os.Stdout, formatForConsole(call.ArgumentList)) | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func builtinConsole_error(call FunctionCall) Value { | ||||
| 	fmt.Fprintln(os.Stdout, formatForConsole(call.ArgumentList)) | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| // Nothing happens.
 | ||||
| func builtinConsole_dir(call FunctionCall) Value { | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func builtinConsole_time(call FunctionCall) Value { | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func builtinConsole_timeEnd(call FunctionCall) Value { | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func builtinConsole_trace(call FunctionCall) Value { | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func builtinConsole_assert(call FunctionCall) Value { | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newConsole() *_object { | ||||
| @ -246,7 +246,10 @@ func TestDate_new(t *testing.T) { | ||||
| 	// This is probably incorrect, due to differences in Go date/time handling
 | ||||
| 	// versus ECMA date/time handling, but we'll leave this here for
 | ||||
| 	// future reference
 | ||||
| 	return | ||||
| 
 | ||||
| 	if true { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| @ -64,7 +64,7 @@ func ExampleSynopsis() { | ||||
| 	// 16
 | ||||
| 	// 16
 | ||||
| 	// undefined
 | ||||
| 	// ReferenceError: abcdefghijlmnopqrstuvwxyz is not defined
 | ||||
| 	// ReferenceError: 'abcdefghijlmnopqrstuvwxyz' is not defined
 | ||||
| 	// Hello, Xyzzy.
 | ||||
| 	// Hello, undefined.
 | ||||
| 	// 4
 | ||||
							
								
								
									
										245
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,245 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/file" | ||||
| ) | ||||
| 
 | ||||
| type _exception struct { | ||||
| 	value interface{} | ||||
| } | ||||
| 
 | ||||
| func newException(value interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: value, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_exception) eject() interface{} { | ||||
| 	value := self.value | ||||
| 	self.value = nil // Prevent Go from holding on to the value, whatever it is
 | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| type _error struct { | ||||
| 	name    string | ||||
| 	message string | ||||
| 	trace   []_frame | ||||
| 
 | ||||
| 	offset int | ||||
| } | ||||
| 
 | ||||
| type _frame struct { | ||||
| 	file   *file.File | ||||
| 	offset int | ||||
| 	callee string | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	nativeFrame = _frame{} | ||||
| ) | ||||
| 
 | ||||
| type _at int | ||||
| 
 | ||||
| func (fr _frame) location() string { | ||||
| 	if fr.file == nil { | ||||
| 		return "<unknown>" | ||||
| 	} | ||||
| 	path := fr.file.Name() | ||||
| 	line, column := _position(fr.file, fr.offset) | ||||
| 
 | ||||
| 	if path == "" { | ||||
| 		path = "<anonymous>" | ||||
| 	} | ||||
| 
 | ||||
| 	str := fmt.Sprintf("%s:%d:%d", path, line, column) | ||||
| 
 | ||||
| 	if fr.callee != "" { | ||||
| 		str = fmt.Sprintf("%s (%s)", fr.callee, str) | ||||
| 	} | ||||
| 
 | ||||
| 	return str | ||||
| } | ||||
| 
 | ||||
| func _position(file *file.File, offset int) (line, column int) { | ||||
| 	{ | ||||
| 		offset := offset - file.Base() | ||||
| 		if offset < 0 { | ||||
| 			return -offset, -1 | ||||
| 		} | ||||
| 
 | ||||
| 		src := file.Source() | ||||
| 		if offset >= len(src) { | ||||
| 			return -offset, -len(src) | ||||
| 		} | ||||
| 		src = src[:offset] | ||||
| 
 | ||||
| 		line := 1 + strings.Count(src, "\n") | ||||
| 		column := 0 | ||||
| 		if index := strings.LastIndex(src, "\n"); index >= 0 { | ||||
| 			column = offset - index | ||||
| 		} else { | ||||
| 			column = 1 + len(src) | ||||
| 		} | ||||
| 		return line, column | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc.
 | ||||
| type Error struct { | ||||
| 	_error | ||||
| } | ||||
| 
 | ||||
| // Error returns a description of the error
 | ||||
| //
 | ||||
| //    TypeError: 'def' is not a function
 | ||||
| //
 | ||||
| func (err Error) Error() string { | ||||
| 	if len(err.name) == 0 { | ||||
| 		return err.message | ||||
| 	} | ||||
| 	if len(err.message) == 0 { | ||||
| 		return err.name | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s: %s", err.name, err.message) | ||||
| } | ||||
| 
 | ||||
| // 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/
 | ||||
| //
 | ||||
| func (err Error) String() string { | ||||
| 	str := err.Error() + "\n" | ||||
| 	for _, frame := range err.trace { | ||||
| 		str += "    at " + frame.location() + "\n" | ||||
| 	} | ||||
| 	return str | ||||
| } | ||||
| 
 | ||||
| func (err _error) describe(format string, in ...interface{}) string { | ||||
| 	return fmt.Sprintf(format, in...) | ||||
| } | ||||
| 
 | ||||
| func (self _error) messageValue() Value { | ||||
| 	if self.message == "" { | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	return toValue_string(self.message) | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) typeErrorResult(throw bool) bool { | ||||
| 	if throw { | ||||
| 		panic(rt.panicTypeError()) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func newError(rt *_runtime, name string, in ...interface{}) _error { | ||||
| 	err := _error{ | ||||
| 		name:   name, | ||||
| 		offset: -1, | ||||
| 	} | ||||
| 	description := "" | ||||
| 	length := len(in) | ||||
| 
 | ||||
| 	if rt != nil { | ||||
| 		scope := rt.scope | ||||
| 		frame := scope.frame | ||||
| 		if length > 0 { | ||||
| 			if at, ok := in[length-1].(_at); ok { | ||||
| 				in = in[0 : length-1] | ||||
| 				if scope != nil { | ||||
| 					frame.offset = int(at) | ||||
| 				} | ||||
| 				length -= 1 | ||||
| 			} | ||||
| 			if length > 0 { | ||||
| 				description, in = in[0].(string), in[1:] | ||||
| 			} | ||||
| 		} | ||||
| 		limit := 10 | ||||
| 		err.trace = append(err.trace, frame) | ||||
| 		if scope != nil { | ||||
| 			for limit > 0 { | ||||
| 				scope = scope.outer | ||||
| 				if scope == nil { | ||||
| 					break | ||||
| 				} | ||||
| 				if scope.frame.offset >= 0 { | ||||
| 					err.trace = append(err.trace, scope.frame) | ||||
| 				} | ||||
| 				limit-- | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		if length > 0 { | ||||
| 			description, in = in[0].(string), in[1:] | ||||
| 		} | ||||
| 	} | ||||
| 	err.message = err.describe(description, in...) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) panicTypeError(argumentList ...interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: newError(rt, "TypeError", argumentList...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) panicReferenceError(argumentList ...interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: newError(rt, "ReferenceError", argumentList...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) panicURIError(argumentList ...interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: newError(rt, "URIError", argumentList...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) panicSyntaxError(argumentList ...interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: newError(rt, "SyntaxError", argumentList...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (rt *_runtime) panicRangeError(argumentList ...interface{}) *_exception { | ||||
| 	return &_exception{ | ||||
| 		value: newError(rt, "RangeError", argumentList...), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func catchPanic(function func()) (err error) { | ||||
| 	defer func() { | ||||
| 		if caught := recover(); caught != nil { | ||||
| 			if exception, ok := caught.(*_exception); ok { | ||||
| 				caught = exception.eject() | ||||
| 			} | ||||
| 			switch caught := caught.(type) { | ||||
| 			case _error: | ||||
| 				err = &Error{caught} | ||||
| 				return | ||||
| 			case Value: | ||||
| 				if vl := caught._object(); vl != nil { | ||||
| 					switch vl := vl.value.(type) { | ||||
| 					case _error: | ||||
| 						err = &Error{vl} | ||||
| 						return | ||||
| 					} | ||||
| 				} | ||||
| 				err = errors.New(caught.string()) | ||||
| 				return | ||||
| 			} | ||||
| 			panic(caught) | ||||
| 		} | ||||
| 	}() | ||||
| 	function() | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										192
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/error_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,192 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestError(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		test(` | ||||
|             [ Error.prototype.name, Error.prototype.message, Error.prototype.hasOwnProperty("message") ]; | ||||
|         `, "Error,,true") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestError_instanceof(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		test(`(new TypeError()) instanceof Error`, true) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestPanicValue(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		vm.Set("abc", func(call FunctionCall) Value { | ||||
| 			value, err := call.Otto.Run(`({ def: 3.14159 })`) | ||||
| 			is(err, nil) | ||||
| 			panic(value) | ||||
| 		}) | ||||
| 
 | ||||
| 		test(` | ||||
|             try { | ||||
|                 abc(); | ||||
|             } | ||||
|             catch (err) { | ||||
|                 error = err; | ||||
|             } | ||||
|             [ error instanceof Error, error.message, error.def ]; | ||||
|         `, "false,,3.14159") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_catchPanic(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		vm := New() | ||||
| 
 | ||||
| 		_, err := vm.Run(` | ||||
|             A syntax error that | ||||
|             does not define | ||||
|             var; | ||||
|                 abc; | ||||
|         `) | ||||
| 		is(err, "!=", nil) | ||||
| 
 | ||||
| 		_, err = vm.Call(`abc.def`, nil) | ||||
| 		is(err, "!=", nil) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestErrorContext(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		vm := New() | ||||
| 
 | ||||
| 		_, err := vm.Run(` | ||||
|             undefined(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'undefined' is not a function") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:13") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             ({}).abc(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'abc' is not a function") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:14") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             ("abc").abc(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'abc' is not a function") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:14") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             var ghi = "ghi"; | ||||
|             ghi(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'ghi' is not a function") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:3:13") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             function def() { | ||||
|                 undefined(); | ||||
|             } | ||||
|             function abc() { | ||||
|                 def(); | ||||
|             } | ||||
|             abc(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'undefined' is not a function") | ||||
| 			is(len(err.trace), 3) | ||||
| 			is(err.trace[0].location(), "def (<anonymous>:3:17)") | ||||
| 			is(err.trace[1].location(), "abc (<anonymous>:6:17)") | ||||
| 			is(err.trace[2].location(), "<anonymous>:8:13") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             function abc() { | ||||
|                 xyz(); | ||||
|             } | ||||
|             abc(); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'xyz' is not defined") | ||||
| 			is(len(err.trace), 2) | ||||
| 			is(err.trace[0].location(), "abc (<anonymous>:3:17)") | ||||
| 			is(err.trace[1].location(), "<anonymous>:5:13") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             mno + 1; | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'mno' is not defined") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:13") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             eval("xyz();"); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'xyz' is not defined") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:1:1") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             xyzzy = "Nothing happens." | ||||
|             eval("xyzzy();"); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "'xyzzy' is not a function") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:1:1") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             throw Error("xyzzy"); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "xyzzy") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:19") | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             throw new Error("xyzzy"); | ||||
|         `) | ||||
| 		{ | ||||
| 			err := err.(*Error) | ||||
| 			is(err.message, "xyzzy") | ||||
| 			is(len(err.trace), 1) | ||||
| 			is(err.trace[0].location(), "<anonymous>:2:23") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| @ -10,7 +10,7 @@ import ( | ||||
| 
 | ||||
| func (self *_runtime) evaluateMultiply(left float64, right float64) Value { | ||||
| 	// TODO 11.5.1
 | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) evaluateDivide(left float64, right float64) Value { | ||||
| @ -49,98 +49,98 @@ func (self *_runtime) evaluateDivide(left float64, right float64) Value { | ||||
| 
 | ||||
| func (self *_runtime) evaluateModulo(left float64, right float64) Value { | ||||
| 	// TODO 11.5.3
 | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) calculateBinaryExpression(operator token.Token, left Value, right Value) Value { | ||||
| 
 | ||||
| 	leftValue := self.GetValue(left) | ||||
| 	leftValue := left.resolve() | ||||
| 
 | ||||
| 	switch operator { | ||||
| 
 | ||||
| 	// Additive
 | ||||
| 	case token.PLUS: | ||||
| 		leftValue = toPrimitive(leftValue) | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		rightValue = toPrimitive(rightValue) | ||||
| 
 | ||||
| 		if leftValue.IsString() || rightValue.IsString() { | ||||
| 			return toValue_string(strings.Join([]string{leftValue.toString(), rightValue.toString()}, "")) | ||||
| 			return toValue_string(strings.Join([]string{leftValue.string(), rightValue.string()}, "")) | ||||
| 		} else { | ||||
| 			return toValue_float64(leftValue.toFloat() + rightValue.toFloat()) | ||||
| 			return toValue_float64(leftValue.float64() + rightValue.float64()) | ||||
| 		} | ||||
| 	case token.MINUS: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		return toValue_float64(leftValue.toFloat() - rightValue.toFloat()) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_float64(leftValue.float64() - rightValue.float64()) | ||||
| 
 | ||||
| 		// Multiplicative
 | ||||
| 	case token.MULTIPLY: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		return toValue_float64(leftValue.toFloat() * rightValue.toFloat()) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_float64(leftValue.float64() * rightValue.float64()) | ||||
| 	case token.SLASH: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		return self.evaluateDivide(leftValue.toFloat(), rightValue.toFloat()) | ||||
| 		rightValue := right.resolve() | ||||
| 		return self.evaluateDivide(leftValue.float64(), rightValue.float64()) | ||||
| 	case token.REMAINDER: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		return toValue_float64(math.Mod(leftValue.toFloat(), rightValue.toFloat())) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_float64(math.Mod(leftValue.float64(), rightValue.float64())) | ||||
| 
 | ||||
| 		// Logical
 | ||||
| 	case token.LOGICAL_AND: | ||||
| 		left := toBoolean(leftValue) | ||||
| 		left := leftValue.bool() | ||||
| 		if !left { | ||||
| 			return FalseValue() | ||||
| 			return falseValue | ||||
| 		} | ||||
| 		return toValue_bool(toBoolean(self.GetValue(right))) | ||||
| 		return toValue_bool(right.resolve().bool()) | ||||
| 	case token.LOGICAL_OR: | ||||
| 		left := toBoolean(leftValue) | ||||
| 		left := leftValue.bool() | ||||
| 		if left { | ||||
| 			return TrueValue() | ||||
| 			return trueValue | ||||
| 		} | ||||
| 		return toValue_bool(toBoolean(self.GetValue(right))) | ||||
| 		return toValue_bool(right.resolve().bool()) | ||||
| 
 | ||||
| 		// Bitwise
 | ||||
| 	case token.AND: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_int32(toInt32(leftValue) & toInt32(rightValue)) | ||||
| 	case token.OR: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_int32(toInt32(leftValue) | toInt32(rightValue)) | ||||
| 	case token.EXCLUSIVE_OR: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_int32(toInt32(leftValue) ^ toInt32(rightValue)) | ||||
| 
 | ||||
| 		// Shift
 | ||||
| 		// (Masking of 0x1f is to restrict the shift to a maximum of 31 places)
 | ||||
| 	case token.SHIFT_LEFT: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_int32(toInt32(leftValue) << (toUint32(rightValue) & 0x1f)) | ||||
| 	case token.SHIFT_RIGHT: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		return toValue_int32(toInt32(leftValue) >> (toUint32(rightValue) & 0x1f)) | ||||
| 	case token.UNSIGNED_SHIFT_RIGHT: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		// Shifting an unsigned integer is a logical shift
 | ||||
| 		return toValue_uint32(toUint32(leftValue) >> (toUint32(rightValue) & 0x1f)) | ||||
| 
 | ||||
| 	case token.INSTANCEOF: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		if !rightValue.IsObject() { | ||||
| 			panic(newTypeError("Expecting a function in instanceof check, but got: %v", rightValue)) | ||||
| 			panic(self.panicTypeError("Expecting a function in instanceof check, but got: %v", rightValue)) | ||||
| 		} | ||||
| 		return toValue_bool(rightValue._object().HasInstance(leftValue)) | ||||
| 		return toValue_bool(rightValue._object().hasInstance(leftValue)) | ||||
| 
 | ||||
| 	case token.IN: | ||||
| 		rightValue := self.GetValue(right) | ||||
| 		rightValue := right.resolve() | ||||
| 		if !rightValue.IsObject() { | ||||
| 			panic(newTypeError()) | ||||
| 			panic(self.panicTypeError()) | ||||
| 		} | ||||
| 		return toValue_bool(rightValue._object().hasProperty(toString(leftValue))) | ||||
| 		return toValue_bool(rightValue._object().hasProperty(leftValue.string())) | ||||
| 	} | ||||
| 
 | ||||
| 	panic(hereBeDragons(operator)) | ||||
| } | ||||
| 
 | ||||
| func valueKindDispatchKey(left _valueType, right _valueType) int { | ||||
| func valueKindDispatchKey(left _valueKind, right _valueKind) int { | ||||
| 	return (int(left) << 2) + int(right) | ||||
| } | ||||
| 
 | ||||
| @ -150,10 +150,10 @@ func makeEqualDispatch() map[int](func(Value, Value) bool) { | ||||
| 	key := valueKindDispatchKey | ||||
| 	return map[int](func(Value, Value) bool){ | ||||
| 
 | ||||
| 		key(valueNumber, valueObject): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, | ||||
| 		key(valueString, valueObject): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, | ||||
| 		key(valueObject, valueNumber): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, | ||||
| 		key(valueObject, valueString): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, | ||||
| 		key(valueNumber, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, | ||||
| 		key(valueString, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, | ||||
| 		key(valueObject, valueNumber): func(x Value, y Value) bool { return x.float64() == y.float64() }, | ||||
| 		key(valueObject, valueString): func(x Value, y Value) bool { return x.float64() == y.float64() }, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -167,7 +167,7 @@ const ( | ||||
| 
 | ||||
| func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult { | ||||
| 
 | ||||
| 	x := UndefinedValue() | ||||
| 	x := Value{} | ||||
| 	y := x | ||||
| 
 | ||||
| 	if leftFirst { | ||||
| @ -179,14 +179,14 @@ func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult | ||||
| 	} | ||||
| 
 | ||||
| 	result := false | ||||
| 	if x._valueType != valueString || y._valueType != valueString { | ||||
| 		x, y := x.toFloat(), y.toFloat() | ||||
| 	if x.kind != valueString || y.kind != valueString { | ||||
| 		x, y := x.float64(), y.float64() | ||||
| 		if math.IsNaN(x) || math.IsNaN(y) { | ||||
| 			return lessThanUndefined | ||||
| 		} | ||||
| 		result = x < y | ||||
| 	} else { | ||||
| 		x, y := x.toString(), y.toString() | ||||
| 		x, y := x.string(), y.string() | ||||
| 		result = x < y | ||||
| 	} | ||||
| 
 | ||||
| @ -197,6 +197,7 @@ func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult | ||||
| 	return lessThanFalse | ||||
| } | ||||
| 
 | ||||
| // FIXME Probably a map is not the most efficient way to do this
 | ||||
| var lessThanTable [4](map[_lessThanResult]bool) = [4](map[_lessThanResult]bool){ | ||||
| 	// <
 | ||||
| 	map[_lessThanResult]bool{ | ||||
| @ -231,8 +232,8 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri | ||||
| 
 | ||||
| 	// FIXME Use strictEqualityComparison?
 | ||||
| 	// TODO This might be redundant now (with regards to evaluateComparison)
 | ||||
| 	x := self.GetValue(left) | ||||
| 	y := self.GetValue(right) | ||||
| 	x := left.resolve() | ||||
| 	y := right.resolve() | ||||
| 
 | ||||
| 	kindEqualKind := false | ||||
| 	result := true | ||||
| @ -251,7 +252,7 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri | ||||
| 		negate = true | ||||
| 		fallthrough | ||||
| 	case token.STRICT_EQUAL: | ||||
| 		if x._valueType != y._valueType { | ||||
| 		if x.kind != y.kind { | ||||
| 			result = false | ||||
| 		} else { | ||||
| 			kindEqualKind = true | ||||
| @ -260,21 +261,21 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri | ||||
| 		negate = true | ||||
| 		fallthrough | ||||
| 	case token.EQUAL: | ||||
| 		if x._valueType == y._valueType { | ||||
| 		if x.kind == y.kind { | ||||
| 			kindEqualKind = true | ||||
| 		} else if x._valueType <= valueUndefined && y._valueType <= valueUndefined { | ||||
| 		} else if x.kind <= valueNull && y.kind <= valueNull { | ||||
| 			result = true | ||||
| 		} else if x._valueType <= valueUndefined || y._valueType <= valueUndefined { | ||||
| 		} else if x.kind <= valueNull || y.kind <= valueNull { | ||||
| 			result = false | ||||
| 		} else if x._valueType <= valueString && y._valueType <= valueString { | ||||
| 			result = x.toFloat() == y.toFloat() | ||||
| 		} else if x._valueType == valueBoolean { | ||||
| 			result = self.calculateComparison(token.EQUAL, toValue_float64(x.toFloat()), y) | ||||
| 		} else if y._valueType == valueBoolean { | ||||
| 			result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.toFloat())) | ||||
| 		} else if x._valueType == valueObject { | ||||
| 		} else if x.kind <= valueString && y.kind <= valueString { | ||||
| 			result = x.float64() == y.float64() | ||||
| 		} else if x.kind == valueBoolean { | ||||
| 			result = self.calculateComparison(token.EQUAL, toValue_float64(x.float64()), y) | ||||
| 		} else if y.kind == valueBoolean { | ||||
| 			result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.float64())) | ||||
| 		} else if x.kind == valueObject { | ||||
| 			result = self.calculateComparison(token.EQUAL, toPrimitive(x), y) | ||||
| 		} else if y._valueType == valueObject { | ||||
| 		} else if y.kind == valueObject { | ||||
| 			result = self.calculateComparison(token.EQUAL, x, toPrimitive(y)) | ||||
| 		} else { | ||||
| 			panic(hereBeDragons("Unable to test for equality: %v ==? %v", x, y)) | ||||
| @ -284,21 +285,21 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri | ||||
| 	} | ||||
| 
 | ||||
| 	if kindEqualKind { | ||||
| 		switch x._valueType { | ||||
| 		switch x.kind { | ||||
| 		case valueUndefined, valueNull: | ||||
| 			result = true | ||||
| 		case valueNumber: | ||||
| 			x := x.toFloat() | ||||
| 			y := y.toFloat() | ||||
| 			x := x.float64() | ||||
| 			y := y.float64() | ||||
| 			if math.IsNaN(x) || math.IsNaN(y) { | ||||
| 				result = false | ||||
| 			} else { | ||||
| 				result = x == y | ||||
| 			} | ||||
| 		case valueString: | ||||
| 			result = x.toString() == y.toString() | ||||
| 			result = x.string() == y.string() | ||||
| 		case valueBoolean: | ||||
| 			result = x.toBoolean() == y.toBoolean() | ||||
| 			result = x.bool() == y.bool() | ||||
| 		case valueObject: | ||||
| 			result = x._object() == y._object() | ||||
| 		default: | ||||
| @ -313,5 +314,5 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri | ||||
| 	return result | ||||
| 
 | ||||
| ERROR: | ||||
| 	panic(hereBeDragons("%v (%v) %s %v (%v)", x, x._valueType, comparator, y, y._valueType)) | ||||
| 	panic(hereBeDragons("%v (%v) %s %v (%v)", x, x.kind, comparator, y, y.kind)) | ||||
| } | ||||
| @ -229,7 +229,7 @@ func TestFunction_bind(t *testing.T) { | ||||
| 
 | ||||
| 		test(`raise: | ||||
|             Math.bind(); | ||||
|         `, "TypeError: undefined is not a function") | ||||
|         `, "TypeError: 'bind' is not a function") | ||||
| 
 | ||||
| 		test(` | ||||
|             function construct(fn, arguments) { | ||||
| @ -251,6 +251,14 @@ func TestFunction_bind(t *testing.T) { | ||||
|             var result = new newFn(); | ||||
|             [ result.hasOwnProperty("abc"), result.hasOwnProperty("def"), result.abc, result.def ]; | ||||
|         `, "true,true,abc,true") | ||||
| 
 | ||||
| 		test(` | ||||
|             abc = function(){ | ||||
|                 return "abc"; | ||||
|             }; | ||||
|             def = abc.bind(); | ||||
|             def.toString(); | ||||
|         `, "function () { [native code] }") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -7,28 +7,28 @@ import ( | ||||
| 
 | ||||
| var ( | ||||
| 	prototypeValueObject   = interface{}(nil) | ||||
| 	prototypeValueFunction = _functionObject{ | ||||
| 		call: _nativeCallFunction{"", func(_ FunctionCall) Value { | ||||
| 			return UndefinedValue() | ||||
| 		}}, | ||||
| 	prototypeValueFunction = _nativeFunctionObject{ | ||||
| 		call: func(_ FunctionCall) Value { | ||||
| 			return Value{} | ||||
| 		}, | ||||
| 	} | ||||
| 	prototypeValueString = _stringASCII("") | ||||
| 	// TODO Make this just false?
 | ||||
| 	prototypeValueBoolean = Value{ | ||||
| 		_valueType: valueBoolean, | ||||
| 		value:      false, | ||||
| 		kind:  valueBoolean, | ||||
| 		value: false, | ||||
| 	} | ||||
| 	prototypeValueNumber = Value{ | ||||
| 		_valueType: valueNumber, | ||||
| 		value:      0, | ||||
| 		kind:  valueNumber, | ||||
| 		value: 0, | ||||
| 	} | ||||
| 	prototypeValueDate = _dateObject{ | ||||
| 		epoch: 0, | ||||
| 		isNaN: false, | ||||
| 		time:  time.Unix(0, 0).UTC(), | ||||
| 		value: Value{ | ||||
| 			_valueType: valueNumber, | ||||
| 			value:      0, | ||||
| 			kind:  valueNumber, | ||||
| 			value: 0, | ||||
| 		}, | ||||
| 	} | ||||
| 	prototypeValueRegExp = _regExpObject{ | ||||
| @ -45,16 +45,13 @@ func newContext() *_runtime { | ||||
| 
 | ||||
| 	self := &_runtime{} | ||||
| 
 | ||||
| 	self.GlobalEnvironment = self.newObjectEnvironment(nil, nil) | ||||
| 	self.GlobalObject = self.GlobalEnvironment.Object | ||||
| 
 | ||||
| 	self.EnterGlobalExecutionContext() | ||||
| 	self.globalStash = self.newObjectStash(nil, nil) | ||||
| 	self.globalObject = self.globalStash.object | ||||
| 
 | ||||
| 	_newContext(self) | ||||
| 
 | ||||
| 	self.eval = self.GlobalObject.property["eval"].value.(Value).value.(*_object) | ||||
| 	self.GlobalObject.prototype = self.Global.ObjectPrototype | ||||
| 	//self.parser = ast.NewParser()
 | ||||
| 	self.eval = self.globalObject.property["eval"].value.(Value).value.(*_object) | ||||
| 	self.globalObject.prototype = self.global.ObjectPrototype | ||||
| 
 | ||||
| 	return self | ||||
| } | ||||
| @ -94,13 +91,13 @@ func (self *_object) hasPrimitive() bool { | ||||
| 
 | ||||
| func (runtime *_runtime) newObject() *_object { | ||||
| 	self := runtime.newClassObject("Object") | ||||
| 	self.prototype = runtime.Global.ObjectPrototype | ||||
| 	self.prototype = runtime.global.ObjectPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newArray(length uint32) *_object { | ||||
| 	self := runtime.newArrayObject(length) | ||||
| 	self.prototype = runtime.Global.ArrayPrototype | ||||
| 	self.prototype = runtime.global.ArrayPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| @ -117,19 +114,19 @@ func (runtime *_runtime) newArrayOf(valueArray []Value) *_object { | ||||
| 
 | ||||
| func (runtime *_runtime) newString(value Value) *_object { | ||||
| 	self := runtime.newStringObject(value) | ||||
| 	self.prototype = runtime.Global.StringPrototype | ||||
| 	self.prototype = runtime.global.StringPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newBoolean(value Value) *_object { | ||||
| 	self := runtime.newBooleanObject(value) | ||||
| 	self.prototype = runtime.Global.BooleanPrototype | ||||
| 	self.prototype = runtime.global.BooleanPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newNumber(value Value) *_object { | ||||
| 	self := runtime.newNumberObject(value) | ||||
| 	self.prototype = runtime.Global.NumberPrototype | ||||
| 	self.prototype = runtime.global.NumberPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| @ -139,17 +136,17 @@ func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_objec | ||||
| 	flags := "" | ||||
| 	if object := patternValue._object(); object != nil && object.class == "RegExp" { | ||||
| 		if flagsValue.IsDefined() { | ||||
| 			panic(newTypeError("Cannot supply flags when constructing one RegExp from another")) | ||||
| 			panic(runtime.panicTypeError("Cannot supply flags when constructing one RegExp from another")) | ||||
| 		} | ||||
| 		regExp := object.regExpValue() | ||||
| 		pattern = regExp.source | ||||
| 		flags = regExp.flags | ||||
| 	} else { | ||||
| 		if patternValue.IsDefined() { | ||||
| 			pattern = toString(patternValue) | ||||
| 			pattern = patternValue.string() | ||||
| 		} | ||||
| 		if flagsValue.IsDefined() { | ||||
| 			flags = toString(flagsValue) | ||||
| 			flags = flagsValue.string() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -158,14 +155,14 @@ func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_objec | ||||
| 
 | ||||
| func (runtime *_runtime) _newRegExp(pattern string, flags string) *_object { | ||||
| 	self := runtime.newRegExpObject(pattern, flags) | ||||
| 	self.prototype = runtime.Global.RegExpPrototype | ||||
| 	self.prototype = runtime.global.RegExpPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| // TODO Should (probably) be one argument, right? This is redundant
 | ||||
| func (runtime *_runtime) newDate(epoch float64) *_object { | ||||
| 	self := runtime.newDateObject(epoch) | ||||
| 	self.prototype = runtime.Global.DatePrototype | ||||
| 	self.prototype = runtime.global.DatePrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| @ -186,8 +183,8 @@ func (runtime *_runtime) newError(name string, message Value) *_object { | ||||
| 		return runtime.newURIError(message) | ||||
| 	} | ||||
| 
 | ||||
| 	self = runtime.newErrorObject(message) | ||||
| 	self.prototype = runtime.Global.ErrorPrototype | ||||
| 	self = runtime.newErrorObject(name, message) | ||||
| 	self.prototype = runtime.global.ErrorPrototype | ||||
| 	if name != "" { | ||||
| 		self.defineProperty("name", toValue_string(name), 0111, false) | ||||
| 	} | ||||
| @ -196,19 +193,29 @@ func (runtime *_runtime) newError(name string, message Value) *_object { | ||||
| 
 | ||||
| func (runtime *_runtime) newNativeFunction(name string, _nativeFunction _nativeFunction) *_object { | ||||
| 	self := runtime.newNativeFunctionObject(name, _nativeFunction, 0) | ||||
| 	self.prototype = runtime.Global.FunctionPrototype | ||||
| 	self.prototype = runtime.global.FunctionPrototype | ||||
| 	prototype := runtime.newObject() | ||||
| 	self.defineProperty("prototype", toValue_object(prototype), 0100, false) | ||||
| 	prototype.defineProperty("constructor", toValue_object(self), 0100, false) | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newNodeFunction(node *_nodeFunctionLiteral, scopeEnvironment _environment) *_object { | ||||
| func (runtime *_runtime) newNodeFunction(node *_nodeFunctionLiteral, scopeEnvironment _stash) *_object { | ||||
| 	// TODO Implement 13.2 fully
 | ||||
| 	self := runtime.newNodeFunctionObject(node, scopeEnvironment) | ||||
| 	self.prototype = runtime.Global.FunctionPrototype | ||||
| 	self.prototype = runtime.global.FunctionPrototype | ||||
| 	prototype := runtime.newObject() | ||||
| 	self.defineProperty("prototype", toValue_object(prototype), 0100, false) | ||||
| 	prototype.defineProperty("constructor", toValue_object(self), 0101, false) | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| // FIXME Only in one place...
 | ||||
| func (runtime *_runtime) newBoundFunction(target *_object, this Value, argumentList []Value) *_object { | ||||
| 	self := runtime.newBoundFunctionObject(target, this, argumentList) | ||||
| 	self.prototype = runtime.global.FunctionPrototype | ||||
| 	prototype := runtime.newObject() | ||||
| 	self.defineProperty("prototype", toValue_object(prototype), 0100, false) | ||||
| 	prototype.defineProperty("constructor", toValue_object(self), 0100, false) | ||||
| 	return self | ||||
| } | ||||
| @ -31,35 +31,38 @@ func TestGlobal(t *testing.T) { | ||||
| 				return value | ||||
| 			} | ||||
| 
 | ||||
| 			value := runtime.localGet("Object")._object().Call(UndefinedValue(), []Value{toValue(runtime.newObject())}) | ||||
| 			is(value.IsObject(), true) | ||||
| 			is(value, "[object Object]") | ||||
| 			is(value._object().prototype == runtime.Global.ObjectPrototype, true) | ||||
| 			is(value._object().prototype == runtime.Global.Object.get("prototype")._object(), true) | ||||
| 			is(value._object().get("toString"), "function toString() { [native code] }") | ||||
| 			is(call(value.Object(), "hasOwnProperty", "hasOwnProperty"), false) | ||||
| 			// FIXME enterGlobalScope
 | ||||
| 			if false { | ||||
| 				value := runtime.scope.lexical.getBinding("Object", false)._object().call(UndefinedValue(), []Value{toValue(runtime.newObject())}, false, nativeFrame) | ||||
| 				is(value.IsObject(), true) | ||||
| 				is(value, "[object Object]") | ||||
| 				is(value._object().prototype == runtime.global.ObjectPrototype, true) | ||||
| 				is(value._object().prototype == runtime.global.Object.get("prototype")._object(), true) | ||||
| 				is(value._object().get("toString"), "function toString() { [native code] }") | ||||
| 				is(call(value.Object(), "hasOwnProperty", "hasOwnProperty"), false) | ||||
| 
 | ||||
| 			is(call(value._object().get("toString")._object().prototype, "toString"), "function () { [native code] }") // TODO Is this right?
 | ||||
| 			is(value._object().get("toString")._object().get("toString"), "function toString() { [native code] }") | ||||
| 			is(value._object().get("toString")._object().get("toString")._object(), "function toString() { [native code] }") | ||||
| 				is(call(value._object().get("toString")._object().prototype, "toString"), "function () { [native code] }") // TODO Is this right?
 | ||||
| 				is(value._object().get("toString")._object().get("toString"), "function toString() { [native code] }") | ||||
| 				is(value._object().get("toString")._object().get("toString")._object(), "function toString() { [native code] }") | ||||
| 
 | ||||
| 			is(call(value._object(), "propertyIsEnumerable", "isPrototypeOf"), false) | ||||
| 			value._object().put("xyzzy", toValue_string("Nothing happens."), false) | ||||
| 			is(call(value, "propertyIsEnumerable", "isPrototypeOf"), false) | ||||
| 			is(call(value, "propertyIsEnumerable", "xyzzy"), true) | ||||
| 			is(value._object().get("xyzzy"), "Nothing happens.") | ||||
| 				is(call(value._object(), "propertyIsEnumerable", "isPrototypeOf"), false) | ||||
| 				value._object().put("xyzzy", toValue_string("Nothing happens."), false) | ||||
| 				is(call(value, "propertyIsEnumerable", "isPrototypeOf"), false) | ||||
| 				is(call(value, "propertyIsEnumerable", "xyzzy"), true) | ||||
| 				is(value._object().get("xyzzy"), "Nothing happens.") | ||||
| 
 | ||||
| 			is(call(runtime.localGet("Object"), "isPrototypeOf", value), false) | ||||
| 			is(call(runtime.localGet("Object")._object().get("prototype"), "isPrototypeOf", value), true) | ||||
| 			is(call(runtime.localGet("Function"), "isPrototypeOf", value), false) | ||||
| 				is(call(runtime.scope.lexical.getBinding("Object", false), "isPrototypeOf", value), false) | ||||
| 				is(call(runtime.scope.lexical.getBinding("Object", false)._object().get("prototype"), "isPrototypeOf", value), true) | ||||
| 				is(call(runtime.scope.lexical.getBinding("Function", false), "isPrototypeOf", value), false) | ||||
| 
 | ||||
| 			is(runtime.newObject().prototype == runtime.Global.Object.get("prototype")._object(), true) | ||||
| 				is(runtime.newObject().prototype == runtime.global.Object.get("prototype")._object(), true) | ||||
| 
 | ||||
| 			abc := runtime.newBoolean(toValue_bool(true)) | ||||
| 			is(toValue_object(abc), "true") // TODO Call primitive?
 | ||||
| 				abc := runtime.newBoolean(toValue_bool(true)) | ||||
| 				is(toValue_object(abc), "true") // TODO Call primitive?
 | ||||
| 
 | ||||
| 			def := runtime.localGet("Boolean")._object().Construct(UndefinedValue(), []Value{}) | ||||
| 			is(def, "false") // TODO Call primitive?
 | ||||
| 				//def := runtime.localGet("Boolean")._object().Construct(UndefinedValue(), []Value{})
 | ||||
| 				//is(def, "false") // TODO Call primitive?
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		test(`new Number().constructor == Number`, true) | ||||
| @ -43,7 +43,7 @@ for (qw/int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float32 float | ||||
| 
 | ||||
| func toValue_$_(value $_) Value { | ||||
|     return Value{ | ||||
|         _valueType: valueNumber, | ||||
|         kind: valueNumber, | ||||
|         value: value, | ||||
|     } | ||||
| } | ||||
| @ -54,28 +54,28 @@ $fmt->print(<<_END_); | ||||
| 
 | ||||
| func toValue_string(value string) Value { | ||||
|     return Value{ | ||||
|         _valueType: valueString, | ||||
|         kind: valueString, | ||||
|         value: value, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| func toValue_string16(value []uint16) Value { | ||||
|     return Value{ | ||||
|         _valueType: valueString, | ||||
|         kind: valueString, | ||||
|         value: value, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| func toValue_bool(value bool) Value { | ||||
|     return Value{ | ||||
|         _valueType: valueBoolean, | ||||
|         kind: valueBoolean, | ||||
|         value: value, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| func toValue_object(value *_object) Value { | ||||
|     return Value{ | ||||
|         _valueType: valueObject, | ||||
|         kind: valueObject, | ||||
|         value: value, | ||||
|     } | ||||
| } | ||||
| @ -642,9 +642,9 @@ sub newContext { | ||||
|             my $propertyOrder = $self->propertyOrder(@propertyMap); | ||||
|             $propertyOrder =~ s/^propertyOrder: //; | ||||
|             return | ||||
|             "runtime.GlobalObject.property =", | ||||
|             "runtime.globalObject.property =", | ||||
|             @propertyMap, | ||||
|             "runtime.GlobalObject.propertyOrder =", | ||||
|             "runtime.globalObject.propertyOrder =", | ||||
|             $propertyOrder, | ||||
|             ; | ||||
|         }), | ||||
| @ -666,7 +666,7 @@ sub block { | ||||
|     while (@input) { | ||||
|         local $_ = shift @input; | ||||
|         if (m/^\./) { | ||||
|             $_ = "runtime.Global$_"; | ||||
|             $_ = "runtime.global$_"; | ||||
|         } | ||||
|         if (m/ :?=$/) { | ||||
|             $_ .= shift @input; | ||||
| @ -712,7 +712,7 @@ sub globalDeclare { | ||||
|     my @got; | ||||
|     while (@_) { | ||||
|         my $name = shift; | ||||
|         push @got, $self->property($name, $self->objectValue("runtime.Global.$name"), "0101"), | ||||
|         push @got, $self->property($name, $self->objectValue("runtime.global.$name"), "0101"), | ||||
|     } | ||||
|     return @got; | ||||
| } | ||||
| @ -743,7 +743,7 @@ sub globalObject { | ||||
|     runtime: runtime, | ||||
|     class: "$name", | ||||
|     objectClass: _classObject, | ||||
|     prototype: runtime.Global.ObjectPrototype, | ||||
|     prototype: runtime.global.ObjectPrototype, | ||||
|     extensible: true, | ||||
|     $propertyMap | ||||
| } | ||||
| @ -757,7 +757,7 @@ sub globalFunction { | ||||
|      | ||||
|     my $builtin = "builtin${name}"; | ||||
|     my $builtinNew = "builtinNew${name}"; | ||||
|     my $prototype = "runtime.Global.${name}Prototype"; | ||||
|     my $prototype = "runtime.global.${name}Prototype"; | ||||
|     my $propertyMap = ""; | ||||
|     unshift @_, | ||||
|         $self->property("length", $self->numberValue($length), "0"), | ||||
| @ -772,7 +772,7 @@ sub globalFunction { | ||||
| 
 | ||||
|     push @postblock, $self->statement( | ||||
|         "$prototype.property[\"constructor\"] =", | ||||
|         $self->property(undef, $self->objectValue("runtime.Global.${name}"), "0101"), | ||||
|         $self->property(undef, $self->objectValue("runtime.global.${name}"), "0101"), | ||||
|     ); | ||||
| 
 | ||||
|     return trim <<_END_; | ||||
| @ -780,9 +780,9 @@ sub globalFunction { | ||||
|     runtime: runtime, | ||||
|     class: "Function", | ||||
|     objectClass: _classObject, | ||||
|     prototype: runtime.Global.FunctionPrototype, | ||||
|     prototype: runtime.global.FunctionPrototype, | ||||
|     extensible: true, | ||||
|     value: @{[ $self->functionOf($self->nativeCallFunction($name, $builtin), $builtinNew) ]}, | ||||
|     value: @{[ $self->nativeFunctionOf($name, $builtin, $builtinNew) ]}, | ||||
|     $propertyMap | ||||
| } | ||||
| _END_ | ||||
| @ -813,7 +813,7 @@ sub globalPrototype { | ||||
|     } | ||||
| 
 | ||||
|     if ($prototype =~ m/^\./) { | ||||
|         $prototype = "runtime.Global$prototype"; | ||||
|         $prototype = "runtime.global$prototype"; | ||||
|     } | ||||
| 
 | ||||
|     my $propertyMap = ""; | ||||
| @ -869,11 +869,11 @@ sub newFunction { | ||||
|     runtime: runtime, | ||||
|     class: "Function", | ||||
|     objectClass: _classObject, | ||||
|     prototype: runtime.Global.FunctionPrototype, | ||||
|     prototype: runtime.global.FunctionPrototype, | ||||
|     extensible: true, | ||||
|     property: @{[ join "\n", $self->propertyMap(@propertyMap) ]}, | ||||
|     $propertyOrder | ||||
|     value: @{[ $self->functionOf($self->nativeCallFunction($name, $func)) ]}, | ||||
|     value: @{[ $self->nativeFunctionOf($name, $func) ]}, | ||||
| }  | ||||
| _END_ | ||||
|     ); | ||||
| @ -892,7 +892,7 @@ sub newObject { | ||||
|     runtime: runtime, | ||||
|     class: "Object", | ||||
|     objectClass: _classObject, | ||||
|     prototype: runtime.Global.ObjectPrototype, | ||||
|     prototype: runtime.global.ObjectPrototype, | ||||
|     extensible: true, | ||||
|     property: $propertyMap, | ||||
|     $propertyOrder, | ||||
| @ -917,7 +917,7 @@ sub newPrototypeObject { | ||||
|     runtime: runtime, | ||||
|     class: "$class", | ||||
|     objectClass: $objectClass, | ||||
|     prototype: runtime.Global.ObjectPrototype, | ||||
|     prototype: runtime.global.ObjectPrototype, | ||||
|     extensible: true, | ||||
|     property: $propertyMap, | ||||
|     $propertyOrder, | ||||
| @ -959,6 +959,26 @@ _functionObject{ | ||||
| _END_ | ||||
| } | ||||
| 
 | ||||
| sub nativeFunctionOf { | ||||
|     my $self = shift; | ||||
|     my $name = shift; | ||||
|     my $call = shift; | ||||
|     my $construct = shift; | ||||
|     if ($construct) { | ||||
|         $construct = "construct: $construct,"; | ||||
|     } else { | ||||
|         $construct = ""; | ||||
|     } | ||||
| 
 | ||||
|     return trim <<_END_ | ||||
| _nativeFunctionObject{ | ||||
|     name: "$name", | ||||
|     call: $call, | ||||
|     $construct | ||||
| } | ||||
| _END_ | ||||
| } | ||||
| 
 | ||||
| sub nameProperty { | ||||
|     my $self = shift; | ||||
|     my $name = shift; | ||||
| @ -977,7 +997,7 @@ sub numberValue { | ||||
|     my $value = shift; | ||||
|     return trim <<_END_; | ||||
| Value{ | ||||
|     _valueType: valueNumber, | ||||
|     kind: valueNumber, | ||||
|     value: $value, | ||||
| } | ||||
| _END_ | ||||
| @ -1028,7 +1048,7 @@ sub objectValue { | ||||
|     my $value = shift; | ||||
|     return trim <<_END_ | ||||
| Value{ | ||||
|     _valueType: valueObject, | ||||
|     kind: valueObject, | ||||
|     value: $value, | ||||
| } | ||||
| _END_ | ||||
| @ -1039,7 +1059,7 @@ sub stringValue { | ||||
|     my $value = shift; | ||||
|     return trim <<_END_ | ||||
| Value{ | ||||
|     _valueType: valueString, | ||||
|     kind: valueString, | ||||
|     value: "$value", | ||||
| } | ||||
| _END_ | ||||
| @ -1050,7 +1070,7 @@ sub booleanValue { | ||||
|     my $value = shift; | ||||
|     return trim <<_END_ | ||||
| Value{ | ||||
|     _valueType: valueBoolean, | ||||
|     kind: valueBoolean, | ||||
|     value: $value, | ||||
| } | ||||
| _END_ | ||||
| @ -1060,7 +1080,7 @@ sub undefinedValue { | ||||
|     my $self = shift; | ||||
|     return trim <<_END_ | ||||
| Value{ | ||||
|     _valueType: valueUndefined, | ||||
|     kind: valueUndefined, | ||||
| } | ||||
| _END_ | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -144,15 +144,13 @@ func TestNumber_toLocaleString(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func Test_toInteger(t *testing.T) { | ||||
| func TestValue_number(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		integer := toInteger(toValue(0.0)) | ||||
| 		is(integer.valid(), true) | ||||
| 		is(integer.exact(), true) | ||||
| 		nm := toValue(0.0).number() | ||||
| 		is(nm.kind, numberInteger) | ||||
| 
 | ||||
| 		integer = toInteger(toValue(3.14159)) | ||||
| 		is(integer.valid(), true) | ||||
| 		is(integer.exact(), false) | ||||
| 		nm = toValue(3.14159).number() | ||||
| 		is(nm.kind, numberFloat) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -85,20 +85,20 @@ func (self *_object) DefaultValue(hint _defaultValueHint) Value { | ||||
| 	} | ||||
| 	for _, methodName := range methodSequence { | ||||
| 		method := self.get(methodName) | ||||
| 		// FIXME This is redundant...
 | ||||
| 		if method.isCallable() { | ||||
| 			result := method._object().Call(toValue_object(self)) | ||||
| 			result := method._object().call(toValue_object(self), nil, false, nativeFrame) | ||||
| 			if result.IsPrimitive() { | ||||
| 				return result | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	panic(newTypeError()) | ||||
| 	return UndefinedValue() | ||||
| 	panic(self.runtime.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func (self *_object) String() string { | ||||
| 	return toString(self.DefaultValue(defaultValueHintString)) | ||||
| 	return self.DefaultValue(defaultValueHintString).string() | ||||
| } | ||||
| 
 | ||||
| func (self *_object) defineProperty(name string, value Value, mode _propertyMode, throw bool) bool { | ||||
| @ -130,7 +130,7 @@ func (self *_object) _read(name string) (_property, bool) { | ||||
| 
 | ||||
| func (self *_object) _write(name string, value interface{}, mode _propertyMode) { | ||||
| 	if value == nil { | ||||
| 		value = UndefinedValue() | ||||
| 		value = Value{} | ||||
| 	} | ||||
| 	_, exists := self.property[name] | ||||
| 	self.property[name] = _property{value, mode} | ||||
| @ -193,7 +193,7 @@ func objectGet(self *_object, name string) Value { | ||||
| 	if property != nil { | ||||
| 		return property.get(self) | ||||
| 	} | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| // 8.12.4
 | ||||
| @ -214,7 +214,7 @@ func _objectCanPut(self *_object, name string) (canPut bool, property *_property | ||||
| 			canPut = setter != nil | ||||
| 			return | ||||
| 		default: | ||||
| 			panic(newTypeError()) | ||||
| 			panic(self.runtime.panicTypeError()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -238,10 +238,8 @@ func _objectCanPut(self *_object, name string) (canPut bool, property *_property | ||||
| 		canPut = setter != nil | ||||
| 		return | ||||
| 	default: | ||||
| 		panic(newTypeError()) | ||||
| 		panic(self.runtime.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	return false, nil, nil | ||||
| } | ||||
| 
 | ||||
| // 8.12.5
 | ||||
| @ -258,9 +256,9 @@ func objectPut(self *_object, name string, value Value, throw bool) { | ||||
| 		// incompatible canPut routine
 | ||||
| 		canPut, property, setter := _objectCanPut(self, name) | ||||
| 		if !canPut { | ||||
| 			typeErrorResult(throw) | ||||
| 			self.runtime.typeErrorResult(throw) | ||||
| 		} else if setter != nil { | ||||
| 			setter.callSet(toValue(self), value) | ||||
| 			setter.call(toValue(self), []Value{value}, false, nativeFrame) | ||||
| 		} else if property != nil { | ||||
| 			property.value = value | ||||
| 			self.defineOwnProperty(name, *property, throw) | ||||
| @ -274,7 +272,7 @@ func objectPut(self *_object, name string, value Value, throw bool) { | ||||
| 	//
 | ||||
| 	// Right now, code should never get here, see above
 | ||||
| 	if !self.canPut(name) { | ||||
| 		typeErrorResult(throw) | ||||
| 		self.runtime.typeErrorResult(throw) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| @ -283,7 +281,7 @@ func objectPut(self *_object, name string, value Value, throw bool) { | ||||
| 		property = self.getProperty(name) | ||||
| 		if property != nil { | ||||
| 			if getSet, isAccessor := property.value.(_propertyGetSet); isAccessor { | ||||
| 				getSet[1].callSet(toValue(self), value) | ||||
| 				getSet[1].call(toValue(self), []Value{value}, false, nativeFrame) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| @ -295,14 +293,14 @@ func objectPut(self *_object, name string, value Value, throw bool) { | ||||
| 			self.defineOwnProperty(name, *property, throw) | ||||
| 		case _propertyGetSet: | ||||
| 			if propertyValue[1] != nil { | ||||
| 				propertyValue[1].callSet(toValue(self), value) | ||||
| 				propertyValue[1].call(toValue(self), []Value{value}, false, nativeFrame) | ||||
| 				return | ||||
| 			} | ||||
| 			if throw { | ||||
| 				panic(newTypeError()) | ||||
| 				panic(self.runtime.panicTypeError()) | ||||
| 			} | ||||
| 		default: | ||||
| 			panic(newTypeError()) | ||||
| 			panic(self.runtime.panicTypeError()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -442,7 +440,7 @@ func objectDefineOwnProperty(self *_object, name string, descriptor _property, t | ||||
| 	} | ||||
| Reject: | ||||
| 	if throw { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(self.runtime.panicTypeError()) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| @ -456,29 +454,40 @@ func objectDelete(self *_object, name string, throw bool) bool { | ||||
| 		self._delete(name) | ||||
| 		return true | ||||
| 	} | ||||
| 	return typeErrorResult(throw) | ||||
| 	return self.runtime.typeErrorResult(throw) | ||||
| } | ||||
| 
 | ||||
| func objectClone(self0 *_object, self1 *_object, clone *_clone) *_object { | ||||
| 	*self1 = *self0 | ||||
| func objectClone(in *_object, out *_object, clone *_clone) *_object { | ||||
| 	*out = *in | ||||
| 
 | ||||
| 	self1.runtime = clone.runtime | ||||
| 	if self1.prototype != nil { | ||||
| 		self1.prototype = clone.object(self0.prototype) | ||||
| 	out.runtime = clone.runtime | ||||
| 	if out.prototype != nil { | ||||
| 		out.prototype = clone.object(in.prototype) | ||||
| 	} | ||||
| 	self1.property = make(map[string]_property, len(self0.property)) | ||||
| 	self1.propertyOrder = make([]string, len(self0.propertyOrder)) | ||||
| 	copy(self1.propertyOrder, self0.propertyOrder) | ||||
| 	for index, property := range self0.property { | ||||
| 		self1.property[index] = clone.property(property) | ||||
| 	out.property = make(map[string]_property, len(in.property)) | ||||
| 	out.propertyOrder = make([]string, len(in.propertyOrder)) | ||||
| 	copy(out.propertyOrder, in.propertyOrder) | ||||
| 	for index, property := range in.property { | ||||
| 		out.property[index] = clone.property(property) | ||||
| 	} | ||||
| 
 | ||||
| 	switch value := self0.value.(type) { | ||||
| 	case _functionObject: | ||||
| 		self1.value = value.clone(clone) | ||||
| 	switch value := in.value.(type) { | ||||
| 	case _nativeFunctionObject: | ||||
| 		out.value = value | ||||
| 	case _bindFunctionObject: | ||||
| 		out.value = _bindFunctionObject{ | ||||
| 			target:       clone.object(value.target), | ||||
| 			this:         clone.value(value.this), | ||||
| 			argumentList: clone.valueArray(value.argumentList), | ||||
| 		} | ||||
| 	case _nodeFunctionObject: | ||||
| 		out.value = _nodeFunctionObject{ | ||||
| 			node:  value.node, | ||||
| 			stash: clone.stash(value.stash), | ||||
| 		} | ||||
| 	case _argumentsObject: | ||||
| 		self1.value = value.clone(clone) | ||||
| 		out.value = value.clone(clone) | ||||
| 	} | ||||
| 
 | ||||
| 	return self1 | ||||
| 	return out | ||||
| } | ||||
| @ -57,7 +57,7 @@ Set a Go function | ||||
| 
 | ||||
|     vm.Set("sayHello", func(call otto.FunctionCall) otto.Value { | ||||
|         fmt.Printf("Hello, %s.\n", call.Argument(0).String()) | ||||
|         return otto.UndefinedValue() | ||||
|         return otto.Value{} | ||||
|     }) | ||||
| 
 | ||||
| Set a Go function that returns something useful | ||||
| @ -131,7 +131,6 @@ Caveat Emptor | ||||
| The following are some limitations with otto: | ||||
| 
 | ||||
|     * "use strict" will parse, but does nothing. | ||||
|     * Error reporting needs to be improved. | ||||
|     * The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification. | ||||
| 
 | ||||
| Regular Expression Incompatibility | ||||
| @ -190,16 +189,18 @@ If you want to stop long running executions (like third-party code), you can use | ||||
|             } | ||||
|             fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration) | ||||
|         }() | ||||
| 
 | ||||
|         vm := otto.New() | ||||
|         vm.Interrupt = make(chan func()) | ||||
|         vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking
 | ||||
| 
 | ||||
|         go func() { | ||||
|             time.Sleep(2 * time.Second) // Stop after two seconds
 | ||||
|             vm.Interrupt <- func() { | ||||
|                 panic(halt) | ||||
|             } | ||||
|         }() | ||||
| 
 | ||||
|         vm.Run(unsafe) // Here be dragons (risky code)
 | ||||
|         vm.Interrupt = nil | ||||
|     } | ||||
| 
 | ||||
| Where is setTimeout/setInterval? | ||||
| @ -242,7 +243,7 @@ func New() *Otto { | ||||
| 	self := &Otto{ | ||||
| 		runtime: newContext(), | ||||
| 	} | ||||
| 	self.runtime.Otto = self | ||||
| 	self.runtime.otto = self | ||||
| 	self.Set("console", self.runtime.newConsole()) | ||||
| 
 | ||||
| 	registry.Apply(func(entry registry.Entry) { | ||||
| @ -256,7 +257,7 @@ func (otto *Otto) clone() *Otto { | ||||
| 	self := &Otto{ | ||||
| 		runtime: otto.runtime.clone(), | ||||
| 	} | ||||
| 	self.runtime.Otto = self | ||||
| 	self.runtime.otto = self | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| @ -272,7 +273,7 @@ func (otto *Otto) clone() *Otto { | ||||
| //
 | ||||
| func Run(src interface{}) (*Otto, Value, error) { | ||||
| 	otto := New() | ||||
| 	value, err := otto.Run(src) | ||||
| 	value, err := otto.Run(src) // This already does safety checking
 | ||||
| 	return otto, value, err | ||||
| } | ||||
| 
 | ||||
| @ -288,7 +289,11 @@ func Run(src interface{}) (*Otto, Value, error) { | ||||
| // src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.
 | ||||
| //
 | ||||
| func (self Otto) Run(src interface{}) (Value, error) { | ||||
| 	return self.runtime.cmpl_run(src) | ||||
| 	value, err := self.runtime.cmpl_run(src) | ||||
| 	if !value.safe() { | ||||
| 		value = Value{} | ||||
| 	} | ||||
| 	return value, err | ||||
| } | ||||
| 
 | ||||
| // Get the value of the top-level binding of the given name.
 | ||||
| @ -296,15 +301,18 @@ func (self Otto) Run(src interface{}) (Value, error) { | ||||
| // If there is an error (like the binding does not exist), then the value
 | ||||
| // will be undefined.
 | ||||
| func (self Otto) Get(name string) (Value, error) { | ||||
| 	value := UndefinedValue() | ||||
| 	value := Value{} | ||||
| 	err := catchPanic(func() { | ||||
| 		value = self.getValue(name) | ||||
| 	}) | ||||
| 	if !value.safe() { | ||||
| 		value = Value{} | ||||
| 	} | ||||
| 	return value, err | ||||
| } | ||||
| 
 | ||||
| func (self Otto) getValue(name string) Value { | ||||
| 	return self.runtime.GlobalEnvironment.GetValue(name, false) | ||||
| 	return self.runtime.globalStash.getBinding(name, false) | ||||
| } | ||||
| 
 | ||||
| // Set the top-level binding of the given name to the given value.
 | ||||
| @ -330,7 +338,7 @@ func (self Otto) Set(name string, value interface{}) error { | ||||
| } | ||||
| 
 | ||||
| func (self Otto) setValue(name string, value Value) { | ||||
| 	self.runtime.GlobalEnvironment.SetValue(name, value, false) | ||||
| 	self.runtime.globalStash.setValue(name, value, false) | ||||
| } | ||||
| 
 | ||||
| // Call the given JavaScript with a given this and arguments.
 | ||||
| @ -355,7 +363,7 @@ func (self Otto) setValue(name string, value Value) { | ||||
| //
 | ||||
| func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error) { | ||||
| 
 | ||||
| 	thisValue := UndefinedValue() | ||||
| 	thisValue := Value{} | ||||
| 
 | ||||
| 	construct := false | ||||
| 	if strings.HasPrefix(source, "new ") { | ||||
| @ -363,6 +371,12 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface | ||||
| 		construct = true | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME enterGlobalScope
 | ||||
| 	self.runtime.enterGlobalScope() | ||||
| 	defer func() { | ||||
| 		self.runtime.leaveScope() | ||||
| 	}() | ||||
| 
 | ||||
| 	if !construct && this == nil { | ||||
| 		program, err := self.runtime.cmpl_parse("", source+"()") | ||||
| 		if err == nil { | ||||
| @ -373,7 +387,7 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface | ||||
| 						value = self.runtime.cmpl_evaluate_nodeCallExpression(node, argumentList) | ||||
| 					}) | ||||
| 					if err != nil { | ||||
| 						return UndefinedValue(), err | ||||
| 						return Value{}, err | ||||
| 					} | ||||
| 					return value, nil | ||||
| 				} | ||||
| @ -382,7 +396,7 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface | ||||
| 	} else { | ||||
| 		value, err := self.ToValue(this) | ||||
| 		if err != nil { | ||||
| 			return UndefinedValue(), err | ||||
| 			return Value{}, err | ||||
| 		} | ||||
| 		thisValue = value | ||||
| 	} | ||||
| @ -392,20 +406,20 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface | ||||
| 
 | ||||
| 		fn, err := self.Run(source) | ||||
| 		if err != nil { | ||||
| 			return UndefinedValue(), err | ||||
| 			return Value{}, err | ||||
| 		} | ||||
| 
 | ||||
| 		if construct { | ||||
| 			result, err := fn.constructSafe(this, argumentList...) | ||||
| 			result, err := fn.constructSafe(self.runtime, this, argumentList...) | ||||
| 			if err != nil { | ||||
| 				return UndefinedValue(), err | ||||
| 				return Value{}, err | ||||
| 			} | ||||
| 			return result, nil | ||||
| 		} | ||||
| 
 | ||||
| 		result, err := fn.Call(this, argumentList...) | ||||
| 		if err != nil { | ||||
| 			return UndefinedValue(), err | ||||
| 			return Value{}, err | ||||
| 		} | ||||
| 		return result, nil | ||||
| 	} | ||||
| @ -441,23 +455,23 @@ func (self Otto) Object(source string) (*Object, error) { | ||||
| 
 | ||||
| // ToValue will convert an interface{} value to a value digestible by otto/JavaScript.
 | ||||
| func (self Otto) ToValue(value interface{}) (Value, error) { | ||||
| 	return self.runtime.ToValue(value) | ||||
| 	return self.runtime.safeToValue(value) | ||||
| } | ||||
| 
 | ||||
| // Copy will create a copy/clone of the runtime.
 | ||||
| //
 | ||||
| // Copy is useful for saving some processing time when creating many similar
 | ||||
| // runtimes.
 | ||||
| // Copy is useful for saving some time when creating many similar runtimes.
 | ||||
| //
 | ||||
| // This implementation is alpha-ish, and works by introspecting every part of the runtime
 | ||||
| // and reallocating and then relinking everything back together. Please report if you
 | ||||
| // notice any inadvertent sharing of data between copies.
 | ||||
| func (self *Otto) Copy() *Otto { | ||||
| 	otto := &Otto{ | ||||
| 		runtime: self.runtime.clone(), | ||||
| // 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 (in *Otto) Copy() *Otto { | ||||
| 	out := &Otto{ | ||||
| 		runtime: in.runtime.clone(), | ||||
| 	} | ||||
| 	otto.runtime.Otto = otto | ||||
| 	return otto | ||||
| 	out.runtime.otto = out | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // Object{}
 | ||||
| @ -495,7 +509,7 @@ func (self Object) Call(name string, argumentList ...interface{}) (Value, error) | ||||
| 
 | ||||
| 	function, err := self.Get(name) | ||||
| 	if err != nil { | ||||
| 		return UndefinedValue(), err | ||||
| 		return Value{}, err | ||||
| 	} | ||||
| 	return function.Call(self.Value(), argumentList...) | ||||
| } | ||||
| @ -507,10 +521,13 @@ func (self Object) Value() Value { | ||||
| 
 | ||||
| // Get the value of the property with the given name.
 | ||||
| func (self Object) Get(name string) (Value, error) { | ||||
| 	value := UndefinedValue() | ||||
| 	value := Value{} | ||||
| 	err := catchPanic(func() { | ||||
| 		value = self.object.get(name) | ||||
| 	}) | ||||
| 	if !value.safe() { | ||||
| 		value = Value{} | ||||
| 	} | ||||
| 	return value, err | ||||
| } | ||||
| 
 | ||||
| @ -520,7 +537,7 @@ func (self Object) Get(name string) (Value, error) { | ||||
| // or there is an error during conversion of the given value.
 | ||||
| func (self Object) Set(name string, value interface{}) error { | ||||
| 	{ | ||||
| 		value, err := self.object.runtime.ToValue(value) | ||||
| 		value, err := self.object.runtime.safeToValue(value) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| @ -37,7 +37,12 @@ func main() { | ||||
| 		return err | ||||
| 	}() | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		switch err := err.(type) { | ||||
| 		case *otto.Error: | ||||
| 			fmt.Print(err.String()) | ||||
| 		default: | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 		os.Exit(64) | ||||
| 	} | ||||
| } | ||||
| @ -67,13 +67,13 @@ func getValueOfArrayIndex(array []Value, index int) (Value, bool) { | ||||
| 			return value, true | ||||
| 		} | ||||
| 	} | ||||
| 	return UndefinedValue(), false | ||||
| 	return Value{}, false | ||||
| } | ||||
| 
 | ||||
| // A range index can be anything from 0 up to length. It is NOT safe to use as an index
 | ||||
| // to an array, but is useful for slicing and in some ECMA algorithms.
 | ||||
| func valueToRangeIndex(indexValue Value, length int64, negativeIsZero bool) int64 { | ||||
| 	index := toInteger(indexValue).value | ||||
| 	index := indexValue.number().int64 | ||||
| 	if negativeIsZero { | ||||
| 		if index < 0 { | ||||
| 			index = 0 | ||||
| @ -129,7 +129,7 @@ func rangeStartLength(source []Value, size int64) (start, length int64) { | ||||
| 	lengthValue := valueOfArrayIndex(source, 1) | ||||
| 	if !lengthValue.IsUndefined() { | ||||
| 		// Which it is not, so get the value as an array index
 | ||||
| 		length = toInteger(lengthValue).value | ||||
| 		length = lengthValue.number().int64 | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| @ -18,14 +18,14 @@ func TestOttoError(t *testing.T) { | ||||
| 		is(err, "TypeError: Nothing happens.") | ||||
| 
 | ||||
| 		_, err = ToValue([]byte{}) | ||||
| 		is(err, "TypeError: Invalid value (slice): Missing runtime: [] ([]uint8)") | ||||
| 		is(err, "TypeError: invalid value (slice): missing runtime: [] ([]uint8)") | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             (function(){ | ||||
|                 return abcdef.length | ||||
|             })() | ||||
|         `) | ||||
| 		is(err, "ReferenceError: abcdef is not defined") | ||||
| 		is(err, "ReferenceError: 'abcdef' is not defined") | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             function start() { | ||||
| @ -35,14 +35,14 @@ func TestOttoError(t *testing.T) { | ||||
| 
 | ||||
|                 xyzzy() | ||||
|         `) | ||||
| 		is(err, "ReferenceError: xyzzy is not defined") | ||||
| 		is(err, "ReferenceError: 'xyzzy' is not defined") | ||||
| 
 | ||||
| 		_, err = vm.Run(` | ||||
|             // Just a comment
 | ||||
| 
 | ||||
|             xyzzy | ||||
|         `) | ||||
| 		is(err, "ReferenceError: xyzzy is not defined") | ||||
| 		is(err, "ReferenceError: 'xyzzy' is not defined") | ||||
| 
 | ||||
| 	}) | ||||
| } | ||||
| @ -649,7 +649,7 @@ func Test_PrimitiveValueObjectValue(t *testing.T) { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		Number11 := test(`new Number(11)`) | ||||
| 		is(toFloat(Number11), 11) | ||||
| 		is(Number11.float64(), 11) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -700,24 +700,22 @@ func Test_evalDirectIndirect(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| 		// (function () {return this;}()).abc = "global";
 | ||||
| 		test(` | ||||
|             var abc = "global"; | ||||
|             (function(){ | ||||
|                 try { | ||||
|                     var _eval = eval; | ||||
|                     var abc = "function"; | ||||
|                     if ( | ||||
|                         _eval("\'global\' === abc") === true && // eval (Indirect)
 | ||||
|                         eval("\'function\' === abc") === true // eval (Direct)
 | ||||
|                     ) { | ||||
|                         return true; | ||||
|                     } | ||||
|                     return false; | ||||
|                     return [ | ||||
|                         _eval("\'global\' === abc"),  // eval (Indirect)
 | ||||
|                         eval("\'function\' === abc"), // eval (Direct)
 | ||||
|                     ]; | ||||
|                 } finally { | ||||
|                     delete this.abc; | ||||
|                 } | ||||
|             })() | ||||
|         `, true) | ||||
|             })(); | ||||
|         `, "true,true") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -766,7 +764,7 @@ func TestShouldError(t *testing.T) { | ||||
| 		test(`raise: | ||||
|             xyzzy | ||||
|                 throw new TypeError("Nothing happens.") | ||||
|         `, "ReferenceError: xyzzy is not defined") | ||||
|         `, "ReferenceError: 'xyzzy' is not defined") | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -868,8 +866,8 @@ func TestDotMember(t *testing.T) { | ||||
| func Test_stringToFloat(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 
 | ||||
| 		is(stringToFloat("10e10000"), _Infinity) | ||||
| 		is(stringToFloat("10e10_."), _NaN) | ||||
| 		is(parseNumber("10e10000"), _Infinity) | ||||
| 		is(parseNumber("10e10_."), _NaN) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -1014,7 +1012,9 @@ func TestOttoCall_throw(t *testing.T) { | ||||
| 	// Looks like this has been broken for a while... what
 | ||||
| 	// behavior do we want here?
 | ||||
| 
 | ||||
| 	return | ||||
| 	if true { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| @ -1024,7 +1024,7 @@ func TestOttoCall_throw(t *testing.T) { | ||||
| 				call.Otto.Call(`throw eval`, nil, "({ def: 3.14159 })") | ||||
| 			} | ||||
| 			call.Otto.Call(`throw Error`, nil, "abcdef") | ||||
| 			return UndefinedValue() | ||||
| 			return Value{} | ||||
| 		}) | ||||
| 		// TODO try { abc(); } catch (err) { error = err }
 | ||||
| 		// Possible unrelated error case:
 | ||||
| @ -1099,6 +1099,54 @@ func TestOttoCopy(t *testing.T) { | ||||
|         `) | ||||
| 		is(err, nil) | ||||
| 		is(value, "Xyzzy0[object Object]") | ||||
| 
 | ||||
| 		{ | ||||
| 			vm0 := New() | ||||
| 			vm0.Run(` | ||||
|                 var global = (function () {return this;}()) | ||||
|                 var abc = 0; | ||||
|                 var vm = "vm0"; | ||||
| 
 | ||||
|                 var def = (function(){ | ||||
|                     var jkl = 0; | ||||
|                     var abc = function() { | ||||
|                         global.abc += 1; | ||||
|                         jkl += 1; | ||||
|                         return 1; | ||||
|                     }; | ||||
| 
 | ||||
|                     return function() { | ||||
|                         return [ vm, global.abc, jkl, abc() ]; | ||||
|                     }; | ||||
|                 })(); | ||||
|             `) | ||||
| 
 | ||||
| 			value, err := vm0.Run(` | ||||
|                 def(); | ||||
|             `) | ||||
| 			is(err, nil) | ||||
| 			is(value, "vm0,0,0,1") | ||||
| 
 | ||||
| 			vm1 := vm0.Copy() | ||||
| 			vm1.Set("vm", "vm1") | ||||
| 			value, err = vm1.Run(` | ||||
|                 def(); | ||||
|             `) | ||||
| 			is(err, nil) | ||||
| 			is(value, "vm1,1,1,1") | ||||
| 
 | ||||
| 			value, err = vm0.Run(` | ||||
|                 def(); | ||||
|             `) | ||||
| 			is(err, nil) | ||||
| 			is(value, "vm0,1,1,1") | ||||
| 
 | ||||
| 			value, err = vm1.Run(` | ||||
|                 def(); | ||||
|             `) | ||||
| 			is(err, nil) | ||||
| 			is(value, "vm1,2,2,1") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -1109,11 +1157,11 @@ func TestOttoCall_clone(t *testing.T) { | ||||
| 
 | ||||
| 		{ | ||||
| 			// FIXME terst, Check how this comparison is done
 | ||||
| 			is(rt.Global.Array.prototype, rt.Global.FunctionPrototype) | ||||
| 			is(rt.Global.ArrayPrototype, "!=", nil) | ||||
| 			is(rt.Global.Array.runtime, rt) | ||||
| 			is(rt.Global.Array.prototype.runtime, rt) | ||||
| 			is(rt.Global.Array.get("prototype")._object().runtime, rt) | ||||
| 			is(rt.global.Array.prototype, rt.global.FunctionPrototype) | ||||
| 			is(rt.global.ArrayPrototype, "!=", nil) | ||||
| 			is(rt.global.Array.runtime, rt) | ||||
| 			is(rt.global.Array.prototype.runtime, rt) | ||||
| 			is(rt.global.Array.get("prototype")._object().runtime, rt) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| @ -1128,14 +1176,14 @@ func TestOttoCall_clone(t *testing.T) { | ||||
| 			is(value, "1,2,3") | ||||
| 			object := value._object() | ||||
| 			is(object, "!=", nil) | ||||
| 			is(object.prototype, rt.Global.ArrayPrototype) | ||||
| 			is(object.prototype, rt.global.ArrayPrototype) | ||||
| 
 | ||||
| 			value, err = vm.Run(`Array.prototype`) | ||||
| 			is(err, nil) | ||||
| 			object = value._object() | ||||
| 			is(object.runtime, rt) | ||||
| 			is(object, "!=", nil) | ||||
| 			is(object, rt.Global.ArrayPrototype) | ||||
| 			is(object, rt.global.ArrayPrototype) | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| @ -85,10 +85,10 @@ func (self _property) get(this *_object) Value { | ||||
| 		return value | ||||
| 	case _propertyGetSet: | ||||
| 		if value[0] != nil { | ||||
| 			return value[0].callGet(toValue(this)) | ||||
| 			return value[0].call(toValue(this), nil, false, nativeFrame) | ||||
| 		} | ||||
| 	} | ||||
| 	return UndefinedValue() | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (self _property) isAccessorDescriptor() bool { | ||||
| @ -115,16 +115,16 @@ func (self _property) isEmpty() bool { | ||||
| // _enumerableValue, _enumerableTrue, _enumerableFalse?
 | ||||
| // .enumerableValue() .enumerableExists()
 | ||||
| 
 | ||||
| func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| func toPropertyDescriptor(rt *_runtime, value Value) (descriptor _property) { | ||||
| 	objectDescriptor := value._object() | ||||
| 	if objectDescriptor == nil { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(rt.panicTypeError()) | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		descriptor.mode = modeSetMask // Initially nothing is set
 | ||||
| 		if objectDescriptor.hasProperty("enumerable") { | ||||
| 			if objectDescriptor.get("enumerable").toBoolean() { | ||||
| 			if objectDescriptor.get("enumerable").bool() { | ||||
| 				descriptor.enumerateOn() | ||||
| 			} else { | ||||
| 				descriptor.enumerateOff() | ||||
| @ -132,7 +132,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| 		} | ||||
| 
 | ||||
| 		if objectDescriptor.hasProperty("configurable") { | ||||
| 			if objectDescriptor.get("configurable").toBoolean() { | ||||
| 			if objectDescriptor.get("configurable").bool() { | ||||
| 				descriptor.configureOn() | ||||
| 			} else { | ||||
| 				descriptor.configureOff() | ||||
| @ -140,7 +140,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| 		} | ||||
| 
 | ||||
| 		if objectDescriptor.hasProperty("writable") { | ||||
| 			if objectDescriptor.get("writable").toBoolean() { | ||||
| 			if objectDescriptor.get("writable").bool() { | ||||
| 				descriptor.writeOn() | ||||
| 			} else { | ||||
| 				descriptor.writeOff() | ||||
| @ -155,7 +155,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| 		value := objectDescriptor.get("get") | ||||
| 		if value.IsDefined() { | ||||
| 			if !value.isCallable() { | ||||
| 				panic(newTypeError()) | ||||
| 				panic(rt.panicTypeError()) | ||||
| 			} | ||||
| 			getter = value._object() | ||||
| 			getterSetter = true | ||||
| @ -169,7 +169,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| 		value := objectDescriptor.get("set") | ||||
| 		if value.IsDefined() { | ||||
| 			if !value.isCallable() { | ||||
| 				panic(newTypeError()) | ||||
| 				panic(rt.panicTypeError()) | ||||
| 			} | ||||
| 			setter = value._object() | ||||
| 			getterSetter = true | ||||
| @ -181,14 +181,14 @@ func toPropertyDescriptor(value Value) (descriptor _property) { | ||||
| 
 | ||||
| 	if getterSetter { | ||||
| 		if descriptor.writeSet() { | ||||
| 			panic(newTypeError()) | ||||
| 			panic(rt.panicTypeError()) | ||||
| 		} | ||||
| 		descriptor.value = _propertyGetSet{getter, setter} | ||||
| 	} | ||||
| 
 | ||||
| 	if objectDescriptor.hasProperty("value") { | ||||
| 		if getterSetter { | ||||
| 			panic(newTypeError()) | ||||
| 			panic(rt.panicTypeError()) | ||||
| 		} | ||||
| 		descriptor.value = objectDescriptor.get("value") | ||||
| 	} | ||||
| @ -203,11 +203,11 @@ func (self *_runtime) fromPropertyDescriptor(descriptor _property) *_object { | ||||
| 		object.defineProperty("writable", toValue_bool(descriptor.writable()), 0111, false) | ||||
| 	} else if descriptor.isAccessorDescriptor() { | ||||
| 		getSet := descriptor.value.(_propertyGetSet) | ||||
| 		get := UndefinedValue() | ||||
| 		get := Value{} | ||||
| 		if getSet[0] != nil { | ||||
| 			get = toValue_object(getSet[0]) | ||||
| 		} | ||||
| 		set := UndefinedValue() | ||||
| 		set := Value{} | ||||
| 		if getSet[1] != nil { | ||||
| 			set = toValue_object(getSet[1]) | ||||
| 		} | ||||
| @ -6,43 +6,63 @@ import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| type testStruct struct { | ||||
| type _abcStruct struct { | ||||
| 	Abc bool | ||||
| 	Def int | ||||
| 	Ghi string | ||||
| 	Jkl interface{} | ||||
| 	Mno _mnoStruct | ||||
| 	Pqr map[string]int8 | ||||
| } | ||||
| 
 | ||||
| func (t *testStruct) FuncPointerReciever() string { | ||||
| func (abc _abcStruct) String() string { | ||||
| 	return abc.Ghi | ||||
| } | ||||
| 
 | ||||
| func (abc *_abcStruct) FuncPointer() string { | ||||
| 	return "abc" | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncNoArgsNoRet() { | ||||
| func (abc _abcStruct) Func() { | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncNoArgs() string { | ||||
| func (abc _abcStruct) FuncReturn1() string { | ||||
| 	return "abc" | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncNoArgsMultRet() (string, error) { | ||||
| func (abc _abcStruct) FuncReturn2() (string, error) { | ||||
| 	return "def", nil | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncOneArgs(a string) string { | ||||
| func (abc _abcStruct) Func1Return1(a string) string { | ||||
| 	return a | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncMultArgs(a, b string) string { | ||||
| 	return a + b | ||||
| func (abc _abcStruct) Func2Return1(x, y string) string { | ||||
| 	return x + y | ||||
| } | ||||
| 
 | ||||
| func (t testStruct) FuncVarArgs(as ...string) int { | ||||
| 	return len(as) | ||||
| func (abc _abcStruct) FuncEllipsis(xyz ...string) int { | ||||
| 	return len(xyz) | ||||
| } | ||||
| 
 | ||||
| func (abc _abcStruct) FuncReturnStruct() _mnoStruct { | ||||
| 	return _mnoStruct{} | ||||
| } | ||||
| 
 | ||||
| type _mnoStruct struct { | ||||
| 	Ghi string | ||||
| } | ||||
| 
 | ||||
| func (mno _mnoStruct) Func() string { | ||||
| 	return "mno" | ||||
| } | ||||
| 
 | ||||
| func TestReflect(t *testing.T) { | ||||
| 	return | ||||
| 	if true { | ||||
| 		return | ||||
| 	} | ||||
| 	tt(t, func() { | ||||
| 		// Testing dbgf
 | ||||
| 		// These should panic
 | ||||
| @ -55,15 +75,11 @@ func Test_reflectStruct(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		// testStruct
 | ||||
| 		// _abcStruct
 | ||||
| 		{ | ||||
| 			abc := &testStruct{} | ||||
| 			abc := &_abcStruct{} | ||||
| 			vm.Set("abc", abc) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncPointerReciever(); | ||||
|             `, "abc") | ||||
| 
 | ||||
| 			test(` | ||||
|                 [ abc.Abc, abc.Ghi ]; | ||||
|             `, "false,") | ||||
| @ -75,7 +91,7 @@ func Test_reflectStruct(t *testing.T) { | ||||
|                 [ abc.Abc, abc.Ghi ]; | ||||
|             `, "true,Nothing happens.") | ||||
| 
 | ||||
| 			*abc = testStruct{} | ||||
| 			*abc = _abcStruct{} | ||||
| 
 | ||||
| 			test(` | ||||
|                 [ abc.Abc, abc.Ghi ]; | ||||
| @ -109,24 +125,40 @@ func Test_reflectStruct(t *testing.T) { | ||||
| 			is(abc.Def, 451) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncNoArgsNoRet(); | ||||
|                 abc.FuncPointer(); | ||||
|             `, "abc") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.Func(); | ||||
|             `, "undefined") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncNoArgs(); | ||||
|                 abc.FuncReturn1(); | ||||
|             `, "abc") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncOneArgs("abc"); | ||||
|                 abc.Func1Return1("abc"); | ||||
|             `, "abc") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncMultArgs("abc", "def"); | ||||
|                 abc.Func2Return1("abc", "def"); | ||||
|             `, "abcdef") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncVarArgs("abc", "def", "ghi"); | ||||
|                 abc.FuncEllipsis("abc", "def", "ghi"); | ||||
|             `, 3) | ||||
| 
 | ||||
| 			test(`raise: | ||||
|                 abc.FuncNoArgsMultRet(); | ||||
|                 abc.FuncReturn2(); | ||||
|             `, "TypeError") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncReturnStruct(); | ||||
|             `, "[object Object]") | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.FuncReturnStruct().Func(); | ||||
|             `, "mno") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| @ -387,7 +419,7 @@ func Test_reflectMapInterface(t *testing.T) { | ||||
| 				"jkl":   "jkl", | ||||
| 			} | ||||
| 			vm.Set("abc", abc) | ||||
| 			vm.Set("mno", &testStruct{}) | ||||
| 			vm.Set("mno", &_abcStruct{}) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.xyz = "pqr"; | ||||
| @ -402,10 +434,50 @@ func Test_reflectMapInterface(t *testing.T) { | ||||
| 			is(abc["xyz"], "pqr") | ||||
| 			is(abc["ghi"], "[object Object]") | ||||
| 			is(abc["jkl"], float64(3.14159)) | ||||
| 			mno, valid := abc["mno"].(*testStruct) | ||||
| 			mno, valid := abc["mno"].(*_abcStruct) | ||||
| 			is(valid, true) | ||||
| 			is(mno.Abc, true) | ||||
| 			is(mno.Ghi, "Something happens.") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestPassthrough(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		test, vm := test() | ||||
| 
 | ||||
| 		{ | ||||
| 			abc := &_abcStruct{ | ||||
| 				Mno: _mnoStruct{ | ||||
| 					Ghi: "<Mno.Ghi>", | ||||
| 				}, | ||||
| 			} | ||||
| 			vm.Set("abc", abc) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.Mno.Ghi; | ||||
|             `, "<Mno.Ghi>") | ||||
| 
 | ||||
| 			vm.Set("pqr", map[string]int8{ | ||||
| 				"xyzzy":            0, | ||||
| 				"Nothing happens.": 1, | ||||
| 			}) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.Ghi = "abc"; | ||||
|                 abc.Pqr = pqr; | ||||
|                 abc.Pqr["Nothing happens."]; | ||||
|             `, 1) | ||||
| 
 | ||||
| 			mno := _mnoStruct{ | ||||
| 				Ghi: "<mno.Ghi>", | ||||
| 			} | ||||
| 			vm.Set("mno", mno) | ||||
| 
 | ||||
| 			test(` | ||||
|                 abc.Mno = mno; | ||||
|                 abc.Mno.Ghi; | ||||
|             `, "<mno.Ghi>") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| @ -160,7 +160,10 @@ func TestRegExp_toString(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestRegExp_zaacbbbcac(t *testing.T) { | ||||
| 	return | ||||
| 	if true { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	tt(t, func() { | ||||
| 		test, _ := test() | ||||
| 
 | ||||
| @ -22,9 +22,9 @@ func newReturnResult(value Value) _result { | ||||
| } | ||||
| 
 | ||||
| func newContinueResult(target string) _result { | ||||
| 	return _result{resultContinue, emptyValue(), target} | ||||
| 	return _result{resultContinue, emptyValue, target} | ||||
| } | ||||
| 
 | ||||
| func newBreakResult(target string) _result { | ||||
| 	return _result{resultBreak, emptyValue(), target} | ||||
| 	return _result{resultBreak, emptyValue, target} | ||||
| } | ||||
| @ -3,6 +3,7 @@ package otto | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"reflect" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/robertkrimen/otto/ast" | ||||
| 	"github.com/robertkrimen/otto/parser" | ||||
| @ -45,100 +46,54 @@ type _global struct { | ||||
| } | ||||
| 
 | ||||
| type _runtime struct { | ||||
| 	Stack [](*_executionContext) | ||||
| 
 | ||||
| 	GlobalObject      *_object | ||||
| 	GlobalEnvironment *_objectEnvironment | ||||
| 
 | ||||
| 	Global _global | ||||
| 
 | ||||
| 	eval *_object // The builtin eval, for determine indirect versus direct invocation
 | ||||
| 
 | ||||
| 	Otto *Otto | ||||
| 	global       _global | ||||
| 	globalObject *_object | ||||
| 	globalStash  *_objectStash | ||||
| 	scope        *_scope | ||||
| 	otto         *Otto | ||||
| 	eval         *_object // The builtin eval, for determine indirect versus direct invocation
 | ||||
| 
 | ||||
| 	labels []string // FIXME
 | ||||
| 	lck    sync.Mutex | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) EnterGlobalExecutionContext() { | ||||
| 	self.EnterExecutionContext(newExecutionContext(self.GlobalEnvironment, self.GlobalEnvironment, self.GlobalObject)) | ||||
| func (self *_runtime) enterScope(scope *_scope) { | ||||
| 	scope.outer = self.scope | ||||
| 	self.scope = scope | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) EnterExecutionContext(scope *_executionContext) { | ||||
| 	self.Stack = append(self.Stack, scope) | ||||
| func (self *_runtime) leaveScope() { | ||||
| 	self.scope = self.scope.outer | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) LeaveExecutionContext() { | ||||
| 	self.Stack = self.Stack[:len(self.Stack)-1] | ||||
| // FIXME This is used in two places (cloning)
 | ||||
| func (self *_runtime) enterGlobalScope() { | ||||
| 	self.enterScope(newScope(self.globalStash, self.globalStash, self.globalObject)) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) _executionContext(depth int) *_executionContext { | ||||
| 	if depth == 0 { | ||||
| 		return self.Stack[len(self.Stack)-1] | ||||
| func (self *_runtime) enterFunctionScope(outer _stash, this Value) *_fnStash { | ||||
| 	if outer == nil { | ||||
| 		outer = self.globalStash | ||||
| 	} | ||||
| 	if len(self.Stack)-1+depth >= 0 { | ||||
| 		return self.Stack[len(self.Stack)-1+depth] | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) EnterFunctionExecutionContext(function *_object, this Value) *_functionEnvironment { | ||||
| 	scopeEnvironment := function.functionValue().call.ScopeEnvironment() | ||||
| 	if scopeEnvironment == nil { | ||||
| 		scopeEnvironment = self.GlobalEnvironment | ||||
| 	} | ||||
| 	environment := self.newFunctionEnvironment(scopeEnvironment) | ||||
| 	stash := self.newFunctionStash(outer) | ||||
| 	var thisObject *_object | ||||
| 	switch this._valueType { | ||||
| 	switch this.kind { | ||||
| 	case valueUndefined, valueNull: | ||||
| 		thisObject = self.GlobalObject | ||||
| 		thisObject = self.globalObject | ||||
| 	default: | ||||
| 		thisObject = self.toObject(this) | ||||
| 	} | ||||
| 	self.EnterExecutionContext(newExecutionContext(environment, environment, thisObject)) | ||||
| 	return environment | ||||
| 	self.enterScope(newScope(stash, stash, thisObject)) | ||||
| 	return stash | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) EnterEvalExecutionContext(call FunctionCall) { | ||||
| 	// Skip the current function lexical/variable environment, which is of the function execution context call
 | ||||
| 	// to eval (the global execution context). Instead, execute in the context of where the eval was called,
 | ||||
| 	// which is essentially dynamic scoping
 | ||||
| 	parent := self._executionContext(-1) | ||||
| 	new := newExecutionContext(parent.LexicalEnvironment, parent.VariableEnvironment, parent.this) | ||||
| 	// FIXME Make passing through of self.GlobalObject more general? Whenever newExecutionContext is passed a nil object?
 | ||||
| 	new.eval = true | ||||
| 	self.EnterExecutionContext(new) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) GetValue(value Value) Value { | ||||
| 	if value.isReference() { | ||||
| 		return value.reference().GetValue() | ||||
| func (self *_runtime) putValue(reference _reference, value Value) { | ||||
| 	name := reference.putValue(value) | ||||
| 	if name != "" { | ||||
| 		// Why? -- If reference.base == nil
 | ||||
| 		// strict = false
 | ||||
| 		self.globalObject.defineProperty(name, value, 0111, false) | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) PutValue(reference _reference, value Value) { | ||||
| 	if !reference.PutValue(value) { | ||||
| 		// Why? -- If reference.Base == nil
 | ||||
| 		strict := false | ||||
| 		self.GlobalObject.defineProperty(reference.GetName(), value, 0111, strict) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) Call(function *_object, this Value, argumentList []Value, evalHint bool) Value { | ||||
| 	// Pass eval boolean through to EnterFunctionExecutionContext for further testing
 | ||||
| 	_functionEnvironment := self.EnterFunctionExecutionContext(function, this) | ||||
| 	defer func() { | ||||
| 		self.LeaveExecutionContext() | ||||
| 	}() | ||||
| 
 | ||||
| 	if evalHint { | ||||
| 		evalHint = function == self.eval // If evalHint is true, then it IS a direct eval
 | ||||
| 	} | ||||
| 	callValue := function.functionValue().call.Dispatch(function, _functionEnvironment, self, this, argumentList, evalHint) | ||||
| 	if value, valid := callValue.value.(_result); valid { | ||||
| 		return value.value | ||||
| 	} | ||||
| 	return callValue | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) tryCatchEvaluate(inner func() Value) (tryValue Value, exception bool) { | ||||
| @ -155,10 +110,7 @@ func (self *_runtime) tryCatchEvaluate(inner func() Value) (tryValue Value, exce | ||||
| 			switch caught := caught.(type) { | ||||
| 			case _error: | ||||
| 				exception = true | ||||
| 				tryValue = toValue_object(self.newError(caught.Name, caught.MessageValue())) | ||||
| 			//case *_syntaxError:
 | ||||
| 			//    exception = true
 | ||||
| 			//    tryValue = toValue_object(self.newError("SyntaxError", toValue_string(caught.Message)))
 | ||||
| 				tryValue = toValue_object(self.newError(caught.name, caught.messageValue())) | ||||
| 			case Value: | ||||
| 				exception = true | ||||
| 				tryValue = caught | ||||
| @ -172,30 +124,12 @@ func (self *_runtime) tryCatchEvaluate(inner func() Value) (tryValue Value, exce | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // _executionContext Proxy
 | ||||
| 
 | ||||
| func (self *_runtime) localGet(name string) Value { | ||||
| 	return self._executionContext(0).getValue(name) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) localSet(name string, value Value) { | ||||
| 	self._executionContext(0).setValue(name, value, false) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) VariableEnvironment() _environment { | ||||
| 	return self._executionContext(0).VariableEnvironment | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) LexicalEnvironment() _environment { | ||||
| 	return self._executionContext(0).LexicalEnvironment | ||||
| } | ||||
| 
 | ||||
| // toObject
 | ||||
| 
 | ||||
| func (self *_runtime) toObject(value Value) *_object { | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueEmpty, valueUndefined, valueNull: | ||||
| 		panic(newTypeError()) | ||||
| 		panic(self.panicTypeError()) | ||||
| 	case valueBoolean: | ||||
| 		return self.newBoolean(value) | ||||
| 	case valueString: | ||||
| @ -205,11 +139,11 @@ func (self *_runtime) toObject(value Value) *_object { | ||||
| 	case valueObject: | ||||
| 		return value._object() | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(self.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) objectCoerce(value Value) (*_object, error) { | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueUndefined: | ||||
| 		return nil, errors.New("undefined") | ||||
| 	case valueNull: | ||||
| @ -223,20 +157,20 @@ func (self *_runtime) objectCoerce(value Value) (*_object, error) { | ||||
| 	case valueObject: | ||||
| 		return value._object(), nil | ||||
| 	} | ||||
| 	panic(newTypeError()) | ||||
| 	panic(self.panicTypeError()) | ||||
| } | ||||
| 
 | ||||
| func checkObjectCoercible(value Value) { | ||||
| func checkObjectCoercible(rt *_runtime, value Value) { | ||||
| 	isObject, mustCoerce := testObjectCoercible(value) | ||||
| 	if !isObject && !mustCoerce { | ||||
| 		panic(newTypeError()) | ||||
| 		panic(rt.panicTypeError()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // testObjectCoercible
 | ||||
| 
 | ||||
| func testObjectCoercible(value Value) (isObject bool, mustCoerce bool) { | ||||
| 	switch value._valueType { | ||||
| 	switch value.kind { | ||||
| 	case valueReference, valueEmpty, valueNull, valueUndefined: | ||||
| 		return false, false | ||||
| 	case valueNumber, valueString, valueBoolean: | ||||
| @ -249,8 +183,8 @@ func testObjectCoercible(value Value) (isObject bool, mustCoerce bool) { | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) ToValue(value interface{}) (Value, error) { | ||||
| 	result := UndefinedValue() | ||||
| func (self *_runtime) safeToValue(value interface{}) (Value, error) { | ||||
| 	result := Value{} | ||||
| 	err := catchPanic(func() { | ||||
| 		result = self.toValue(value) | ||||
| 	}) | ||||
| @ -267,7 +201,8 @@ func (self *_runtime) toValue(value interface{}) Value { | ||||
| 		return toValue_object(self.newNativeFunction("", value)) | ||||
| 	case Object, *Object, _object, *_object: | ||||
| 		// Nothing happens.
 | ||||
| 		// FIXME
 | ||||
| 		// FIXME We should really figure out what can come here.
 | ||||
| 		// This catch-all is ugly.
 | ||||
| 	default: | ||||
| 		{ | ||||
| 			value := reflect.ValueOf(value) | ||||
| @ -280,19 +215,21 @@ func (self *_runtime) toValue(value interface{}) Value { | ||||
| 					return toValue_object(self.newGoArray(value)) | ||||
| 				} | ||||
| 			case reflect.Func: | ||||
| 				// TODO Maybe cache this?
 | ||||
| 				return toValue_object(self.newNativeFunction("", func(call FunctionCall) Value { | ||||
| 					args := make([]reflect.Value, len(call.ArgumentList)) | ||||
| 					for i, a := range call.ArgumentList { | ||||
| 						args[i] = reflect.ValueOf(a.export()) | ||||
| 					in := make([]reflect.Value, len(call.ArgumentList)) | ||||
| 					for i, value := range call.ArgumentList { | ||||
| 						in[i] = reflect.ValueOf(value.export()) | ||||
| 					} | ||||
| 
 | ||||
| 					retvals := value.Call(args) | ||||
| 					if len(retvals) > 1 { | ||||
| 						panic(newTypeError()) | ||||
| 					} else if len(retvals) == 1 { | ||||
| 						return toValue(retvals[0].Interface()) | ||||
| 					out := value.Call(in) | ||||
| 					if len(out) == 1 { | ||||
| 						return self.toValue(out[0].Interface()) | ||||
| 					} else if len(out) == 0 { | ||||
| 						return Value{} | ||||
| 					} | ||||
| 					return UndefinedValue() | ||||
| 
 | ||||
| 					panic(call.runtime.panicTypeError()) | ||||
| 				})) | ||||
| 			case reflect.Struct: | ||||
| 				return toValue_object(self.newGoStructObject(value)) | ||||
| @ -310,13 +247,13 @@ func (self *_runtime) toValue(value interface{}) Value { | ||||
| 
 | ||||
| func (runtime *_runtime) newGoSlice(value reflect.Value) *_object { | ||||
| 	self := runtime.newGoSliceObject(value) | ||||
| 	self.prototype = runtime.Global.ArrayPrototype | ||||
| 	self.prototype = runtime.global.ArrayPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newGoArray(value reflect.Value) *_object { | ||||
| 	self := runtime.newGoArrayObject(value) | ||||
| 	self.prototype = runtime.Global.ArrayPrototype | ||||
| 	self.prototype = runtime.global.ArrayPrototype | ||||
| 	return self | ||||
| } | ||||
| 
 | ||||
| @ -344,7 +281,7 @@ func (self *_runtime) parseSource(src interface{}) (*_nodeProgram, *ast.Program, | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) cmpl_run(src interface{}) (Value, error) { | ||||
| 	result := UndefinedValue() | ||||
| 	result := Value{} | ||||
| 	cmpl_program, program, err := self.parseSource(src) | ||||
| 	if err != nil { | ||||
| 		return result, err | ||||
| @ -353,13 +290,13 @@ func (self *_runtime) cmpl_run(src interface{}) (Value, error) { | ||||
| 		cmpl_program = cmpl_parse(program) | ||||
| 	} | ||||
| 	err = catchPanic(func() { | ||||
| 		result = self.cmpl_evaluate_nodeProgram(cmpl_program) | ||||
| 		result = self.cmpl_evaluate_nodeProgram(cmpl_program, false) | ||||
| 	}) | ||||
| 	switch result._valueType { | ||||
| 	switch result.kind { | ||||
| 	case valueEmpty: | ||||
| 		result = UndefinedValue() | ||||
| 		result = Value{} | ||||
| 	case valueReference: | ||||
| 		result = self.GetValue(result) | ||||
| 		result = result.resolve() | ||||
| 	} | ||||
| 	return result, err | ||||
| } | ||||
| @ -373,12 +310,12 @@ func (self *_runtime) parseThrow(err error) { | ||||
| 		{ | ||||
| 			err := err[0] | ||||
| 			if err.Message == "Invalid left-hand side in assignment" { | ||||
| 				panic(newReferenceError(err.Message)) | ||||
| 				panic(self.panicReferenceError(err.Message)) | ||||
| 			} | ||||
| 			panic(newSyntaxError(err.Message)) | ||||
| 			panic(self.panicSyntaxError(err.Message)) | ||||
| 		} | ||||
| 	} | ||||
| 	panic(newSyntaxError(err.Error())) | ||||
| 	panic(self.panicSyntaxError(err.Error())) | ||||
| } | ||||
| 
 | ||||
| func (self *_runtime) parseOrThrow(source string) *ast.Program { | ||||
| @ -359,7 +359,7 @@ func TestComparison(t *testing.T) { | ||||
| 
 | ||||
| 		test("1 == 'Hello, World.'", false) | ||||
| 
 | ||||
| 		is(stringToFloat("-1"), -1) | ||||
| 		is(parseNumber("-1"), -1) | ||||
| 
 | ||||
| 		test("0+Object", "0function Object() { [native code] }") | ||||
| 	}) | ||||
							
								
								
									
										34
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/scope.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| package otto | ||||
| 
 | ||||
| // _scope:
 | ||||
| // entryFile
 | ||||
| // entryIdx
 | ||||
| // top?
 | ||||
| // outer => nil
 | ||||
| 
 | ||||
| // _stash:
 | ||||
| // lexical
 | ||||
| // variable
 | ||||
| //
 | ||||
| // _thisStash (ObjectEnvironment)
 | ||||
| // _fnStash
 | ||||
| // _dclStash
 | ||||
| 
 | ||||
| // An ECMA-262 ExecutionContext
 | ||||
| type _scope struct { | ||||
| 	lexical  _stash | ||||
| 	variable _stash | ||||
| 	this     *_object | ||||
| 	eval     bool // Replace this with kind?
 | ||||
| 	outer    *_scope | ||||
| 
 | ||||
| 	frame _frame | ||||
| } | ||||
| 
 | ||||
| func newScope(lexical _stash, variable _stash, this *_object) *_scope { | ||||
| 	return &_scope{ | ||||
| 		lexical:  lexical, | ||||
| 		variable: variable, | ||||
| 		this:     this, | ||||
| 	} | ||||
| } | ||||
| @ -6,8 +6,6 @@ import ( | ||||
| 
 | ||||
| func TestScript(t *testing.T) { | ||||
| 	tt(t, func() { | ||||
| 		return | ||||
| 
 | ||||
| 		vm := New() | ||||
| 
 | ||||
| 		script, err := vm.Compile("xyzzy", `var abc; if (!abc) abc = 0; abc += 2; abc;`) | ||||
| @ -20,6 +18,10 @@ func TestScript(t *testing.T) { | ||||
| 		is(err, nil) | ||||
| 		is(value, 2) | ||||
| 
 | ||||
| 		if true { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		tmp, err := script.marshalBinary() | ||||
| 		is(err, nil) | ||||
| 		is(len(tmp), 1228) | ||||
							
								
								
									
										275
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								Godeps/_workspace/src/github.com/robertkrimen/otto/stash.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,275 @@ | ||||
| package otto | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
| 
 | ||||
| // ======
 | ||||
| // _stash
 | ||||
| // ======
 | ||||
| 
 | ||||
| type _stash interface { | ||||
| 	hasBinding(string) bool            //
 | ||||
| 	createBinding(string, bool, Value) // CreateMutableBinding
 | ||||
| 	setBinding(string, Value, bool)    // SetMutableBinding
 | ||||
| 	getBinding(string, bool) Value     // GetBindingValue
 | ||||
| 	deleteBinding(string) bool         //
 | ||||
| 	setValue(string, Value, bool)      // createBinding + setBinding
 | ||||
| 
 | ||||
| 	outer() _stash | ||||
| 	runtime() *_runtime | ||||
| 
 | ||||
| 	newReference(string, bool, _at) _reference | ||||
| 
 | ||||
| 	clone(clone *_clone) _stash | ||||
| } | ||||
| 
 | ||||
| // ==========
 | ||||
| // _objectStash
 | ||||
| // ==========
 | ||||
| 
 | ||||
| type _objectStash struct { | ||||
| 	_runtime *_runtime | ||||
| 	_outer   _stash | ||||
| 	object   *_object | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) runtime() *_runtime { | ||||
| 	return self._runtime | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newObjectStash(object *_object, outer _stash) *_objectStash { | ||||
| 	if object == nil { | ||||
| 		object = runtime.newBaseObject() | ||||
| 		object.class = "environment" | ||||
| 	} | ||||
| 	return &_objectStash{ | ||||
| 		_runtime: runtime, | ||||
| 		_outer:   outer, | ||||
| 		object:   object, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (in *_objectStash) clone(clone *_clone) _stash { | ||||
| 	out, exists := clone.objectStash(in) | ||||
| 	if exists { | ||||
| 		return out | ||||
| 	} | ||||
| 	*out = _objectStash{ | ||||
| 		clone.runtime, | ||||
| 		clone.stash(in._outer), | ||||
| 		clone.object(in.object), | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) hasBinding(name string) bool { | ||||
| 	return self.object.hasProperty(name) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) createBinding(name string, deletable bool, value Value) { | ||||
| 	if self.object.hasProperty(name) { | ||||
| 		panic(hereBeDragons()) | ||||
| 	} | ||||
| 	mode := _propertyMode(0111) | ||||
| 	if !deletable { | ||||
| 		mode = _propertyMode(0110) | ||||
| 	} | ||||
| 	// TODO False?
 | ||||
| 	self.object.defineProperty(name, value, mode, false) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) setBinding(name string, value Value, strict bool) { | ||||
| 	self.object.put(name, value, strict) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) setValue(name string, value Value, throw bool) { | ||||
| 	if !self.hasBinding(name) { | ||||
| 		self.createBinding(name, true, value) // Configurable by default
 | ||||
| 	} else { | ||||
| 		self.setBinding(name, value, throw) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) getBinding(name string, throw bool) Value { | ||||
| 	if self.object.hasProperty(name) { | ||||
| 		return self.object.get(name) | ||||
| 	} | ||||
| 	if throw { // strict?
 | ||||
| 		panic(self._runtime.panicReferenceError("Not Defined", name)) | ||||
| 	} | ||||
| 	return Value{} | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) deleteBinding(name string) bool { | ||||
| 	return self.object.delete(name, false) | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) outer() _stash { | ||||
| 	return self._outer | ||||
| } | ||||
| 
 | ||||
| func (self *_objectStash) newReference(name string, strict bool, at _at) _reference { | ||||
| 	return newPropertyReference(self._runtime, self.object, name, strict, at) | ||||
| } | ||||
| 
 | ||||
| // =========
 | ||||
| // _dclStash
 | ||||
| // =========
 | ||||
| 
 | ||||
| type _dclStash struct { | ||||
| 	_runtime *_runtime | ||||
| 	_outer   _stash | ||||
| 	property map[string]_dclProperty | ||||
| } | ||||
| 
 | ||||
| type _dclProperty struct { | ||||
| 	value     Value | ||||
| 	mutable   bool | ||||
| 	deletable bool | ||||
| 	readable  bool | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newDeclarationStash(outer _stash) *_dclStash { | ||||
| 	return &_dclStash{ | ||||
| 		_runtime: runtime, | ||||
| 		_outer:   outer, | ||||
| 		property: map[string]_dclProperty{}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (in *_dclStash) clone(clone *_clone) _stash { | ||||
| 	out, exists := clone.dclStash(in) | ||||
| 	if exists { | ||||
| 		return out | ||||
| 	} | ||||
| 	property := make(map[string]_dclProperty, len(in.property)) | ||||
| 	for index, value := range in.property { | ||||
| 		property[index] = clone.dclProperty(value) | ||||
| 	} | ||||
| 	*out = _dclStash{ | ||||
| 		clone.runtime, | ||||
| 		clone.stash(in._outer), | ||||
| 		property, | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) hasBinding(name string) bool { | ||||
| 	_, exists := self.property[name] | ||||
| 	return exists | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) runtime() *_runtime { | ||||
| 	return self._runtime | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) createBinding(name string, deletable bool, value Value) { | ||||
| 	_, exists := self.property[name] | ||||
| 	if exists { | ||||
| 		panic(fmt.Errorf("createBinding: %s: already exists", name)) | ||||
| 	} | ||||
| 	self.property[name] = _dclProperty{ | ||||
| 		value:     value, | ||||
| 		mutable:   true, | ||||
| 		deletable: deletable, | ||||
| 		readable:  false, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) setBinding(name string, value Value, strict bool) { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		panic(fmt.Errorf("setBinding: %s: missing", name)) | ||||
| 	} | ||||
| 	if property.mutable { | ||||
| 		property.value = value | ||||
| 		self.property[name] = property | ||||
| 	} else { | ||||
| 		self._runtime.typeErrorResult(strict) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) setValue(name string, value Value, throw bool) { | ||||
| 	if !self.hasBinding(name) { | ||||
| 		self.createBinding(name, false, value) // NOT deletable by default
 | ||||
| 	} else { | ||||
| 		self.setBinding(name, value, throw) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // FIXME This is called a __lot__
 | ||||
| func (self *_dclStash) getBinding(name string, throw bool) Value { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		panic(fmt.Errorf("getBinding: %s: missing", name)) | ||||
| 	} | ||||
| 	if !property.mutable && !property.readable { | ||||
| 		if throw { // strict?
 | ||||
| 			panic(self._runtime.panicTypeError()) | ||||
| 		} | ||||
| 		return Value{} | ||||
| 	} | ||||
| 	return property.value | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) deleteBinding(name string) bool { | ||||
| 	property, exists := self.property[name] | ||||
| 	if !exists { | ||||
| 		return true | ||||
| 	} | ||||
| 	if !property.deletable { | ||||
| 		return false | ||||
| 	} | ||||
| 	delete(self.property, name) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) outer() _stash { | ||||
| 	return self._outer | ||||
| } | ||||
| 
 | ||||
| func (self *_dclStash) newReference(name string, strict bool, _ _at) _reference { | ||||
| 	return &_stashReference{ | ||||
| 		name: name, | ||||
| 		base: self, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ========
 | ||||
| // _fnStash
 | ||||
| // ========
 | ||||
| 
 | ||||
| type _fnStash struct { | ||||
| 	_dclStash | ||||
| 	arguments           *_object | ||||
| 	indexOfArgumentName map[string]string | ||||
| } | ||||
| 
 | ||||
| func (runtime *_runtime) newFunctionStash(outer _stash) *_fnStash { | ||||
| 	return &_fnStash{ | ||||
| 		_dclStash: _dclStash{ | ||||
| 			_runtime: runtime, | ||||
| 			_outer:   outer, | ||||
| 			property: map[string]_dclProperty{}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (in *_fnStash) clone(clone *_clone) _stash { | ||||
| 	out, exists := clone.fnStash(in) | ||||
| 	if exists { | ||||
| 		return out | ||||
| 	} | ||||
| 	dclStash := in._dclStash.clone(clone).(*_dclStash) | ||||
| 	index := make(map[string]string, len(in.indexOfArgumentName)) | ||||
| 	for name, value := range in.indexOfArgumentName { | ||||
| 		index[name] = value | ||||
| 	} | ||||
| 	*out = _fnStash{ | ||||
| 		_dclStash:           *dclStash, | ||||
| 		arguments:           clone.object(in.arguments), | ||||
| 		indexOfArgumentName: index, | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user