Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 86 additions & 49 deletions docs/advanced/compiler-annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,55 +137,6 @@ local inst = MyConstructor(3)

</SideBySide>

## @luaIterator

**Target elements:** `(declare) interface`

Denotes a type is a Lua iterator. When an object of a type with this annotation is used in a for...of statement, it will transpile directly as a lua iterator in a for...in statement, instead of being treated as a TypeScript iterable. Typically, this is used on an interface that extends `Iterable` or `Array` so that TypeScript will allow it to be used in a for...of statement.

**Example**

<SideBySide>

<!-- prettier-ignore -->
```typescript
/** @luaIterator */
type LuaIterable<T> = Iterable<T>;

declare function myIterator(): LuaIterable<string>;
for (const s of myIterator()) {}
```

```lua
for s in myIterator() do end
```

</SideBySide>

This can also be combined with [@tupleReturn](#tuplereturn), if the iterator returns multiple values.

**Example**

<SideBySide>

<!-- prettier-ignore -->
```typescript
/** @luaIterator @tupleReturn */
type LuaTupleIterable<T extends any[]> = Iterable<T>;

declare namespace string {
function gmatch(s: string, pattern: string): LuaTupleIterable<string[]>;
}

for (const [a, b] of string.gmatch("foo", "(.)(.)")) {}
```

```lua
for a, b in string.gmatch("foo", "(.)(.)") do end
```

</SideBySide>

## @luaTable

**Target elements:** `type`
Expand Down Expand Up @@ -797,3 +748,89 @@ for i = 10, 1, -1 do end
```

</SideBySide>

### @luaIterator

<DeprecatedInVersion deprecated="0.39.0" removed="TBD" />

**Target elements:** `(declare) interface`

Denotes a type is a Lua iterator. When an object of a type with this annotation is used in a for...of statement, it will transpile directly as a lua iterator in a for...in statement, instead of being treated as a TypeScript iterable. Typically, this is used on an interface that extends `Iterable` or `Array` so that TypeScript will allow it to be used in a for...of statement.

**Example**

<SideBySide>

<!-- prettier-ignore -->
```typescript
/** @luaIterator */
type LuaIterator<T> = Iterable<T>;

declare function myIterator(): LuaIterator<string>;
for (const s of myIterator()) {}
```

```lua
for s in myIterator() do end
```

</SideBySide>

This can also be combined with [@tupleReturn](#tuplereturn), if the iterator returns multiple values.

**Example**

<SideBySide>

<!-- prettier-ignore -->
```typescript
/** @luaIterator @tupleReturn */
type LuaTupleIterator<T extends any[]> = Iterable<T>;

declare namespace string {
function gmatch(s: string, pattern: string): LuaTupleIterator<string[]>;
}

for (const [a, b] of string.gmatch("foo", "(.)(.)")) {}
```

```lua
for a, b in string.gmatch("foo", "(.)(.)") do end
```

</SideBySide>

**Upgrade Instructions**

Use the [`LuaIterable` and `LuaMultiReturn` language extensions](language-extensions.md#luaiterable-type) instead of a custom annotated types.

<SideBySide>

<!-- prettier-ignore -->
```typescript
declare function myIterator(): LuaIterable<string>;
for (const s of myIterator()) {}
```

```lua
for s in myIterator() do end
```

</SideBySide>

<SideBySide>

<!-- prettier-ignore -->
```typescript
declare namespace string {
function gmatch(s: string, pattern: string): LuaIterable<LuaMultiReturn<string[]>>;
}

for (const [a, b] of string.gmatch("foo", "(.)(.)")) {}
```

```lua
for a, b in string.gmatch("foo", "(.)(.)") do end
```

</SideBySide>
70 changes: 67 additions & 3 deletions docs/advanced/language-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ start, ____end = string.find("Hello, world!", "world")
Prefer LuaMultiReturn over the similar [@tupleReturn annotation](./compiler-annotations.md#tuplereturn). LuaMultiReturn can do anything tupleReturn can, with the added benefit of being able to distinguish between actual tuple tables and multiple return values in the type system.
:::

### \$multi
### $multi

In order to create a function that returns multiple values it needs to return a `LuaMultiReturn<>` type. This is where the `$multi` function comes in. Calling `$multi` in a return statement will create an instance of the `LuaMultiReturn<>` type:

Expand Down Expand Up @@ -84,6 +84,70 @@ for i = 5, 1, -1 do end

</SideBySide>

## LuaIterable Type

Iterators in Lua work quite differently than in Typescript/Javscript, so a special type is needed to use them.

For example, to declare and use a Lua function that returns an iterator for a set of strings, you can do this:

<SideBySide>

```ts
declare function myIterator(): LuaIterable<string>;

for (const s of myIterator()) {
console.log(s);
}
```

```lua
for s in myIterator() do
print(s)
end
```

</SideBySide>

Some iterators return multiple values each iteration. To declare these, combine `LuaIterable` with [`LuaMultiReturn`](#luamultireturn-type):

<SideBySide>

```ts
declare function myIterator(): LuaIterable<LuaMultiReturn<[string, string]>>;

for (const [a, b] of myIterator()) {
console.log(a, b);
}
```

```lua
for a, b in myIterator() do
print(a, b)
end
```

</SideBySide>

Lua iterators support passing an invisible state object each iteration. If your iterator type does this, you can declare the state type as a second type parameter:

```ts
type MyStateType = ...
declare function myIterator(): LuaIterable<string, MyStateType>;
```

This is only really required if you need to use the iterator outside of a `for...of` loop.

```ts
let [iteratorFunction, state, lastValue] = myIterator();
while (true) {
const value = iteratorFunction(state, lastValue);
console.log(value);
lastValue = value;
}
```

See the [Lua Reference Manual](https://www.lua.org/manual/5.3/manual.html#3.3.5) for more information on Lua for loops.

## Operator Map Types

Lua supports overloading operators on types using [metatable methods](https://www.lua.org/manual/5.4/manual.html#2.4) such as `__add`. But, Javascript and Typescript do not support this. In order to use overloaded operators on types that support them, you can declare special mapping functions in TS that will translate to those operators in Lua.
Expand Down Expand Up @@ -145,15 +209,15 @@ const scaled: Vector = Vector.mul(a, 2);
- LuaAddition / LuaAdditionMethod (`a + b`)
- LuaSubtraction / LuaSubtractionMethod (`a - b`)
- LuaMultiplication / LuaMultiplicationMethod (`a * b`)
- LuaDivision / LuaDivisionMethod (`a /b `)
- LuaDivision / LuaDivisionMethod (`a / b `)
- LuaModulo / LuaModuloMethod (`a % b`)
- LuaPower / LuaPowerMethod (`a ^ b`)
- LuaFloorDivision / LuaFloorDivisionMethod (`a // b`, only when targeting Lua 5.3 or later)
- LuaNegation / LuaNegationMethod (`-x`)
- Bitwise operators (only when targeting Lua 5.3 or later)
- LuaBitwiseAnd / LuaBitwiseAndMethod (`a & b`)
- LuaBitwiseOr / LuaBitwiseOrMethod (`a | b`)
- LuaBitwiseExclusiveOr / LuaBitwiseExclusiveOrMethod (`a ^ b`)
- LuaBitwiseExclusiveOr / LuaBitwiseExclusiveOrMethod (`a ~ b`)
- LuaBitwiseLeftShift / LuaBitwiseLeftShiftMethod (`a << b`)
- LuaBitwiseRightShift / LuaBitwiseRightShiftMethod (`a >> b`)
- LuaBitwiseNot / LuaBitwiseNotMethod (`~x`)
Expand Down