From 91adb754f823054ba224614ffd9c77626f165222 Mon Sep 17 00:00:00 2001 From: SrTobi Date: Sun, 16 Jun 2019 13:39:31 +0200 Subject: [PATCH] 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 --- samples/valueExpression.d.ts | 8 +++++ samples/valueExpression.d.ts.scala | 27 ++++++++++++++++ .../tsimporter/parser/TSDefLexical.scala | 4 +-- .../tools/tsimporter/parser/TSDefParser.scala | 31 +++++++++++++++++-- 4 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 samples/valueExpression.d.ts create mode 100644 samples/valueExpression.d.ts.scala diff --git a/samples/valueExpression.d.ts b/samples/valueExpression.d.ts new file mode 100644 index 00000000..2727c2fe --- /dev/null +++ b/samples/valueExpression.d.ts @@ -0,0 +1,8 @@ +declare module valueExpression { + export enum Color { + A = 3 + 3, + B = "test" + "teste", + C = 1 << 3, + D = 10**2+1*8- - -3/3>>2<<3>>>+19%~~~3+ + +9 + } +} \ No newline at end of file diff --git a/samples/valueExpression.d.ts.scala b/samples/valueExpression.d.ts.scala new file mode 100644 index 00000000..19e22818 --- /dev/null +++ b/samples/valueExpression.d.ts.scala @@ -0,0 +1,27 @@ + +import scala.scalajs.js +import js.annotation._ +import js.| + +package valueExpression { + +package valueExpression { + +@js.native +sealed trait Color extends js.Object { +} + +@js.native +@JSGlobal("valueExpression.Color") +object Color extends js.Object { + var A: Color = js.native + var B: Color = js.native + var C: Color = js.native + var D: Color = js.native + @JSBracketAccess + def apply(value: Color): String = js.native +} + +} + +} diff --git a/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefLexical.scala b/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefLexical.scala index d04a4a58..46afcb27 100644 --- a/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefLexical.scala +++ b/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefLexical.scala @@ -42,8 +42,8 @@ class TSDefLexical extends Lexical with StdTokens with ImplicitConversions { digits => digits.foldLeft(0L)(_ * 8 + _).toString } ) - | opt('-') ~ stringOf1(digit) ~ opt(stringOf1('.', digit)) ^^ { - case sign ~ part1 ~ part2 => sign.getOrElse("") + part1 + (part2.getOrElse("")) + | stringOf1(digit) ~ opt(stringOf1('.', digit)) ^^ { + case part1 ~ part2 => part1 + part2.getOrElse("") } ) ^^ NumericLit diff --git a/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala b/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala index cc3c3ea2..7a715517 100644 --- a/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala +++ b/src/main/scala/org/scalajs/tools/tsimporter/parser/TSDefParser.scala @@ -46,6 +46,18 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions { "...", "=>" ) + // for value expressions + val binaryValueOperators = Set( + "+", "-", "*", "/", "**", "%", + "<<", ">>>", ">>", "&", "|", "^" + ) + lexical.delimiters ++= binaryValueOperators + + val unaryValueOperators = Set( + "+", "-", "~" + ) + lexical.delimiters ++= unaryValueOperators + def parseDefinitions(input: Reader[Char]) = phrase(ambientDeclarations)(new lexical.Scanner(input)) @@ -105,7 +117,20 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions { "enum" ~> typeName ~ ("{" ~> ambientEnumBody <~ "}") ^^ EnumDecl lazy val ambientEnumBody: Parser[List[Ident]] = - repsep(identifier <~ opt("=" ~ (numericLit | stringLit) ), ",") <~ opt(",") + repsep(identifier <~ opt("=" ~! valueExpression), ",") <~ opt(",") + + lazy val valueExpression: Parser[_] = + rep1sep(success() ~>! rep(unaryValueOperator) ~ + (numericLit | stringLit | identifierName | parenthesizedValueExpression), binaryValueOperator) + + lazy val parenthesizedValueExpression = + "(" ~! valueExpression ~ ")" + + lazy val binaryValueOperator = + elem("binary operator", tok => binaryValueOperators.contains(tok.chars)) + + lazy val unaryValueOperator = + elem("unary operator", tok => unaryValueOperators.contains(tok.chars)) lazy val ambientClassDecl: Parser[DeclTree] = (abstractModifier <~ "class") ~ typeName ~ tparams ~ classParent ~ classImplements ~ memberBlock <~ opt(";") ^^ { @@ -342,8 +367,8 @@ class TSDefParser extends StdTokenParsers with ImplicitConversions { stringLit ^^ StringLiteral lazy val numberLiteral: Parser[NumberLiteral] = - numericLit ^^ { s => - val d = s.toDouble + opt("-") ~ numericLit ^^ { case minus ~ s => + val d = (minus.getOrElse("") + s).toDouble if (!s.contains(".") && d.isValidInt) { IntLiteral(d.toInt) } else {