diff options
| author | V1K1NGbg <victor@ilchev.com> | 2024-08-22 17:48:57 -0300 |
|---|---|---|
| committer | Hisham Muhammad <hisham@gobolinux.org> | 2024-10-21 13:30:51 -0300 |
| commit | 68a5ee0d17a366cd49c4fa9ff6ac887fe917acd8 (patch) | |
| tree | 71e70b9534f3da3197ed12249d797ff71956deb7 /src | |
| parent | f2697b158f0b94f615dffee553ac18cfbd72cd52 (diff) | |
| download | luarocks-68a5ee0d17a366cd49c4fa9ff6ac887fe917acd8.tar.gz luarocks-68a5ee0d17a366cd49c4fa9ff6ac887fe917acd8.tar.bz2 luarocks-68a5ee0d17a366cd49c4fa9ff6ac887fe917acd8.zip | |
Teal: convert luarocks.type_check
Diffstat (limited to 'src')
| -rw-r--r-- | src/luarocks/type_check.tl (renamed from src/luarocks/type_check.lua) | 100 |
1 files changed, 62 insertions, 38 deletions
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.tl index 21085ef9..1b332be0 100644 --- a/src/luarocks/type_check.lua +++ b/src/luarocks/type_check.tl | |||
| @@ -1,20 +1,42 @@ | |||
| 1 | 1 | ||
| 2 | local type_check = {} | 2 | local record type_check |
| 3 | type_check_table: function(version: string, tbl: {any: any}, typetbl: TableSchema, context: string): boolean, string --! tbl and typetbl types) | ||
| 4 | |||
| 5 | record TableSchema | ||
| 6 | fields: {string: TableSchema} | ||
| 7 | _type: string | ||
| 8 | _name: string | ||
| 9 | _pattern: string | ||
| 10 | _version: string | ||
| 11 | _more: boolean | ||
| 12 | _mandatory: boolean | ||
| 13 | _any: TableSchema | ||
| 14 | end | ||
| 15 | |||
| 16 | MAGIC_PLATFORMS: TableSchema | ||
| 17 | end | ||
| 3 | 18 | ||
| 4 | local cfg = require("luarocks.core.cfg") | 19 | local cfg = require("luarocks.core.cfg") |
| 5 | local fun = require("luarocks.fun") | 20 | local fun = require("luarocks.fun") |
| 6 | local util = require("luarocks.util") | 21 | local util = require("luarocks.util") |
| 7 | local vers = require("luarocks.core.vers") | 22 | local vers = require("luarocks.core.vers") |
| 23 | |||
| 24 | local type TableSchema = type_check.TableSchema | ||
| 8 | -------------------------------------------------------------------------------- | 25 | -------------------------------------------------------------------------------- |
| 9 | 26 | ||
| 10 | -- A magic constant that is not used anywhere in a schema definition | 27 | -- A magic constant that is not used anywhere in a schema definition |
| 11 | -- and retains equality when the table is deep-copied. | 28 | -- and retains equality when the table is deep-copied. |
| 12 | type_check.MAGIC_PLATFORMS = 0xEBABEFAC | 29 | type_check.MAGIC_PLATFORMS = {} |
| 13 | 30 | ||
| 14 | do | 31 | do |
| 15 | local function fill_in_version(tbl, version) | 32 | local function fill_in_version(tbl: TableSchema, version?: string) |
| 16 | for _, v in pairs(tbl) do | 33 | |
| 17 | if type(v) == "table" then | 34 | if not tbl.fields then --! validation |
| 35 | return | ||
| 36 | end | ||
| 37 | |||
| 38 | for _, v in pairs(tbl.fields) do | ||
| 39 | if v is TableSchema then | ||
| 18 | if v._version == nil then | 40 | if v._version == nil then |
| 19 | v._version = version | 41 | v._version = version |
| 20 | end | 42 | end |
| @@ -23,14 +45,13 @@ do | |||
| 23 | end | 45 | end |
| 24 | end | 46 | end |
| 25 | 47 | ||
| 26 | local function expand_magic_platforms(tbl) | 48 | local function expand_magic_platforms(tbl: TableSchema) |
| 27 | for k,v in pairs(tbl) do | 49 | for k,v in pairs(tbl.fields) do |
| 28 | if v == type_check.MAGIC_PLATFORMS then | 50 | if v == type_check.MAGIC_PLATFORMS then |
| 29 | tbl[k] = { | 51 | tbl.fields[k] = { |
| 30 | _any = util.deep_copy(tbl) | 52 | _any = util.deep_copy(tbl as {string: any}) as TableSchema |
| 31 | } | 53 | } |
| 32 | tbl[k]._any[k] = nil | 54 | tbl.fields[k]._any.fields[k] = nil |
| 33 | elseif type(v) == "table" then | ||
| 34 | expand_magic_platforms(v) | 55 | expand_magic_platforms(v) |
| 35 | end | 56 | end |
| 36 | end | 57 | end |
| @@ -41,17 +62,17 @@ do | |||
| 41 | -- and the value is a schema specification. Schema versions are considered | 62 | -- and the value is a schema specification. Schema versions are considered |
| 42 | -- incremental: version "2.0" only needs to specify what's new/changed from | 63 | -- incremental: version "2.0" only needs to specify what's new/changed from |
| 43 | -- version "1.0". | 64 | -- version "1.0". |
| 44 | function type_check.declare_schemas(inputs) | 65 | function type_check.declare_schemas(inputs: {string: TableSchema}): {string : TableSchema}, {string} |
| 45 | local schemas = {} | 66 | local schemas: {string: TableSchema} = {} |
| 46 | local parent_version | 67 | local parent_version: string |
| 47 | 68 | ||
| 48 | local versions = fun.reverse_in(fun.sort_in(util.keys(inputs), vers.compare_versions)) | 69 | local versions = fun.reverse_in(fun.sort_in(util.keys(inputs), vers.compare_versions)) |
| 49 | 70 | ||
| 50 | for _, version in ipairs(versions) do | 71 | for _, version in ipairs(versions) do |
| 51 | local schema = inputs[version] | 72 | local schema = inputs[version] |
| 52 | if parent_version ~= nil then | 73 | if parent_version then |
| 53 | local copy = util.deep_copy(schemas[parent_version]) | 74 | local copy: TableSchema = util.deep_copy(schemas[parent_version] as {any: any}) as TableSchema |
| 54 | util.deep_merge(copy, schema) | 75 | util.deep_merge(copy as {any: any}, schema as {any: any}) |
| 55 | schema = copy | 76 | schema = copy |
| 56 | end | 77 | end |
| 57 | fill_in_version(schema, version) | 78 | fill_in_version(schema, version) |
| @@ -66,7 +87,7 @@ end | |||
| 66 | 87 | ||
| 67 | -------------------------------------------------------------------------------- | 88 | -------------------------------------------------------------------------------- |
| 68 | 89 | ||
| 69 | local function check_version(version, typetbl, context) | 90 | local function check_version(version: string, typetbl: TableSchema, context: string): boolean, string |
| 70 | local typetbl_version = typetbl._version or "1.0" | 91 | local typetbl_version = typetbl._version or "1.0" |
| 71 | if vers.compare_versions(typetbl_version, version) then | 92 | if vers.compare_versions(typetbl_version, version) then |
| 72 | if context == "" then | 93 | if context == "" then |
| @@ -78,6 +99,8 @@ local function check_version(version, typetbl, context) | |||
| 78 | return true | 99 | return true |
| 79 | end | 100 | end |
| 80 | 101 | ||
| 102 | |||
| 103 | |||
| 81 | --- Type check an object. | 104 | --- Type check an object. |
| 82 | -- The object is compared against an archetypical value | 105 | -- The object is compared against an archetypical value |
| 83 | -- matching the expected type -- the actual values don't matter, | 106 | -- matching the expected type -- the actual values don't matter, |
| @@ -90,8 +113,7 @@ end | |||
| 90 | -- @return boolean or (nil, string): true if type checking | 113 | -- @return boolean or (nil, string): true if type checking |
| 91 | -- succeeded, or nil and an error message if it failed. | 114 | -- succeeded, or nil and an error message if it failed. |
| 92 | -- @see type_check_table | 115 | -- @see type_check_table |
| 93 | local function type_check_item(version, item, typetbl, context) | 116 | local function type_check_item(version: string, item: any, typetbl: TableSchema, context: string): boolean, string |
| 94 | assert(type(version) == "string") | ||
| 95 | 117 | ||
| 96 | if typetbl._version and typetbl._version ~= "1.0" then | 118 | if typetbl._version and typetbl._version ~= "1.0" then |
| 97 | local ok, err = check_version(version, typetbl, context) | 119 | local ok, err = check_version(version, typetbl, context) |
| @@ -100,7 +122,6 @@ local function type_check_item(version, item, typetbl, context) | |||
| 100 | end | 122 | end |
| 101 | end | 123 | end |
| 102 | 124 | ||
| 103 | local item_type = type(item) or "nil" | ||
| 104 | local expected_type = typetbl._type or "table" | 125 | local expected_type = typetbl._type or "table" |
| 105 | 126 | ||
| 106 | if expected_type == "number" then | 127 | if expected_type == "number" then |
| @@ -108,32 +129,32 @@ local function type_check_item(version, item, typetbl, context) | |||
| 108 | return nil, "Type mismatch on field "..context..": expected a number" | 129 | return nil, "Type mismatch on field "..context..": expected a number" |
| 109 | end | 130 | end |
| 110 | elseif expected_type == "string" then | 131 | elseif expected_type == "string" then |
| 111 | if item_type ~= "string" then | 132 | if not item is string then |
| 112 | return nil, "Type mismatch on field "..context..": expected a string, got "..item_type | 133 | return nil, "Type mismatch on field "..context..": expected a string, got "..type(item) |
| 113 | end | 134 | end |
| 114 | local pattern = typetbl._pattern | 135 | local pattern = typetbl._pattern |
| 115 | if pattern then | 136 | if pattern then |
| 116 | if not item:match("^"..pattern.."$") then | 137 | if not item:match("^"..pattern.."$") then --! cast or tostring |
| 117 | local what = typetbl._name or ("'"..pattern.."'") | 138 | local what = typetbl._name or ("'"..pattern.."'") |
| 118 | return nil, "Type mismatch on field "..context..": invalid value '"..item.."' does not match " .. what | 139 | return nil, "Type mismatch on field "..context..": invalid value '"..item.."' does not match " .. what |
| 119 | end | 140 | end |
| 120 | end | 141 | end |
| 121 | elseif expected_type == "table" then | 142 | elseif expected_type == "table" then |
| 122 | if item_type ~= expected_type then | 143 | if not item is table then |
| 123 | return nil, "Type mismatch on field "..context..": expected a table" | 144 | return nil, "Type mismatch on field "..context..": expected a table" |
| 124 | else | 145 | else |
| 125 | return type_check.type_check_table(version, item, typetbl, context) | 146 | return type_check.type_check_table(version, item, typetbl, context) |
| 126 | end | 147 | end |
| 127 | elseif item_type ~= expected_type then | 148 | elseif type(item) ~= expected_type then |
| 128 | return nil, "Type mismatch on field "..context..": expected "..expected_type | 149 | return nil, "Type mismatch on field "..context..": expected "..expected_type |
| 129 | end | 150 | end |
| 130 | return true | 151 | return true |
| 131 | end | 152 | end |
| 132 | 153 | ||
| 133 | local function mkfield(context, field) | 154 | local function mkfield(context: string, field: any): string |
| 134 | if context == "" then | 155 | if context == "" then |
| 135 | return tostring(field) | 156 | return tostring(field) |
| 136 | elseif type(field) == "string" then | 157 | elseif field is string then |
| 137 | return context.."."..field | 158 | return context.."."..field |
| 138 | else | 159 | else |
| 139 | return context.."["..tostring(field).."]" | 160 | return context.."["..tostring(field).."]" |
| @@ -162,30 +183,33 @@ end | |||
| 162 | -- to be used by error messages. | 183 | -- to be used by error messages. |
| 163 | -- @return boolean or (nil, string): true if type checking | 184 | -- @return boolean or (nil, string): true if type checking |
| 164 | -- succeeded, or nil and an error message if it failed. | 185 | -- succeeded, or nil and an error message if it failed. |
| 165 | function type_check.type_check_table(version, tbl, typetbl, context) | 186 | function type_check.type_check_table(version: string, tbl: {any: any}, typetbl: TableSchema, context: string): boolean, string |
| 166 | assert(type(version) == "string") | ||
| 167 | assert(type(tbl) == "table") | ||
| 168 | assert(type(typetbl) == "table") | ||
| 169 | 187 | ||
| 170 | local ok, err = check_version(version, typetbl, context) | 188 | local ok, err = check_version(version, typetbl, context) |
| 171 | if not ok then | 189 | if not ok then |
| 172 | return nil, err | 190 | return nil, err |
| 173 | end | 191 | end |
| 174 | 192 | ||
| 193 | if not typetbl.fields then --! validation | ||
| 194 | -- if there are no fields, exit the checker | ||
| 195 | return true | ||
| 196 | end | ||
| 197 | |||
| 175 | for k, v in pairs(tbl) do | 198 | for k, v in pairs(tbl) do |
| 176 | local t = typetbl[k] or typetbl._any | 199 | local t = typetbl.fields[tostring(k)] or typetbl._any |
| 177 | if t then | 200 | if t then |
| 178 | local ok, err = type_check_item(version, v, t, mkfield(context, k)) | 201 | ok, err = type_check_item(version, v, t, mkfield(context, k)) |
| 179 | if not ok then return nil, err end | 202 | if not ok then return nil, err end |
| 180 | elseif typetbl._more then | 203 | elseif typetbl._more then |
| 181 | -- Accept unknown field | 204 | -- Accept unknown field |
| 182 | else | 205 | else |
| 183 | if not cfg.accept_unknown_fields then | 206 | if not cfg.accept_unknown_fields then |
| 184 | return nil, "Unknown field "..k | 207 | return nil, "Unknown field "..tostring(k) |
| 185 | end | 208 | end |
| 186 | end | 209 | end |
| 187 | end | 210 | end |
| 188 | for k, v in pairs(typetbl) do | 211 | |
| 212 | for k, v in pairs(typetbl.fields) do | ||
| 189 | if k:sub(1,1) ~= "_" and v._mandatory then | 213 | if k:sub(1,1) ~= "_" and v._mandatory then |
| 190 | if not tbl[k] then | 214 | if not tbl[k] then |
| 191 | return nil, "Mandatory field "..mkfield(context, k).." is missing." | 215 | return nil, "Mandatory field "..mkfield(context, k).." is missing." |
| @@ -195,10 +219,10 @@ function type_check.type_check_table(version, tbl, typetbl, context) | |||
| 195 | return true | 219 | return true |
| 196 | end | 220 | end |
| 197 | 221 | ||
| 198 | function type_check.check_undeclared_globals(globals, typetbl) | 222 | function type_check.check_undeclared_globals(globals: {string: any}, typetbl: TableSchema): boolean, string --! tbl and typetbl types |
| 199 | local undeclared = {} | 223 | local undeclared = {} |
| 200 | for glob, _ in pairs(globals) do | 224 | for glob, _ in pairs(globals) do |
| 201 | if not (typetbl[glob] or typetbl["MUST_"..glob]) then | 225 | if not (typetbl.fields[glob] or typetbl.fields["MUST_"..glob]) then |
| 202 | table.insert(undeclared, glob) | 226 | table.insert(undeclared, glob) |
| 203 | end | 227 | end |
| 204 | end | 228 | end |
