diff --git a/compiler/logger.py b/compiler/logger.py index 09ab1d8..ab1980b 100644 --- a/compiler/logger.py +++ b/compiler/logger.py @@ -1,5 +1,20 @@ -import logging +from __future__ import annotations + import enum +import logging +import os + +_TRACE = (logging.DEBUG + logging.NOTSET) // 2 +logging.addLevelName(_TRACE, "TRACE") + +rootLogger = logging.getLogger() + +loglevel = os.getenv("LOGLEVEL", None) +if loglevel is not None: + rootLogger.setLevel(loglevel.upper()) + rootLogger.debug("Set loglevel from LOGLEVEL environment variable: %s", loglevel) + +rootLogger.handlers.clear() class LogLevel(enum.IntEnum): @@ -8,21 +23,59 @@ class LogLevel(enum.IntEnum): Warning = logging.WARNING Info = logging.INFO Debug = logging.DEBUG + Trace = _TRACE + Notset = logging.NOTSET -def make_logger(name: str, level: LogLevel = LogLevel.Debug) -> logging.Logger: - _logger = logging.getLogger(name) - _logger.setLevel(level) - # create console handler and set level to debug - ch = logging.StreamHandler() - ch.setLevel(level) - # create formatter - formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') - ch.setFormatter(formatter) - # add ch to logger - _logger.addHandler(ch) +class Logger: + def __init__(self, name: str, level: LogLevel | None = None): + self.name = name + if level is None: + level = rootLogger.level + self.level = level + self.logger = Logger._make_logger(self.name, self.level) - return _logger + @staticmethod + def _make_logger(name: str, level: LogLevel) -> logging.Logger: + _logger = logging.getLogger(name) + _logger.setLevel(level) + _logger.propagate = False + + # create console handler and set level to debug + ch = logging.StreamHandler() + ch.setLevel(level) + # create formatter + formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + # add ch to logger + _logger.addHandler(ch) + + return _logger + + def log(self, level: LogLevel, *args, exc_info: bool = False, **kwargs): + assert args[0] != "%s" + message = " ".join(arg if type(arg) == str else repr(arg) for arg in args) + self.logger.log(level, "%s", + message, + exc_info=exc_info, **kwargs) + + def critical(self, *args): + self.log(LogLevel.Critical, *args) + + def error(self, *args): + self.log(LogLevel.Error, *args) + + def warning(self, *args): + self.log(LogLevel.Warning, *args) + + def info(self, *args): + self.log(LogLevel.Info, *args) + + def debug(self, *args): + self.log(LogLevel.Debug, *args) + + def trace(self, *args): + self.log(LogLevel.Trace, *args) -logger = make_logger("compiler") +logger = Logger("compiler") diff --git a/compiler/parser.py b/compiler/parser.py index 1cf732a..5076764 100644 --- a/compiler/parser.py +++ b/compiler/parser.py @@ -1,13 +1,14 @@ from __future__ import annotations -from beartype.typing import List -from .logger import make_logger -from .nodes import Number, Sum, Expression, Product +from beartype.typing import List, Dict, Callable + +from .logger import Logger +from .nodes import Float, Sum, Value, Product, Node, Division, Sub, Integer, Expression from .source import SourceLocation from .tokenizer import Tokens, Token -logger = make_logger(__name__) +logger = Logger(__name__) class ParsingError(Exception): diff --git a/compiler/tokenizer.py b/compiler/tokenizer.py index 6145765..a3f85f0 100644 --- a/compiler/tokenizer.py +++ b/compiler/tokenizer.py @@ -3,12 +3,12 @@ from dataclasses import dataclass, field from beartype import beartype from beartype.typing import Optional, List -import enum -import re - -from .logger import logger +from .logger import Logger from .source import SourceLocation, Location +logger = Logger(__name__) + + @beartype @dataclass class Token: