Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ssjs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: ssjs

on:
pull_request:
branches:
- main

jobs:
pr:
runs-on: ubuntu-latest

steps:
- name: checkout
uses: actions/checkout@v2

- name: setup-python
uses: actions/setup-python@v2
with:
python-version: 3.12

- name: install
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov

- name: tests
run: |
pytest --rootdir=. -c=test/cfg/pytest.ini
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.*
__pycache__
main.py
*.json
*.jsonc
Empty file added ssjs/__init__.py
Empty file.
Empty file added ssjs/cast/__init__.py
Empty file.
14 changes: 14 additions & 0 deletions ssjs/cast/flex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import ssjs.core.cast as cast
import ssjs.core.flex as flex
import ssjs.core.util as util


class Flex(cast.Cast):
def sign(self) -> type:
return flex.Flex

def cast(self, obj: object) -> flex.Flex:
if isinstance(obj, dict):
return flex.Flex(obj, self.depo)

raise TypeError(f'no cast from "{util.otn(obj)}" to "Flex"')
16 changes: 16 additions & 0 deletions ssjs/cast/int.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ssjs.core.cast as cast
import ssjs.core.util as util


class Int(cast.Cast):
def sign(self) -> type:
return int

def cast(self, obj: object) -> int:
if isinstance(obj, bool):
return 1 if obj else 0

if isinstance(obj, str):
return int(obj)

raise TypeError(f'no cast from "{util.otn(obj)}" to "int"')
13 changes: 13 additions & 0 deletions ssjs/cast/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ssjs.core.cast as cast
import ssjs.core.util as util


class List(cast.Cast):
def sign(self) -> type:
return list

def cast(self, obj: object) -> list:
if isinstance(obj, tuple):
return list(obj)

raise TypeError(f'no cast from "{util.otn(obj)}" to "list"')
14 changes: 14 additions & 0 deletions ssjs/cast/rex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import re
import ssjs.core.cast as cast
import ssjs.core.util as util


class Rex(cast.Cast):
def sign(self) -> type:
return re.Pattern

def cast(self, obj: object) -> re.Pattern:
if isinstance(obj, str):
return re.compile(obj)

raise TypeError(f'no cast from "{util.otn(obj)}" to "re.Pattern"')
16 changes: 16 additions & 0 deletions ssjs/cast/str.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ssjs.core.cast as cast
import ssjs.core.util as util


class Str(cast.Cast):
def sign(self) -> type:
return str

def cast(self, obj: object) -> str:
if isinstance(obj, bool):
return 'true' if obj else 'false'

if isinstance(obj, int):
return str(obj)

raise TypeError(f'no cast from "{util.otn(obj)}" to "str"')
Empty file added ssjs/core/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions ssjs/core/bone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
''' Super Simple AST Bone '''


import abc


class Dot(abc.ABC):
def __str__(self) -> str:
return self.pretty()

__repr__ = __str__

@abc.abstractmethod
def pretty(self) -> str: ...


class Key(Dot):
def __init__(self, key: str) -> None:
self.key = key

def pretty(self) -> str:
return self.key


class Act(Dot, abc.ABC):
def __init__(self, lop: Dot, rop: Dot) -> None:
self.lop, self.act, self.rop = lop, self.code(), rop

def pretty(self) -> str:
return f'( {self.lop} {self.act} {self.rop} )'

@abc.abstractmethod
def code(self) -> str: ...


class ActAnd(Act):
def code(self) -> str:
return '&'


class ActAlt(Act):
def code(self) -> str:
return '|'
12 changes: 12 additions & 0 deletions ssjs/core/cast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
''' Super Simple Type Cast '''


import abc


class Cast(abc.ABC):
@abc.abstractmethod
def sign(self) -> type: pass

@abc.abstractmethod
def cast(self, obj: object) -> object: pass
80 changes: 80 additions & 0 deletions ssjs/core/chop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
''' Super Simple AST Chop '''


import ssjs.core.bone as bone
import ssjs.core.util as util


def chop(line: str) -> bone.Dot:
if not line:
raise util.ChopError('nil line', 0, line)

return chop_dot(line, 0, True, False)[0]


def chop_dot(line: str, beg: int, grd: bool, par: bool) -> tuple[bone.Dot, int]:
dot, idx = None, beg

while char := line[idx:idx + 1]:
if char == ' ':
idx += 1
continue

if char == '(':
if dot:
raise util.ChopError('hasty "("', idx, line)

dot, idx = chop_dot(line, idx + 1, False, True)
if not grd and not par:
break

continue

if char == ')':
if not par:
raise util.ChopError('hasty ")"', idx, line)

if not dot:
raise util.ChopError('empty "()"', idx, line)

return dot, idx + 1

if char == '&':
if not dot:
raise util.ChopError('miss "lop" for act "&"', idx, line)

rop, idx = chop_dot(line, idx + 1, False, False)
dot = bone.ActAnd(dot, rop)
continue

if char == '|':
if not dot:
raise util.ChopError('miss "lop" for act "|"', idx, line)

rop, idx = chop_dot(line, idx + 1, False, False)
dot = bone.ActAlt(dot, rop)
continue

if dot:
raise util.ChopError('miss act "&" or "|"', idx, line)

dot, idx = chop_key(line, idx)
if not grd and not par:
break

if par:
raise util.ChopError('miss ")"', idx, line)

if not dot:
raise util.ChopError('hasty eol', idx, line)

return dot, idx


def chop_key(line: str, beg: int) -> tuple[bone.Key, int]:
idx = beg

while line[idx:idx + 1] not in ' ()&|':
idx += 1

return bone.Key(line[beg:idx]), idx
57 changes: 57 additions & 0 deletions ssjs/core/depo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
''' Super Simple Type Depo '''


import typing
import inspect
import ssjs.core.util as util


DT = typing.TypeVar('DT')


class Depo(typing.Generic[DT]):
def __init__(self) -> None:
oc = util.goc(self)
args = getattr(oc, '__args__', None)

if not oc or not args or len(args) != 1:
raise TypeError('1 generic arg expected')

if not inspect.isclass(args[0]):
raise TypeError('generic arg must be a class')

self.__generic: type[DT] = args[0]
self.__collection: set[type[DT]] = set()

def __str__(self) -> str:
cnt = len(self.__collection)
otn = util.otn(self.__generic)
return f'total {cnt:,} "{otn}" items in depo'

def __iter__(self) -> typing.Iterator[type[DT]]:
return iter(self.__collection)

def push(self, obj: object) -> bool:
if not inspect.isclass(obj):
return False

if not issubclass(obj, self.__generic):
return False

if obj is self.__generic:
return False

if obj in self.__collection:
return False

self.__collection.add(obj)
return True

def scan(self, tgt: str) -> int:
cnt = 0

for obj in util.scan(tgt):
if self.push(obj):
cnt += 1

return cnt
Loading