Example #1
0
func TestCommentMap_move(t *testing.T) {
	statement1 := &EmptyStatement{file.Idx(1)}
	statement2 := &EmptyStatement{file.Idx(2)}
	comment := &Comment{1, "test", LEADING}

	cm := CommentMap{}
	cm.AddComment(statement1, comment)

	if cm.Size() != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if len(cm[statement1]) != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if len(cm[statement2]) != 0 {
		t.Errorf("the number of comments is %v, not 0", cm.Size())
	}

	cm.MoveComments(statement1, statement2, LEADING)

	if cm.Size() != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if len(cm[statement2]) != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if len(cm[statement1]) != 0 {
		t.Errorf("the number of comments is %v, not 0", cm.Size())
	}
}
Example #2
0
func (fr _frame) location() string {
	str := "<unknown>"

	switch {
	case fr.native:
		str = "<native code>"
		if fr.nativeFile != "" && fr.nativeLine != 0 {
			str = fmt.Sprintf("%s:%d", fr.nativeFile, fr.nativeLine)
		}
	case fr.file != nil:
		if p := fr.file.Position(file.Idx(fr.offset)); p != nil {
			path, line, column := p.Filename, p.Line, p.Column

			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
}
Example #3
0
func TestCommentMap(t *testing.T) {
	statement := &EmptyStatement{file.Idx(1)}
	comment := &Comment{1, "test", LEADING}

	cm := CommentMap{}
	cm.AddComment(statement, comment)

	if cm.Size() != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if len(cm[statement]) != 1 {
		t.Errorf("the number of comments is %v, not 1", cm.Size())
	}

	if cm[statement][0].Text != "test" {
		t.Errorf("the text is %v, not \"test\"", cm[statement][0].Text)
	}
}
Example #4
0
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]
}
Example #5
0
func (self *_parser) parseNewExpression() ast.Expression {
	idx := self.expect(token.NEW)
	callee := self.parseLeftHandSideExpression()
	node := &ast.NewExpression{
		New:              idx,
		Callee:           callee,
		RightParenthesis: idx + file.Idx(3),
	}
	if self.token == token.LEFT_PARENTHESIS {
		argumentList, idx0, idx1 := self.parseArgumentList()
		node.ArgumentList = argumentList
		node.LeftParenthesis = idx0
		node.RightParenthesis = idx1
	}

	if self.mode&StoreComments != 0 {
		self.comments.SetExpression(node)
	}

	return node
}
Example #6
0
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)
}
Example #7
0
func (fr _frame) location() string {
	if fr.file == nil {
		return "<unknown>"
	}

	p := fr.file.Position(file.Idx(fr.offset))

	path, line, column := p.Filename, p.Line, p.Column

	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
}
Example #8
0
func (self *RegExpLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) }
Example #9
0
func (self *_parser) idxOf(offset int) file.Idx {
	return file.Idx(self.base + offset)
}
Example #10
0
func (self *VariableExpression) Idx1() file.Idx {
	if self.Initializer == nil {
		return file.Idx(int(self.Idx) + len(self.Name) + 1)
	}
	return self.Initializer.Idx1()
}
Example #11
0
func (self *StringLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) }
Example #12
0
func (self *NumberLiteral) Idx1() file.Idx         { return file.Idx(int(self.Idx) + len(self.Literal)) }
Example #13
0
func (self *NullLiteral) Idx1() file.Idx           { return file.Idx(int(self.Idx) + 4) } // "null"
Example #14
0
func (self *Identifier) Idx1() file.Idx            { return file.Idx(int(self.Idx) + len(self.Name)) }
Example #15
0
func (self *BooleanLiteral) Idx1() file.Idx        { return file.Idx(int(self.Idx) + len(self.Literal)) }
Example #16
0
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 = /*test*/",
			token.IDENTIFIER, "abc", 1,
			token.ASSIGN, "", 5,
			token.EOF, "", 15,
		)

		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(";;//test",
			token.SEMICOLON, "", 1,
			token.SEMICOLON, "", 2,
			token.EOF, "", 9,
		)

		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,
		)

	})
}
Example #17
0
// ContextSkip returns the current execution context of the vm, with a
// specific limit on the number of stack frames to traverse, optionally
// skipping any innermost native function stack frames.
func (self Otto) ContextSkip(limit int, skipNative bool) (ctx Context) {
	// Ensure we are operating in a scope
	if self.runtime.scope == nil {
		self.runtime.enterGlobalScope()
		defer self.runtime.leaveScope()
	}

	scope := self.runtime.scope
	frame := scope.frame

	for skipNative && frame.native && scope.outer != nil {
		scope = scope.outer
		frame = scope.frame
	}

	// Get location information
	ctx.Filename = "<unknown>"
	ctx.Callee = frame.callee

	switch {
	case frame.native:
		ctx.Filename = frame.nativeFile
		ctx.Line = frame.nativeLine
		ctx.Column = 0
	case frame.file != nil:
		ctx.Filename = "<anonymous>"

		if p := frame.file.Position(file.Idx(frame.offset)); p != nil {
			ctx.Line = p.Line
			ctx.Column = p.Column

			if p.Filename != "" {
				ctx.Filename = p.Filename
			}
		}
	}

	// Get the current scope this Value
	ctx.This = toValue_object(scope.this)

	// Build stacktrace (up to 10 levels deep)
	ctx.Symbols = make(map[string]Value)
	ctx.Stacktrace = append(ctx.Stacktrace, frame.location())
	for limit != 0 {
		// Get variables
		stash := scope.lexical
		for {
			for _, name := range getStashProperties(stash) {
				if _, ok := ctx.Symbols[name]; !ok {
					ctx.Symbols[name] = stash.getBinding(name, true)
				}
			}
			stash = stash.outer()
			if stash == nil || stash.outer() == nil {
				break
			}
		}

		scope = scope.outer
		if scope == nil {
			break
		}
		if scope.frame.offset >= 0 {
			ctx.Stacktrace = append(ctx.Stacktrace, scope.frame.location())
		}
		limit--
	}

	return
}