Skip to content

Commit

Permalink
Fixed compilation of object literals with numeric keys. Fixes #221.
Browse files Browse the repository at this point in the history
  • Loading branch information
dop251 committed Oct 22, 2020
1 parent bf9dcfb commit e21ccf3
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 26 deletions.
2 changes: 1 addition & 1 deletion ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ type (
}

Property struct {
Key unistring.String
Key Expression
Kind string
Value Expression
}
Expand Down
14 changes: 10 additions & 4 deletions compiler_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1377,18 +1377,24 @@ func (e *compiledObjectLiteral) emitGetter(putOnStack bool) {
e.addSrcMap()
e.c.emit(newObject)
for _, prop := range e.expr.Value {
keyExpr := e.c.compileExpression(prop.Key)
cl, ok := keyExpr.(*compiledLiteral)
if !ok {
e.c.throwSyntaxError(e.offset, "non-literal properties in object literal are not supported yet")
}
key := cl.val.string()
e.c.compileExpression(prop.Value).emitGetter(true)
switch prop.Kind {
case "value":
if prop.Key == __proto__ {
if key == __proto__ {
e.c.emit(setProto)
} else {
e.c.emit(setProp1(prop.Key))
e.c.emit(setProp1(key))
}
case "get":
e.c.emit(setPropGetter(prop.Key))
e.c.emit(setPropGetter(key))
case "set":
e.c.emit(setPropSetter(prop.Key))
e.c.emit(setPropSetter(key))
default:
panic(fmt.Errorf("Unknown property kind: %s", prop.Kind))
}
Expand Down
15 changes: 15 additions & 0 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2148,6 +2148,21 @@ func TestDummyCompileForUpdate(t *testing.T) {
}
}

func TestObjectLiteralWithNumericKeys(t *testing.T) {
const SCRIPT = `
var o = {1e3: true};
var keys = Object.keys(o);
var o1 = {get 1e3() {return true;}};
var keys1 = Object.keys(o1);
var o2 = {1e21: true};
var keys2 = Object.keys(o2);
keys.length === 1 && keys[0] === "1000" &&
keys1.length === 1 && keys1[0] === "1000" && o1[1e3] === true &&
keys2.length === 1 && keys2[0] === "1e+21";
`
testScript1(SCRIPT, valueTrue, t)
}

func BenchmarkCompile(b *testing.B) {
f, err := os.Open("testdata/S15.10.2.12_A1_T1.js")

Expand Down
31 changes: 23 additions & 8 deletions parser/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,27 +189,42 @@ func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expressio
return list
}

func (self *_parser) parseObjectPropertyKey() (string, unistring.String) {
func (self *_parser) parseObjectPropertyKey() (string, ast.Expression) {
idx, tkn, literal, parsedLiteral := self.idx, self.token, self.literal, self.parsedLiteral
var value unistring.String
var value ast.Expression
self.next()
switch tkn {
case token.IDENTIFIER:
value = parsedLiteral
value = &ast.StringLiteral{
Idx: idx,
Literal: literal,
Value: unistring.String(literal),
}
case token.NUMBER:
var err error
_, err = parseNumberLiteral(literal)
num, err := parseNumberLiteral(literal)
if err != nil {
self.error(idx, err.Error())
} else {
value = unistring.String(literal)
value = &ast.NumberLiteral{
Idx: idx,
Literal: literal,
Value: num,
}
}
case token.STRING:
value = parsedLiteral
value = &ast.StringLiteral{
Idx: idx,
Literal: literal,
Value: parsedLiteral,
}
default:
// null, false, class, etc.
if isId(tkn) {
value = unistring.String(literal)
value = &ast.StringLiteral{
Idx: idx,
Literal: literal,
Value: unistring.String(literal),
}
}
}
return literal, value
Expand Down
40 changes: 27 additions & 13 deletions parser/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package parser
import (
"bytes"
"encoding/json"
"fmt"
"os"
"reflect"
"strings"
"testing"
Expand Down Expand Up @@ -176,10 +174,6 @@ func testMarshalNode(node interface{}) interface{} {
}
}

if node != nil {
fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node)
}

return nil
}

Expand Down Expand Up @@ -361,8 +355,12 @@ func TestParserAST(t *testing.T) {
"Right": {
"Object": [
{
"Key": "abc",
"Value": {
"Key": {
"Idx": 7,
"Literal": "abc",
"Value": "abc"
},
"Value": {
"Literal": true
}
}
Expand Down Expand Up @@ -594,8 +592,12 @@ func TestParserAST(t *testing.T) {
{
"Object": [
{
"Key": "abc",
"Value": {
"Key": {
"Idx": 77,
"Literal": "abc",
"Value": "abc"
},
"Value": {
"Literal": "'def'"
}
}
Expand Down Expand Up @@ -636,7 +638,11 @@ func TestParserAST(t *testing.T) {
{
"Object": [
{
"Key": "abc",
"Key": {
"Idx": 8,
"Literal": "abc",
"Value": "abc"
},
"Value": {
"Function": {
"BlockStatement": []
Expand Down Expand Up @@ -836,13 +842,21 @@ func TestParserAST(t *testing.T) {
"Right": {
"Object": [
{
"Key": "\"",
"Key": {
"Idx": 21,
"Literal": "'\"'",
"Value": "\""
},
"Value": {
"Literal": "\"'\""
}
},
{
"Key": "'",
"Key": {
"Idx": 43,
"Literal": "\"'\"",
"Value": "'"
},
"Value": {
"Literal": "'\"'"
}
Expand Down

0 comments on commit e21ccf3

Please sign in to comment.