Browse Source

Fixed compilation of object literals with numeric keys. Fixes #221.

Dmitry Panov 5 years ago
parent
commit
e21ccf39bf
5 changed files with 76 additions and 26 deletions
  1. 1 1
      ast/node.go
  2. 10 4
      compiler_expr.go
  3. 15 0
      compiler_test.go
  4. 23 8
      parser/expression.go
  5. 27 13
      parser/marshal_test.go

+ 1 - 1
ast/node.go

@@ -135,7 +135,7 @@ type (
 	}
 
 	Property struct {
-		Key   unistring.String
+		Key   Expression
 		Kind  string
 		Value Expression
 	}

+ 10 - 4
compiler_expr.go

@@ -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))
 		}

+ 15 - 0
compiler_test.go

@@ -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")
 

+ 23 - 8
parser/expression.go

@@ -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

+ 27 - 13
parser/marshal_test.go

@@ -3,8 +3,6 @@ package parser
 import (
 	"bytes"
 	"encoding/json"
-	"fmt"
-	"os"
 	"reflect"
 	"strings"
 	"testing"
@@ -176,10 +174,6 @@ func testMarshalNode(node interface{}) interface{} {
 		}
 	}
 
-	if node != nil {
-		fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node)
-	}
-
 	return nil
 }
 
@@ -361,8 +355,12 @@ func TestParserAST(t *testing.T) {
       "Right": {
         "Object": [
           {
-            "Key": "abc",
-            "Value": {
+            "Key": {
+               "Idx": 7,
+               "Literal": "abc",
+               "Value": "abc"
+            },
+			"Value": {
               "Literal": true
             }
           }
@@ -594,8 +592,12 @@ func TestParserAST(t *testing.T) {
   {
     "Object": [
       {
-        "Key": "abc",
-        "Value": {
+		"Key": {
+		   "Idx": 77,
+		   "Literal": "abc",
+		   "Value": "abc"
+		},
+		"Value": {
           "Literal": "'def'"
         }
       }
@@ -636,7 +638,11 @@ func TestParserAST(t *testing.T) {
   {
     "Object": [
       {
-        "Key": "abc",
+		"Key": {
+		   "Idx": 8,
+		   "Literal": "abc",
+		   "Value": "abc"
+		},
         "Value": {
           "Function": {
             "BlockStatement": []
@@ -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": "'\"'"
             }