mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Add files via upload
This commit is contained in:
parent
752d09c8da
commit
36ba1dd9ac
17 changed files with 3230 additions and 315 deletions
1268
Ast/include/lluz/Ast.h
Normal file
1268
Ast/include/lluz/Ast.h
Normal file
File diff suppressed because it is too large
Load diff
9
Ast/include/lluz/Confusables.h
Normal file
9
Ast/include/lluz/Confusables.h
Normal 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);
|
||||
}
|
524
Ast/include/lluz/DenseHash.h
Normal file
524
Ast/include/lluz/DenseHash.h
Normal 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
241
Ast/include/lluz/Lexer.h
Normal 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
109
Ast/include/lluz/Location.h
Normal 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
|
23
Ast/include/lluz/ParseOptions.h
Normal file
23
Ast/include/lluz/ParseOptions.h
Normal 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
|
69
Ast/include/lluz/ParseResult.h
Normal file
69
Ast/include/lluz/ParseResult.h
Normal 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
383
Ast/include/lluz/Parser.h
Normal 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
|
40
Ast/include/lluz/StringUtils.h
Normal file
40
Ast/include/lluz/StringUtils.h
Normal 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
|
230
Ast/include/lluz/TimeTrace.h
Normal file
230
Ast/include/lluz/TimeTrace.h
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue