diff --git a/addon.json b/addon.json index 66d8922e..72d5e156 100644 --- a/addon.json +++ b/addon.json @@ -4,6 +4,7 @@ "tags" : [ "fun", "roleplay" ], "ignore" : [ + "check.lua", ".gitignore", ".editorconfig", ".git*", diff --git a/lua/autorun/pac_core_init.lua b/lua/autorun/pac_core_init.lua index 0dc788cf..a4741227 100644 --- a/lua/autorun/pac_core_init.lua +++ b/lua/autorun/pac_core_init.lua @@ -1,3 +1,28 @@ +--[[# + import_type("nattlua/glua.nlua") + type pac = any + type VLL_CURR_FILE = false + type VLL2_FILEDEF = false + + + type function include(path: string) + local full_path = analyzer:ResolvePath("lua/" .. path:GetData()) + + local code_data = assert(require("nattlua").File(full_path)) + + assert(code_data:Lex()) + assert(code_data:Parse()) + + local res = analyzer:AnalyzeRootStatement(code_data.SyntaxTree) + + analyzer.loaded = analyzer.loaded or {} + analyzer.loaded[path] = res + + return res + end + +]] + -- VLL_CURR_FILE is local to each file if CLIENT and pac and not VLL_CURR_FILE and not VLL2_FILEDEF then return end diff --git a/nattlua.lua b/nattlua.lua new file mode 100644 index 00000000..39142fe3 --- /dev/null +++ b/nattlua.lua @@ -0,0 +1,80 @@ +package.path = '/home/caps/github/nattlua/?.lua;' .. package.path + +local nl = require("nattlua") + +local function GetFilesRecursively(dir, ext) + ext = ext or ".lua" + + local f = assert(io.popen("find " .. dir)) + local lines = f:read("*all") + local paths = {} + for line in lines:gmatch("(.-)\n") do + if line:sub(-4) == ext then + table.insert(paths, line) + end + end + return paths +end + +local function read_file(path) + local f = assert(io.open(path, "r")) + local contents = f:read("*all") + f:close() + return contents +end + +local function write_file(path, contents) + local f = assert(io.open(path, "w")) + f:write(contents) + f:close() +end + +local function LintCodebase() + local lua_files = GetFilesRecursively("./lua/", ".lua") + + local blacklist = { + ["./lua/entities/gmod_wire_expression2/core/custom/pac.lua"] = true, + } + + local config = { + preserve_whitespace = false, + string_quote = "\"", + no_semicolon = true, + force_parenthesis = true, + extra_indent = { + StartStorableVars = { + to = "EndStorableVars", + }, + + Start2D = {to = "End2D"}, + Start3D = {to = "End3D"}, + Start3D2D = {to = "End3D2D"}, + + -- in case it's localized + cam_Start2D = {to = "cam_End2D"}, + cam_Start3D = {to = "cam_End3D"}, + cam_Start3D2D = {to = "cam_End3D2D"}, + cam_Start = {to = "cam_End"}, + + SetPropertyGroup = "toggle", + } + } + + for _, path in ipairs(lua_files) do + if not blacklist[path] then + local lua_code = read_file(path) + local new_lua_code = assert(nl.Code(lua_code, "@" .. path, config)):Emit() + if new_lua_code:sub(#new_lua_code, #new_lua_code) ~= "\n" then + new_lua_code = new_lua_code .. "\n" + end + --assert(loadstring(new_lua_code, "@" .. path)) + write_file(path, new_lua_code) + end + end +end + +if false then LintCodebase() end + +return { + main = "lua/autorun/pac_core_init.lua", +} \ No newline at end of file diff --git a/nattlua/glua.nlua b/nattlua/glua.nlua new file mode 100644 index 00000000..ba67997d --- /dev/null +++ b/nattlua/glua.nlua @@ -0,0 +1,325 @@ + +type Color = { + r = number, + g = number, + b = number, + a = number, + __index = self, -- __index = self is shortcut for type Color.__index = Color, + @MetaTable = self, -- shortcut for setmetatable<|Color, Color|>, + @Name = "Color", +} + +type Vector = { + x = number, + y = number, + z = number, +} + +type Angle = { + p = number, + y = number, + r = number, + __index = Angle, + __call = (function(self, number, number, number): Angle), + @MetaTable = self, + @Name = "Angle", + Right = (function(self): Vector), -- TODO: Vector():Angle():Right() seems to cause infinte loop if Right is not defined +} + +local type ToScreenData = { + x = number, + y = number, + visible = boolean, +} + + +-- We can mutate the Vector type if we want +type Vector.__index = Vector +type Vector.__call = function(Vector, number, number, number): Vector +type Vector.__add = function(Vector, Vector): Vector +type Vector.__mul = function(number | Vector, number | Vector): Vector +type Vector.__unm = function(Vector): Vector + +--type Vector.@Name = "Vector" + +-- Or we can add a table: +type Vector = Vector & { + Zero = (function(self): nil), + WithinAABox = (function(self, boxStart: Vector, boxEnd: Vector): boolean), + ToScreen = (function(self): ToScreenData), + ToColor = (function(self): Color), + Sub = (function(self, vector: Vector): nil), + Set = (function(self, vector: Vector): nil), + Rotate = (function(self, rotation: Angle): nil), + Normalize = (function(self): nil), + Mul = (function(self, multiplier: number): nil), + LengthSqr = (function(self): number), + Length2DSqr = (function(self): number), + Length2D = (function(self): number), + Length = (function(self): number), + IsZero = (function(self): boolean), + IsEqualTol = (function(self, compare: Vector, tolerance: number): boolean), + GetNormalized = (function(self): Vector), + GetNormal = (function(self): Vector), + DotProduct = (function(self, Vector: Vector): number), + Dot = (function(self, otherVector: Vector): number), + Div = (function(self, divisor: number): nil), + DistToSqr = (function(self, otherVec: Vector): number), + Distance = (function(self, otherVector: Vector): number), + Cross = (function(self, otherVector: Vector): Vector), + AngleEx = (function(self, up: Vector): Angle), + Angle = (function(self): Angle), + Add = (function(self, vector: Vector): nil), +} + +setmetatable<|Vector, Vector|> + +-- because we can't easily forward declare types +-- we add a ToVector function here +type Color.ToVector = (function(Color): Vector), + + +local type BodyGroup = { + id = number, + name = string, + num = number, + submodels = {[number] = any} -- not sure what's in here +} + +local type Matrix = { + GetTranslation = (function(self): Vector), + GetAngles = (function(self): Angle), +} + +local type Triangle = { + color = Color, + normal = Vector, + binormal = Vector, + pos = Vector, + u = number, + v = number, + userdata = {number, number, number, number}, + weights = {[number] = { + bone = number, + weight = number + }} +} + +local type Mesh = { + Draw = (function(self): nil), + BuildFromTriangles = (function(self, {[number] = Triangle}): self), + @MetaTable = self, + __index = self, + __call = function(self, number, number, number): self +} + +local type PhysicsObject = { + @Name = "PhysicsObject", + IsValid = (function(self): boolean), +} + + +local type EntityAttachments = { + [1 .. inf] = { + id = number, + name = string, + } +} + +local type EntityAttachment = { + Ang = Angle, + Pos = Vector, +} + + +local type Entity = { + GetModel = (function(self): string), + SetAngles = (function(self, Angle): nil), + GetBodyGroups = (function(self, number): {[number] = BodyGroup}), + GetBodygroup = (function(self, number): number), + LookupSequence = (function(self, string): number), + ResetSequence = (function(self, number): nil), + SetCycle = (function(self, number): nil), + SetupBones = (function(self): nil), + TranslatePhysBoneToBone = (function(self, number): number), + TranslateBoneToPhysBone = (function(self, number): number), + GetBoneMatrix = (function(self, number): Matrix | nil), + GetChildBones = (function(self, number): {[number] = number}), + BoneLength = (function(self, number): number), + Remove = (function(self): nil), + GetBoneParent = (function(self): number), + GetBoneName = (function(self, number): string), + EyePos = (function(self): Vector), + EyeAngles = (function(self): Angle), + GetBoneCount = (function(self): number), + GetPos = (function(self): Vector), + IsStuck = (function(self): boolean), + GetAimVector = (function(self): Vector), + SetPos = (function(self, Vector): nil), + IsValid = (function(self): boolean), + GetPhysicsObject = (function(self): PhysicsObject), + GetVelocity = (function(self): Vector), + SetVelocity = (function(self, Vector): Vector), + GetAttachment = (function(self, number): EntityAttachment), + GetAttachments = (function(self): EntityAttachments), +} + + +type Entity.@Name = "Entity" + + +local type Player = Entity & {} +type Player.@Name = "Player" + +type LocalPlayer = function(): Player + +type timer = { + Simple = function(delay: number, callback: function(): nil): nil +} + +type ClientsideModel = function(string): Entity + +local type ModelMeshes = { + [number] = { + material = string, + triangles = {[number] = Triangle}, + verticies = {[number] = Triangle}, + } +} + +type util = {} +type util.GetModelMeshes = (function(string, number, number): ModelMeshes) + +local type WorldToLocal = (function(Vector, Angle, Vector, Angle): Vector, Angle) + +local type hook = {} + +local type Events = { + OnStart = (function(string, boolean): nil), + OnStop = (function(string, string, string): number) +} + +type function hook.Add(eventName: string, obj: any, callback: (function(...): ...)) + local event_callback = env.typesystem.Events:Get(eventName) + + callback:SetReturnTypes(event_callback:GetReturnTypes()) + callback:SetArguments(event_callback:GetArguments()) +end + + +type function Entity:IsPlayer() + return types.Boolean() +end + +type function CompileString(code: string, name: string, should_throw: boolean | nil) + should_throw = should_throw and should_throw:IsLiteral() and should_throw:GetData() + if should_throw == nil then should_throw = true end + + code = code:IsLiteral() and code:GetData() or nil + name = name and name:IsLiteral() and name:GetData() or nil + + if code then + local func, err = nl.load(code, name) + + if func then + return func + end + + if should_throw then + error(err) + end + + return err + end +end + +local type function isstring(obj: any) + local typ = analyzer:Call(env.typesystem.type, types.Tuple({obj}), analyzer.current_expression):Get(1) + return analyzer:BinaryOperator(analyzer.current_expression, typ, types.String("string"):SetLiteral(true), "runtime", "==") +end + +local type function istable(obj: any) + local typ = analyzer:Call(env.typesystem.type, types.Tuple({obj}), analyzer.current_expression):Get(1) + return analyzer:BinaryOperator(analyzer.current_expression, typ, types.String("table"):SetLiteral(true), "runtime", "==") +end + +local type function isentity(obj: any) + local Entity = env.typesystem.Entity + return analyzer:BinaryOperator(analyzer.current_expression, obj:GetMetaTable() or obj, Entity, "typesystem", "==") +end + +type function table.Count(tbl: any): number + +function string.Implode( seperator: literal string, Table: literal {[1 .. inf] = string} ) + return table.concat( Table, seperator ) +end + +function string.GetFileFromFilename( path: literal string ) + if ( !path:find( "\\" ) && !path:find( "/" ) ) then return path end + return path:match( "[\\/]([^/\\]+)$" ) or "" +end + +function string.GetPathFromFilename( path: literal string ) + return path:match( "^(.*[/\\])[^/\\]-$" ) or "" +end + +function string.ToTable( str: literal string ) + local tbl = {} + + for i = 1, string.len( str ) do + tbl[i] = string.sub( str, i, i ) + end + + return tbl +end + +function math.Clamp(low: literal number, n: literal number, high: literal number) return math.min(math.max(n, low), high) end + +do + local totable = string.ToTable + local string_sub = string.sub + local string_find = string.find + local string_len = string.len + function string.Explode(separator: literal string, str: literal string, withpattern: literal boolean | nil) + if ( separator == "" ) then return totable( str ) end + if ( withpattern == nil ) then withpattern = false end + + local ret = {} + local current_pos = 1 + + for i = 1, string_len( str ) do + local start_pos, end_pos = string_find( str, separator, current_pos, !withpattern ) + if ( !start_pos ) then break end + ret[ i ] = string_sub( str, current_pos, start_pos - 1 ) + current_pos = end_pos + 1 + end + + ret[ #ret + 1 ] = string_sub( str, current_pos ) + + return ret + end + + function string.Split( str: literal string, delimiter: literal string ) + + return string.Explode( delimiter, str ) + end +end + +return { + hook = hook, + WorldToLocal = WorldToLocal, + Vector = Vector, + Angle = Angle, + Matrix = Matrix, + Player = Player, + util = util, + Mesh = Mesh, + ClientsideModel = ClientsideModel, + EntityAttachment = EntityAttachment, + EntityAttachments = EntityAttachments, + Entity = Entity, + istable = istable, + isentity = isentity, + isstring = isstring, + CompileString = CompileString, +} \ No newline at end of file