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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/Ast.h"
|
#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)
|
static void visitTypeList(AstVisitor* visitor, const AstTypeList& list)
|
||||||
|
@ -237,14 +239,14 @@ std::string toString(AstExprUnary::Op op)
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case AstExprUnary::Minus:
|
case AstExprUnary::Minus:
|
||||||
return "-";
|
return XorStr("-");
|
||||||
case AstExprUnary::Not:
|
case AstExprUnary::Not:
|
||||||
return "not";
|
return XorStr("not");
|
||||||
case AstExprUnary::Len:
|
case AstExprUnary::Len:
|
||||||
return "#";
|
return XorStr("#");
|
||||||
default:
|
default:
|
||||||
LUAU_ASSERT(false);
|
lluz_ASSERT(false);
|
||||||
return ""; // MSVC requires this even though the switch/case is exhaustive
|
return XorStr(""); // MSVC requires this even though the switch/case is exhaustive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,38 +272,38 @@ std::string toString(AstExprBinary::Op op)
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case AstExprBinary::Add:
|
case AstExprBinary::Add:
|
||||||
return "+";
|
return XorStr("+");
|
||||||
case AstExprBinary::Sub:
|
case AstExprBinary::Sub:
|
||||||
return "-";
|
return XorStr("-");
|
||||||
case AstExprBinary::Mul:
|
case AstExprBinary::Mul:
|
||||||
return "*";
|
return XorStr("*");
|
||||||
case AstExprBinary::Div:
|
case AstExprBinary::Div:
|
||||||
return "/";
|
return XorStr("/");
|
||||||
case AstExprBinary::Mod:
|
case AstExprBinary::Mod:
|
||||||
return "%";
|
return XorStr("%");
|
||||||
case AstExprBinary::Pow:
|
case AstExprBinary::Pow:
|
||||||
return "^";
|
return XorStr("^");
|
||||||
case AstExprBinary::Concat:
|
case AstExprBinary::Concat:
|
||||||
return "..";
|
return XorStr("..");
|
||||||
case AstExprBinary::CompareNe:
|
case AstExprBinary::CompareNe:
|
||||||
return "~=";
|
return XorStr("~=");
|
||||||
case AstExprBinary::CompareEq:
|
case AstExprBinary::CompareEq:
|
||||||
return "==";
|
return XorStr("==");
|
||||||
case AstExprBinary::CompareLt:
|
case AstExprBinary::CompareLt:
|
||||||
return "<";
|
return XorStr("<");
|
||||||
case AstExprBinary::CompareLe:
|
case AstExprBinary::CompareLe:
|
||||||
return "<=";
|
return XorStr("<=");
|
||||||
case AstExprBinary::CompareGt:
|
case AstExprBinary::CompareGt:
|
||||||
return ">";
|
return XorStr(">");
|
||||||
case AstExprBinary::CompareGe:
|
case AstExprBinary::CompareGe:
|
||||||
return ">=";
|
return XorStr(">=");
|
||||||
case AstExprBinary::And:
|
case AstExprBinary::And:
|
||||||
return "and";
|
return XorStr("and");
|
||||||
case AstExprBinary::Or:
|
case AstExprBinary::Or:
|
||||||
return "or";
|
return XorStr("or");
|
||||||
default:
|
default:
|
||||||
LUAU_ASSERT(false);
|
lluz_ASSERT(false);
|
||||||
return ""; // MSVC requires this even though the switch/case is exhaustive
|
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)
|
, argNames(argNames)
|
||||||
, returnTypes(returnTypes)
|
, 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)
|
void AstTypeFunction::visit(AstVisitor* visitor)
|
||||||
|
@ -935,4 +937,4 @@ AstName getIdentifier(AstExpr* node)
|
||||||
return AstName();
|
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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/Confusables.h"
|
#include "lluz/Confusables.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace Luau
|
namespace lluz
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Confusable
|
struct Confusable
|
||||||
|
@ -1815,4 +1815,4 @@ const char* findConfusable(uint32_t codepoint)
|
||||||
return (it != std::end(kConfusables) && it->codepoint == codepoint) ? it->text : nullptr;
|
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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/Lexer.h"
|
#include "lluz/Lexer.h"
|
||||||
|
|
||||||
#include "Luau/Confusables.h"
|
#include "lluz/Confusables.h"
|
||||||
#include "Luau/StringUtils.h"
|
#include "lluz/StringUtils.h"
|
||||||
|
|
||||||
|
#include "..\..\..\..\Security\XorString.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
namespace Luau
|
namespace lluz
|
||||||
{
|
{
|
||||||
|
|
||||||
Allocator::Allocator()
|
Allocator::Allocator()
|
||||||
|
@ -89,7 +91,7 @@ Lexeme::Lexeme(const Location& location, Type type, const char* data, size_t siz
|
||||||
, length(unsigned(size))
|
, length(unsigned(size))
|
||||||
, data(data)
|
, 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)
|
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)
|
, length(0)
|
||||||
, name(name)
|
, 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",
|
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)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Eof:
|
case Eof:
|
||||||
return "<eof>";
|
return XorStr("<eof>");
|
||||||
|
|
||||||
case Equal:
|
case Equal:
|
||||||
return "'=='";
|
return XorStr("'=='");
|
||||||
|
|
||||||
case LessEqual:
|
case LessEqual:
|
||||||
return "'<='";
|
return XorStr("'<='");
|
||||||
|
|
||||||
case GreaterEqual:
|
case GreaterEqual:
|
||||||
return "'>='";
|
return XorStr("'>='");
|
||||||
|
|
||||||
case NotEqual:
|
case NotEqual:
|
||||||
return "'~='";
|
return XorStr("'~='");
|
||||||
|
|
||||||
case Dot2:
|
case Dot2:
|
||||||
return "'..'";
|
return XorStr("'..'");
|
||||||
|
|
||||||
case Dot3:
|
case Dot3:
|
||||||
return "'...'";
|
return XorStr("'...'");
|
||||||
|
|
||||||
case SkinnyArrow:
|
case SkinnyArrow:
|
||||||
return "'->'";
|
return XorStr("'->'");
|
||||||
|
|
||||||
case DoubleColon:
|
case DoubleColon:
|
||||||
return "'::'";
|
return XorStr("'::'");
|
||||||
|
|
||||||
case AddAssign:
|
case AddAssign:
|
||||||
return "'+='";
|
return XorStr("'+='");
|
||||||
|
|
||||||
case SubAssign:
|
case SubAssign:
|
||||||
return "'-='";
|
return XorStr("'-='");
|
||||||
|
|
||||||
case MulAssign:
|
case MulAssign:
|
||||||
return "'*='";
|
return XorStr("'*='");
|
||||||
|
|
||||||
case DivAssign:
|
case DivAssign:
|
||||||
return "'/='";
|
return XorStr("'/='");
|
||||||
|
|
||||||
case ModAssign:
|
case ModAssign:
|
||||||
return "'%='";
|
return XorStr("'%='");
|
||||||
|
|
||||||
case PowAssign:
|
case PowAssign:
|
||||||
return "'^='";
|
return XorStr("'^='");
|
||||||
|
|
||||||
case ConcatAssign:
|
case ConcatAssign:
|
||||||
return "'..='";
|
return XorStr("'..='");
|
||||||
|
|
||||||
case RawString:
|
case RawString:
|
||||||
case QuotedString:
|
case QuotedString:
|
||||||
return data ? format("\"%.*s\"", length, data) : "string";
|
return data ? format(XorStr("\"%.*s\""), length, data) : "string";
|
||||||
|
|
||||||
case Number:
|
case Number:
|
||||||
return data ? format("'%.*s'", length, data) : "number";
|
return data ? format(XorStr("'%.*s'"), length, data) : "number";
|
||||||
|
|
||||||
case Name:
|
case Name:
|
||||||
return name ? format("'%s'", name) : "identifier";
|
return name ? format(XorStr("'%s'"), name) : "identifier";
|
||||||
|
|
||||||
case Comment:
|
case Comment:
|
||||||
return "comment";
|
return XorStr("comment");
|
||||||
|
|
||||||
case BrokenString:
|
case BrokenString:
|
||||||
return "malformed string";
|
return XorStr("malformed string");
|
||||||
|
|
||||||
case BrokenComment:
|
case BrokenComment:
|
||||||
return "unfinished comment";
|
return XorStr("unfinished comment");
|
||||||
|
|
||||||
case BrokenUnicode:
|
case BrokenUnicode:
|
||||||
if (codepoint)
|
if (codepoint)
|
||||||
{
|
{
|
||||||
if (const char* confusable = findConfusable(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
|
else
|
||||||
{
|
{
|
||||||
return "invalid UTF-8 sequence";
|
return XorStr("invalid UTF-8 sequence");
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (type < Char_END)
|
if (type < Char_END)
|
||||||
return format("'%c'", type);
|
return format(XorStr("'%c'"), type);
|
||||||
else if (type >= Reserved_BEGIN && type < Reserved_END)
|
else if (type >= Reserved_BEGIN && type < Reserved_END)
|
||||||
return format("'%s'", kReserved[type - Reserved_BEGIN]);
|
return format(XorStr("'%s'"), kReserved[type - Reserved_BEGIN]);
|
||||||
else
|
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};
|
AstNameTable::Entry entry = {AstName(name), uint32_t(strlen(name)), type};
|
||||||
|
|
||||||
LUAU_ASSERT(!data.contains(entry));
|
lluz_ASSERT(!data.contains(entry));
|
||||||
data.insert(entry);
|
data.insert(entry);
|
||||||
|
|
||||||
return entry.value;
|
return entry.value;
|
||||||
|
@ -405,13 +407,13 @@ bool Lexer::isReserved(const std::string& word)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LUAU_FORCEINLINE
|
lluz_FORCEINLINE
|
||||||
char Lexer::peekch() const
|
char Lexer::peekch() const
|
||||||
{
|
{
|
||||||
return (offset < bufferSize) ? buffer[offset] : 0;
|
return (offset < bufferSize) ? buffer[offset] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LUAU_FORCEINLINE
|
lluz_FORCEINLINE
|
||||||
char Lexer::peekch(unsigned int lookahead) const
|
char Lexer::peekch(unsigned int lookahead) const
|
||||||
{
|
{
|
||||||
return (offset + lookahead < bufferSize) ? buffer[offset + lookahead] : 0;
|
return (offset + lookahead < bufferSize) ? buffer[offset + lookahead] : 0;
|
||||||
|
@ -437,7 +439,7 @@ Lexeme Lexer::readCommentBody()
|
||||||
{
|
{
|
||||||
Position start = position();
|
Position start = position();
|
||||||
|
|
||||||
LUAU_ASSERT(peekch(0) == '-' && peekch(1) == '-');
|
lluz_ASSERT(peekch(0) == '-' && peekch(1) == '-');
|
||||||
consume();
|
consume();
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
|
@ -469,7 +471,7 @@ int Lexer::skipLongSeparator()
|
||||||
{
|
{
|
||||||
char start = peekch();
|
char start = peekch();
|
||||||
|
|
||||||
LUAU_ASSERT(start == '[' || start == ']');
|
lluz_ASSERT(start == '[' || start == ']');
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -486,7 +488,7 @@ int Lexer::skipLongSeparator()
|
||||||
Lexeme Lexer::readLongString(const Position& start, int sep, Lexeme::Type ok, Lexeme::Type broken)
|
Lexeme Lexer::readLongString(const Position& start, int sep, Lexeme::Type ok, Lexeme::Type broken)
|
||||||
{
|
{
|
||||||
// skip (second) [
|
// skip (second) [
|
||||||
LUAU_ASSERT(peekch() == '[');
|
lluz_ASSERT(peekch() == '[');
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
unsigned int startOffset = offset;
|
unsigned int startOffset = offset;
|
||||||
|
@ -497,11 +499,11 @@ Lexeme Lexer::readLongString(const Position& start, int sep, Lexeme::Type ok, Le
|
||||||
{
|
{
|
||||||
if (skipLongSeparator() == sep)
|
if (skipLongSeparator() == sep)
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(peekch() == ']');
|
lluz_ASSERT(peekch() == ']');
|
||||||
consume(); // skip (second) ]
|
consume(); // skip (second) ]
|
||||||
|
|
||||||
unsigned int endOffset = offset - sep - 2;
|
unsigned int endOffset = offset - sep - 2;
|
||||||
LUAU_ASSERT(endOffset >= startOffset);
|
lluz_ASSERT(endOffset >= startOffset);
|
||||||
|
|
||||||
return Lexeme(Location(start, position()), ok, &buffer[startOffset], endOffset - startOffset);
|
return Lexeme(Location(start, position()), ok, &buffer[startOffset], endOffset - startOffset);
|
||||||
}
|
}
|
||||||
|
@ -520,7 +522,7 @@ Lexeme Lexer::readQuotedString()
|
||||||
Position start = position();
|
Position start = position();
|
||||||
|
|
||||||
char delimiter = peekch();
|
char delimiter = peekch();
|
||||||
LUAU_ASSERT(delimiter == '\'' || delimiter == '"');
|
lluz_ASSERT(delimiter == '\'' || delimiter == '"');
|
||||||
consume();
|
consume();
|
||||||
|
|
||||||
unsigned int startOffset = offset;
|
unsigned int startOffset = offset;
|
||||||
|
@ -570,7 +572,7 @@ Lexeme Lexer::readQuotedString()
|
||||||
|
|
||||||
Lexeme Lexer::readNumber(const Position& start, unsigned int startOffset)
|
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.
|
// 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
|
// 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()
|
std::pair<AstName, Lexeme::Type> Lexer::readName()
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(isAlpha(peekch()) || peekch() == '_');
|
lluz_ASSERT(isAlpha(peekch()) || peekch() == '_');
|
||||||
|
|
||||||
unsigned int startOffset = offset;
|
unsigned int startOffset = offset;
|
||||||
|
|
||||||
|
@ -855,7 +857,7 @@ Lexeme Lexer::readNext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LUAU_NOINLINE Lexeme Lexer::readUtf8Error()
|
lluz_NOINLINE Lexeme Lexer::readUtf8Error()
|
||||||
{
|
{
|
||||||
Position start = position();
|
Position start = position();
|
||||||
uint32_t codepoint = 0;
|
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);
|
data.resize(write);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1138,4 +1140,4 @@ void Lexer::fixupMultilineString(std::string& data)
|
||||||
data.resize(dst - &data[0]);
|
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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/Location.h"
|
#include "lluz/Location.h"
|
||||||
|
|
||||||
namespace Luau
|
#include "..\..\..\..\Security\XorString.h"
|
||||||
|
|
||||||
|
namespace lluz
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string toString(const Position& position)
|
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)
|
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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/StringUtils.h"
|
#include "lluz/StringUtils.h"
|
||||||
|
|
||||||
#include "Luau/Common.h"
|
#include "lluz/Common.h"
|
||||||
|
|
||||||
|
#include "..\..\..\..\Security\XorString.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
namespace Luau
|
namespace lluz
|
||||||
{
|
{
|
||||||
|
|
||||||
void vformatAppend(std::string& ret, const char* fmt, va_list args)
|
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)
|
static std::string joinImpl(const std::vector<String>& segments, std::string_view delimiter)
|
||||||
{
|
{
|
||||||
if (segments.empty())
|
if (segments.empty())
|
||||||
return "";
|
return XorStr("");
|
||||||
|
|
||||||
size_t len = (segments.size() - 1) * delimiter.size();
|
size_t len = (segments.size() - 1) * delimiter.size();
|
||||||
for (const auto& sv : segments)
|
for (const auto& sv : segments)
|
||||||
|
@ -81,7 +83,7 @@ static std::string joinImpl(const std::vector<String>& segments, std::string_vie
|
||||||
dest += it->size();
|
dest += it->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
LUAU_ASSERT(dest == result.data() + len);
|
lluz_ASSERT(dest == result.data() + len);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -276,11 +278,11 @@ std::string escape(std::string_view s)
|
||||||
r += '\\';
|
r += '\\';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Luau::formatAppend(r, "%03u", c);
|
lluz::formatAppend(r, "%03u", c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
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
|
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/TimeTrace.h"
|
#include "lluz/TimeTrace.h"
|
||||||
|
|
||||||
#include "Luau/StringUtils.h"
|
#include "lluz/StringUtils.h"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -24,9 +24,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include "../../../../Security/Lazy_Importer.h"
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(DebugLuauTimeTracing, false)
|
lluz_FASTFLAGVARIABLE(DebugLluTimeTracing, false)
|
||||||
namespace Luau
|
namespace lluz
|
||||||
{
|
{
|
||||||
namespace TimeTrace
|
namespace TimeTrace
|
||||||
{
|
{
|
||||||
|
@ -34,7 +35,7 @@ static double getClockPeriod()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
LARGE_INTEGER result = {};
|
LARGE_INTEGER result = {};
|
||||||
QueryPerformanceFrequency(&result);
|
LI_FN(QueryPerformanceFrequency).in(LI_MODULE("kernel32.dll").cached())(&result);
|
||||||
return 1.0 / double(result.QuadPart);
|
return 1.0 / double(result.QuadPart);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
mach_timebase_info_data_t result = {};
|
mach_timebase_info_data_t result = {};
|
||||||
|
@ -51,7 +52,7 @@ static double getClockTimestamp()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
LARGE_INTEGER result = {};
|
LARGE_INTEGER result = {};
|
||||||
QueryPerformanceCounter(&result);
|
LI_FN(QueryPerformanceCounter).in(LI_MODULE("kernel32.dll").cached())(&result);
|
||||||
return double(result.QuadPart);
|
return double(result.QuadPart);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
return double(mach_absolute_time());
|
return double(mach_absolute_time());
|
||||||
|
@ -80,11 +81,11 @@ uint32_t getClockMicroseconds()
|
||||||
return uint32_t((getClockTimestamp() - start) * period);
|
return uint32_t((getClockTimestamp() - start) * period);
|
||||||
}
|
}
|
||||||
} // namespace TimeTrace
|
} // namespace TimeTrace
|
||||||
} // namespace Luau
|
} // namespace lluz
|
||||||
|
|
||||||
#if defined(LUAU_ENABLE_TIME_TRACE)
|
#if defined(lluz_ENABLE_TIME_TRACE)
|
||||||
|
|
||||||
namespace Luau
|
namespace lluz
|
||||||
{
|
{
|
||||||
namespace TimeTrace
|
namespace TimeTrace
|
||||||
{
|
{
|
||||||
|
@ -122,7 +123,7 @@ uint16_t createToken(GlobalContext& context, const char* name, const char* categ
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(context.mutex);
|
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});
|
context.tokens.push_back({name, category});
|
||||||
return uint16_t(context.tokens.size() - 1);
|
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)
|
if (!context.traceFile)
|
||||||
{
|
{
|
||||||
context.traceFile = fopen("trace.json", "w");
|
context.traceFile = fopen(XorStr("trace.json", "w"));
|
||||||
|
|
||||||
if (!context.traceFile)
|
if (!context.traceFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fprintf(context.traceFile, "[\n");
|
fprintf(context.traceFile, XorStr("[\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string temp;
|
std::string temp;
|
||||||
|
@ -177,13 +178,13 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
|
||||||
{
|
{
|
||||||
if (unfinishedArgs)
|
if (unfinishedArgs)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "}");
|
formatAppend(temp, XorStr("}"));
|
||||||
unfinishedArgs = false;
|
unfinishedArgs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unfinishedEnter)
|
if (unfinishedEnter)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "},\n");
|
formatAppend(temp, XorStr("},\n"));
|
||||||
unfinishedEnter = false;
|
unfinishedEnter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +198,12 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
|
||||||
case EventType::Leave:
|
case EventType::Leave:
|
||||||
if (unfinishedArgs)
|
if (unfinishedArgs)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "}");
|
formatAppend(temp, XorStr("}"));
|
||||||
unfinishedArgs = false;
|
unfinishedArgs = false;
|
||||||
}
|
}
|
||||||
if (unfinishedEnter)
|
if (unfinishedEnter)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "},\n");
|
formatAppend(temp, XorStr("},\n"));
|
||||||
unfinishedEnter = false;
|
unfinishedEnter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +213,7 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
|
||||||
ev.data.microsec, threadId);
|
ev.data.microsec, threadId);
|
||||||
break;
|
break;
|
||||||
case EventType::ArgName:
|
case EventType::ArgName:
|
||||||
LUAU_ASSERT(unfinishedEnter);
|
lluz_ASSERT(unfinishedEnter);
|
||||||
|
|
||||||
if (!unfinishedArgs)
|
if (!unfinishedArgs)
|
||||||
{
|
{
|
||||||
|
@ -225,7 +226,7 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EventType::ArgValue:
|
case EventType::ArgValue:
|
||||||
LUAU_ASSERT(unfinishedArgs);
|
lluz_ASSERT(unfinishedArgs);
|
||||||
formatAppend(temp, R"("%s")", rawData + ev.data.dataPos);
|
formatAppend(temp, R"("%s")", rawData + ev.data.dataPos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -240,12 +241,12 @@ void flushEvents(GlobalContext& context, uint32_t threadId, const std::vector<Ev
|
||||||
|
|
||||||
if (unfinishedArgs)
|
if (unfinishedArgs)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "}");
|
formatAppend(temp, XorStr("}"));
|
||||||
unfinishedArgs = false;
|
unfinishedArgs = false;
|
||||||
}
|
}
|
||||||
if (unfinishedEnter)
|
if (unfinishedEnter)
|
||||||
{
|
{
|
||||||
formatAppend(temp, "},\n");
|
formatAppend(temp, XorStr("},\n"));
|
||||||
unfinishedEnter = false;
|
unfinishedEnter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,9 +262,9 @@ ThreadContext& getThreadContext()
|
||||||
|
|
||||||
uint16_t createScopeData(const char* name, const char* category)
|
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 TimeTrace
|
||||||
} // namespace Luau
|
} // namespace lluz
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue