diff --git a/Ast/include/Luau/Parser.h b/Ast/include/Luau/Parser.h index 504e19e6..32229ded 100644 --- a/Ast/include/Luau/Parser.h +++ b/Ast/include/Luau/Parser.h @@ -1,387 +1,387 @@ -// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details -#pragma once - -#include "Luau/Ast.h" -#include "Luau/Lexer.h" -#include "Luau/ParseOptions.h" -#include "Luau/ParseResult.h" -#include "Luau/StringUtils.h" -#include "Luau/DenseHash.h" -#include "Luau/Common.h" - -#include -#include - -namespace Luau -{ - -template -class TempVector -{ -public: - explicit TempVector(std::vector& storage); - - ~TempVector(); - - const T& operator[](std::size_t index) const; - - const T& front() const; - - const T& back() const; - - bool empty() const; - - std::size_t size() const; - - void push_back(const T& item); - - typename std::vector::const_iterator begin() const - { - return storage.begin() + offset; - } - typename std::vector::const_iterator end() const - { - return storage.begin() + offset + size_; - } - -private: - std::vector& storage; - size_t offset; - size_t size_; -}; - -class Parser -{ -public: - static ParseResult parse( - const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions()); - -private: - struct Name; - struct Binding; - - Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options); - - bool blockFollow(const Lexeme& l); - - AstStatBlock* parseChunk(); - - // chunk ::= {stat [`;']} [laststat [`;']] - // block ::= chunk - AstStatBlock* parseBlock(); - - AstStatBlock* parseBlockNoScope(); - - // stat ::= - // varlist `=' explist | - // functioncall | - // do block end | - // while exp do block end | - // repeat block until exp | - // if exp then block {elseif exp then block} [else block] end | - // for Name `=' exp `,' exp [`,' exp] do block end | - // for namelist in explist do block end | - // function funcname funcbody | - // local function Name funcbody | - // local namelist [`=' explist] - // laststat ::= return [explist] | break - AstStat* parseStat(); - - // if exp then block {elseif exp then block} [else block] end - AstStat* parseIf(); - - // while exp do block end - AstStat* parseWhile(); - - // repeat block until exp - AstStat* parseRepeat(); - - // do block end - AstStat* parseDo(); - - // break - AstStat* parseBreak(); - - // continue - AstStat* parseContinue(const Location& start); - - // for Name `=' exp `,' exp [`,' exp] do block end | - // for namelist in explist do block end | - AstStat* parseFor(); - - // function funcname funcbody | - // funcname ::= Name {`.' Name} [`:' Name] - AstStat* parseFunctionStat(); - - // local function Name funcbody | - // local namelist [`=' explist] - AstStat* parseLocal(); - - // return [explist] - AstStat* parseReturn(); - - // type Name `=' typeannotation - AstStat* parseTypeAlias(const Location& start, bool exported); - - AstDeclaredClassProp parseDeclaredClassMethod(); - - // `declare global' Name: typeannotation | - // `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation] - AstStat* parseDeclaration(const Location& start); - - // varlist `=' explist - AstStat* parseAssignment(AstExpr* initial); - - // var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp - AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op); - - // funcbody ::= `(' [parlist] `)' block end - // parlist ::= namelist [`,' `...'] | `...' - std::pair parseFunctionBody( - bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional localName); - - // explist ::= {exp `,'} exp - void parseExprList(TempVector& result); - - // binding ::= Name [`:` TypeAnnotation] - Binding parseBinding(); - - // bindinglist ::= (binding | `...') {`,' bindinglist} - // Returns the location of the vararg ..., or std::nullopt if the function is not vararg. - std::pair, AstTypePack*> parseBindingList(TempVector& result, bool allowDot3 = false); - - AstType* parseOptionalTypeAnnotation(); - - // TypeList ::= TypeAnnotation [`,' TypeList] - // ReturnType ::= TypeAnnotation | `(' TypeList `)' - // TableProp ::= Name `:' TypeAnnotation - // TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation - // PropList ::= (TableProp | TableIndexer) [`,' PropList] - // TypeAnnotation - // ::= Name - // | `nil` - // | `{' [PropList] `}' - // | `(' [TypeList] `)' `->` ReturnType - - // Returns the variadic annotation, if it exists. - AstTypePack* parseTypeList(TempVector& result, TempVector>& resultNames); - - std::optional parseOptionalReturnTypeAnnotation(); - std::pair parseReturnTypeAnnotation(); - - AstTableIndexer* parseTableIndexerAnnotation(); - - AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack); - AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray generics, AstArray genericPacks, - AstArray& params, AstArray>& paramNames, AstTypePack* varargAnnotation); - - AstType* parseTableTypeAnnotation(); - AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack); - - AstTypeOrPack parseTypeOrPackAnnotation(); - AstType* parseTypeAnnotation(TempVector& parts, const Location& begin); - AstType* parseTypeAnnotation(); - - AstTypePack* parseTypePackAnnotation(); - AstTypePack* parseVariadicArgumentAnnotation(); - - static std::optional parseUnaryOp(const Lexeme& l); - static std::optional parseBinaryOp(const Lexeme& l); - static std::optional parseCompoundOp(const Lexeme& l); - - struct BinaryOpPriority - { - unsigned char left, right; - }; - - std::optional checkUnaryConfusables(); - std::optional checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit); - - // subexpr -> (asexp | unop subexpr) { binop subexpr } - // where `binop' is any binary operator with a priority higher than `limit' - AstExpr* parseExpr(unsigned int limit = 0); - - // NAME - AstExpr* parseNameExpr(const char* context = nullptr); - - // prefixexp -> NAME | '(' expr ')' - AstExpr* parsePrefixExpr(); - - // primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } - AstExpr* parsePrimaryExpr(bool asStatement); - - // asexp -> simpleexp [`::' typeAnnotation] - AstExpr* parseAssertionExpr(); - - // simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp - AstExpr* parseSimpleExpr(); - - // args ::= `(' [explist] `)' | tableconstructor | String - AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation); - - // tableconstructor ::= `{' [fieldlist] `}' - // fieldlist ::= field {fieldsep field} [fieldsep] - // field ::= `[' exp `]' `=' exp | Name `=' exp | exp - // fieldsep ::= `,' | `;' - AstExpr* parseTableConstructor(); - - // TODO: Add grammar rules here? - AstExpr* parseIfElseExpr(); - - // stringinterp ::= exp { exp} - AstExpr* parseInterpString(); - - // Name - std::optional parseNameOpt(const char* context = nullptr); - Name parseName(const char* context = nullptr); - Name parseIndexName(const char* context, const Position& previous); - - // `<' namelist `>' - std::pair, AstArray> parseGenericTypeList(bool withDefaultValues); - - // `<' typeAnnotation[, ...] `>' - AstArray parseTypeParams(); - - std::optional> parseCharArray(); - AstExpr* parseString(); - - AstLocal* pushLocal(const Binding& binding); - - unsigned int saveLocals(); - - void restoreLocals(unsigned int offset); - - // check that parser is at lexeme/symbol, move to next lexeme/symbol on success, report failure and continue on failure - bool expectAndConsume(char value, const char* context = nullptr); - bool expectAndConsume(Lexeme::Type type, const char* context = nullptr); - void expectAndConsumeFail(Lexeme::Type type, const char* context); - - bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false); - void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr); - - bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin); - void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin); - - template - AstArray copy(const T* data, std::size_t size); - - template - AstArray copy(const TempVector& data); - - template - AstArray copy(std::initializer_list data); - - AstArray copy(const std::string& data); - - void incrementRecursionCounter(const char* context); - - void report(const Location& location, const char* format, va_list args); - void report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4); - - void reportNameError(const char* context); - - AstStatError* reportStatError(const Location& location, const AstArray& expressions, const AstArray& statements, - const char* format, ...) LUAU_PRINTF_ATTR(5, 6); - AstExprError* reportExprError(const Location& location, const AstArray& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5); - AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray& types, bool isMissing, const char* format, ...) - LUAU_PRINTF_ATTR(5, 6); - - void nextLexeme(); - - struct Function - { - bool vararg; - unsigned int loopDepth; - - Function() - : vararg(false) - , loopDepth(0) - { - } - }; - - struct Local - { - AstLocal* local; - unsigned int offset; - - Local() - : local(nullptr) - , offset(0) - { - } - }; - - struct Name - { - AstName name; - Location location; - - Name(const AstName& name, const Location& location) - : name(name) - , location(location) - { - } - }; - - struct Binding - { - Name name; - AstType* annotation; - - explicit Binding(const Name& name, AstType* annotation = nullptr) - : name(name) - , annotation(annotation) - { - } - }; - - ParseOptions options; - - Lexer lexer; - Allocator& allocator; - - std::vector commentLocations; - std::vector hotcomments; - - bool hotcommentHeader = true; - - unsigned int recursionCounter; - - AstName nameSelf; - AstName nameNumber; - AstName nameError; - AstName nameNil; - - Lexeme endMismatchSuspect; - - std::vector functionStack; - - DenseHashMap localMap; - std::vector localStack; - - std::vector parseErrors; - - std::vector matchRecoveryStopOnToken; - - std::vector scratchStat; - std::vector> scratchString; - std::vector scratchExpr; - std::vector scratchExprAux; - std::vector scratchName; - std::vector scratchPackName; - std::vector scratchBinding; - std::vector scratchLocal; - std::vector scratchTableTypeProps; - std::vector scratchAnnotation; - std::vector scratchTypeOrPackAnnotation; - std::vector scratchDeclaredClassProps; - std::vector scratchItem; - std::vector scratchArgName; - std::vector scratchGenericTypes; - std::vector scratchGenericTypePacks; - std::vector> scratchOptArgName; - std::string scratchData; -}; - -} // namespace Luau +// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details +#pragma once + +#include "Luau/Ast.h" +#include "Luau/Lexer.h" +#include "Luau/ParseOptions.h" +#include "Luau/ParseResult.h" +#include "Luau/StringUtils.h" +#include "Luau/DenseHash.h" +#include "Luau/Common.h" + +#include +#include + +namespace Luau +{ + +template +class TempVector +{ +public: + explicit TempVector(std::vector& storage); + + ~TempVector(); + + const T& operator[](std::size_t index) const; + + const T& front() const; + + const T& back() const; + + bool empty() const; + + std::size_t size() const; + + void push_back(const T& item); + + typename std::vector::const_iterator begin() const + { + return storage.begin() + offset; + } + typename std::vector::const_iterator end() const + { + return storage.begin() + offset + size_; + } + +private: + std::vector& storage; + size_t offset; + size_t size_; +}; + +class Parser +{ +public: + static ParseResult parse( + const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions()); + +private: + struct Name; + struct Binding; + + Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options); + + bool blockFollow(const Lexeme& l); + + AstStatBlock* parseChunk(); + + // chunk ::= {stat [`;']} [laststat [`;']] + // block ::= chunk + AstStatBlock* parseBlock(); + + AstStatBlock* parseBlockNoScope(); + + // stat ::= + // varlist `=' explist | + // functioncall | + // do block end | + // while exp do block end | + // repeat block until exp | + // if exp then block {elseif exp then block} [else block] end | + // for Name `=' exp `,' exp [`,' exp] do block end | + // for namelist in explist do block end | + // function funcname funcbody | + // local function Name funcbody | + // local namelist [`=' explist] + // laststat ::= return [explist] | break + AstStat* parseStat(); + + // if exp then block {elseif exp then block} [else block] end + AstStat* parseIf(); + + // while exp do block end + AstStat* parseWhile(); + + // repeat block until exp + AstStat* parseRepeat(); + + // do block end + AstStat* parseDo(); + + // break + AstStat* parseBreak(); + + // continue + AstStat* parseContinue(const Location& start); + + // for Name `=' exp `,' exp [`,' exp] do block end | + // for namelist in explist do block end | + AstStat* parseFor(); + + // function funcname funcbody | + // funcname ::= Name {`.' Name} [`:' Name] + AstStat* parseFunctionStat(); + + // local function Name funcbody | + // local namelist [`=' explist] + AstStat* parseLocal(); + + // return [explist] + AstStat* parseReturn(); + + // type Name `=' typeannotation + AstStat* parseTypeAlias(const Location& start, bool exported); + + AstDeclaredClassProp parseDeclaredClassMethod(); + + // `declare global' Name: typeannotation | + // `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation] + AstStat* parseDeclaration(const Location& start); + + // varlist `=' explist + AstStat* parseAssignment(AstExpr* initial); + + // var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp + AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op); + + // funcbody ::= `(' [parlist] `)' block end + // parlist ::= namelist [`,' `...'] | `...' + std::pair parseFunctionBody( + bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional localName); + + // explist ::= {exp `,'} exp + void parseExprList(TempVector& result); + + // binding ::= Name [`:` TypeAnnotation] + Binding parseBinding(); + + // bindinglist ::= (binding | `...') {`,' bindinglist} + // Returns the location of the vararg ..., or std::nullopt if the function is not vararg. + std::pair, AstTypePack*> parseBindingList(TempVector& result, bool allowDot3 = false); + + AstType* parseOptionalTypeAnnotation(); + + // TypeList ::= TypeAnnotation [`,' TypeList] + // ReturnType ::= TypeAnnotation | `(' TypeList `)' + // TableProp ::= Name `:' TypeAnnotation + // TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation + // PropList ::= (TableProp | TableIndexer) [`,' PropList] + // TypeAnnotation + // ::= Name + // | `nil` + // | `{' [PropList] `}' + // | `(' [TypeList] `)' `->` ReturnType + + // Returns the variadic annotation, if it exists. + AstTypePack* parseTypeList(TempVector& result, TempVector>& resultNames); + + std::optional parseOptionalReturnTypeAnnotation(); + std::pair parseReturnTypeAnnotation(); + + AstTableIndexer* parseTableIndexerAnnotation(); + + AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack); + AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray generics, AstArray genericPacks, + AstArray& params, AstArray>& paramNames, AstTypePack* varargAnnotation); + + AstType* parseTableTypeAnnotation(); + AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack); + + AstTypeOrPack parseTypeOrPackAnnotation(); + AstType* parseTypeAnnotation(TempVector& parts, const Location& begin); + AstType* parseTypeAnnotation(); + + AstTypePack* parseTypePackAnnotation(); + AstTypePack* parseVariadicArgumentAnnotation(); + + static std::optional parseUnaryOp(const Lexeme& l); + static std::optional parseBinaryOp(const Lexeme& l); + static std::optional parseCompoundOp(const Lexeme& l); + + struct BinaryOpPriority + { + unsigned char left, right; + }; + + std::optional checkUnaryConfusables(); + std::optional checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit); + + // subexpr -> (asexp | unop subexpr) { binop subexpr } + // where `binop' is any binary operator with a priority higher than `limit' + AstExpr* parseExpr(unsigned int limit = 0); + + // NAME + AstExpr* parseNameExpr(const char* context = nullptr); + + // prefixexp -> NAME | '(' expr ')' + AstExpr* parsePrefixExpr(); + + // primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } + AstExpr* parsePrimaryExpr(bool asStatement); + + // asexp -> simpleexp [`::' typeAnnotation] + AstExpr* parseAssertionExpr(); + + // simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp + AstExpr* parseSimpleExpr(); + + // args ::= `(' [explist] `)' | tableconstructor | String + AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation); + + // tableconstructor ::= `{' [fieldlist] `}' + // fieldlist ::= field {fieldsep field} [fieldsep] + // field ::= `[' exp `]' `=' exp | Name `=' exp | exp + // fieldsep ::= `,' | `;' + AstExpr* parseTableConstructor(); + + // TODO: Add grammar rules here? + AstExpr* parseIfElseExpr(); + + // stringinterp ::= exp { exp} + AstExpr* parseInterpString(); + + // Name + std::optional parseNameOpt(const char* context = nullptr); + Name parseName(const char* context = nullptr); + Name parseIndexName(const char* context, const Position& previous); + + // `<' namelist `>' + std::pair, AstArray> parseGenericTypeList(bool withDefaultValues); + + // `<' typeAnnotation[, ...] `>' + AstArray parseTypeParams(); + + std::optional> parseCharArray(); + AstExpr* parseString(); + + AstLocal* pushLocal(const Binding& binding); + + unsigned int saveLocals(); + + void restoreLocals(unsigned int offset); + + // check that parser is at lexeme/symbol, move to next lexeme/symbol on success, report failure and continue on failure + bool expectAndConsume(char value, const char* context = nullptr); + bool expectAndConsume(Lexeme::Type type, const char* context = nullptr); + void expectAndConsumeFail(Lexeme::Type type, const char* context); + + bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false); + void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr); + + bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin); + void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin); + + template + AstArray copy(const T* data, std::size_t size); + + template + AstArray copy(const TempVector& data); + + template + AstArray copy(std::initializer_list data); + + AstArray copy(const std::string& data); + + void incrementRecursionCounter(const char* context); + + void report(const Location& location, const char* format, va_list args); + void report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4); + + void reportNameError(const char* context); + + AstStatError* reportStatError(const Location& location, const AstArray& expressions, const AstArray& statements, + const char* format, ...) LUAU_PRINTF_ATTR(5, 6); + AstExprError* reportExprError(const Location& location, const AstArray& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5); + AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray& types, bool isMissing, const char* format, ...) + LUAU_PRINTF_ATTR(5, 6); + + void nextLexeme(); + + struct Function + { + bool vararg; + unsigned int loopDepth; + + Function() + : vararg(false) + , loopDepth(0) + { + } + }; + + struct Local + { + AstLocal* local; + unsigned int offset; + + Local() + : local(nullptr) + , offset(0) + { + } + }; + + struct Name + { + AstName name; + Location location; + + Name(const AstName& name, const Location& location) + : name(name) + , location(location) + { + } + }; + + struct Binding + { + Name name; + AstType* annotation; + + explicit Binding(const Name& name, AstType* annotation = nullptr) + : name(name) + , annotation(annotation) + { + } + }; + + ParseOptions options; + + Lexer lexer; + Allocator& allocator; + + std::vector commentLocations; + std::vector hotcomments; + + bool hotcommentHeader = true; + + unsigned int recursionCounter; + + AstName nameSelf; + AstName nameNumber; + AstName nameError; + AstName nameNil; + + Lexeme endMismatchSuspect; + + std::vector functionStack; + + DenseHashMap localMap; + std::vector localStack; + + std::vector parseErrors; + + std::vector matchRecoveryStopOnToken; + + std::vector scratchStat; + std::vector> scratchString; + std::vector scratchExpr; + std::vector scratchExprAux; + std::vector scratchName; + std::vector scratchPackName; + std::vector scratchBinding; + std::vector scratchLocal; + std::vector scratchTableTypeProps; + std::vector scratchAnnotation; + std::vector scratchTypeOrPackAnnotation; + std::vector scratchDeclaredClassProps; + std::vector scratchItem; + std::vector scratchArgName; + std::vector scratchGenericTypes; + std::vector scratchGenericTypePacks; + std::vector> scratchOptArgName; + std::string scratchData; +}; + +} // namespace Luau