add tclint

This commit is contained in:
2025-07-24 21:31:08 +02:00
parent e842d9d74e
commit 666c537f07
31 changed files with 6721 additions and 308 deletions
+61 -15
View File
@@ -1,19 +1,64 @@
from tools.lexer import Lexer, TclSyntaxError, Tok, TOK_EOF
from tools import syntax_tree as st
from tools.commands import CommandArgError, get_commands
from tools.checks import check_command
import string
import re
from src.tools.lexer import (
Lexer,
TclSyntaxError,
STATE_BRACEDWORD,
TOK_BACKSLASH_NEWLINE,
TOK_NEWLINE,
TOK_SEMI,
TOK_WS,
TOK_QUOTE,
TOK_ARG_EXPANSION,
TOK_LBRACE,
TOK_RBRACE,
TOK_LBRACKET,
TOK_RBRACKET,
TOK_DOLLAR,
TOK_LPAREN,
TOK_RPAREN,
TOK_HASH,
TOK_ALPHA_CHARS,
TOK_NUM_CHARS,
TOK_NAMESPACE_SEP,
TOK_EOF,
)
from src.tools.syntax_tree import (
Script,
Comment,
Command,
CommandSub,
ArgExpansion,
VarSub,
BareWord,
BracedWord,
QuotedWord,
CompoundBareWord,
List,
Expression,
BracedExpression,
ParenExpression,
UnaryOp,
BinaryOp,
TernaryOp,
Function,
)
from src.tools.commands import CommandArgError, get_commands
from src.tools.commands.checks import check_command
from src.tools.violations import Rule, Violation
def _strip_ws(parse_func):
"""Decorator used by expression parser for stripping whitespace around a node."""
def func(parser, ts):
while ts.type() in {Tok.TOK_WS, Tok.TOK_BACKSLASH_NEWLINE, Tok.TOK_NEWLINE}:
while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE}:
ts.next()
node = parse_func(parser, ts)
while ts.type() in {Tok.TOK_WS, Tok.TOK_BACKSLASH_NEWLINE, Tok.TOK_NEWLINE}:
while ts.type() in {TOK_WS, TOK_BACKSLASH_NEWLINE, TOK_NEWLINE}:
ts.next()
return node
@@ -22,6 +67,8 @@ def _strip_ws(parse_func):
class _Word:
"""Helper class for constructing Word nodes out of multiple segments."""
def __init__(self):
self.segments = []
self.current_segment = ""
@@ -30,13 +77,12 @@ class _Word:
def add_tok(self, tok):
if self.current_start is None:
self.current_start = tok.value[1]
self.current_segment += tok.value[0]
def add_node(self, node):
if self.current_segment != "":
self.segments.append(
st.BareWord(
self.current_segment, pos=self.current_start, end_pos=node.pos
)
BareWord(self.current_segment, pos=self.current_start, end_pos=node.pos)
)
self.current_segment = ""
self.current_start = None
@@ -45,9 +91,7 @@ class _Word:
def resolve(self, end_pos):
if self.current_segment:
self.segments.append(
st.BareWord(
self.current_segment, pos=self.current_start, end_pos=end_pos
)
BareWord(self.current_segment, pos=self.current_start, end_pos=end_pos)
)
return self.segments
@@ -57,7 +101,9 @@ class Parser:
def __init__(self, debug=False, command_plugins=None):
self._debug = debug
self._debug_indent = 0
# TODO: better way to handle this?
self.violations = []
if command_plugins is None:
command_plugins = []
self._commands = get_commands(command_plugins)
@@ -726,7 +772,7 @@ class Parser:
pos=name.pos,
)
delims = {Tok.TOK_RPAREN, TOK_EOF}
delims = {TOK_RPAREN, TOK_EOF}
arguments = []
if ts.type() not in delims:
@@ -745,11 +791,11 @@ class Parser:
arguments.append(self._parse_expression(ts))
ts.expect(
Tok.TOK_RPAREN,
TOK_RPAREN,
message="expected close paren after function arguments",
pos=name.pos,
)
return st.Function(name, *arguments, pos=name.pos, end_pos=ts.pos())
return Function(name, *arguments, pos=name.pos, end_pos=ts.pos())
def _all(_list, non_empty=False):