Skip to content

Commit

Permalink
Add Luau language (#6612)
Browse files Browse the repository at this point in the history
* Feature: Add `Luau` language.

* Featire: Add `Luau` code samples.

* Feature: Add the grammar.

* Feature: Add `Luau` to grammar index.

* Fix: Add comment block and change the interpreter.

* Feature: Add new samples in place of the old ones.

* Patch: Slight typo in the header.

* Patch: Header typos again, I'm such a genius.

* Patch: Introduce the languageId.

* Patch: Resolve grammar conflict.

* Patch: Resolve grammar conflict.

* Patch: Update the hex value.

* Patch: Update the hex value.

* Sort

* Patch: Update the submodule to the latest commit.

* Patch: Resolve merge conflicts.

* Patch: Resolve further conflicts.

* Patch: Remove conflict.

* Patch: Reintroduce Luau into grammar index.

* Revert "Patch: Reintroduce Luau into grammar index."

This reverts commit f5eaf45.

* Patch: Retry resolving the conflict issue.

* Update vendor/licenses/git_submodule/Luau.tmLanguage.dep.yml

* Enhancement: Update old samples and their sources.

* Patch: Update old samples and their sources.

* Patch: Update old samples and their sources.

* Patch: Update old samples and their sources.

* Patch: Update the samples further.

Enhancement: Replace the signal sample.

* Revert "Patch: Update old samples and their sources."

This reverts commit 2f9a8a2.

Revert "Enhancement: Update old samples and their sources."

This reverts commit d005379.

* Test: New samples, sadly one source.

---------

Co-authored-by: Colin Seymour <colin@symr.io>
Co-authored-by: Colin Seymour <colin@github.com>
  • Loading branch information
3 people authored Jun 7, 2024
1 parent e2012cd commit 0204ffa
Show file tree
Hide file tree
Showing 11 changed files with 806 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
[submodule "vendor/grammars/LiveScript.tmbundle"]
path = vendor/grammars/LiveScript.tmbundle
url = https://github.com/paulmillr/LiveScript.tmbundle
[submodule "vendor/grammars/Luau.tmLanguage"]
path = vendor/grammars/Luau.tmLanguage
url = https://github.com/JohnnyMorganz/Luau.tmLanguage.git
[submodule "vendor/grammars/MATLAB-Language-grammar"]
path = vendor/grammars/MATLAB-Language-grammar
url = https://github.com/mathworks/MATLAB-Language-grammar
Expand Down
2 changes: 2 additions & 0 deletions grammars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ vendor/grammars/Ligo-grammar:
- source.religo
vendor/grammars/LiveScript.tmbundle:
- source.livescript
vendor/grammars/Luau.tmLanguage:
- source.luau
vendor/grammars/MATLAB-Language-grammar:
- source.matlab
vendor/grammars/MQL5-sublime:
Expand Down
12 changes: 12 additions & 0 deletions lib/linguist/languages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3931,6 +3931,18 @@ Lua:
interpreters:
- lua
language_id: 213
Luau:
type: programming
tm_scope: source.luau
ace_mode: lua
codemirror_mode: lua
codemirror_mime_type: text/x-lua
color: "#00A2FF"
extensions:
- ".luau"
interpreters:
- luau
language_id: 365050359
M:
type: programming
aliases:
Expand Down
116 changes: 116 additions & 0 deletions samples/Luau/EnumList.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
--!optimize 2
--!strict
--!native

--// EnumList v2.1.0
--// Authored by @sleitnick and modified by @robloxiandemo
--// Fetched from (https://github.com/Sleitnick/RbxUtil/blob/main/modules/enum-list/init.lua)
--// Licensed under the MIT License (https://github.com/Sleitnick/RbxUtil/blob/main/LICENSE.md)

type EnumNames = { string }

--[=[
@interface EnumItem
.Name string
.Value number
.EnumType EnumList
@within EnumList
]=]
export type EnumItem = {
Name: string,
Value: number,
EnumType: any,
}

local LIST_KEY = newproxy()
local NAME_KEY = newproxy()

local function makeReadOnly<ITable>(_table: ITable)
return setmetatable({}, {
__index = _table,
__newindex = function()
error("Attempt to modify read-only table", 2)
end,
__metatable = false,
})
end

local function CreateEnumItem(name: string, value: number, enum: any): EnumItem
local enumItem = {
Name = name,
Value = value,
EnumType = enum,
}
makeReadOnly(enumItem)
return enumItem
end

--[=[
@class EnumList
Defines a new Enum.
]=]
local EnumList = {}
EnumList.__index = EnumList

--[=[
@param name string
@param enums {string}
@return EnumList
Constructs a new EnumList.
```lua
local directions = EnumList.new("Directions", {
"Up",
"Down",
"Left",
"Right",
})
local direction = directions.Up
```
]=]
function EnumList.new(name: string, enums: EnumNames)
assert(type(name) == "string", "Name string required")
assert(type(enums) == "table", "Enums table required")
local self = {}
self[LIST_KEY] = {}
self[NAME_KEY] = name
for i, enumName in ipairs(enums) do
assert(type(enumName) == "string", "Enum name must be a string")
local enumItem = CreateEnumItem(enumName, i, self)
self[enumName] = enumItem
table.insert(self[LIST_KEY], enumItem)
end
return makeReadOnly(setmetatable(self, EnumList))
end

--[=[
@param obj any
@return boolean
Returns `true` if `obj` belongs to the EnumList.
]=]
function EnumList:BelongsTo(obj: any): boolean
return type(obj) == "table" and obj.EnumType == self
end

--[=[
Returns an array of all enum items.
@return {EnumItem}
@since v2.0.0
]=]
function EnumList:GetEnumItems()
return self[LIST_KEY]
end

--[=[
Get the name of the enum.
@return string
@since v2.0.0
]=]
function EnumList:GetName()
return self[NAME_KEY]
end

export type EnumList = typeof(EnumList.new(...))

return EnumList
229 changes: 229 additions & 0 deletions samples/Luau/Option.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
--!optimize 2
--!strict
--!native

--// EnumList v1.0.5
--// Authored by @sleitnick and modified by @robloxiandemo
--// Fetched from (https://github.com/Sleitnick/RbxUtil/blob/main/modules/option/init.lua)
--// Licensed under the MIT License (https://github.com/Sleitnick/RbxUtil/blob/main/LICENSE.md)

export type MatchTable<T> = {
Some: (value: T) -> any,
None: () -> any,
}

export type MatchFn<T> = (matches: MatchTable<T>) -> any

export type DefaultFn<T> = () -> T

export type AndThenFn<T> = (value: T) -> Option<T>

export type OrElseFn<T> = () -> Option<T>

export type Option<T> = typeof(setmetatable(
{} :: {
Match: (self: Option<T>) -> MatchFn<T>,
IsSome: (self: Option<T>) -> boolean,
IsNone: (self: Option<T>) -> boolean,
Contains: (self: Option<T>, value: T) -> boolean,
Unwrap: (self: Option<T>) -> T,
Expect: (self: Option<T>, errMsg: string) -> T,
ExpectNone: (self: Option<T>, errMsg: string) -> nil,
UnwrapOr: (self: Option<T>, default: T) -> T,
UnwrapOrElse: (self: Option<T>, defaultFn: DefaultFn<T>) -> T,
And: (self: Option<T>, opt2: Option<T>) -> Option<T>,
AndThen: (self: Option<T>, predicate: AndThenFn<T>) -> Option<T>,
Or: (self: Option<T>, opt2: Option<T>) -> Option<T>,
OrElse: (self: Option<T>, orElseFunc: OrElseFn<T>) -> Option<T>,
XOr: (self: Option<T>, opt2: Option<T>) -> Option<T>,
},
{} :: {
__index: Option<T>,
}
))

local CLASSNAME = "Option"

local Option = {}
Option.__index = Option

function Option._new(value)
local self = setmetatable({
ClassName = CLASSNAME,
_v = value,
_s = (value ~= nil),
}, Option)
return self
end

function Option.Some(value)
assert(value ~= nil, "Option.Some() value cannot be nil")
return Option._new(value)
end

function Option.Wrap(value)
if value == nil then
return Option.None
else
return Option.Some(value)
end
end

function Option.Is(obj)
return type(obj) == "table" and getmetatable(obj) == Option
end

function Option.Assert(obj)
assert(Option.Is(obj), "Result was not of type Option")
end

function Option.Deserialize(data) -- type data = {ClassName: string, Value: any}
assert(type(data) == "table" and data.ClassName == CLASSNAME, "Invalid data for deserializing Option")
return data.Value == nil and Option.None or Option.Some(data.Value)
end

function Option:Serialize()
return {
ClassName = self.ClassName,
Value = self._v,
}
end

function Option:Match(matches)
local onSome = matches.Some
local onNone = matches.None
assert(type(onSome) == "function", "Missing 'Some' match")
assert(type(onNone) == "function", "Missing 'None' match")
if self:IsSome() then
return onSome(self:Unwrap())
else
return onNone()
end
end

function Option:IsSome()
return self._s
end

function Option:IsNone()
return not self._s
end

function Option:Expect(msg)
assert(self:IsSome(), msg)
return self._v
end

function Option:ExpectNone(msg)
assert(self:IsNone(), msg)
end

function Option:Unwrap()
return self:Expect("Cannot unwrap option of None type")
end

function Option:UnwrapOr(default)
if self:IsSome() then
return self:Unwrap()
else
return default
end
end

function Option:UnwrapOrElse(defaultFn)
if self:IsSome() then
return self:Unwrap()
else
return defaultFn()
end
end

function Option:And(optionB)
if self:IsSome() then
return optionB
else
return Option.None
end
end

function Option:AndThen(andThenFn)
if self:IsSome() then
local result = andThenFn(self:Unwrap())
Option.Assert(result)
return result
else
return Option.None
end
end

function Option:Or(optionB)
if self:IsSome() then
return self
else
return optionB
end
end

function Option:OrElse(orElseFn)
if self:IsSome() then
return self
else
local result = orElseFn()
Option.Assert(result)
return result
end
end

function Option:XOr(optionB)
local someOptA = self:IsSome()
local someOptB = optionB:IsSome()
if someOptA == someOptB then
return Option.None
elseif someOptA then
return self
else
return optionB
end
end

function Option:Filter(predicate)
if self:IsNone() or not predicate(self._v) then
return Option.None
else
return self
end
end

function Option:Contains(value)
return self:IsSome() and self._v == value
end

function Option:__tostring()
if self:IsSome() then
return ("Option<" .. type(self._v) .. ">")
else
return "Option<None>"
end
end

function Option:__eq(opt)
if Option.Is(opt) then
if self:IsSome() and opt:IsSome() then
return (self:Unwrap() == opt:Unwrap())
elseif self:IsNone() and opt:IsNone() then
return true
end
end
return false
end

Option.None = Option._new()

return (Option :: any) :: {
Some: <T>(value: T) -> Option<T>,
Wrap: <T>(value: T) -> Option<T>,

Is: (obj: any) -> boolean,

None: Option<any>,
}
Loading

0 comments on commit 0204ffa

Please sign in to comment.