Skip to content

Commit 1ed9dbd

Browse files
committed
correctly parse enum values
enum values can be expressions including - unary operators - binary operators - string and number literals - parenthesis - identifiers See: https://github.com/microsoft/TypeScript/blob/master/doc/spec.md#92-enum-members https://github.com/microsoft/TypeScript/blob/master/doc/spec.md#419-binary-operators Note: this implementation performs a flat parse that neither handles expression-tree-building nor operator precedences. Note: This commit removes the minus from the NumericLit-token and parses it explicitly in TSDefParser.numberLiteral
1 parent 1a9a723 commit 1ed9dbd

File tree

4 files changed

+82
-5
lines changed

4 files changed

+82
-5
lines changed

samples/valueExpression.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
declare module valueExpression {
2+
export enum StringEnum {
3+
A = "test",
4+
B = A,
5+
C = "test" + "test"
6+
}
7+
export enum NumberEnum {
8+
A = 3 + 3,
9+
B = 1 << 3,
10+
C = 10**2+1*8- - -3/3>>2<<3>>>+19%~~~3+ + +9
11+
}
12+
}

samples/valueExpression.d.ts.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
import scala.scalajs.js
3+
import js.annotation._
4+
import js.|
5+
6+
package valueExpression {
7+
8+
package valueExpression {
9+
10+
@js.native
11+
sealed trait StringEnum extends js.Object {
12+
}
13+
14+
@js.native
15+
@JSGlobal("valueExpression.StringEnum")
16+
object StringEnum extends js.Object {
17+
var A: StringEnum = js.native
18+
var B: StringEnum = js.native
19+
var C: StringEnum = js.native
20+
@JSBracketAccess
21+
def apply(value: StringEnum): String = js.native
22+
}
23+
24+
@js.native
25+
sealed trait NumberEnum extends js.Object {
26+
}
27+
28+
@js.native
29+
@JSGlobal("valueExpression.NumberEnum")
30+
object NumberEnum extends js.Object {
31+
var A: NumberEnum = js.native
32+
var B: NumberEnum = js.native
33+
var C: NumberEnum = js.native
34+
@JSBracketAccess
35+
def apply(value: NumberEnum): String = js.native
36+
}
37+
38+
}
39+
40+
}

src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefLexical.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ class TSDefLexical extends Lexical with StdTokens with ImplicitConversions {
4242
digits => digits.foldLeft(0L)(_ * 8 + _).toString
4343
}
4444
)
45-
| opt('-') ~ stringOf1(digit) ~ opt(stringOf1('.', digit)) ^^ {
46-
case sign ~ part1 ~ part2 => sign.getOrElse("") + part1 + (part2.getOrElse(""))
45+
| stringOf1(digit) ~ opt(stringOf1('.', digit)) ^^ {
46+
case part1 ~ part2 => part1 + part2.getOrElse("")
4747
}
4848
) ^^ NumericLit
4949

src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions {
4646
"...", "=>"
4747
)
4848

49+
// for value expressions
50+
val binaryValueOperators = Set(
51+
"+", "-", "*", "/", "**", "%",
52+
"<<", ">>>", ">>", "&", "|", "^"
53+
)
54+
lexical.delimiters ++= binaryValueOperators
55+
56+
val unaryValueOperators = Set(
57+
"+", "-", "~"
58+
)
59+
lexical.delimiters ++= unaryValueOperators
60+
4961
def parseDefinitions(input: Reader[Char]) =
5062
phrase(ambientDeclarations)(new lexical.Scanner(input))
5163

@@ -105,7 +117,20 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions {
105117
"enum" ~> typeName ~ ("{" ~> ambientEnumBody <~ "}") ^^ EnumDecl
106118

107119
lazy val ambientEnumBody: Parser[List[Ident]] =
108-
repsep(identifier <~ opt("=" ~ (numericLit | stringLit) ), ",") <~ opt(",")
120+
repsep(identifier <~ opt("=" ~! valueExpression), ",") <~ opt(",")
121+
122+
lazy val valueExpression: Parser[_] =
123+
rep1sep(success() ~>! rep(unaryValueOperator) ~
124+
(numericLit | stringLit | identifierName | parenthesizedValueExpression), binaryValueOperator)
125+
126+
lazy val parenthesizedValueExpression =
127+
"(" ~! valueExpression ~ ")"
128+
129+
lazy val binaryValueOperator =
130+
elem("binary operator", tok => binaryValueOperators.contains(tok.chars))
131+
132+
lazy val unaryValueOperator =
133+
elem("unary operator", tok => unaryValueOperators.contains(tok.chars))
109134

110135
lazy val ambientClassDecl: Parser[DeclTree] =
111136
(abstractModifier <~ "class") ~ typeName ~ tparams ~ classParent ~ classImplements ~ memberBlock <~ opt(";") ^^ {
@@ -342,8 +367,8 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions {
342367
stringLit ^^ StringLiteral
343368

344369
lazy val numberLiteral: Parser[NumberLiteral] =
345-
numericLit ^^ { s =>
346-
val d = s.toDouble
370+
opt("-") ~ numericLit ^^ { case minus ~ s =>
371+
val d = (minus.getOrElse("") + s).toDouble
347372
if (!s.contains(".") && d.isValidInt) {
348373
IntLiteral(d.toInt)
349374
} else {

0 commit comments

Comments
 (0)