add updates libs

This commit is contained in:
Christoph Brandau
2026-06-18 17:21:58 +02:00
parent 91ce762570
commit 41f331d4c4
150 changed files with 8249 additions and 2550 deletions
+233 -117
View File
@@ -32,13 +32,9 @@ these would be helpful for your use case, please file an issue.
- https://www.tcl.tk/man/tcl/TclCmd/mathop.html
"""
from tclint.commands.checks import (
CommandArgError,
check_count,
eval,
)
from tclint.commands.checks import CommandArgError, check_arg_spec, check_count, eval
from tclint.commands.schema import commands_schema
from tclint.syntax_tree import BareWord
from tclint.syntax_tree import BareWord, Node
def _check_code(arg):
@@ -77,7 +73,7 @@ def _after(args, parser):
def _after_cancel(args, parser):
"""after id|(script...)"""
# ref: https://www.tcl.tk/man/tcl/TclCmd/after.html
check_count("after cancel", 1, None)
check_count("after cancel", 1, None)(args, parser)
# TODO: raise warning about not checking code
@@ -181,20 +177,6 @@ _array = {
}
def _catch(args, parser):
"""catch script [resultVarName] [optionsVarName]"""
if len(args) < 1:
raise CommandArgError(
f"not enough args to catch: got {len(args)}, expected at least 1"
)
if len(args) > 3:
raise CommandArgError(
f"too many args to catch: got {len(args)}, expected no more than 3"
)
return [parser.parse_script(args[0])] + args[1:]
_chan = {
"subcommands": {
"blocked": {
@@ -350,43 +332,37 @@ def _dict_filter(args, parser):
def _dict_map_for(cmd):
def check(args, parser):
if len(args) != 3:
raise CommandArgError(
f"wrong # of args to '{cmd}': got {len(args)}, expected 3"
)
spec = {
"positionals": [
{"name": "keyValueList", "value": {"type": "any"}, "required": True},
{"name": "dictionaryValue", "value": {"type": "any"}, "required": True},
{"name": "body", "value": {"type": "script"}, "required": True},
],
"switches": {},
}
# TODO: might be worth checking that arg[0] is a pair?
return args[0:2] + [parser.parse_script(args[2])]
return check_arg_spec(cmd, args, parser, spec)
return check
def _dict_update(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/dict.html#M25
"""dict update dictionaryVariable key varName ?key varName ...? body
if len(args) < 4:
raise CommandArgError(
f"not enough args to 'dict update': got {len(args)}, expected at least 4"
)
if len(args) % 2 != 0:
raise CommandArgError(
"invalid # of args to 'dict update': expected an even number"
)
return args[0:-1] + [parser.parse_script(args[-1])]
def _dict_with(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/dict.html#M27
if len(args) < 2:
raise CommandArgError(
f"not enough args to 'dict with': got {len(args)}, expected at least 2"
)
return args[0:-1] + [parser.parse_script(args[-1])]
ref: https://www.tcl-lang.org/man/tcl8.6/TclCmd/dict.htm#M25
"""
spec = {
"positionals": [
{"name": "dictionaryVariable", "value": {"type": "any"}, "required": True},
{"name": "key", "value": {"type": "any"}, "required": True},
{"name": "varName", "value": {"type": "any"}, "required": True},
{"name": "key varName", "value": {"type": "variadic"}, "required": False},
{"name": "body", "value": {"type": "script"}, "required": True},
],
"switches": {},
}
# TODO: Check that number of variadic words is even.
return check_arg_spec("dict update", args, parser, spec)
def _eval(args, parser):
@@ -434,53 +410,100 @@ def _fileevent(args, parser):
)
def _for(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/for.html
if len(args) != 4:
raise CommandArgError(f"wrong # of args to for: got {len(args)}, expected 4")
def foreach(args, parser):
"""
foreach varname list ?varlist list ...? body
return [
parser.parse_script(args[0]),
parser.parse_expression(args[1]),
parser.parse_script(args[2]),
parser.parse_script(args[3]),
]
ref: https://www.tcl-lang.org/man/tcl8.6/TclCmd/foreach.htm
"""
spec = {
"positionals": [
{"name": "varname", "value": {"type": "any"}, "required": True},
{"name": "list", "value": {"type": "any"}, "required": True},
{"name": "varlist list", "value": {"type": "variadic"}, "required": False},
{"name": "body", "value": {"type": "script"}, "required": True},
],
"switches": {},
}
# TODO: check that "varlist list" comes in pairs.
return check_arg_spec("foreach", args, parser, spec)
def _foreach(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/foreach.html
if len(args) < 3:
raise CommandArgError(
f"insufficient args to foreach: got {len(args)}, expected at least 3"
)
def _if(args, parser) -> list[Node]:
# ref: https://www.tcl-lang.org/man/tcl8.6/TclCmd/if.htm
# last argument is script body
return args[0:-1] + [parser.parse_script(args[-1])]
def _if(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/if.html
# TODO: make arg checking strict
new_args = []
new_args: list[Node] = []
# Parse if condition.
if len(new_args) == len(args):
raise CommandArgError("Expected condition argument in 'if'")
new_args.append(parser.parse_expression(args[0]))
while len(new_args) < len(args):
arg = args[len(new_args)]
if arg.contents == "then" or arg.contents == "else":
new_args.append(arg)
continue
if arg.contents == "elseif":
new_args.append(arg)
new_args.append(parser.parse_expression(args[len(new_args)]))
continue
arg = parser.parse_script(arg)
# Parse optional noise word then.
if len(new_args) == len(args):
raise CommandArgError("Expected then or body argument in 'if'")
arg = args[len(new_args)]
if arg.contents == "then":
new_args.append(arg)
return new_args
# Parse if body.
if len(new_args) == len(args):
raise CommandArgError("Expected body argument in 'if'")
new_args.append(parser.parse_script(args[len(new_args)]))
# Parse elseif.
while (
len(new_args) < len(args)
and (arg := args[len(new_args)])
and arg.contents == "elseif"
):
new_args.append(arg)
# Parse elseif condition.
if len(new_args) == len(args):
raise CommandArgError(
"Expected condition argument in 'elseif' part of 'if'"
)
new_args.append(parser.parse_expression(args[len(new_args)]))
# Parse optional noise word then.
if len(new_args) == len(args):
raise CommandArgError(
"Expected then or body argument in 'elseif' part of 'if'"
)
arg = args[len(new_args)]
if arg.contents == "then":
new_args.append(arg)
# Parse elseif body.
if len(new_args) == len(args):
raise CommandArgError("Expected body argument in 'elseif' part of 'if'")
new_args.append(parser.parse_script(args[len(new_args)]))
if len(new_args) == len(args):
# No else part, we're done.
return new_args
# Parse optional noise word else.
arg = args[len(new_args)]
if arg.contents == "else":
new_args.append(arg)
# Parse else body.
if len(new_args) == len(args):
raise CommandArgError("Expected body argument to 'else' part of 'if'")
new_args.append(parser.parse_script(args[len(new_args)]))
if len(new_args) == len(args):
# Else part parsed, we're done.
return new_args
# Handle superfluous args.
arg = args[len(new_args)]
if arg.contents is None or not arg.contents:
raise CommandArgError("Argument after complete 'if'")
else:
raise CommandArgError(f"Argument after complete 'if': {arg.contents}")
def _interp_eval(args, parser):
@@ -492,13 +515,22 @@ def _interp_eval(args, parser):
def _lmap(args, parser):
# ref: https://www.tcl.tk/man/tcl/TclCmd/lmap.html
if len(args) < 3:
raise CommandArgError(
f"not enough args to lmap: got {len(args)}, expected at least 3"
)
"""
lmap varlist1 list1 ?varlist2 list2 ...? body
return args[:-1] + [parser.parse_script(args[-1])]
ref: https://www.tcl-lang.org/man/tcl8.6/TclCmd/lmap.htm
"""
spec = {
"positionals": [
{"name": "varlist1", "value": {"type": "any"}, "required": True},
{"name": "list1", "value": {"type": "any"}, "required": True},
{"name": "varlist list", "value": {"type": "variadic"}, "required": False},
{"name": "body", "value": {"type": "script"}, "required": True},
],
"switches": {},
}
# TODO: Check that number of variadic words is even.
return check_arg_spec("lmap", args, parser, spec)
def _namespace_code(args, parser):
@@ -656,6 +688,9 @@ def _switch(args, parser):
for i, node in enumerate(pattern_and_commands):
if i % 2 == 0:
parsed_patterns_and_commands.append(node)
elif node.contents == "-":
# Detect passthrough.
parsed_patterns_and_commands.append(node)
else:
parsed_patterns_and_commands.append(parser.parse_script(node))
@@ -795,16 +830,6 @@ def _try(args, parser):
return new_args
def _while(args, parser):
if len(args) != 2:
raise CommandArgError(f"wrong # of args to while: got {len(args)}, expected 2")
return [
parser.parse_expression(args[0]),
parser.parse_script(args[1]),
]
commands = commands_schema({
"after": {
"subcommands": {
@@ -828,14 +853,63 @@ commands = commands_schema({
"array": _array,
"binary": {
"subcommands": {
"decode": check_count("binary decode", 2, None),
"encode": check_count("binary encode", 2, None),
"format": check_count("binary format", 1, None),
"scan": check_count("binary scan", 2, None),
"decode": {
"positionals": [
{"name": "format", "value": {"type": "any"}, "required": True},
{
"name": "options",
"value": {"type": "variadic"},
"required": False,
},
{"name": "data", "value": {"type": "any"}, "required": True},
],
},
"encode": {
"positionals": [
{"name": "format", "value": {"type": "any"}, "required": True},
{
"name": "options",
"value": {"type": "variadic"},
"required": False,
},
{"name": "data", "value": {"type": "any"}, "required": True},
],
},
"format": {
"positionals": [
{
"name": "formatString",
"value": {"type": "any"},
"required": True,
},
{"name": "args", "value": {"type": "variadic"}, "required": False},
],
},
"scan": {
"positionals": [
{"name": "string", "value": {"type": "any"}, "required": True},
{
"name": "formatString",
"value": {"type": "any"},
"required": True,
},
{
"name": "varName",
"value": {"type": "variadic"},
"required": False,
},
],
},
},
},
"break": check_count("break", 0, 0),
"catch": _catch,
"break": {},
"catch": {
"positionals": [
{"name": "script", "value": {"type": "script"}, "required": True},
{"name": "resultVarName", "value": {"type": "any"}, "required": False},
{"name": "optionsVarName", "value": {"type": "any"}, "required": False},
]
},
"cd": {
"positionals": [
{"name": "dirName", "value": {"type": "any"}, "required": False}
@@ -884,7 +958,17 @@ commands = commands_schema({
"unset": check_count("dict unset", 2, None),
"update": _dict_update,
"values": check_count("dict values", 1, 2),
"with": _dict_with,
"with": {
"positionals": [
{
"name": "dictionaryVariable",
"value": {"type": "any"},
"required": True,
},
{"name": "key", "value": {"type": "variadic"}, "required": False},
{"name": "script", "value": {"type": "script"}, "required": True},
]
},
},
},
"encoding": {
@@ -909,8 +993,15 @@ commands = commands_schema({
"file": check_count("file", 1, None),
"fileevent": _fileevent,
"flush": check_count("flush", 1, 1),
"for": _for,
"foreach": _foreach,
"for": {
"positionals": [
{"name": "start", "value": {"type": "script"}, "required": True},
{"name": "test", "value": {"type": "expression"}, "required": True},
{"name": "next", "value": {"type": "script"}, "required": True},
{"name": "body", "value": {"type": "script"}, "required": True},
],
},
"foreach": foreach,
"format": check_count("format", 1, None),
"gets": check_count("gets", 1, 2),
"glob": check_count("glob"),
@@ -974,8 +1065,28 @@ commands = commands_schema({
"inscope": _namespace_inscope,
"origin": check_count("namespace origin", 1, 1),
"parent": check_count("namespace parent", 0, 1),
"path": {
"positionals": [
{
"name": "namespaceList",
"value": {"type": "any"},
"required": False,
},
]
},
"qualifiers": check_count("namespace qualifiers", 1, 1),
"tail": check_count("namespace tail", 1, 1),
"unknown": {
"positionals": [
{"name": "script", "value": {"type": "script"}, "required": False}
]
},
"upvar": {
"positionals": [
{"name": "namespace", "value": {"type": "any"}, "required": True},
{"name": "var", "value": {"type": "variadic"}, "required": False},
]
},
"which": check_count("namespace which", 1, 2),
"ensemble": {
"subcommands": {
@@ -1028,7 +1139,7 @@ commands = commands_schema({
"source": check_count("source", 1, 3),
"split": check_count("split", 1, 2),
# TODO: check subcommands
"string": check_count("string", 2, None),
"string": check_count("string", 1, None),
"subst": check_count("subst", 1, 4),
"switch": _switch,
"tailcall": check_count("tailcall", 1, None),
@@ -1061,7 +1172,12 @@ commands = commands_schema({
"upvar": check_count("upvar", 2, None),
"variable": check_count("variable", 1, None),
"vwait": check_count("vwait", 1, 1),
"while": _while,
"while": {
"positionals": [
{"name": "test", "value": {"type": "expression"}, "required": True},
{"name": "body", "value": {"type": "script"}, "required": True},
],
},
"yield": {
"positionals": [
{"name": "value", "value": {"type": "any"}, "required": False},
@@ -1074,5 +1190,5 @@ commands = commands_schema({
]
},
# TODO: check subcommands
"zlib": check_count("zlib", 3, None),
"zlib": check_count("zlib", 2, None),
})