diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..e1e8d91 --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,63 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "main" ] + pull_request: + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[tests] + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + - name: Test with pytest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + pytest --cov=src + coveralls --service=github + + flake8: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.8"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e .[tests] + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --show-source --statistics + - name: Static Test with Mypy + run: | + mypy src/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..de7c184 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,48 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "vba_stdlib" +version = "0.0.1" +authors = [ + { name="Kevin Nowaczyk", email="beakerboy99@yahoo.com" }, +] +description = "VBA Standard Library." +readme = "README.md" +requires-python = ">=3.7" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", +] +dependencies = [ + 'antlr4-python3-runtime', + 'antlr4-tools', + 'antlr4-vba', + 'python-dateutil', +] +[project.optional-dependencies] +tests = [ + 'coveralls', + 'flake8-annotations', + 'mypy', + 'pep8-naming', + 'pytest', + 'pytest-cov', + 'pytest-mock', + 'types-antlr4-python3-runtime', + 'types-python-dateutil', +] +[project.urls] +"Homepage" = "https://github.com/Beakerboy/VBA-Linter" +"Bug Tracker" = "https://github.com/Beakerboy/VBA-Linter/issues" + +[tool.setuptools.package-data] +"vba_stdlib" = ["py.typed"] + +[tool.pytest.ini_options] +pythonpath = "src:tests" +testpaths = [ + "tests", +] diff --git a/src/vba_stdlib/__init__.py b/src/vba_stdlib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/vba_stdlib/like_pattern_converer.py b/src/vba_stdlib/like_pattern_converer.py new file mode 100644 index 0000000..7e4b3d3 --- /dev/null +++ b/src/vba_stdlib/like_pattern_converer.py @@ -0,0 +1,5 @@ +from antlr4_vba.vba_likeVisitor import vba_likeVisitor + + +class LikePatternConverter(vba_likeVisitor): + pass diff --git a/src/vba_stdlib/literal_factory.py b/src/vba_stdlib/literal_factory.py new file mode 100644 index 0000000..fee5791 --- /dev/null +++ b/src/vba_stdlib/literal_factory.py @@ -0,0 +1,52 @@ +import re +from dateutil.parser import parse +from typing import Any + + +def literal_from_string(value: str) -> Any: + """ + Create a VBA literal type from a string. + """ + boolean_pattern = "TRUE|FALSE" + hex_pattern = r"&H[\dA-F]+" + oct_pattern = "&[Oo]?[0-7]+" + dec_pattern = r"\d+" + date_pattern = "##" + exp = r"[DEde][+-]?\d\d*" + float_pattern1 = r"\.\d\d*(" + exp + ")?" + float_pattern2 = r"\d\d*" + exp + float_pattern3 = r"\d\d*\.(\d\d*)?(" + exp + ")?" + + # Date Literal + sep = "([ ]+|([]*[/-][]*))" + eng_month = ("(JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE" + + "|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER)") + month_abv = "(JAN|FEB|MAR|APR|JUN|JUL|AUG|SEP|OCT|NOV|DEC)" + month_name = "(" + eng_month + "|" + month_abv + ")" + date_val_part = r"(\d+|" + month_name + ")" + date = (date_val_part + sep + date_val_part + + "(" + sep + date_val_part + ")?") + time_pattern1 = r"(\d+(AM|PM|A|P))" + time_pattern2 = r"(\d+[ ]?[:.][ ]?\d+([ ]?[:.][ ]?\d+)?)" + time_pattern = "(" + time_pattern1 + "|" + time_pattern2 + ")" + date_pattern = date + "([ ]+" + time_pattern + ")?" + if re.fullmatch(boolean_pattern, value.upper()): + return value.upper() == "TRUE" + if re.fullmatch(hex_pattern, value): + return int("0x" + value[2:], 16) + if re.fullmatch(oct_pattern, value): + start = 2 if value[1].upper() == 'O' else 1 + return int(value[start:], 8) + if re.fullmatch(dec_pattern, value): + return int(value) + if (re.fullmatch(float_pattern1, value) or + re.fullmatch(float_pattern2, value) or + re.fullmatch(float_pattern3, value)): + return float(value) + if value[-1] == '"' and value[0] == '"': + return value[1:-1] + if (re.fullmatch("#" + date_pattern + "#", value) or + re.fullmatch("#" + time_pattern + "#", value)): + return parse(value[1:-1]) + # assume non-quoted string. + return value diff --git a/src/vba_stdlib/py.typed b/src/vba_stdlib/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/Unit/test_int.py b/tests/Unit/test_int.py new file mode 100644 index 0000000..bfc52e3 --- /dev/null +++ b/tests/Unit/test_int.py @@ -0,0 +1,13 @@ +from vba_stdlib.literal_factory import literal_from_string + + +def test_decimal() -> None: + assert literal_from_string("10") == 10 + + +def test_hex() -> None: + assert literal_from_string("&HA") == 10 + + +def test_oct() -> None: + assert literal_from_string("&O12") == 10