mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Avoid extra allocations
This commit is contained in:
parent
dadbd4cd47
commit
2a41dca9d4
3 changed files with 3443 additions and 3442 deletions
|
@ -1,386 +1,386 @@
|
||||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Luau/Ast.h"
|
#include "Luau/Ast.h"
|
||||||
#include "Luau/Lexer.h"
|
#include "Luau/Lexer.h"
|
||||||
#include "Luau/ParseOptions.h"
|
#include "Luau/ParseOptions.h"
|
||||||
#include "Luau/ParseResult.h"
|
#include "Luau/ParseResult.h"
|
||||||
#include "Luau/StringUtils.h"
|
#include "Luau/StringUtils.h"
|
||||||
#include "Luau/DenseHash.h"
|
#include "Luau/DenseHash.h"
|
||||||
#include "Luau/Common.h"
|
#include "Luau/Common.h"
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class TempVector
|
class TempVector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TempVector(std::vector<T>& storage);
|
explicit TempVector(std::vector<T>& storage);
|
||||||
|
|
||||||
~TempVector();
|
~TempVector();
|
||||||
|
|
||||||
const T& operator[](std::size_t index) const;
|
const T& operator[](std::size_t index) const;
|
||||||
|
|
||||||
const T& front() const;
|
const T& front() const;
|
||||||
|
|
||||||
const T& back() const;
|
const T& back() const;
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
|
||||||
void push_back(const T& item);
|
void push_back(const T& item);
|
||||||
|
|
||||||
typename std::vector<T>::const_iterator begin() const
|
typename std::vector<T>::const_iterator begin() const
|
||||||
{
|
{
|
||||||
return storage.begin() + offset;
|
return storage.begin() + offset;
|
||||||
}
|
}
|
||||||
typename std::vector<T>::const_iterator end() const
|
typename std::vector<T>::const_iterator end() const
|
||||||
{
|
{
|
||||||
return storage.begin() + offset + size_;
|
return storage.begin() + offset + size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<T>& storage;
|
std::vector<T>& storage;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t size_;
|
size_t size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static ParseResult parse(
|
static ParseResult parse(
|
||||||
const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions());
|
const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options = ParseOptions());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Name;
|
struct Name;
|
||||||
struct Binding;
|
struct Binding;
|
||||||
|
|
||||||
Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options);
|
Parser(const char* buffer, std::size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options);
|
||||||
|
|
||||||
bool blockFollow(const Lexeme& l);
|
bool blockFollow(const Lexeme& l);
|
||||||
|
|
||||||
AstStatBlock* parseChunk();
|
AstStatBlock* parseChunk();
|
||||||
|
|
||||||
// chunk ::= {stat [`;']} [laststat [`;']]
|
// chunk ::= {stat [`;']} [laststat [`;']]
|
||||||
// block ::= chunk
|
// block ::= chunk
|
||||||
AstStatBlock* parseBlock();
|
AstStatBlock* parseBlock();
|
||||||
|
|
||||||
AstStatBlock* parseBlockNoScope();
|
AstStatBlock* parseBlockNoScope();
|
||||||
|
|
||||||
// stat ::=
|
// stat ::=
|
||||||
// varlist `=' explist |
|
// varlist `=' explist |
|
||||||
// functioncall |
|
// functioncall |
|
||||||
// do block end |
|
// do block end |
|
||||||
// while exp do block end |
|
// while exp do block end |
|
||||||
// repeat block until exp |
|
// repeat block until exp |
|
||||||
// if exp then block {elseif exp then block} [else block] end |
|
// if exp then block {elseif exp then block} [else block] end |
|
||||||
// for Name `=' exp `,' exp [`,' exp] do block end |
|
// for Name `=' exp `,' exp [`,' exp] do block end |
|
||||||
// for namelist in explist do block end |
|
// for namelist in explist do block end |
|
||||||
// function funcname funcbody |
|
// function funcname funcbody |
|
||||||
// local function Name funcbody |
|
// local function Name funcbody |
|
||||||
// local namelist [`=' explist]
|
// local namelist [`=' explist]
|
||||||
// laststat ::= return [explist] | break
|
// laststat ::= return [explist] | break
|
||||||
AstStat* parseStat();
|
AstStat* parseStat();
|
||||||
|
|
||||||
// if exp then block {elseif exp then block} [else block] end
|
// if exp then block {elseif exp then block} [else block] end
|
||||||
AstStat* parseIf();
|
AstStat* parseIf();
|
||||||
|
|
||||||
// while exp do block end
|
// while exp do block end
|
||||||
AstStat* parseWhile();
|
AstStat* parseWhile();
|
||||||
|
|
||||||
// repeat block until exp
|
// repeat block until exp
|
||||||
AstStat* parseRepeat();
|
AstStat* parseRepeat();
|
||||||
|
|
||||||
// do block end
|
// do block end
|
||||||
AstStat* parseDo();
|
AstStat* parseDo();
|
||||||
|
|
||||||
// break
|
// break
|
||||||
AstStat* parseBreak();
|
AstStat* parseBreak();
|
||||||
|
|
||||||
// continue
|
// continue
|
||||||
AstStat* parseContinue(const Location& start);
|
AstStat* parseContinue(const Location& start);
|
||||||
|
|
||||||
// for Name `=' exp `,' exp [`,' exp] do block end |
|
// for Name `=' exp `,' exp [`,' exp] do block end |
|
||||||
// for namelist in explist do block end |
|
// for namelist in explist do block end |
|
||||||
AstStat* parseFor();
|
AstStat* parseFor();
|
||||||
|
|
||||||
// function funcname funcbody |
|
// function funcname funcbody |
|
||||||
// funcname ::= Name {`.' Name} [`:' Name]
|
// funcname ::= Name {`.' Name} [`:' Name]
|
||||||
AstStat* parseFunctionStat();
|
AstStat* parseFunctionStat();
|
||||||
|
|
||||||
// local function Name funcbody |
|
// local function Name funcbody |
|
||||||
// local namelist [`=' explist]
|
// local namelist [`=' explist]
|
||||||
AstStat* parseLocal();
|
AstStat* parseLocal();
|
||||||
|
|
||||||
// return [explist]
|
// return [explist]
|
||||||
AstStat* parseReturn();
|
AstStat* parseReturn();
|
||||||
|
|
||||||
// type Name `=' typeannotation
|
// type Name `=' typeannotation
|
||||||
AstStat* parseTypeAlias(const Location& start, bool exported);
|
AstStat* parseTypeAlias(const Location& start, bool exported);
|
||||||
|
|
||||||
AstDeclaredClassProp parseDeclaredClassMethod();
|
AstDeclaredClassProp parseDeclaredClassMethod();
|
||||||
|
|
||||||
// `declare global' Name: typeannotation |
|
// `declare global' Name: typeannotation |
|
||||||
// `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation]
|
// `declare function' Name`(' [parlist] `)' [`:` TypeAnnotation]
|
||||||
AstStat* parseDeclaration(const Location& start);
|
AstStat* parseDeclaration(const Location& start);
|
||||||
|
|
||||||
// varlist `=' explist
|
// varlist `=' explist
|
||||||
AstStat* parseAssignment(AstExpr* initial);
|
AstStat* parseAssignment(AstExpr* initial);
|
||||||
|
|
||||||
// var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp
|
// var [`+=' | `-=' | `*=' | `/=' | `%=' | `^=' | `..='] exp
|
||||||
AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op);
|
AstStat* parseCompoundAssignment(AstExpr* initial, AstExprBinary::Op op);
|
||||||
|
|
||||||
// funcbody ::= `(' [parlist] `)' block end
|
// funcbody ::= `(' [parlist] `)' block end
|
||||||
// parlist ::= namelist [`,' `...'] | `...'
|
// parlist ::= namelist [`,' `...'] | `...'
|
||||||
std::pair<AstExprFunction*, AstLocal*> parseFunctionBody(
|
std::pair<AstExprFunction*, AstLocal*> parseFunctionBody(
|
||||||
bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional<Name> localName);
|
bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional<Name> localName);
|
||||||
|
|
||||||
// explist ::= {exp `,'} exp
|
// explist ::= {exp `,'} exp
|
||||||
void parseExprList(TempVector<AstExpr*>& result);
|
void parseExprList(TempVector<AstExpr*>& result);
|
||||||
|
|
||||||
// binding ::= Name [`:` TypeAnnotation]
|
// binding ::= Name [`:` TypeAnnotation]
|
||||||
Binding parseBinding();
|
Binding parseBinding();
|
||||||
|
|
||||||
// bindinglist ::= (binding | `...') {`,' bindinglist}
|
// bindinglist ::= (binding | `...') {`,' bindinglist}
|
||||||
// Returns the location of the vararg ..., or std::nullopt if the function is not vararg.
|
// Returns the location of the vararg ..., or std::nullopt if the function is not vararg.
|
||||||
std::pair<std::optional<Location>, AstTypePack*> parseBindingList(TempVector<Binding>& result, bool allowDot3 = false);
|
std::pair<std::optional<Location>, AstTypePack*> parseBindingList(TempVector<Binding>& result, bool allowDot3 = false);
|
||||||
|
|
||||||
AstType* parseOptionalTypeAnnotation();
|
AstType* parseOptionalTypeAnnotation();
|
||||||
|
|
||||||
// TypeList ::= TypeAnnotation [`,' TypeList]
|
// TypeList ::= TypeAnnotation [`,' TypeList]
|
||||||
// ReturnType ::= TypeAnnotation | `(' TypeList `)'
|
// ReturnType ::= TypeAnnotation | `(' TypeList `)'
|
||||||
// TableProp ::= Name `:' TypeAnnotation
|
// TableProp ::= Name `:' TypeAnnotation
|
||||||
// TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation
|
// TableIndexer ::= `[' TypeAnnotation `]' `:' TypeAnnotation
|
||||||
// PropList ::= (TableProp | TableIndexer) [`,' PropList]
|
// PropList ::= (TableProp | TableIndexer) [`,' PropList]
|
||||||
// TypeAnnotation
|
// TypeAnnotation
|
||||||
// ::= Name
|
// ::= Name
|
||||||
// | `nil`
|
// | `nil`
|
||||||
// | `{' [PropList] `}'
|
// | `{' [PropList] `}'
|
||||||
// | `(' [TypeList] `)' `->` ReturnType
|
// | `(' [TypeList] `)' `->` ReturnType
|
||||||
|
|
||||||
// Returns the variadic annotation, if it exists.
|
// Returns the variadic annotation, if it exists.
|
||||||
AstTypePack* parseTypeList(TempVector<AstType*>& result, TempVector<std::optional<AstArgumentName>>& resultNames);
|
AstTypePack* parseTypeList(TempVector<AstType*>& result, TempVector<std::optional<AstArgumentName>>& resultNames);
|
||||||
|
|
||||||
std::optional<AstTypeList> parseOptionalReturnTypeAnnotation();
|
std::optional<AstTypeList> parseOptionalReturnTypeAnnotation();
|
||||||
std::pair<Location, AstTypeList> parseReturnTypeAnnotation();
|
std::pair<Location, AstTypeList> parseReturnTypeAnnotation();
|
||||||
|
|
||||||
AstTableIndexer* parseTableIndexerAnnotation();
|
AstTableIndexer* parseTableIndexerAnnotation();
|
||||||
|
|
||||||
AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack);
|
AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack);
|
||||||
AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks,
|
AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks,
|
||||||
AstArray<AstType*>& params, AstArray<std::optional<AstArgumentName>>& paramNames, AstTypePack* varargAnnotation);
|
AstArray<AstType*>& params, AstArray<std::optional<AstArgumentName>>& paramNames, AstTypePack* varargAnnotation);
|
||||||
|
|
||||||
AstType* parseTableTypeAnnotation();
|
AstType* parseTableTypeAnnotation();
|
||||||
AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack);
|
AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack);
|
||||||
|
|
||||||
AstTypeOrPack parseTypeOrPackAnnotation();
|
AstTypeOrPack parseTypeOrPackAnnotation();
|
||||||
AstType* parseTypeAnnotation(TempVector<AstType*>& parts, const Location& begin);
|
AstType* parseTypeAnnotation(TempVector<AstType*>& parts, const Location& begin);
|
||||||
AstType* parseTypeAnnotation();
|
AstType* parseTypeAnnotation();
|
||||||
|
|
||||||
AstTypePack* parseTypePackAnnotation();
|
AstTypePack* parseTypePackAnnotation();
|
||||||
AstTypePack* parseVariadicArgumentAnnotation();
|
AstTypePack* parseVariadicArgumentAnnotation();
|
||||||
|
|
||||||
static std::optional<AstExprUnary::Op> parseUnaryOp(const Lexeme& l);
|
static std::optional<AstExprUnary::Op> parseUnaryOp(const Lexeme& l);
|
||||||
static std::optional<AstExprBinary::Op> parseBinaryOp(const Lexeme& l);
|
static std::optional<AstExprBinary::Op> parseBinaryOp(const Lexeme& l);
|
||||||
static std::optional<AstExprBinary::Op> parseCompoundOp(const Lexeme& l);
|
static std::optional<AstExprBinary::Op> parseCompoundOp(const Lexeme& l);
|
||||||
|
|
||||||
struct BinaryOpPriority
|
struct BinaryOpPriority
|
||||||
{
|
{
|
||||||
unsigned char left, right;
|
unsigned char left, right;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<AstExprUnary::Op> checkUnaryConfusables();
|
std::optional<AstExprUnary::Op> checkUnaryConfusables();
|
||||||
std::optional<AstExprBinary::Op> checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit);
|
std::optional<AstExprBinary::Op> checkBinaryConfusables(const BinaryOpPriority binaryPriority[], unsigned int limit);
|
||||||
|
|
||||||
// subexpr -> (asexp | unop subexpr) { binop subexpr }
|
// subexpr -> (asexp | unop subexpr) { binop subexpr }
|
||||||
// where `binop' is any binary operator with a priority higher than `limit'
|
// where `binop' is any binary operator with a priority higher than `limit'
|
||||||
AstExpr* parseExpr(unsigned int limit = 0);
|
AstExpr* parseExpr(unsigned int limit = 0);
|
||||||
|
|
||||||
// NAME
|
// NAME
|
||||||
AstExpr* parseNameExpr(const char* context = nullptr);
|
AstExpr* parseNameExpr(const char* context = nullptr);
|
||||||
|
|
||||||
// prefixexp -> NAME | '(' expr ')'
|
// prefixexp -> NAME | '(' expr ')'
|
||||||
AstExpr* parsePrefixExpr();
|
AstExpr* parsePrefixExpr();
|
||||||
|
|
||||||
// primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs }
|
// primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs }
|
||||||
AstExpr* parsePrimaryExpr(bool asStatement);
|
AstExpr* parsePrimaryExpr(bool asStatement);
|
||||||
|
|
||||||
// asexp -> simpleexp [`::' typeAnnotation]
|
// asexp -> simpleexp [`::' typeAnnotation]
|
||||||
AstExpr* parseAssertionExpr();
|
AstExpr* parseAssertionExpr();
|
||||||
|
|
||||||
// simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp
|
// simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor | FUNCTION body | primaryexp
|
||||||
AstExpr* parseSimpleExpr();
|
AstExpr* parseSimpleExpr();
|
||||||
|
|
||||||
// args ::= `(' [explist] `)' | tableconstructor | String
|
// args ::= `(' [explist] `)' | tableconstructor | String
|
||||||
AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation);
|
AstExpr* parseFunctionArgs(AstExpr* func, bool self, const Location& selfLocation);
|
||||||
|
|
||||||
// tableconstructor ::= `{' [fieldlist] `}'
|
// tableconstructor ::= `{' [fieldlist] `}'
|
||||||
// fieldlist ::= field {fieldsep field} [fieldsep]
|
// fieldlist ::= field {fieldsep field} [fieldsep]
|
||||||
// field ::= `[' exp `]' `=' exp | Name `=' exp | exp
|
// field ::= `[' exp `]' `=' exp | Name `=' exp | exp
|
||||||
// fieldsep ::= `,' | `;'
|
// fieldsep ::= `,' | `;'
|
||||||
AstExpr* parseTableConstructor();
|
AstExpr* parseTableConstructor();
|
||||||
|
|
||||||
// TODO: Add grammar rules here?
|
// TODO: Add grammar rules here?
|
||||||
AstExpr* parseIfElseExpr();
|
AstExpr* parseIfElseExpr();
|
||||||
|
|
||||||
// stringinterp ::= <INTERP_BEGIN> exp {<INTERP_MID> exp} <INTERP_END>
|
// stringinterp ::= <INTERP_BEGIN> exp {<INTERP_MID> exp} <INTERP_END>
|
||||||
AstExpr* parseInterpString();
|
AstExpr* parseInterpString();
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
std::optional<Name> parseNameOpt(const char* context = nullptr);
|
std::optional<Name> parseNameOpt(const char* context = nullptr);
|
||||||
Name parseName(const char* context = nullptr);
|
Name parseName(const char* context = nullptr);
|
||||||
Name parseIndexName(const char* context, const Position& previous);
|
Name parseIndexName(const char* context, const Position& previous);
|
||||||
|
|
||||||
// `<' namelist `>'
|
// `<' namelist `>'
|
||||||
std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> parseGenericTypeList(bool withDefaultValues);
|
std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> parseGenericTypeList(bool withDefaultValues);
|
||||||
|
|
||||||
// `<' typeAnnotation[, ...] `>'
|
// `<' typeAnnotation[, ...] `>'
|
||||||
AstArray<AstTypeOrPack> parseTypeParams();
|
AstArray<AstTypeOrPack> parseTypeParams();
|
||||||
|
|
||||||
std::optional<AstArray<char>> parseCharArray();
|
std::optional<AstArray<char>> parseCharArray();
|
||||||
AstExpr* parseString();
|
AstExpr* parseString();
|
||||||
|
|
||||||
AstLocal* pushLocal(const Binding& binding);
|
AstLocal* pushLocal(const Binding& binding);
|
||||||
|
|
||||||
unsigned int saveLocals();
|
unsigned int saveLocals();
|
||||||
|
|
||||||
void restoreLocals(unsigned int offset);
|
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
|
// 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(char value, const char* context = nullptr);
|
||||||
bool expectAndConsume(Lexeme::Type type, const char* context = nullptr);
|
bool expectAndConsume(Lexeme::Type type, const char* context = nullptr);
|
||||||
void expectAndConsumeFail(Lexeme::Type type, const char* context);
|
void expectAndConsumeFail(Lexeme::Type type, const char* context);
|
||||||
|
|
||||||
bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false);
|
bool expectMatchAndConsume(char value, const Lexeme& begin, bool searchForMissing = false);
|
||||||
void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr);
|
void expectMatchAndConsumeFail(Lexeme::Type type, const Lexeme& begin, const char* extra = nullptr);
|
||||||
|
|
||||||
bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin);
|
bool expectMatchEndAndConsume(Lexeme::Type type, const Lexeme& begin);
|
||||||
void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin);
|
void expectMatchEndAndConsumeFail(Lexeme::Type type, const Lexeme& begin);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
AstArray<T> copy(const T* data, std::size_t size);
|
AstArray<T> copy(const T* data, std::size_t size);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
AstArray<T> copy(const TempVector<T>& data);
|
AstArray<T> copy(const TempVector<T>& data);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
AstArray<T> copy(std::initializer_list<T> data);
|
AstArray<T> copy(std::initializer_list<T> data);
|
||||||
|
|
||||||
AstArray<char> copy(const std::string& data);
|
AstArray<char> copy(const std::string& data);
|
||||||
|
|
||||||
void incrementRecursionCounter(const char* context);
|
void incrementRecursionCounter(const char* context);
|
||||||
|
|
||||||
void report(const Location& location, const char* format, va_list args);
|
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 report(const Location& location, const char* format, ...) LUAU_PRINTF_ATTR(3, 4);
|
||||||
|
|
||||||
void reportNameError(const char* context);
|
void reportNameError(const char* context);
|
||||||
|
|
||||||
AstStatError* reportStatError(const Location& location, const AstArray<AstExpr*>& expressions, const AstArray<AstStat*>& statements,
|
AstStatError* reportStatError(const Location& location, const AstArray<AstExpr*>& expressions, const AstArray<AstStat*>& statements,
|
||||||
const char* format, ...) LUAU_PRINTF_ATTR(5, 6);
|
const char* format, ...) LUAU_PRINTF_ATTR(5, 6);
|
||||||
AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5);
|
AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) LUAU_PRINTF_ATTR(4, 5);
|
||||||
AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
|
AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
|
||||||
LUAU_PRINTF_ATTR(5, 6);
|
LUAU_PRINTF_ATTR(5, 6);
|
||||||
|
|
||||||
void nextLexeme();
|
void nextLexeme();
|
||||||
|
|
||||||
struct Function
|
struct Function
|
||||||
{
|
{
|
||||||
bool vararg;
|
bool vararg;
|
||||||
unsigned int loopDepth;
|
unsigned int loopDepth;
|
||||||
|
|
||||||
Function()
|
Function()
|
||||||
: vararg(false)
|
: vararg(false)
|
||||||
, loopDepth(0)
|
, loopDepth(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Local
|
struct Local
|
||||||
{
|
{
|
||||||
AstLocal* local;
|
AstLocal* local;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
|
||||||
Local()
|
Local()
|
||||||
: local(nullptr)
|
: local(nullptr)
|
||||||
, offset(0)
|
, offset(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Name
|
struct Name
|
||||||
{
|
{
|
||||||
AstName name;
|
AstName name;
|
||||||
Location location;
|
Location location;
|
||||||
|
|
||||||
Name(const AstName& name, const Location& location)
|
Name(const AstName& name, const Location& location)
|
||||||
: name(name)
|
: name(name)
|
||||||
, location(location)
|
, location(location)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Binding
|
struct Binding
|
||||||
{
|
{
|
||||||
Name name;
|
Name name;
|
||||||
AstType* annotation;
|
AstType* annotation;
|
||||||
|
|
||||||
explicit Binding(const Name& name, AstType* annotation = nullptr)
|
explicit Binding(const Name& name, AstType* annotation = nullptr)
|
||||||
: name(name)
|
: name(name)
|
||||||
, annotation(annotation)
|
, annotation(annotation)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ParseOptions options;
|
ParseOptions options;
|
||||||
|
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
Allocator& allocator;
|
Allocator& allocator;
|
||||||
|
|
||||||
std::vector<Comment> commentLocations;
|
std::vector<Comment> commentLocations;
|
||||||
std::vector<HotComment> hotcomments;
|
std::vector<HotComment> hotcomments;
|
||||||
|
|
||||||
bool hotcommentHeader = true;
|
bool hotcommentHeader = true;
|
||||||
|
|
||||||
unsigned int recursionCounter;
|
unsigned int recursionCounter;
|
||||||
|
|
||||||
AstName nameSelf;
|
AstName nameSelf;
|
||||||
AstName nameNumber;
|
AstName nameNumber;
|
||||||
AstName nameError;
|
AstName nameError;
|
||||||
AstName nameNil;
|
AstName nameNil;
|
||||||
|
|
||||||
Lexeme endMismatchSuspect;
|
Lexeme endMismatchSuspect;
|
||||||
|
|
||||||
std::vector<Function> functionStack;
|
std::vector<Function> functionStack;
|
||||||
|
|
||||||
DenseHashMap<AstName, AstLocal*> localMap;
|
DenseHashMap<AstName, AstLocal*> localMap;
|
||||||
std::vector<AstLocal*> localStack;
|
std::vector<AstLocal*> localStack;
|
||||||
|
|
||||||
std::vector<ParseError> parseErrors;
|
std::vector<ParseError> parseErrors;
|
||||||
|
|
||||||
std::vector<unsigned int> matchRecoveryStopOnToken;
|
std::vector<unsigned int> matchRecoveryStopOnToken;
|
||||||
|
|
||||||
std::vector<AstStat*> scratchStat;
|
std::vector<AstStat*> scratchStat;
|
||||||
std::vector<AstExpr*> scratchExpr;
|
std::vector<AstExpr*> scratchExpr;
|
||||||
std::vector<AstExpr*> scratchExprAux;
|
std::vector<AstExpr*> scratchExprAux;
|
||||||
std::vector<AstName> scratchName;
|
std::vector<AstName> scratchName;
|
||||||
std::vector<AstName> scratchPackName;
|
std::vector<AstName> scratchPackName;
|
||||||
std::vector<Binding> scratchBinding;
|
std::vector<Binding> scratchBinding;
|
||||||
std::vector<AstLocal*> scratchLocal;
|
std::vector<AstLocal*> scratchLocal;
|
||||||
std::vector<AstTableProp> scratchTableTypeProps;
|
std::vector<AstTableProp> scratchTableTypeProps;
|
||||||
std::vector<AstType*> scratchAnnotation;
|
std::vector<AstType*> scratchAnnotation;
|
||||||
std::vector<AstTypeOrPack> scratchTypeOrPackAnnotation;
|
std::vector<AstTypeOrPack> scratchTypeOrPackAnnotation;
|
||||||
std::vector<AstDeclaredClassProp> scratchDeclaredClassProps;
|
std::vector<AstDeclaredClassProp> scratchDeclaredClassProps;
|
||||||
std::vector<AstExprTable::Item> scratchItem;
|
std::vector<AstExprTable::Item> scratchItem;
|
||||||
std::vector<AstArgumentName> scratchArgName;
|
std::vector<AstArgumentName> scratchArgName;
|
||||||
std::vector<AstGenericType> scratchGenericTypes;
|
std::vector<AstGenericType> scratchGenericTypes;
|
||||||
std::vector<AstGenericTypePack> scratchGenericTypePacks;
|
std::vector<AstGenericTypePack> scratchGenericTypePacks;
|
||||||
std::vector<std::optional<AstArgumentName>> scratchOptArgName;
|
std::vector<std::optional<AstArgumentName>> scratchOptArgName;
|
||||||
std::string scratchData;
|
std::string scratchData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Luau
|
} // namespace Luau
|
||||||
|
|
6096
Ast/src/Parser.cpp
6096
Ast/src/Parser.cpp
File diff suppressed because it is too large
Load diff
|
@ -1488,18 +1488,19 @@ struct Compiler
|
||||||
|
|
||||||
for (AstArray<char> const& string : expr->strings)
|
for (AstArray<char> const& string : expr->strings)
|
||||||
{
|
{
|
||||||
std::string stringEscaped(string.data);
|
if (memchr(string.data, '%', string.size))
|
||||||
|
|
||||||
for (size_t characterIndex = 0; characterIndex < stringEscaped.size(); ++characterIndex)
|
|
||||||
{
|
{
|
||||||
if (stringEscaped[characterIndex] == '%')
|
for (size_t characterIndex = 0; characterIndex < string.size; ++characterIndex)
|
||||||
{
|
{
|
||||||
stringEscaped.insert(characterIndex, 1, '%');
|
char character = string.data[characterIndex];
|
||||||
characterIndex++;
|
formatString.push_back(character);
|
||||||
|
|
||||||
|
if (character == '%')
|
||||||
|
formatString.push_back('%');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
formatString += stringEscaped;
|
formatString += std::string(string.data, string.size);
|
||||||
|
|
||||||
stringsLeft--;
|
stringsLeft--;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue