Add files via upload

This commit is contained in:
Babyhamsta 2022-07-30 22:29:41 -05:00 committed by GitHub
parent 752d09c8da
commit 36ba1dd9ac
Signed by: DevComp
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 3230 additions and 315 deletions

1268
Ast/include/lluz/Ast.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include <stdint.h>
namespace lluz
{
const char* findConfusable(uint32_t codepoint);
}

View file

@ -0,0 +1,524 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "lluz/Common.h"
#include <functional>
#include <utility>
#include <vector>
#include <type_traits>
#include <stdint.h>
namespace lluz
{
struct DenseHashPointer
{
size_t operator()(const void* key) const
{
return (uintptr_t(key) >> 4) ^ (uintptr_t(key) >> 9);
}
};
// Internal implementation of DenseHashSet and DenseHashMap
namespace detail
{
template<typename T>
using DenseHashDefault = std::conditional_t<std::is_pointer_v<T>, DenseHashPointer, std::hash<T>>;
template<typename Key, typename Item, typename MutableItem, typename ItemInterface, typename Hash, typename Eq>
class DenseHashTable
{
public:
class const_iterator;
class iterator;
DenseHashTable(const Key& empty_key, size_t buckets = 0)
: count(0)
, empty_key(empty_key)
{
// buckets has to be power-of-two or zero
lluz_ASSERT((buckets & (buckets - 1)) == 0);
// don't move this to initializer list! this works around an MSVC codegen issue on AMD CPUs:
// https://developercommunity.visualstudio.com/t/stdvector-constructor-from-size-t-is-25-times-slow/1546547
if (buckets)
resize_data<Item>(buckets);
}
void clear()
{
data.clear();
count = 0;
}
Item* insert_unsafe(const Key& key)
{
// It is invalid to insert empty_key into the table since it acts as a "entry does not exist" marker
lluz_ASSERT(!eq(key, empty_key));
size_t hashmod = data.size() - 1;
size_t bucket = hasher(key) & hashmod;
for (size_t probe = 0; probe <= hashmod; ++probe)
{
Item& probe_item = data[bucket];
// Element does not exist, insert here
if (eq(ItemInterface::getKey(probe_item), empty_key))
{
ItemInterface::setKey(probe_item, key);
count++;
return &probe_item;
}
// Element already exists
if (eq(ItemInterface::getKey(probe_item), key))
{
return &probe_item;
}
// Hash collision, quadratic probing
bucket = (bucket + probe + 1) & hashmod;
}
// Hash table is full - this should not happen
lluz_ASSERT(false);
return NULL;
}
const Item* find(const Key& key) const
{
if (data.empty())
return 0;
if (eq(key, empty_key))
return 0;
size_t hashmod = data.size() - 1;
size_t bucket = hasher(key) & hashmod;
for (size_t probe = 0; probe <= hashmod; ++probe)
{
const Item& probe_item = data[bucket];
// Element exists
if (eq(ItemInterface::getKey(probe_item), key))
return &probe_item;
// Element does not exist
if (eq(ItemInterface::getKey(probe_item), empty_key))
return NULL;
// Hash collision, quadratic probing
bucket = (bucket + probe + 1) & hashmod;
}
// Hash table is full - this should not happen
lluz_ASSERT(false);
return NULL;
}
void rehash()
{
size_t newsize = data.empty() ? 16 : data.size() * 2;
if (data.empty() && data.capacity() >= newsize)
{
lluz_ASSERT(count == 0);
resize_data<Item>(newsize);
return;
}
DenseHashTable newtable(empty_key, newsize);
for (size_t i = 0; i < data.size(); ++i)
{
const Key& key = ItemInterface::getKey(data[i]);
if (!eq(key, empty_key))
{
Item* item = newtable.insert_unsafe(key);
*item = std::move(data[i]);
}
}
lluz_ASSERT(count == newtable.count);
data.swap(newtable.data);
}
void rehash_if_full()
{
if (count >= data.size() * 3 / 4)
{
rehash();
}
}
const_iterator begin() const
{
size_t start = 0;
while (start < data.size() && eq(ItemInterface::getKey(data[start]), empty_key))
start++;
return const_iterator(this, start);
}
const_iterator end() const
{
return const_iterator(this, data.size());
}
iterator begin()
{
size_t start = 0;
while (start < data.size() && eq(ItemInterface::getKey(data[start]), empty_key))
start++;
return iterator(this, start);
}
iterator end()
{
return iterator(this, data.size());
}
size_t size() const
{
return count;
}
class const_iterator
{
public:
const_iterator()
: set(0)
, index(0)
{
}
const_iterator(const DenseHashTable<Key, Item, MutableItem, ItemInterface, Hash, Eq>* set, size_t index)
: set(set)
, index(index)
{
}
const Item& operator*() const
{
return set->data[index];
}
const Item* operator->() const
{
return &set->data[index];
}
bool operator==(const const_iterator& other) const
{
return set == other.set && index == other.index;
}
bool operator!=(const const_iterator& other) const
{
return set != other.set || index != other.index;
}
const_iterator& operator++()
{
size_t size = set->data.size();
do
{
index++;
} while (index < size && set->eq(ItemInterface::getKey(set->data[index]), set->empty_key));
return *this;
}
const_iterator operator++(int)
{
const_iterator res = *this;
++*this;
return res;
}
private:
const DenseHashTable<Key, Item, MutableItem, ItemInterface, Hash, Eq>* set;
size_t index;
};
class iterator
{
public:
iterator()
: set(0)
, index(0)
{
}
iterator(DenseHashTable<Key, Item, MutableItem, ItemInterface, Hash, Eq>* set, size_t index)
: set(set)
, index(index)
{
}
MutableItem& operator*() const
{
return *reinterpret_cast<MutableItem*>(&set->data[index]);
}
MutableItem* operator->() const
{
return reinterpret_cast<MutableItem*>(&set->data[index]);
}
bool operator==(const iterator& other) const
{
return set == other.set && index == other.index;
}
bool operator!=(const iterator& other) const
{
return set != other.set || index != other.index;
}
iterator& operator++()
{
size_t size = set->data.size();
do
{
index++;
} while (index < size && set->eq(ItemInterface::getKey(set->data[index]), set->empty_key));
return *this;
}
iterator operator++(int)
{
iterator res = *this;
++*this;
return res;
}
private:
DenseHashTable<Key, Item, MutableItem, ItemInterface, Hash, Eq>* set;
size_t index;
};
private:
template<typename T>
void resize_data(size_t count, typename std::enable_if_t<std::is_copy_assignable_v<T>>* dummy = nullptr)
{
data.resize(count, ItemInterface::create(empty_key));
}
template<typename T>
void resize_data(size_t count, typename std::enable_if_t<!std::is_copy_assignable_v<T>>* dummy = nullptr)
{
size_t size = data.size();
data.resize(count);
for (size_t i = size; i < count; i++)
data[i].first = empty_key;
}
std::vector<Item> data;
size_t count;
Key empty_key;
Hash hasher;
Eq eq;
};
template<typename Key>
struct ItemInterfaceSet
{
static const Key& getKey(const Key& item)
{
return item;
}
static void setKey(Key& item, const Key& key)
{
item = key;
}
static Key create(const Key& key)
{
return key;
}
};
template<typename Key, typename Value>
struct ItemInterfaceMap
{
static const Key& getKey(const std::pair<Key, Value>& item)
{
return item.first;
}
static void setKey(std::pair<Key, Value>& item, const Key& key)
{
item.first = key;
}
static std::pair<Key, Value> create(const Key& key)
{
return std::pair<Key, Value>(key, Value());
}
};
} // namespace detail
// This is a faster alternative of unordered_set, but it does not implement the same interface (i.e. it does not support erasing)
template<typename Key, typename Hash = detail::DenseHashDefault<Key>, typename Eq = std::equal_to<Key>>
class DenseHashSet
{
typedef detail::DenseHashTable<Key, Key, Key, detail::ItemInterfaceSet<Key>, Hash, Eq> Impl;
Impl impl;
public:
typedef typename Impl::const_iterator const_iterator;
typedef typename Impl::iterator iterator;
DenseHashSet(const Key& empty_key, size_t buckets = 0)
: impl(empty_key, buckets)
{
}
void clear()
{
impl.clear();
}
const Key& insert(const Key& key)
{
impl.rehash_if_full();
return *impl.insert_unsafe(key);
}
const Key* find(const Key& key) const
{
return impl.find(key);
}
bool contains(const Key& key) const
{
return impl.find(key) != 0;
}
size_t size() const
{
return impl.size();
}
bool empty() const
{
return impl.size() == 0;
}
const_iterator begin() const
{
return impl.begin();
}
const_iterator end() const
{
return impl.end();
}
iterator begin()
{
return impl.begin();
}
iterator end()
{
return impl.end();
}
};
// This is a faster alternative of unordered_map, but it does not implement the same interface (i.e. it does not support erasing and has
// contains() instead of find())
template<typename Key, typename Value, typename Hash = detail::DenseHashDefault<Key>, typename Eq = std::equal_to<Key>>
class DenseHashMap
{
typedef detail::DenseHashTable<Key, std::pair<Key, Value>, std::pair<const Key, Value>, detail::ItemInterfaceMap<Key, Value>, Hash, Eq> Impl;
Impl impl;
public:
typedef typename Impl::const_iterator const_iterator;
typedef typename Impl::iterator iterator;
DenseHashMap(const Key& empty_key, size_t buckets = 0)
: impl(empty_key, buckets)
{
}
void clear()
{
impl.clear();
}
// Note: this reference is invalidated by any insert operation (i.e. operator[])
Value& operator[](const Key& key)
{
impl.rehash_if_full();
return impl.insert_unsafe(key)->second;
}
// Note: this pointer is invalidated by any insert operation (i.e. operator[])
const Value* find(const Key& key) const
{
const std::pair<Key, Value>* result = impl.find(key);
return result ? &result->second : NULL;
}
// Note: this pointer is invalidated by any insert operation (i.e. operator[])
Value* find(const Key& key)
{
const std::pair<Key, Value>* result = impl.find(key);
return result ? const_cast<Value*>(&result->second) : NULL;
}
bool contains(const Key& key) const
{
return impl.find(key) != 0;
}
size_t size() const
{
return impl.size();
}
bool empty() const
{
return impl.size() == 0;
}
const_iterator begin() const
{
return impl.begin();
}
const_iterator end() const
{
return impl.end();
}
iterator begin()
{
return impl.begin();
}
iterator end()
{
return impl.end();
}
};
} // namespace lluz

241
Ast/include/lluz/Lexer.h Normal file
View file

@ -0,0 +1,241 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "lluz/Ast.h"
#include "lluz/Location.h"
#include "lluz/DenseHash.h"
#include "lluz/Common.h"
namespace lluz
{
class Allocator
{
public:
Allocator();
Allocator(Allocator&&);
Allocator& operator=(Allocator&&) = delete;
~Allocator();
void* allocate(size_t size);
template<typename T, typename... Args>
T* alloc(Args&&... args)
{
static_assert(std::is_trivially_destructible<T>::value, "Objects allocated with this allocator will never have their destructors run!");
T* t = static_cast<T*>(allocate(sizeof(T)));
new (t) T(std::forward<Args>(args)...);
return t;
}
private:
struct Page
{
Page* next;
char data[8192];
};
Page* root;
size_t offset;
};
struct Lexeme
{
enum Type
{
Eof = 0,
// 1..255 means actual character values
Char_END = 256,
Equal,
LessEqual,
GreaterEqual,
NotEqual,
Dot2,
Dot3,
SkinnyArrow,
DoubleColon,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
ModAssign,
PowAssign,
ConcatAssign,
RawString,
QuotedString,
Number,
Name,
Comment,
BlockComment,
BrokenString,
BrokenComment,
BrokenUnicode,
Error,
Reserved_BEGIN,
ReservedAnd = Reserved_BEGIN,
ReservedBreak,
ReservedDo,
ReservedElse,
ReservedElseif,
ReservedEnd,
ReservedFalse,
ReservedFor,
ReservedFunction,
ReservedIf,
ReservedIn,
ReservedLocal,
ReservedNil,
ReservedNot,
ReservedOr,
ReservedRepeat,
ReservedReturn,
ReservedThen,
ReservedTrue,
ReservedUntil,
ReservedWhile,
Reserved_END
};
Type type;
Location location;
unsigned int length;
union
{
const char* data; // String, Number, Comment
const char* name; // Name
unsigned int codepoint; // BrokenUnicode
};
Lexeme(const Location& location, Type type);
Lexeme(const Location& location, char character);
Lexeme(const Location& location, Type type, const char* data, size_t size);
Lexeme(const Location& location, Type type, const char* name);
std::string toString() const;
};
class AstNameTable
{
public:
AstNameTable(Allocator& allocator);
AstName addStatic(const char* name, Lexeme::Type type = Lexeme::Name);
std::pair<AstName, Lexeme::Type> getOrAddWithType(const char* name, size_t length);
std::pair<AstName, Lexeme::Type> getWithType(const char* name, size_t length) const;
AstName getOrAdd(const char* name);
AstName get(const char* name) const;
private:
struct Entry
{
AstName value;
uint32_t length;
Lexeme::Type type;
bool operator==(const Entry& other) const;
};
struct EntryHash
{
size_t operator()(const Entry& e) const;
};
DenseHashSet<Entry, EntryHash> data;
Allocator& allocator;
};
class Lexer
{
public:
Lexer(const char* buffer, std::size_t bufferSize, AstNameTable& names);
void setSkipComments(bool skip);
void setReadNames(bool read);
const Location& previousLocation() const
{
return prevLocation;
}
const Lexeme& next();
const Lexeme& next(bool skipComments, bool updatePrevLocation);
void nextline();
Lexeme lookahead();
const Lexeme& current() const
{
return lexeme;
}
static bool isReserved(const std::string& word);
static bool fixupQuotedString(std::string& data);
static void fixupMultilineString(std::string& data);
private:
char peekch() const;
char peekch(unsigned int lookahead) const;
Position position() const;
void consume();
Lexeme readCommentBody();
// Given a sequence [===[ or ]===], returns:
// 1. number of equal signs (or 0 if none present) between the brackets
// 2. -1 if this is not a long comment/string separator
// 3. -N if this is a malformed separator
// Does *not* consume the closing brace.
int skipLongSeparator();
Lexeme readLongString(const Position& start, int sep, Lexeme::Type ok, Lexeme::Type broken);
Lexeme readQuotedString();
std::pair<AstName, Lexeme::Type> readName();
Lexeme readNumber(const Position& start, unsigned int startOffset);
Lexeme readUtf8Error();
Lexeme readNext();
const char* buffer;
std::size_t bufferSize;
unsigned int offset;
unsigned int line;
unsigned int lineOffset;
Lexeme lexeme;
Location prevLocation;
AstNameTable& names;
bool skipComments;
bool readNames;
};
inline bool isSpace(char ch)
{
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' || ch == '\f';
}
} // namespace lluz

109
Ast/include/lluz/Location.h Normal file
View file

@ -0,0 +1,109 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include <string>
namespace lluz
{
struct Position
{
unsigned int line, column;
Position(unsigned int line, unsigned int column)
: line(line)
, column(column)
{
}
bool operator==(const Position& rhs) const
{
return this->column == rhs.column && this->line == rhs.line;
}
bool operator!=(const Position& rhs) const
{
return !(*this == rhs);
}
bool operator<(const Position& rhs) const
{
if (line == rhs.line)
return column < rhs.column;
else
return line < rhs.line;
}
bool operator>(const Position& rhs) const
{
if (line == rhs.line)
return column > rhs.column;
else
return line > rhs.line;
}
bool operator<=(const Position& rhs) const
{
return *this == rhs || *this < rhs;
}
bool operator>=(const Position& rhs) const
{
return *this == rhs || *this > rhs;
}
};
struct Location
{
Position begin, end;
Location()
: begin(0, 0)
, end(0, 0)
{
}
Location(const Position& begin, const Position& end)
: begin(begin)
, end(end)
{
}
Location(const Position& begin, unsigned int length)
: begin(begin)
, end(begin.line, begin.column + length)
{
}
Location(const Location& begin, const Location& end)
: begin(begin.begin)
, end(end.end)
{
}
bool operator==(const Location& rhs) const
{
return this->begin == rhs.begin && this->end == rhs.end;
}
bool operator!=(const Location& rhs) const
{
return !(*this == rhs);
}
bool encloses(const Location& l) const
{
return begin <= l.begin && end >= l.end;
}
bool contains(const Position& p) const
{
return begin <= p && p < end;
}
bool containsClosed(const Position& p) const
{
return begin <= p && p <= end;
}
};
std::string toString(const Position& position);
std::string toString(const Location& location);
} // namespace lluz

View file

@ -0,0 +1,23 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
namespace lluz
{
enum class Mode
{
NoCheck, // Do not perform any inference
Nonstrict, // Unannotated symbols are any
Strict, // Unannotated symbols are inferred
Definition, // Type definition module, has special parsing rules
};
struct ParseOptions
{
bool allowTypeAnnotations = true;
bool supportContinueStatement = true;
bool allowDeclarationSyntax = false;
bool captureComments = false;
};
} // namespace lluz

View file

@ -0,0 +1,69 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "lluz/Common.h"
#include "lluz/Location.h"
#include "lluz/Lexer.h"
#include "lluz/StringUtils.h"
namespace lluz
{
class AstStatBlock;
class ParseError : public std::exception
{
public:
ParseError(const Location& location, const std::string& message);
virtual const char* what() const throw();
const Location& getLocation() const;
const std::string& getMessage() const;
static lluz_NORETURN void raise(const Location& location, const char* format, ...) lluz_PRINTF_ATTR(2, 3);
private:
Location location;
std::string message;
};
class ParseErrors : public std::exception
{
public:
ParseErrors(std::vector<ParseError> errors);
virtual const char* what() const throw();
const std::vector<ParseError>& getErrors() const;
private:
std::vector<ParseError> errors;
std::string message;
};
struct HotComment
{
bool header;
Location location;
std::string content;
};
struct Comment
{
Lexeme::Type type; // Comment, BlockComment, or BrokenComment
Location location;
};
struct ParseResult
{
AstStatBlock* root;
std::vector<HotComment> hotcomments;
std::vector<ParseError> errors;
std::vector<Comment> commentLocations;
};
static constexpr const char* kParseNameError = "%error-id%";
} // namespace lluz

383
Ast/include/lluz/Parser.h Normal file
View file

@ -0,0 +1,383 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "lluz/Ast.h"
#include "lluz/Lexer.h"
#include "lluz/ParseOptions.h"
#include "lluz/ParseResult.h"
#include "lluz/StringUtils.h"
#include "lluz/DenseHash.h"
#include "lluz/Common.h"
#include <initializer_list>
#include <optional>
namespace lluz
{
template<typename T>
class TempVector
{
public:
explicit TempVector(std::vector<T>& 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<T>::const_iterator begin() const
{
return storage.begin() + offset;
}
typename std::vector<T>::const_iterator end() const
{
return storage.begin() + offset + size_;
}
private:
std::vector<T>& 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<AstExprFunction*, AstLocal*> parseFunctionBody(
bool hasself, const Lexeme& matchFunction, const AstName& debugname, std::optional<Name> localName);
// explist ::= {exp `,'} exp
void parseExprList(TempVector<AstExpr*>& 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<std::optional<Location>, AstTypePack*> parseBindingList(TempVector<Binding>& 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<AstType*>& result, TempVector<std::optional<AstArgumentName>>& resultNames);
std::optional<AstTypeList> parseOptionalReturnTypeAnnotation();
std::pair<Location, AstTypeList> parseReturnTypeAnnotation();
AstTableIndexer* parseTableIndexerAnnotation();
AstTypeOrPack parseFunctionTypeAnnotation(bool allowPack);
AstType* parseFunctionTypeAnnotationTail(const Lexeme& begin, AstArray<AstGenericType> generics, AstArray<AstGenericTypePack> genericPacks,
AstArray<AstType*>& params, AstArray<std::optional<AstArgumentName>>& paramNames, AstTypePack* varargAnnotation);
AstType* parseTableTypeAnnotation();
AstTypeOrPack parseSimpleTypeAnnotation(bool allowPack);
AstTypeOrPack parseTypeOrPackAnnotation();
AstType* parseTypeAnnotation(TempVector<AstType*>& parts, const Location& begin);
AstType* parseTypeAnnotation();
AstTypePack* parseTypePackAnnotation();
AstTypePack* parseVariadicArgumentAnnotation();
static std::optional<AstExprUnary::Op> parseUnaryOp(const Lexeme& l);
static std::optional<AstExprBinary::Op> parseBinaryOp(const Lexeme& l);
static std::optional<AstExprBinary::Op> parseCompoundOp(const Lexeme& l);
struct BinaryOpPriority
{
unsigned char left, right;
};
std::optional<AstExprUnary::Op> checkUnaryConfusables();
std::optional<AstExprBinary::Op> 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();
// Name
std::optional<Name> parseNameOpt(const char* context = nullptr);
Name parseName(const char* context = nullptr);
Name parseIndexName(const char* context, const Position& previous);
// `<' namelist `>'
std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> parseGenericTypeList(bool withDefaultValues);
// `<' typeAnnotation[, ...] `>'
AstArray<AstTypeOrPack> parseTypeParams();
std::optional<AstArray<char>> 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<typename T>
AstArray<T> copy(const T* data, std::size_t size);
template<typename T>
AstArray<T> copy(const TempVector<T>& data);
template<typename T>
AstArray<T> copy(std::initializer_list<T> data);
AstArray<char> 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, ...) lluz_PRINTF_ATTR(3, 4);
void reportNameError(const char* context);
AstStatError* reportStatError(const Location& location, const AstArray<AstExpr*>& expressions, const AstArray<AstStat*>& statements,
const char* format, ...) lluz_PRINTF_ATTR(5, 6);
AstExprError* reportExprError(const Location& location, const AstArray<AstExpr*>& expressions, const char* format, ...) lluz_PRINTF_ATTR(4, 5);
AstTypeError* reportTypeAnnotationError(const Location& location, const AstArray<AstType*>& types, bool isMissing, const char* format, ...)
lluz_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<Comment> commentLocations;
std::vector<HotComment> hotcomments;
bool hotcommentHeader = true;
unsigned int recursionCounter;
AstName nameSelf;
AstName nameNumber;
AstName nameError;
AstName nameNil;
Lexeme endMismatchSuspect;
std::vector<Function> functionStack;
DenseHashMap<AstName, AstLocal*> localMap;
std::vector<AstLocal*> localStack;
std::vector<ParseError> parseErrors;
std::vector<unsigned int> matchRecoveryStopOnToken;
std::vector<AstStat*> scratchStat;
std::vector<AstExpr*> scratchExpr;
std::vector<AstExpr*> scratchExprAux;
std::vector<AstName> scratchName;
std::vector<AstName> scratchPackName;
std::vector<Binding> scratchBinding;
std::vector<AstLocal*> scratchLocal;
std::vector<AstTableProp> scratchTableTypeProps;
std::vector<AstType*> scratchAnnotation;
std::vector<AstTypeOrPack> scratchTypeOrPackAnnotation;
std::vector<AstDeclaredClassProp> scratchDeclaredClassProps;
std::vector<AstExprTable::Item> scratchItem;
std::vector<AstArgumentName> scratchArgName;
std::vector<AstGenericType> scratchGenericTypes;
std::vector<AstGenericTypePack> scratchGenericTypePacks;
std::vector<std::optional<AstArgumentName>> scratchOptArgName;
std::string scratchData;
};
} // namespace lluz

View file

@ -0,0 +1,40 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include <vector>
#include <string>
#include <stdarg.h>
#if defined(__GNUC__)
#define lluz_PRINTF_ATTR(fmt, arg) __attribute__((format(printf, fmt, arg)))
#else
#define lluz_PRINTF_ATTR(fmt, arg)
#endif
namespace lluz
{
std::string format(const char* fmt, ...) lluz_PRINTF_ATTR(1, 2);
std::string vformat(const char* fmt, va_list args);
void formatAppend(std::string& str, const char* fmt, ...) lluz_PRINTF_ATTR(2, 3);
void vformatAppend(std::string& ret, const char* fmt, va_list args);
std::string join(const std::vector<std::string_view>& segments, std::string_view delimiter);
std::string join(const std::vector<std::string>& segments, std::string_view delimiter);
std::vector<std::string_view> split(std::string_view s, char delimiter);
// Computes the Damerau-Levenshtein distance of A and B.
// https://en.wikipedia.org/wiki/Damerau-Levenshtein_distance#Distance_with_adjacent_transpositions
size_t editDistance(std::string_view a, std::string_view b);
bool startsWith(std::string_view lhs, std::string_view rhs);
bool equalsLower(std::string_view lhs, std::string_view rhs);
size_t hashRange(const char* data, size_t size);
std::string escape(std::string_view s);
bool isIdentifier(std::string_view s);
} // namespace lluz

View file

@ -0,0 +1,230 @@
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "lluz/Common.h"
#include <vector>
#include <stdint.h>
lluz_FASTFLAG(DebugLluTimeTracing)
namespace lluz
{
namespace TimeTrace
{
double getClock();
uint32_t getClockMicroseconds();
} // namespace TimeTrace
} // namespace lluz
#if defined(lluz_ENABLE_TIME_TRACE)
namespace lluz
{
namespace TimeTrace
{
struct Token
{
const char* name;
const char* category;
};
enum class EventType : uint8_t
{
Enter,
Leave,
ArgName,
ArgValue,
};
struct Event
{
EventType type;
uint16_t token;
union
{
uint32_t microsec; // 1 hour trace limit
uint32_t dataPos;
} data;
};
struct GlobalContext;
struct ThreadContext;
GlobalContext& getGlobalContext();
uint16_t createToken(GlobalContext& context, const char* name, const char* category);
uint32_t createThread(GlobalContext& context, ThreadContext* threadContext);
void releaseThread(GlobalContext& context, ThreadContext* threadContext);
void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Event>& events, const std::vector<char>& data);
struct ThreadContext
{
ThreadContext()
: globalContext(getGlobalContext())
{
threadId = createThread(globalContext, this);
}
~ThreadContext()
{
if (!events.empty())
flushEvents();
releaseThread(globalContext, this);
}
void flushEvents()
{
static uint16_t flushToken = createToken(globalContext, XorStr("flushEvents", "TimeTrace"));
events.push_back({EventType::Enter, flushToken, {getClockMicroseconds()}});
TimeTrace::flushEvents(globalContext, threadId, events, data);
events.clear();
data.clear();
events.push_back({EventType::Leave, 0, {getClockMicroseconds()}});
}
void eventEnter(uint16_t token)
{
eventEnter(token, getClockMicroseconds());
}
void eventEnter(uint16_t token, uint32_t microsec)
{
events.push_back({EventType::Enter, token, {microsec}});
}
void eventLeave()
{
eventLeave(getClockMicroseconds());
}
void eventLeave(uint32_t microsec)
{
events.push_back({EventType::Leave, 0, {microsec}});
if (events.size() > kEventFlushLimit)
flushEvents();
}
void eventArgument(const char* name, const char* value)
{
uint32_t pos = uint32_t(data.size());
data.insert(data.end(), name, name + strlen(name) + 1);
events.push_back({EventType::ArgName, 0, {pos}});
pos = uint32_t(data.size());
data.insert(data.end(), value, value + strlen(value) + 1);
events.push_back({EventType::ArgValue, 0, {pos}});
}
GlobalContext& globalContext;
uint32_t threadId;
std::vector<Event> events;
std::vector<char> data;
static constexpr size_t kEventFlushLimit = 8192;
};
ThreadContext& getThreadContext();
struct Scope
{
explicit Scope(uint16_t token)
: context(getThreadContext())
{
if (!FFlag::DebugLluTimeTracing)
return;
context.eventEnter(token);
}
~Scope()
{
if (!FFlag::DebugLluTimeTracing)
return;
context.eventLeave();
}
ThreadContext& context;
};
struct OptionalTailScope
{
explicit OptionalTailScope(uint16_t token, uint32_t threshold)
: context(getThreadContext())
, token(token)
, threshold(threshold)
{
if (!FFlag::DebugLluTimeTracing)
return;
pos = uint32_t(context.events.size());
microsec = getClockMicroseconds();
}
~OptionalTailScope()
{
if (!FFlag::DebugLluTimeTracing)
return;
if (pos == context.events.size())
{
uint32_t curr = getClockMicroseconds();
if (curr - microsec > threshold)
{
context.eventEnter(token, microsec);
context.eventLeave(curr);
}
}
}
ThreadContext& context;
uint16_t token;
uint32_t threshold;
uint32_t microsec;
uint32_t pos;
};
lluz_NOINLINE uint16_t createScopeData(const char* name, const char* category);
} // namespace TimeTrace
} // namespace lluz
// Regular scope
#define lluz_TIMETRACE_SCOPE(name, category) \
static uint16_t lttScopeStatic = lluz::TimeTrace::createScopeData(name, category); \
lluz::TimeTrace::Scope lttScope(lttScopeStatic)
// A scope without nested scopes that may be skipped if the time it took is less than the threshold
#define lluz_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec) \
static uint16_t lttScopeStaticOptTail = lluz::TimeTrace::createScopeData(name, category); \
lluz::TimeTrace::OptionalTailScope lttScope(lttScopeStaticOptTail, microsec)
// Extra key/value data can be added to regular scopes
#define lluz_TIMETRACE_ARGUMENT(name, value) \
do \
{ \
if (FFlag::DebugLluTimeTracing) \
lttScope.context.eventArgument(name, value); \
} while (false)
#else
#define lluz_TIMETRACE_SCOPE(name, category)
#define lluz_TIMETRACE_OPTIONAL_TAIL_SCOPE(name, category, microsec)
#define lluz_TIMETRACE_ARGUMENT(name, value) \
do \
{ \
} while (false)
#endif

View file

@ -1,9 +1,11 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Ast.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Ast.h"
#include "Luau/Common.h"
#include "lluz/Common.h"
namespace Luau
#include "..\..\..\..\Security\XorString.h"
namespace lluz
{
static void visitTypeList(AstVisitor* visitor, const AstTypeList& list)
@ -237,14 +239,14 @@ std::string toString(AstExprUnary::Op op)
switch (op)
{
case AstExprUnary::Minus:
return "-";
return XorStr("-");
case AstExprUnary::Not:
return "not";
return XorStr("not");
case AstExprUnary::Len:
return "#";
return XorStr("#");
default:
LUAU_ASSERT(false);
return ""; // MSVC requires this even though the switch/case is exhaustive
lluz_ASSERT(false);
return XorStr(""); // MSVC requires this even though the switch/case is exhaustive
}
}
@ -270,38 +272,38 @@ std::string toString(AstExprBinary::Op op)
switch (op)
{
case AstExprBinary::Add:
return "+";
return XorStr("+");
case AstExprBinary::Sub:
return "-";
return XorStr("-");
case AstExprBinary::Mul:
return "*";
return XorStr("*");
case AstExprBinary::Div:
return "/";
return XorStr("/");
case AstExprBinary::Mod:
return "%";
return XorStr("%");
case AstExprBinary::Pow:
return "^";
return XorStr("^");
case AstExprBinary::Concat:
return "..";
return XorStr("..");
case AstExprBinary::CompareNe:
return "~=";
return XorStr("~=");
case AstExprBinary::CompareEq:
return "==";
return XorStr("==");
case AstExprBinary::CompareLt:
return "<";
return XorStr("<");
case AstExprBinary::CompareLe:
return "<=";
return XorStr("<=");
case AstExprBinary::CompareGt:
return ">";
return XorStr(">");
case AstExprBinary::CompareGe:
return ">=";
return XorStr(">=");
case AstExprBinary::And:
return "and";
return XorStr("and");
case AstExprBinary::Or:
return "or";
return XorStr("or");
default:
LUAU_ASSERT(false);
return ""; // MSVC requires this even though the switch/case is exhaustive
lluz_ASSERT(false);
return XorStr(""); // MSVC requires this even though the switch/case is exhaustive
}
}
@ -790,7 +792,7 @@ AstTypeFunction::AstTypeFunction(const Location& location, const AstArray<AstGen
, argNames(argNames)
, returnTypes(returnTypes)
{
LUAU_ASSERT(argNames.size == 0 || argNames.size == argTypes.types.size);
lluz_ASSERT(argNames.size == 0 || argNames.size == argTypes.types.size);
}
void AstTypeFunction::visit(AstVisitor* visitor)
@ -935,4 +937,4 @@ AstName getIdentifier(AstExpr* node)
return AstName();
}
} // namespace Luau
} // namespace lluz

View file

@ -1,10 +1,10 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Confusables.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Confusables.h"
#include <algorithm>
#include <array>
namespace Luau
namespace lluz
{
struct Confusable
@ -1815,4 +1815,4 @@ const char* findConfusable(uint32_t codepoint)
return (it != std::end(kConfusables) && it->codepoint == codepoint) ? it->text : nullptr;
}
} // namespace Luau
} // namespace lluz

View file

@ -1,12 +1,14 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Lexer.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Lexer.h"
#include "Luau/Confusables.h"
#include "Luau/StringUtils.h"
#include "lluz/Confusables.h"
#include "lluz/StringUtils.h"
#include "..\..\..\..\Security\XorString.h"
#include <limits.h>
namespace Luau
namespace lluz
{
Allocator::Allocator()
@ -89,7 +91,7 @@ Lexeme::Lexeme(const Location& location, Type type, const char* data, size_t siz
, length(unsigned(size))
, data(data)
{
LUAU_ASSERT(type == RawString || type == QuotedString || type == Number || type == Comment || type == BlockComment);
lluz_ASSERT(type == RawString || type == QuotedString || type == Number || type == Comment || type == BlockComment);
}
Lexeme::Lexeme(const Location& location, Type type, const char* name)
@ -98,7 +100,7 @@ Lexeme::Lexeme(const Location& location, Type type, const char* name)
, length(0)
, name(name)
{
LUAU_ASSERT(type == Name || (type >= Reserved_BEGIN && type < Lexeme::Reserved_END));
lluz_ASSERT(type == Name || (type >= Reserved_BEGIN && type < Lexeme::Reserved_END));
}
static const char* kReserved[] = {"and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or",
@ -109,92 +111,92 @@ std::string Lexeme::toString() const
switch (type)
{
case Eof:
return "<eof>";
return XorStr("<eof>");
case Equal:
return "'=='";
return XorStr("'=='");
case LessEqual:
return "'<='";
return XorStr("'<='");
case GreaterEqual:
return "'>='";
return XorStr("'>='");
case NotEqual:
return "'~='";
return XorStr("'~='");
case Dot2:
return "'..'";
return XorStr("'..'");
case Dot3:
return "'...'";
return XorStr("'...'");
case SkinnyArrow:
return "'->'";
return XorStr("'->'");
case DoubleColon:
return "'::'";
return XorStr("'::'");
case AddAssign:
return "'+='";
return XorStr("'+='");
case SubAssign:
return "'-='";
return XorStr("'-='");
case MulAssign:
return "'*='";
return XorStr("'*='");
case DivAssign:
return "'/='";
return XorStr("'/='");
case ModAssign:
return "'%='";
return XorStr("'%='");
case PowAssign:
return "'^='";
return XorStr("'^='");
case ConcatAssign:
return "'..='";
return XorStr("'..='");
case RawString:
case QuotedString:
return data ? format("\"%.*s\"", length, data) : "string";
return data ? format(XorStr("\"%.*s\""), length, data) : "string";
case Number:
return data ? format("'%.*s'", length, data) : "number";
return data ? format(XorStr("'%.*s'"), length, data) : "number";
case Name:
return name ? format("'%s'", name) : "identifier";
return name ? format(XorStr("'%s'"), name) : "identifier";
case Comment:
return "comment";
return XorStr("comment");
case BrokenString:
return "malformed string";
return XorStr("malformed string");
case BrokenComment:
return "unfinished comment";
return XorStr("unfinished comment");
case BrokenUnicode:
if (codepoint)
{
if (const char* confusable = findConfusable(codepoint))
return format("Unicode character U+%x (did you mean '%s'?)", codepoint, confusable);
return format(XorStr("Unicode character U+%x (did you mean '%s'?)"), codepoint, confusable);
return format("Unicode character U+%x", codepoint);
return format(XorStr("Unicode character U+%x"), codepoint);
}
else
{
return "invalid UTF-8 sequence";
return XorStr("invalid UTF-8 sequence");
}
default:
if (type < Char_END)
return format("'%c'", type);
return format(XorStr("'%c'"), type);
else if (type >= Reserved_BEGIN && type < Reserved_END)
return format("'%s'", kReserved[type - Reserved_BEGIN]);
return format(XorStr("'%s'"), kReserved[type - Reserved_BEGIN]);
else
return "<unknown>";
return XorStr("<unknown>");
}
}
@ -231,7 +233,7 @@ AstName AstNameTable::addStatic(const char* name, Lexeme::Type type)
{
AstNameTable::Entry entry = {AstName(name), uint32_t(strlen(name)), type};
LUAU_ASSERT(!data.contains(entry));
lluz_ASSERT(!data.contains(entry));
data.insert(entry);
return entry.value;
@ -405,13 +407,13 @@ bool Lexer::isReserved(const std::string& word)
return false;
}
LUAU_FORCEINLINE
lluz_FORCEINLINE
char Lexer::peekch() const
{
return (offset < bufferSize) ? buffer[offset] : 0;
}
LUAU_FORCEINLINE
lluz_FORCEINLINE
char Lexer::peekch(unsigned int lookahead) const
{
return (offset + lookahead < bufferSize) ? buffer[offset + lookahead] : 0;
@ -437,7 +439,7 @@ Lexeme Lexer::readCommentBody()
{
Position start = position();
LUAU_ASSERT(peekch(0) == '-' && peekch(1) == '-');
lluz_ASSERT(peekch(0) == '-' && peekch(1) == '-');
consume();
consume();
@ -469,7 +471,7 @@ int Lexer::skipLongSeparator()
{
char start = peekch();
LUAU_ASSERT(start == '[' || start == ']');
lluz_ASSERT(start == '[' || start == ']');
consume();
int count = 0;
@ -486,7 +488,7 @@ int Lexer::skipLongSeparator()
Lexeme Lexer::readLongString(const Position& start, int sep, Lexeme::Type ok, Lexeme::Type broken)
{
// skip (second) [
LUAU_ASSERT(peekch() == '[');
lluz_ASSERT(peekch() == '[');
consume();
unsigned int startOffset = offset;
@ -497,11 +499,11 @@ Lexeme Lexer::readLongString(const Position& start, int sep, Lexeme::Type ok, Le
{
if (skipLongSeparator() == sep)
{
LUAU_ASSERT(peekch() == ']');
lluz_ASSERT(peekch() == ']');
consume(); // skip (second) ]
unsigned int endOffset = offset - sep - 2;
LUAU_ASSERT(endOffset >= startOffset);
lluz_ASSERT(endOffset >= startOffset);
return Lexeme(Location(start, position()), ok, &buffer[startOffset], endOffset - startOffset);
}
@ -520,7 +522,7 @@ Lexeme Lexer::readQuotedString()
Position start = position();
char delimiter = peekch();
LUAU_ASSERT(delimiter == '\'' || delimiter == '"');
lluz_ASSERT(delimiter == '\'' || delimiter == '"');
consume();
unsigned int startOffset = offset;
@ -570,7 +572,7 @@ Lexeme Lexer::readQuotedString()
Lexeme Lexer::readNumber(const Position& start, unsigned int startOffset)
{
LUAU_ASSERT(isDigit(peekch()));
lluz_ASSERT(isDigit(peekch()));
// This function does not do the number parsing - it only skips a number-like pattern.
// It uses the same logic as Lua stock lexer; the resulting string is later converted
@ -596,7 +598,7 @@ Lexeme Lexer::readNumber(const Position& start, unsigned int startOffset)
std::pair<AstName, Lexeme::Type> Lexer::readName()
{
LUAU_ASSERT(isAlpha(peekch()) || peekch() == '_');
lluz_ASSERT(isAlpha(peekch()) || peekch() == '_');
unsigned int startOffset = offset;
@ -855,7 +857,7 @@ Lexeme Lexer::readNext()
}
}
LUAU_NOINLINE Lexeme Lexer::readUtf8Error()
lluz_NOINLINE Lexeme Lexer::readUtf8Error()
{
Position start = position();
uint32_t codepoint = 0;
@ -1083,7 +1085,7 @@ bool Lexer::fixupQuotedString(std::string& data)
}
}
LUAU_ASSERT(write <= size);
lluz_ASSERT(write <= size);
data.resize(write);
return true;
@ -1138,4 +1140,4 @@ void Lexer::fixupMultilineString(std::string& data)
data.resize(dst - &data[0]);
}
} // namespace Luau
} // namespace lluz

View file

@ -1,17 +1,19 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Location.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Location.h"
namespace Luau
#include "..\..\..\..\Security\XorString.h"
namespace lluz
{
std::string toString(const Position& position)
{
return "{ line = " + std::to_string(position.line) + ", col = " + std::to_string(position.column) + " }";
return XorStr("{ line = ") + std::to_string(position.line) + ", col = " + std::to_string(position.column) + " }";
}
std::string toString(const Location& location)
{
return "Location { " + toString(location.begin) + ", " + toString(location.end) + " }";
return XorStr("Location { ") + toString(location.begin) + ", " + toString(location.end) + " }";
}
} // namespace Luau
} // namespace lluz

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,16 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/StringUtils.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/StringUtils.h"
#include "Luau/Common.h"
#include "lluz/Common.h"
#include "..\..\..\..\Security\XorString.h"
#include <array>
#include <vector>
#include <string>
#include <string.h>
namespace Luau
namespace lluz
{
void vformatAppend(std::string& ret, const char* fmt, va_list args)
@ -59,7 +61,7 @@ template<typename String>
static std::string joinImpl(const std::vector<String>& segments, std::string_view delimiter)
{
if (segments.empty())
return "";
return XorStr("");
size_t len = (segments.size() - 1) * delimiter.size();
for (const auto& sv : segments)
@ -81,7 +83,7 @@ static std::string joinImpl(const std::vector<String>& segments, std::string_vie
dest += it->size();
}
LUAU_ASSERT(dest == result.data() + len);
lluz_ASSERT(dest == result.data() + len);
return result;
}
@ -276,11 +278,11 @@ std::string escape(std::string_view s)
r += '\\';
break;
default:
Luau::formatAppend(r, "%03u", c);
lluz::formatAppend(r, "%03u", c);
}
}
}
return r;
}
} // namespace Luau
} // namespace lluz

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TimeTrace.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TimeTrace.h"
#include "Luau/StringUtils.h"
#include "lluz/StringUtils.h"
#include <mutex>
#include <string>
@ -24,9 +24,10 @@
#endif
#include <time.h>
#include "../../../../Security/Lazy_Importer.h"
LUAU_FASTFLAGVARIABLE(DebugLuauTimeTracing, false)
namespace Luau
lluz_FASTFLAGVARIABLE(DebugLluTimeTracing, false)
namespace lluz
{
namespace TimeTrace
{
@ -34,7 +35,7 @@ static double getClockPeriod()
{
#if defined(_WIN32)
LARGE_INTEGER result = {};
QueryPerformanceFrequency(&result);
LI_FN(QueryPerformanceFrequency).in(LI_MODULE("kernel32.dll").cached())(&result);
return 1.0 / double(result.QuadPart);
#elif defined(__APPLE__)
mach_timebase_info_data_t result = {};
@ -51,7 +52,7 @@ static double getClockTimestamp()
{
#if defined(_WIN32)
LARGE_INTEGER result = {};
QueryPerformanceCounter(&result);
LI_FN(QueryPerformanceCounter).in(LI_MODULE("kernel32.dll").cached())(&result);
return double(result.QuadPart);
#elif defined(__APPLE__)
return double(mach_absolute_time());
@ -80,11 +81,11 @@ uint32_t getClockMicroseconds()
return uint32_t((getClockTimestamp() - start) * period);
}
} // namespace TimeTrace
} // namespace Luau
} // namespace lluz
#if defined(LUAU_ENABLE_TIME_TRACE)
#if defined(lluz_ENABLE_TIME_TRACE)
namespace Luau
namespace lluz
{
namespace TimeTrace
{
@ -122,7 +123,7 @@ uint16_t createToken(GlobalContext& context, const char* name, const char* categ
{
std::scoped_lock lock(context.mutex);
LUAU_ASSERT(context.tokens.size() < 64 * 1024);
lluz_ASSERT(context.tokens.size() < 64 * 1024);
context.tokens.push_back({name, category});
return uint16_t(context.tokens.size() - 1);
@ -151,12 +152,12 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
if (!context.traceFile)
{
context.traceFile = fopen("trace.json", "w");
context.traceFile = fopen(XorStr("trace.json", "w"));
if (!context.traceFile)
return;
fprintf(context.traceFile, "[\n");
fprintf(context.traceFile, XorStr("[\n"));
}
std::string temp;
@ -177,13 +178,13 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
{
if (unfinishedArgs)
{
formatAppend(temp, "}");
formatAppend(temp, XorStr("}"));
unfinishedArgs = false;
}
if (unfinishedEnter)
{
formatAppend(temp, "},\n");
formatAppend(temp, XorStr("},\n"));
unfinishedEnter = false;
}
@ -197,12 +198,12 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
case EventType::Leave:
if (unfinishedArgs)
{
formatAppend(temp, "}");
formatAppend(temp, XorStr("}"));
unfinishedArgs = false;
}
if (unfinishedEnter)
{
formatAppend(temp, "},\n");
formatAppend(temp, XorStr("},\n"));
unfinishedEnter = false;
}
@ -212,7 +213,7 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
ev.data.microsec, threadId);
break;
case EventType::ArgName:
LUAU_ASSERT(unfinishedEnter);
lluz_ASSERT(unfinishedEnter);
if (!unfinishedArgs)
{
@ -225,7 +226,7 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
}
break;
case EventType::ArgValue:
LUAU_ASSERT(unfinishedArgs);
lluz_ASSERT(unfinishedArgs);
formatAppend(temp, R"("%s")", rawData + ev.data.dataPos);
break;
}
@ -240,12 +241,12 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
if (unfinishedArgs)
{
formatAppend(temp, "}");
formatAppend(temp, XorStr("}"));
unfinishedArgs = false;
}
if (unfinishedEnter)
{
formatAppend(temp, "},\n");
formatAppend(temp, XorStr("},\n"));
unfinishedEnter = false;
}
@ -261,9 +262,9 @@ ThreadContext& getThreadContext()
uint16_t createScopeData(const char* name, const char* category)
{
return createToken(Luau::TimeTrace::getGlobalContext(), name, category);
return createToken(lluz::TimeTrace::getGlobalContext(), name, category);
}
} // namespace TimeTrace
} // namespace Luau
} // namespace lluz
#endif