import re
from collections import namedtuple

Token = namedtuple("Token", ["type", "value", "line", "col"])

token_specification = [
    ("NUMBER",   r"\d+"),
    ("ID",       r"[A-Za-z_][A-Za-z0-9_]*"),
    ("LPAREN",   r"\("),
    ("RPAREN",   r"\)"),
    ("COMMA",    r","),
    ("SKIP",     r"[ \t]+"),
    ("NEWLINE",  r"\n"),
    ("MISMATCH", r"."),
]

token_regex = "|".join(f"(?P<{name}>{pattern})" for name, pattern in token_specification)

def lex(code):
    line_num = 1
    line_start = 0
    tokens = []

    for mo in re.finditer(token_regex, code):
        kind = mo.lastgroup
        value = mo.group()
        col = mo.start() - line_start + 1

        if kind == "NUMBER":
            value = int(value)
            tokens.append(Token(kind, value, line_num, col))
        elif kind == "ID":
            tokens.append(Token(kind, value, line_num, col))
        elif kind == "NEWLINE":
            line_num += 1
            line_start = mo.end()
        elif kind == "SKIP":
            pass
        elif kind in ("LPAREN", "RPAREN", "COMMA"):
            tokens.append(Token(kind, value, line_num, col))
        else:
            raise RuntimeError(f"Unexpected character {value} at line {line_num} col {col}")

    return tokens
