From edb445392441582b722026dbfabed86706d6750d Mon Sep 17 00:00:00 2001 From: JohnnyMorganz Date: Tue, 18 Oct 2022 18:15:26 +0100 Subject: [PATCH] Support `["prop"]` syntax on class definitions (#704) Some classes have properties which are not valid identifiers (such as https://create.roblox.com/docs/reference/engine/classes/Studio) This adds support for the following syntax in definition files: ```lua declare class Foo ["a property"]: string end ``` Closes #702 --- Ast/src/Parser.cpp | 19 +++++++++++++++++++ tests/TypeInfer.definitions.test.cpp | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp index c20c0847..7150b18f 100644 --- a/Ast/src/Parser.cpp +++ b/Ast/src/Parser.cpp @@ -905,6 +905,25 @@ AstStat* Parser::parseDeclaration(const Location& start) { props.push_back(parseDeclaredClassMethod()); } + else if (lexer.current().type == '[') + { + const Lexeme begin = lexer.current(); + nextLexeme(); // [ + + std::optional> chars = parseCharArray(); + + expectMatchAndConsume(']', begin); + expectAndConsume(':', "property type annotation"); + AstType* type = parseTypeAnnotation(); + + // TODO: since AstName conains a char*, it can't contain null + bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size); + + if (chars && !containsNull) + props.push_back(AstDeclaredClassProp{AstName(chars->data), type, false}); + else + report(begin.location, "String literal contains malformed escape sequence"); + } else { Name propName = parseName("property name"); diff --git a/tests/TypeInfer.definitions.test.cpp b/tests/TypeInfer.definitions.test.cpp index 26280c13..15c63ec7 100644 --- a/tests/TypeInfer.definitions.test.cpp +++ b/tests/TypeInfer.definitions.test.cpp @@ -362,4 +362,21 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_overload_metamethods") CHECK_EQ(toString(requireType("shouldBeVector")), "Vector3"); } +TEST_CASE_FIXTURE(Fixture, "class_definition_string_props") +{ + loadDefinition(R"( + declare class Foo + ["a property"]: string + end + )"); + + CheckResult result = check(R"( + local x: Foo + local y = x["a property"] + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + CHECK_EQ(toString(requireType("y")), "string"); +} + TEST_SUITE_END();