mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
Spelling (#119)
Fixed various spelling errors. Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
This commit is contained in:
parent
57a42c4cb9
commit
278e848cc2
@ -389,7 +389,7 @@ const std::string* getName(TypeId type);
|
|||||||
// Checks whether a union contains all types of another union.
|
// Checks whether a union contains all types of another union.
|
||||||
bool isSubset(const UnionTypeVar& super, const UnionTypeVar& sub);
|
bool isSubset(const UnionTypeVar& super, const UnionTypeVar& sub);
|
||||||
|
|
||||||
// Checks if a type conains generic type binders
|
// Checks if a type contains generic type binders
|
||||||
bool isGeneric(const TypeId ty);
|
bool isGeneric(const TypeId ty);
|
||||||
|
|
||||||
// Checks if a type may be instantiated to one containing generic type binders
|
// Checks if a type may be instantiated to one containing generic type binders
|
||||||
|
@ -1461,7 +1461,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
|
|||||||
result.erase(std::string(stringKey->value.data, stringKey->value.size));
|
result.erase(std::string(stringKey->value.data, stringKey->value.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we know for sure that a key is being written, do not offer general epxression suggestions
|
// If we know for sure that a key is being written, do not offer general expression suggestions
|
||||||
if (!key)
|
if (!key)
|
||||||
autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position, result);
|
autocompleteExpression(sourceModule, *module, typeChecker, typeArena, finder.ancestry, position, result);
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ struct RequireTracer : AstVisitor
|
|||||||
|
|
||||||
result.exprs[call] = fileResolver->concat(*rootName, v);
|
result.exprs[call] = fileResolver->concat(*rootName, v);
|
||||||
|
|
||||||
// 'WaitForChild' can be used on modules that are not awailable at the typecheck time, but will be awailable at runtime
|
// 'WaitForChild' can be used on modules that are not available at the typecheck time, but will be available at runtime
|
||||||
// If we fail to find such module, we will not report an UnknownRequire error
|
// If we fail to find such module, we will not report an UnknownRequire error
|
||||||
if (FFlag::LuauTraceRequireLookupChild && indexName->index == "WaitForChild")
|
if (FFlag::LuauTraceRequireLookupChild && indexName->index == "WaitForChild")
|
||||||
result.optional[call] = true;
|
result.optional[call] = true;
|
||||||
|
@ -412,7 +412,7 @@ void TypeChecker::checkBlock(const ScopePtr& scope, const AstStatBlock& block)
|
|||||||
// ```
|
// ```
|
||||||
// These both call each other, so `f` will be ordered before `g`, so the call to `g`
|
// These both call each other, so `f` will be ordered before `g`, so the call to `g`
|
||||||
// is typechecked before `g` has had its body checked. For this reason, there's three
|
// is typechecked before `g` has had its body checked. For this reason, there's three
|
||||||
// types for each functuion: before its body is checked, during checking its body,
|
// types for each function: before its body is checked, during checking its body,
|
||||||
// and after its body is checked.
|
// and after its body is checked.
|
||||||
//
|
//
|
||||||
// We currently treat the before-type and the during-type as the same,
|
// We currently treat the before-type and the during-type as the same,
|
||||||
@ -1076,7 +1076,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco
|
|||||||
checkFunctionBody(funScope, ty, *function.func);
|
checkFunctionBody(funScope, ty, *function.func);
|
||||||
|
|
||||||
// If in nonstrict mode and allowing redefinition of global function, restore the previous definition type
|
// If in nonstrict mode and allowing redefinition of global function, restore the previous definition type
|
||||||
// in case this function has a differing signature. The signature discrepency will be caught in checkBlock.
|
// in case this function has a differing signature. The signature discrepancy will be caught in checkBlock.
|
||||||
if (previouslyDefined)
|
if (previouslyDefined)
|
||||||
globalBindings[name] = oldBinding;
|
globalBindings[name] = oldBinding;
|
||||||
else
|
else
|
||||||
@ -3150,7 +3150,7 @@ void TypeChecker::checkArgumentList(
|
|||||||
const ScopePtr& scope, Unifier& state, TypePackId argPack, TypePackId paramPack, const std::vector<Location>& argLocations)
|
const ScopePtr& scope, Unifier& state, TypePackId argPack, TypePackId paramPack, const std::vector<Location>& argLocations)
|
||||||
{
|
{
|
||||||
/* Important terminology refresher:
|
/* Important terminology refresher:
|
||||||
* A function requires paramaters.
|
* A function requires parameters.
|
||||||
* To call a function, you supply arguments.
|
* To call a function, you supply arguments.
|
||||||
*/
|
*/
|
||||||
TypePackIterator argIter = begin(argPack);
|
TypePackIterator argIter = begin(argPack);
|
||||||
|
@ -1025,7 +1025,7 @@ void Unifier::tryUnifySealedTables(TypeId left, TypeId right, bool isIntersectio
|
|||||||
// If the superTy/left is an immediate part of an intersection type, do not do extra-property check.
|
// If the superTy/left is an immediate part of an intersection type, do not do extra-property check.
|
||||||
// Otherwise, we would falsely generate an extra-property-error for 's' in this code:
|
// Otherwise, we would falsely generate an extra-property-error for 's' in this code:
|
||||||
// local a: {n: number} & {s: string} = {n=1, s=""}
|
// local a: {n: number} & {s: string} = {n=1, s=""}
|
||||||
// When checking agaist the table '{n: number}'.
|
// When checking against the table '{n: number}'.
|
||||||
if (!isIntersection && lt->state != TableState::Unsealed && !lt->indexer)
|
if (!isIntersection && lt->state != TableState::Unsealed && !lt->indexer)
|
||||||
{
|
{
|
||||||
// Check for extra properties in the subTy
|
// Check for extra properties in the subTy
|
||||||
|
@ -1535,7 +1535,7 @@ AstType* Parser::parseSimpleTypeAnnotation()
|
|||||||
{
|
{
|
||||||
Location location = lexer.current().location;
|
Location location = lexer.current().location;
|
||||||
|
|
||||||
// For a missing type annoation, capture 'space' between last token and the next one
|
// For a missing type annotation, capture 'space' between last token and the next one
|
||||||
location = Location(lexer.previousLocation().end, lexer.current().location.begin);
|
location = Location(lexer.previousLocation().end, lexer.current().location.begin);
|
||||||
|
|
||||||
return reportTypeAnnotationError(location, {}, /*isMissing*/ true, "Expected type, got %s", lexer.current().toString().c_str());
|
return reportTypeAnnotationError(location, {}, /*isMissing*/ true, "Expected type, got %s", lexer.current().toString().c_str());
|
||||||
|
@ -208,14 +208,14 @@ enum LuauOpcode
|
|||||||
LOP_MODK,
|
LOP_MODK,
|
||||||
LOP_POWK,
|
LOP_POWK,
|
||||||
|
|
||||||
// AND, OR: perform `and` or `or` operation (selecting first or second register based on whether the first one is truthful) and put the result into target register
|
// AND, OR: perform `and` or `or` operation (selecting first or second register based on whether the first one is truthy) and put the result into target register
|
||||||
// A: target register
|
// A: target register
|
||||||
// B: source register 1
|
// B: source register 1
|
||||||
// C: source register 2
|
// C: source register 2
|
||||||
LOP_AND,
|
LOP_AND,
|
||||||
LOP_OR,
|
LOP_OR,
|
||||||
|
|
||||||
// ANDK, ORK: perform `and` or `or` operation (selecting source register or constant based on whether the source register is truthful) and put the result into target register
|
// ANDK, ORK: perform `and` or `or` operation (selecting source register or constant based on whether the source register is truthy) and put the result into target register
|
||||||
// A: target register
|
// A: target register
|
||||||
// B: source register
|
// B: source register
|
||||||
// C: constant table index (0..255)
|
// C: constant table index (0..255)
|
||||||
|
@ -712,9 +712,9 @@ struct Compiler
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compile expr to target temp register
|
// compile expr to target temp register
|
||||||
// if the expr (or not expr if onlyTruth is false) is truthful, jump via skipJump
|
// if the expr (or not expr if onlyTruth is false) is truthy, jump via skipJump
|
||||||
// if the expr (or not expr if onlyTruth is false) is falseful, fall through (target isn't guaranteed to be updated in this case)
|
// if the expr (or not expr if onlyTruth is false) is falsy, fall through (target isn't guaranteed to be updated in this case)
|
||||||
// if target is omitted, then the jump behavior is the same - skipJump or fallthrough depending on the truthfulness of the expression
|
// if target is omitted, then the jump behavior is the same - skipJump or fallthrough depending on the truthiness of the expression
|
||||||
void compileConditionValue(AstExpr* node, const uint8_t* target, std::vector<size_t>& skipJump, bool onlyTruth)
|
void compileConditionValue(AstExpr* node, const uint8_t* target, std::vector<size_t>& skipJump, bool onlyTruth)
|
||||||
{
|
{
|
||||||
// Optimization: we don't need to compute constant values
|
// Optimization: we don't need to compute constant values
|
||||||
@ -722,7 +722,7 @@ struct Compiler
|
|||||||
|
|
||||||
if (cv && cv->type != Constant::Type_Unknown)
|
if (cv && cv->type != Constant::Type_Unknown)
|
||||||
{
|
{
|
||||||
// note that we only need to compute the value if it's truthful; otherwise we cal fall through
|
// note that we only need to compute the value if it's truthy; otherwise we cal fall through
|
||||||
if (cv->isTruthful() == onlyTruth)
|
if (cv->isTruthful() == onlyTruth)
|
||||||
{
|
{
|
||||||
if (target)
|
if (target)
|
||||||
@ -741,7 +741,7 @@ struct Compiler
|
|||||||
case AstExprBinary::And:
|
case AstExprBinary::And:
|
||||||
case AstExprBinary::Or:
|
case AstExprBinary::Or:
|
||||||
{
|
{
|
||||||
// disambiguation: there's 4 cases (we only need truthful or falseful results based on onlyTruth)
|
// disambiguation: there's 4 cases (we only need truthy or falsy results based on onlyTruth)
|
||||||
// onlyTruth = 1: a and b transforms to a ? b : dontcare
|
// onlyTruth = 1: a and b transforms to a ? b : dontcare
|
||||||
// onlyTruth = 1: a or b transforms to a ? a : a
|
// onlyTruth = 1: a or b transforms to a ? a : a
|
||||||
// onlyTruth = 0: a and b transforms to !a ? a : b
|
// onlyTruth = 0: a and b transforms to !a ? a : b
|
||||||
@ -785,8 +785,8 @@ struct Compiler
|
|||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
// since target is a temp register, we'll initialize it to 1, and then jump if the comparison is true
|
// since target is a temp register, we'll initialize it to 1, and then jump if the comparison is true
|
||||||
// if the comparison is false, we'll fallthrough and target will still be 1 but target has unspecified value for falseful results
|
// if the comparison is false, we'll fallthrough and target will still be 1 but target has unspecified value for falsy results
|
||||||
// when we only care about falseful values instead of truthful values, the process is the same but with flipped conditionals
|
// when we only care about falsy values instead of truthy values, the process is the same but with flipped conditionals
|
||||||
bytecode.emitABC(LOP_LOADB, *target, onlyTruth ? 1 : 0, 0);
|
bytecode.emitABC(LOP_LOADB, *target, onlyTruth ? 1 : 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ To gain advantage of many performance improvements it's highly recommended to us
|
|||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
Luau has an internal test suite; in CMake builds it is split into two targets, `Luau.UnitTest` (for bytecode compiler and type checker/linter tests) and `Luau.Conformance` (for VM tests). The unit tests are written in C++, whereas the conformance tests are largerly written in Luau (see `tests/conformance`).
|
Luau has an internal test suite; in CMake builds it is split into two targets, `Luau.UnitTest` (for bytecode compiler and type checker/linter tests) and `Luau.Conformance` (for VM tests). The unit tests are written in C++, whereas the conformance tests are largely written in Luau (see `tests/conformance`).
|
||||||
|
|
||||||
Makefile builds combine both into a single target and can be ran via `make test`.
|
Makefile builds combine both into a single target and can be ran via `make test`.
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ struct luaL_Buffer
|
|||||||
char buffer[LUA_BUFFERSIZE];
|
char buffer[LUA_BUFFERSIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
// when internal buffer storage is exhaused, a mutable string value 'storage' will be placed on the stack
|
// when internal buffer storage is exhausted, a mutable string value 'storage' will be placed on the stack
|
||||||
// in general, functions expect the mutable string buffer to be placed on top of the stack (top-1)
|
// in general, functions expect the mutable string buffer to be placed on top of the stack (top-1)
|
||||||
// with the exception of luaL_addvalue that expects the value at the top and string buffer further away (top-2)
|
// with the exception of luaL_addvalue that expects the value at the top and string buffer further away (top-2)
|
||||||
// functions that accept a 'boxloc' support string buffer placement at any location in the stack
|
// functions that accept a 'boxloc' support string buffer placement at any location in the stack
|
||||||
|
@ -313,7 +313,7 @@ static size_t getnextbuffersize(lua_State* L, size_t currentsize, size_t desired
|
|||||||
{
|
{
|
||||||
size_t newsize = currentsize + currentsize / 2;
|
size_t newsize = currentsize + currentsize / 2;
|
||||||
|
|
||||||
// check for size oveflow
|
// check for size overflow
|
||||||
if (SIZE_MAX - desiredsize < currentsize)
|
if (SIZE_MAX - desiredsize < currentsize)
|
||||||
luaL_error(L, "buffer too large");
|
luaL_error(L, "buffer too large");
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ static int costatus(lua_State* L, lua_State* co)
|
|||||||
return CO_SUS;
|
return CO_SUS;
|
||||||
if (co->status == LUA_BREAK)
|
if (co->status == LUA_BREAK)
|
||||||
return CO_NOR;
|
return CO_NOR;
|
||||||
if (co->status != 0) /* some error occured */
|
if (co->status != 0) /* some error occurred */
|
||||||
return CO_DEAD;
|
return CO_DEAD;
|
||||||
if (co->ci != co->base_ci) /* does it have frames? */
|
if (co->ci != co->base_ci) /* does it have frames? */
|
||||||
return CO_NOR;
|
return CO_NOR;
|
||||||
|
@ -532,7 +532,7 @@ int luaD_pcall(lua_State* L, Pfunc func, void* u, ptrdiff_t old_top, ptrdiff_t e
|
|||||||
status = LUA_ERRERR;
|
status = LUA_ERRERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// an error occured, check if we have a protected error callback
|
// an error occurred, check if we have a protected error callback
|
||||||
if (L->global->cb.debugprotectederror)
|
if (L->global->cb.debugprotectederror)
|
||||||
{
|
{
|
||||||
L->global->cb.debugprotectederror(L);
|
L->global->cb.debugprotectederror(L);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
/* results from luaD_precall */
|
/* results from luaD_precall */
|
||||||
#define PCRLUA 0 /* initiated a call to a Lua function */
|
#define PCRLUA 0 /* initiated a call to a Lua function */
|
||||||
#define PCRC 1 /* did a call to a C function */
|
#define PCRC 1 /* did a call to a C function */
|
||||||
#define PCRYIELD 2 /* C funtion yielded */
|
#define PCRYIELD 2 /* C function yielded */
|
||||||
|
|
||||||
/* type of protected functions, to be ran by `runprotected' */
|
/* type of protected functions, to be ran by `runprotected' */
|
||||||
typedef void (*Pfunc)(lua_State* L, void* ud);
|
typedef void (*Pfunc)(lua_State* L, void* ud);
|
||||||
|
@ -76,7 +76,7 @@ UpVal* luaF_findupval(lua_State* L, StkId level)
|
|||||||
if (p->v == level)
|
if (p->v == level)
|
||||||
{ /* found a corresponding upvalue? */
|
{ /* found a corresponding upvalue? */
|
||||||
if (isdead(g, obj2gco(p))) /* is it dead? */
|
if (isdead(g, obj2gco(p))) /* is it dead? */
|
||||||
changewhite(obj2gco(p)); /* ressurect it */
|
changewhite(obj2gco(p)); /* resurrect it */
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
pp = &p->next;
|
pp = &p->next;
|
||||||
|
@ -884,7 +884,7 @@ void luaC_step(lua_State* L, bool assist)
|
|||||||
g->gcstats.currcycle.explicitwork += lim;
|
g->gcstats.currcycle.explicitwork += lim;
|
||||||
|
|
||||||
int lastgcstate = g->gcstate;
|
int lastgcstate = g->gcstate;
|
||||||
double lastttimestamp = lua_clock();
|
double lasttimestamp = lua_clock();
|
||||||
|
|
||||||
// always perform at least one single step
|
// always perform at least one single step
|
||||||
do
|
do
|
||||||
@ -899,14 +899,14 @@ void luaC_step(lua_State* L, bool assist)
|
|||||||
|
|
||||||
double now = lua_clock();
|
double now = lua_clock();
|
||||||
|
|
||||||
recordGcStateTime(g, lastgcstate, now - lastttimestamp, assist);
|
recordGcStateTime(g, lastgcstate, now - lasttimestamp, assist);
|
||||||
|
|
||||||
lastttimestamp = now;
|
lasttimestamp = now;
|
||||||
lastgcstate = g->gcstate;
|
lastgcstate = g->gcstate;
|
||||||
}
|
}
|
||||||
} while (lim > 0 && g->gcstate != GCSpause);
|
} while (lim > 0 && g->gcstate != GCSpause);
|
||||||
|
|
||||||
recordGcStateTime(g, lastgcstate, lua_clock() - lastttimestamp, assist);
|
recordGcStateTime(g, lastgcstate, lua_clock() - lasttimestamp, assist);
|
||||||
|
|
||||||
// at the end of the last cycle
|
// at the end of the last cycle
|
||||||
if (g->gcstate == GCSpause)
|
if (g->gcstate == GCSpause)
|
||||||
|
@ -28,7 +28,7 @@ LUAU_FASTFLAG(LuauGcFullSkipInactiveThreads)
|
|||||||
#define keepinvariant(g) ((g)->gcstate == GCSpropagate || (g)->gcstate == GCSpropagateagain)
|
#define keepinvariant(g) ((g)->gcstate == GCSpropagate || (g)->gcstate == GCSpropagateagain)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** some userful bit tricks
|
** some useful bit tricks
|
||||||
*/
|
*/
|
||||||
#define resetbits(x, m) ((x) &= cast_to(uint8_t, ~(m)))
|
#define resetbits(x, m) ((x) &= cast_to(uint8_t, ~(m)))
|
||||||
#define setbits(x, m) ((x) |= (m))
|
#define setbits(x, m) ((x) |= (m))
|
||||||
|
@ -21,7 +21,7 @@ local bench = script and require(script.Parent.bench_support) or require("bench_
|
|||||||
-- This implementation of the DeltaBlue benchmark is derived
|
-- This implementation of the DeltaBlue benchmark is derived
|
||||||
-- from the Smalltalk implementation by John Maloney and Mario
|
-- from the Smalltalk implementation by John Maloney and Mario
|
||||||
-- Wolczko. Some parts have been translated directly, whereas
|
-- Wolczko. Some parts have been translated directly, whereas
|
||||||
-- others have been modified more aggresively to make it feel
|
-- others have been modified more aggressively to make it feel
|
||||||
-- more like a JavaScript program.
|
-- more like a JavaScript program.
|
||||||
|
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ end
|
|||||||
--
|
--
|
||||||
-- Normal constraints are not input constraints. An input constraint
|
-- Normal constraints are not input constraints. An input constraint
|
||||||
-- is one that depends on external state, such as the mouse, the
|
-- is one that depends on external state, such as the mouse, the
|
||||||
-- keybord, a clock, or some arbitraty piece of imperative code.
|
-- keyboard, a clock, or some arbitrary piece of imperative code.
|
||||||
--
|
--
|
||||||
function Constraint:isInput ()
|
function Constraint:isInput ()
|
||||||
return false
|
return false
|
||||||
@ -614,7 +614,7 @@ end
|
|||||||
|
|
||||||
--
|
--
|
||||||
-- Attempt to satisfy the given constraint and, if successful,
|
-- Attempt to satisfy the given constraint and, if successful,
|
||||||
-- incrementally update the dataflow graph. Details: If satifying
|
-- incrementally update the dataflow graph. Details: If satisfying
|
||||||
-- the constraint is successful, it may override a weaker constraint
|
-- the constraint is successful, it may override a weaker constraint
|
||||||
-- on its output. The algorithm attempts to resatisfy that
|
-- on its output. The algorithm attempts to resatisfy that
|
||||||
-- constraint using some other method. This process is repeated
|
-- constraint using some other method. This process is repeated
|
||||||
@ -837,7 +837,7 @@ end
|
|||||||
-- In case 1, the added constraint is stronger than the stay
|
-- In case 1, the added constraint is stronger than the stay
|
||||||
-- constraint and values must propagate down the entire length of the
|
-- constraint and values must propagate down the entire length of the
|
||||||
-- chain. In case 2, the added constraint is weaker than the stay
|
-- chain. In case 2, the added constraint is weaker than the stay
|
||||||
-- constraint so it cannot be accomodated. The cost in this case is,
|
-- constraint so it cannot be accommodated. The cost in this case is,
|
||||||
-- of course, very low. Typical situations lie somewhere between these
|
-- of course, very low. Typical situations lie somewhere between these
|
||||||
-- two extremes.
|
-- two extremes.
|
||||||
--
|
--
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
-- Modificatin to be compatible with Lua 5.3
|
-- Modification to be compatible with Lua 5.3
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
local bench = script and require(script.Parent.bench_support) or require("bench_support")
|
local bench = script and require(script.Parent.bench_support) or require("bench_support")
|
||||||
|
@ -18,7 +18,7 @@ While most library functions are provided as part of a library like `table`, a f
|
|||||||
function assert<T>(value: T, message: string?): T
|
function assert<T>(value: T, message: string?): T
|
||||||
```
|
```
|
||||||
|
|
||||||
`assert` checks if the value is truthful; if it's not (which means it's `false` or `nil`), it raises an error. The error message can be customized with an optional parameter.
|
`assert` checks if the value is truthy; if it's not (which means it's `false` or `nil`), it raises an error. The error message can be customized with an optional parameter.
|
||||||
Upon success the function returns the `condition` argument.
|
Upon success the function returns the `condition` argument.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -146,7 +146,7 @@ Returns the triple (generator, state, nil) that can be used to traverse the tabl
|
|||||||
function pcall(f: function, args: ...any): (boolean, ...any)
|
function pcall(f: function, args: ...any): (boolean, ...any)
|
||||||
```
|
```
|
||||||
|
|
||||||
Calls function `f` with parameters `args`. If the function suceeds, returns `true` followed by all return values of `f`. If the function raises an error, returns `false` followed by the error object.
|
Calls function `f` with parameters `args`. If the function succeeds, returns `true` followed by all return values of `f`. If the function raises an error, returns `false` followed by the error object.
|
||||||
Note that `f` can yield, which results in the entire coroutine yielding as well.
|
Note that `f` can yield, which results in the entire coroutine yielding as well.
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -205,7 +205,7 @@ Rounds `n` upwards to the next integer boundary.
|
|||||||
function math.cosh(n: number): number
|
function math.cosh(n: number): number
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns the hyberbolic cosine of `n`.
|
Returns the hyperbolic cosine of `n`.
|
||||||
|
|
||||||
```
|
```
|
||||||
function math.cos(n: number): number
|
function math.cos(n: number): number
|
||||||
@ -792,4 +792,4 @@ function debug.traceback(co: thread, msg: string?, level: number?): string
|
|||||||
function debug.traceback(msg: string?, level: number?): string
|
function debug.traceback(msg: string?, level: number?): string
|
||||||
```
|
```
|
||||||
|
|
||||||
Produces a stringifed callstack of the given thread, or the current thread, starting with level `level`. If `msg` is specified, then the resulting callstack includes the string before the callstack output, separated with a newline. The format of the callstack is human-readable and subject to change.
|
Produces a stringified callstack of the given thread, or the current thread, starting with level `level`. If `msg` is specified, then the resulting callstack includes the string before the callstack output, separated with a newline. The format of the callstack is human-readable and subject to change.
|
||||||
|
@ -88,7 +88,7 @@ The mechanism works by directly invoking a highly specialized and optimized impl
|
|||||||
|
|
||||||
As a result, builtin calls are very fast in Luau - they are still slightly slower than core instructions such as arithmetic operations, but only slightly so. The set of fastcall builtins is slowly expanding over time and as of this writing contains `assert`, `type`, `typeof`, `rawget`/`rawset`/`rawequal`, all functions from `math` and `bit32`, and some functions from `string` and `table` library.
|
As a result, builtin calls are very fast in Luau - they are still slightly slower than core instructions such as arithmetic operations, but only slightly so. The set of fastcall builtins is slowly expanding over time and as of this writing contains `assert`, `type`, `typeof`, `rawget`/`rawset`/`rawequal`, all functions from `math` and `bit32`, and some functions from `string` and `table` library.
|
||||||
|
|
||||||
> Note: The partial specialization mechanism is cute in that for `assert`, it only specializes on truthful conditions; hopefully performance of `assert(false)` isn't crucial for most code!
|
> Note: The partial specialization mechanism is cute in that for `assert`, it only specializes on truthy conditions; hopefully performance of `assert(false)` isn't crucial for most code!
|
||||||
|
|
||||||
## Optimized table iteration
|
## Optimized table iteration
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ Today Luau provides only one method to get the callstack, `debug.traceback`. Thi
|
|||||||
|
|
||||||
There are a few cases where this can be inconvenient:
|
There are a few cases where this can be inconvenient:
|
||||||
|
|
||||||
- Sometimes it is useful to pass the resulting call stack to some system expecting a structured input, e.g. for crash aggreggation
|
- Sometimes it is useful to pass the resulting call stack to some system expecting a structured input, e.g. for crash aggregation
|
||||||
- Sometimes it is useful to use the information about the caller for logging or filtering purposes; in these cases using just the script name can be useful, and getting script name out of the traceback is slow and imprecise
|
- Sometimes it is useful to use the information about the caller for logging or filtering purposes; in these cases using just the script name can be useful, and getting script name out of the traceback is slow and imprecise
|
||||||
|
|
||||||
Additionally, in some cases instead of getting the information (such as script or function name) from the callstack, it can be useful to get it from a function object for diagnostic purposes. For example, maybe you want to call a callback and if it doesn't return expected results, display a user-friendly error message that contains the function name & script location - these aren't possible today at all.
|
Additionally, in some cases instead of getting the information (such as script or function name) from the callstack, it can be useful to get it from a function object for diagnostic purposes. For example, maybe you want to call a callback and if it doesn't return expected results, display a user-friendly error message that contains the function name & script location - these aren't possible today at all.
|
||||||
|
@ -44,7 +44,7 @@ To limit the use of `table.freeze` to cases when table contents can be freely ma
|
|||||||
|
|
||||||
Exposing the internal "readonly" feature may have an impact on interoperability between scripts - for example, it becomes possible to freeze some tables that scripts may be expecting to have write access to from other scripts. Since we don't provide a way to unfreeze tables and freezing a table with a locked metatable fails, in theory the impact should not be any worse than allowing to change a metatable, but the full extents are unclear.
|
Exposing the internal "readonly" feature may have an impact on interoperability between scripts - for example, it becomes possible to freeze some tables that scripts may be expecting to have write access to from other scripts. Since we don't provide a way to unfreeze tables and freezing a table with a locked metatable fails, in theory the impact should not be any worse than allowing to change a metatable, but the full extents are unclear.
|
||||||
|
|
||||||
There may be existing code in the VM that allows changing frozen tables in ways that are benign to the current sanboxing code, but expose a "gap" in the implementation that becomes significant with this feature; thus we would need to audit all table writes when implementing this.
|
There may be existing code in the VM that allows changing frozen tables in ways that are benign to the current sandboxing code, but expose a "gap" in the implementation that becomes significant with this feature; thus we would need to audit all table writes when implementing this.
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ end
|
|||||||
|
|
||||||
These rules are simple to implement. In any Lua parser there is already a point where you have to disambiguate an identifier that starts an assignment statement (`foo = 5`) from an identifier that starts a function call (`foo(5)`). It's one of the few, if not the only, place in the Lua grammar where single token lookahead is not sufficient to parse Lua, because you could have `foo.bar(5)` or `foo.bar=5` or `foo.bar(5)[6] = 7`.
|
These rules are simple to implement. In any Lua parser there is already a point where you have to disambiguate an identifier that starts an assignment statement (`foo = 5`) from an identifier that starts a function call (`foo(5)`). It's one of the few, if not the only, place in the Lua grammar where single token lookahead is not sufficient to parse Lua, because you could have `foo.bar(5)` or `foo.bar=5` or `foo.bar(5)[6] = 7`.
|
||||||
|
|
||||||
Because of this, we need to parse the entire left hand side of an assignment statement (primaryexpr in Lua's BNF) and then check if it was a function call; if not, we'd expect it to be an assignment statement.
|
Because of this, we need to parse the entire left hand side of an assignment statement (primaryexp in Lua's BNF) and then check if it was a function call; if not, we'd expect it to be an assignment statement.
|
||||||
|
|
||||||
Alternatively in this specific case we could parse "continue", parse the next token, and if it's one of the exclusion list above, roll the parser state back and re-parse the non-continue statement. Our lexer currently doesn't support rollbacks but it's also an easy strategy that other implementations might employ for `continue` specifically.
|
Alternatively in this specific case we could parse "continue", parse the next token, and if it's one of the exclusion list above, roll the parser state back and re-parse the non-continue statement. Our lexer currently doesn't support rollbacks but it's also an easy strategy that other implementations might employ for `continue` specifically.
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ Introduce a form of ternary conditional using `if cond then value else alternati
|
|||||||
|
|
||||||
Luau does not have a first-class ternary operator; when a ternary operator is needed, it is usually emulated with `and/or` expression, such as `cond and value or alternative`.
|
Luau does not have a first-class ternary operator; when a ternary operator is needed, it is usually emulated with `and/or` expression, such as `cond and value or alternative`.
|
||||||
|
|
||||||
This expression evaluates to `value` if `cond` and `value` are truthful, and `alternative` otherwise. In particular it means that when `value` is `false` or `nil`, the result of the entire expression is `alternative` even when `cond` is truthful - which doesn't match the expected ternary logic and is a frequent source of subtle errors.
|
This expression evaluates to `value` if `cond` and `value` are truthy, and `alternative` otherwise. In particular it means that when `value` is `false` or `nil`, the result of the entire expression is `alternative` even when `cond` is truthy - which doesn't match the expected ternary logic and is a frequent source of subtle errors.
|
||||||
|
|
||||||
Instead of `and/or`, `if/else` statement can be used but since that requires a separate mutable variable, this option isn't ergonomic. An immediately invoked function expression is also unergonomic and results in performance issues at runtime.
|
Instead of `and/or`, `if/else` statement can be used but since that requires a separate mutable variable, this option isn't ergonomic. An immediately invoked function expression is also unergonomic and results in performance issues at runtime.
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ To solve these problems, we propose introducing a first-class ternary conditiona
|
|||||||
|
|
||||||
Concretely, the `if-then-else` expression must match `if <expr> then <expr> else <expr>`; it can also contain an arbitrary number of `elseif` clauses, like `if <expr> then <expr> elseif <expr> then <expr> else <expr>`. Note that in either case, `else` is mandatory.
|
Concretely, the `if-then-else` expression must match `if <expr> then <expr> else <expr>`; it can also contain an arbitrary number of `elseif` clauses, like `if <expr> then <expr> elseif <expr> then <expr> else <expr>`. Note that in either case, `else` is mandatory.
|
||||||
|
|
||||||
The result of the expression is the then-expression when condition is truthful (not `nil` or `false`) and else-expression otherwise. Only one of the two possible resulting expressions is evaluated.
|
The result of the expression is the then-expression when condition is truthy (not `nil` or `false`) and else-expression otherwise. Only one of the two possible resulting expressions is evaluated.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_2_args_o
|
|||||||
CHECK_EQ(typeChecker.stringType, requireType("s"));
|
CHECK_EQ(typeChecker.stringType, requireType("s"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "table_insert_corrrectly_infers_type_of_array_3_args_overload")
|
TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_3_args_overload")
|
||||||
{
|
{
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
local t = {}
|
local t = {}
|
||||||
|
@ -14,7 +14,7 @@ using namespace Luau;
|
|||||||
|
|
||||||
TEST_SUITE_BEGIN("ProvisionalTests");
|
TEST_SUITE_BEGIN("ProvisionalTests");
|
||||||
|
|
||||||
// These tests check for behavior that differes from the final behavior we'd
|
// These tests check for behavior that differs from the final behavior we'd
|
||||||
// like to have. They serve to document the current state of the typechecker.
|
// like to have. They serve to document the current state of the typechecker.
|
||||||
// When making future improvements, its very likely these tests will break and
|
// When making future improvements, its very likely these tests will break and
|
||||||
// will need to be replaced.
|
// will need to be replaced.
|
||||||
|
@ -405,7 +405,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_error_on_factory_not_returning_the_right
|
|||||||
|
|
||||||
for p in primes2() do print(p) end -- mismatch in argument types, prime_iter takes {}, number, we are given {}, string
|
for p in primes2() do print(p) end -- mismatch in argument types, prime_iter takes {}, number, we are given {}, string
|
||||||
|
|
||||||
for p in primes3() do print(p) end -- no errror
|
for p in primes3() do print(p) end -- no error
|
||||||
)");
|
)");
|
||||||
|
|
||||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||||
@ -2582,7 +2582,7 @@ TEST_CASE_FIXTURE(Fixture, "toposort_doesnt_break_mutual_recursion")
|
|||||||
--!strict
|
--!strict
|
||||||
local x = nil
|
local x = nil
|
||||||
function f() g() end
|
function f() g() end
|
||||||
-- make sure print(x) doen't get toposorted here, breaking the mutual block
|
-- make sure print(x) doesn't get toposorted here, breaking the mutual block
|
||||||
function g() x = f end
|
function g() x = f end
|
||||||
print(x)
|
print(x)
|
||||||
)");
|
)");
|
||||||
@ -3062,7 +3062,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_while")
|
|||||||
CHECK_EQ(us->name, "a");
|
CHECK_EQ(us->name, "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "ipairs_produces_integral_indeces")
|
TEST_CASE_FIXTURE(Fixture, "ipairs_produces_integral_indices")
|
||||||
{
|
{
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
local key
|
local key
|
||||||
@ -4885,7 +4885,7 @@ f(function(a) return a.x + a.y end)
|
|||||||
|
|
||||||
LUAU_REQUIRE_NO_ERRORS(result);
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
|
|
||||||
// An optional funciton is accepted, but since we already provide a function, nil can be ignored
|
// An optional function is accepted, but since we already provide a function, nil can be ignored
|
||||||
result = check(R"(
|
result = check(R"(
|
||||||
type Table = { x: number, y: number }
|
type Table = { x: number, y: number }
|
||||||
local function f(a: ((Table) -> number)?) if a then return a({x = 1, y = 2}) else return 0 end end
|
local function f(a: ((Table) -> number)?) if a then return a({x = 1, y = 2}) else return 0 end end
|
||||||
@ -4913,7 +4913,7 @@ f(function(a: number, b, c) return c and a + b or b - a end)
|
|||||||
|
|
||||||
LUAU_REQUIRE_NO_ERRORS(result);
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
|
|
||||||
// Anonymous function has a varyadic pack
|
// Anonymous function has a variadic pack
|
||||||
result = check(R"(
|
result = check(R"(
|
||||||
type Table = { x: number, y: number }
|
type Table = { x: number, y: number }
|
||||||
local function f(a: (Table) -> number) return a({x = 1, y = 2}) end
|
local function f(a: (Table) -> number) return a({x = 1, y = 2}) end
|
||||||
@ -4932,7 +4932,7 @@ f(function(a, b, c, ...) return a + b end)
|
|||||||
LUAU_REQUIRE_ERRORS(result);
|
LUAU_REQUIRE_ERRORS(result);
|
||||||
CHECK_EQ("Type '(number, number, a) -> number' could not be converted into '(number, number) -> number'", toString(result.errors[0]));
|
CHECK_EQ("Type '(number, number, a) -> number' could not be converted into '(number, number) -> number'", toString(result.errors[0]));
|
||||||
|
|
||||||
// Infer from varyadic packs into elements
|
// Infer from variadic packs into elements
|
||||||
result = check(R"(
|
result = check(R"(
|
||||||
function f(a: (...number) -> number) return a(1, 2) end
|
function f(a: (...number) -> number) return a(1, 2) end
|
||||||
f(function(a, b) return a + b end)
|
f(function(a, b) return a + b end)
|
||||||
@ -4940,7 +4940,7 @@ f(function(a, b) return a + b end)
|
|||||||
|
|
||||||
LUAU_REQUIRE_NO_ERRORS(result);
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
|
|
||||||
// Infer from varyadic packs into varyadic packs
|
// Infer from variadic packs into variadic packs
|
||||||
result = check(R"(
|
result = check(R"(
|
||||||
type Table = { x: number, y: number }
|
type Table = { x: number, y: number }
|
||||||
function f(a: (...Table) -> number) return a({x = 1, y = 2}, {x = 3, y = 4}) end
|
function f(a: (...Table) -> number) return a({x = 1, y = 2}, {x = 3, y = 4}) end
|
||||||
|
@ -52,7 +52,7 @@ TEST_CASE_FIXTURE(Fixture, "allow_more_specific_assign")
|
|||||||
LUAU_REQUIRE_NO_ERRORS(result);
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "disallow_less_specifc_assign")
|
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign")
|
||||||
{
|
{
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
local a:number = 10
|
local a:number = 10
|
||||||
@ -63,7 +63,7 @@ TEST_CASE_FIXTURE(Fixture, "disallow_less_specifc_assign")
|
|||||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "disallow_less_specifc_assign2")
|
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign2")
|
||||||
{
|
{
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
local a:number? = 10
|
local a:number? = 10
|
||||||
|
@ -319,7 +319,7 @@ end
|
|||||||
assert(a == 5^4)
|
assert(a == 5^4)
|
||||||
|
|
||||||
|
|
||||||
-- access to locals of collected corroutines
|
-- access to locals of collected coroutines
|
||||||
local C = {}; setmetatable(C, {__mode = "kv"})
|
local C = {}; setmetatable(C, {__mode = "kv"})
|
||||||
local x = coroutine.wrap (function ()
|
local x = coroutine.wrap (function ()
|
||||||
local a = 10
|
local a = 10
|
||||||
|
@ -185,7 +185,7 @@ end
|
|||||||
assert(a == 5^4)
|
assert(a == 5^4)
|
||||||
|
|
||||||
|
|
||||||
-- access to locals of collected corroutines
|
-- access to locals of collected coroutines
|
||||||
local C = {}; setmetatable(C, {__mode = "kv"})
|
local C = {}; setmetatable(C, {__mode = "kv"})
|
||||||
local x = coroutine.wrap (function ()
|
local x = coroutine.wrap (function ()
|
||||||
local a = 10
|
local a = 10
|
||||||
|
@ -277,7 +277,7 @@ do
|
|||||||
assert(getmetatable(o) == tt)
|
assert(getmetatable(o) == tt)
|
||||||
-- create new objects during GC
|
-- create new objects during GC
|
||||||
local a = 'xuxu'..(10+3)..'joao', {}
|
local a = 'xuxu'..(10+3)..'joao', {}
|
||||||
___Glob = o -- ressurect object!
|
___Glob = o -- resurrect object!
|
||||||
newproxy(o) -- creates a new one with same metatable
|
newproxy(o) -- creates a new one with same metatable
|
||||||
print(">>> closing state " .. "<<<\n")
|
print(">>> closing state " .. "<<<\n")
|
||||||
end
|
end
|
||||||
|
@ -117,7 +117,7 @@ if rawget(_G, "querytab") then
|
|||||||
local t = querytab(a)
|
local t = querytab(a)
|
||||||
|
|
||||||
for k,_ in pairs(a) do a[k] = nil end
|
for k,_ in pairs(a) do a[k] = nil end
|
||||||
collectgarbage() -- restore GC and collect dead fiels in `a'
|
collectgarbage() -- restore GC and collect dead fields in `a'
|
||||||
for i=0,t-1 do
|
for i=0,t-1 do
|
||||||
local k = querytab(a, i)
|
local k = querytab(a, i)
|
||||||
assert(k == nil or type(k) == 'number' or k == 'alo')
|
assert(k == nil or type(k) == 'number' or k == 'alo')
|
||||||
|
@ -172,7 +172,7 @@ end
|
|||||||
|
|
||||||
a = nil
|
a = nil
|
||||||
|
|
||||||
-- testing implicit convertions
|
-- testing implicit conversions
|
||||||
|
|
||||||
local a,b = '10', '20'
|
local a,b = '10', '20'
|
||||||
assert(a*b == 200 and a+b == 30 and a-b == -10 and a/b == 0.5 and -b == -20)
|
assert(a*b == 200 and a+b == 30 and a-b == -10 and a/b == 0.5 and -b == -20)
|
||||||
|
@ -21,9 +21,9 @@ a,b = string.find('alo', '')
|
|||||||
assert(a == 1 and b == 0)
|
assert(a == 1 and b == 0)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
|
a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
|
||||||
assert(a == 1 and b == 1)
|
assert(a == 1 and b == 1)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the midle
|
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the middle
|
||||||
assert(a == 5 and b == 7)
|
assert(a == 5 and b == 7)
|
||||||
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the midle
|
a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the middle
|
||||||
assert(a == 9 and b == 11)
|
assert(a == 9 and b == 11)
|
||||||
a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
|
a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
|
||||||
assert(a == 9 and b == 11);
|
assert(a == 9 and b == 11);
|
||||||
|
Loading…
Reference in New Issue
Block a user