Skip to content

Commit

Permalink
feat, refactor!: store objects as ayumu object instead of just object…
Browse files Browse the repository at this point in the history
…, rename exception module to `errors`, capital o (`O`) in `:o` and dash (`-`) for type define is now allowed, replace `self.types` with `OsakaType` and modularized a lot of the parsing in OsakerParser
  • Loading branch information
THEGOLDENPRO committed Sep 12, 2024
1 parent 240e50f commit 1f2ee8f
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 70 deletions.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"cSpell.words": [
"Ayumu",
"CHIYO",
"NYAN",
"osaker"
]
}
2 changes: 1 addition & 1 deletion osaker/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .lexer import OsakerLexer
from .parser import OsakerParser
from .logger import osaker_logger
from .exception import OsakerError, OsakerParseError
from .errors import OsakerError, OsakerParseError

app = typer.Typer(
pretty_exceptions_enable = False,
Expand Down
18 changes: 18 additions & 0 deletions osaker/ayumu_object.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Any

from .osaka_type import OsakaType

from dataclasses import dataclass

__all__ = (
"AyumuObject",
)

@dataclass
class AyumuObject():
type: OsakaType
value: Any
3 changes: 3 additions & 0 deletions osaker/exception.py → osaker/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ def __init__(self, error: Exception) -> None:
super().__init__(f"uhhh idk parse error! Error: {error}")

class OsakerSyntaxError(OsakerError):
...

class OsakerIncorrectTypeError(OsakerError):
...
6 changes: 3 additions & 3 deletions osaker/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class OsakerLexer():

tokens: Dict[str, str] = {
"OP_DELETE": ":3",
"OP_DEFINE": ":o", # TODO: Capital "o" should also be allowed.
"OP_DEFINE": r":[oO]",
"OP_INSPECT": ":<",

"NAME": r"[!a-zA-Z_][a-zA-Z0-9_]*",
"ASSIGN": "<--",

"LITERAL": r"(?<!<)-?\b\d+\b|(['\"])(?:\\.|[^\\])*?\1",

"TYPE": r"~[a-zA-Z0-9_]+",
"TYPE": r"[~-][a-zA-Z0-9_]+", # characters starting with either "-" or "~"

"PLUS": r"\+",
"MINUS": r"-",
Expand Down Expand Up @@ -81,7 +81,7 @@ def __manipulate_token_value(
value = None

if token_type == "TYPE":
value = token_value.replace("~", "")
value = token_value.replace("~", "").replace("-", "")
elif token_type == "LITERAL":
value = token_value.replace('"', "").replace("'", "")
else:
Expand Down
19 changes: 19 additions & 0 deletions osaker/osaka_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from __future__ import annotations

from enum import Enum

__all__ = (
"OsakaType",
)

class OsakaType(Enum):
NYAN = str
CHIYO = int

@classmethod
def from_python_type(cls, py_type: type) -> OsakaType:
return cls._value2member_map_[py_type]

@classmethod
def from_osaka_type_string(cls, osaka_type: str) -> OsakaType:
return cls._member_map_[osaka_type.upper()]
161 changes: 95 additions & 66 deletions osaker/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from typing import Dict, List, Generator
from typing import Dict, List, Generator, Type, Any

from .token import Token

import random
from pprint import pformat
from devgoldyutils import LoggerAdapter, Colours
from devgoldyutils import LoggerAdapter, Colours, short_str

from .logger import osaker_logger
from .exception import OsakerSyntaxError, OsakerError
from .osaka_type import OsakaType
from .ayumu_object import AyumuObject
from .errors import OsakerSyntaxError, OsakerError, OsakerIncorrectTypeError

__all__ = (
"OsakerParser"
Expand All @@ -20,17 +22,8 @@
logger = LoggerAdapter(osaker_logger, prefix = "Parser")

class OsakerParser():
types: Dict[str, type] = {
"chiyo": int,
"nyan": str
}

def __init__(self):
self._globals: Dict[str, object] = {}

self.__reverse_types: Dict[type, str] = dict(
(v, k) for k, v in self.types.items()
)
self._globals: Dict[str, AyumuObject] = {}

def parse(self, tokens: List[Token]) -> None:
logger.debug(f"Tokens --> {pformat(tokens)}")
Expand All @@ -57,6 +50,70 @@ def __parse_define(self, tokens: List[Token], index: int):
"you are trying to define after ':o'. \nFor example: ':o apple'."
)

literal_token = self.__parse_assign_literal(tokens, variable_token)

osaka_type = self.__parse_type(tokens, literal_token)

value = self.__cast_correct_type_or_error(literal_token.value, osaka_type)

ayumu_object = AyumuObject(
type = osaka_type,
value = value
)

# TODO: Catch the type error.
self._globals[variable_token.value] = ayumu_object

def __parse_delete(self, tokens: List[Token], index: int):
tokens: Generator[Token] = iter(tokens[index + 1:])

name_token = self.__parse_name(
tokens_after_operator = tokens,
error_message = "A name must be given for the Ayumu object " \
"you are trying to delete from memory after ':3'. \nFor example: ':3 !print'."
)

if name_token.value not in self._globals:
raise OsakerError(
f"'{name_token.value}' is not present in memory! Maybe you already deleted it?"
)

del self._globals[name_token.value]

def __parse_inspect(self, tokens: List[Token], index: int):
tokens: Generator[Token] = iter(tokens[index + 1:])

name_token = self.__parse_name(
tokens_after_operator = tokens,
error_message = "A name must be given for the Ayumu object " \
"you are trying to delete from memory after ':3'. \nFor example: ':3 !print'."
)

if name_token.value in self._globals:
ayumu_object = self._globals[name_token.value]

osaka_type = ayumu_object.type

literal_representation = Colours.ORANGE.apply(f'"{ayumu_object.value}"')

if osaka_type == OsakaType.CHIYO:
literal_representation = Colours.BLUE.apply(ayumu_object.value)

print(
">>", f"{Colours.BLUE.apply(name_token.value)} <-- {literal_representation} ~{Colours.CLAY.apply(osaka_type.name.lower())}"
)

def __parse_name(self, tokens_after_operator: Generator[Token], error_message: str) -> Token:
next_token = next(tokens_after_operator, None)

if next_token is None or not next_token.type == "NAME":
raise OsakerSyntaxError(error_message)

return next_token

def __parse_assign_literal(self, tokens_after_operator: Generator[Token], variable_token: Token) -> Token:
tokens = tokens_after_operator

next_token = next(tokens, None)

if next_token is None or not next_token.type == "ASSIGN":
Expand All @@ -83,18 +140,23 @@ def __parse_define(self, tokens: List[Token], index: int):

literal_token = next_token

return literal_token

def __parse_type(self, tokens_after_operator: Generator[Token], literal_token: Token) -> OsakaType:
tokens = tokens_after_operator

next_token = next(tokens, None)

if next_token is None or not next_token.type == "TYPE":
_type = self.__guess_literal_type(literal_token.value)
osaka_type = self.__reverse_types[_type]
osaka_type = OsakaType.from_python_type(_type)

hint_value = Colours.ORANGE.apply(f'"{literal_token.value}"')

if _type is int:
hint_value = Colours.BLUE.apply(literal_token.value)

hint_msg = f"Did you mean: {hint_value} ~{Colours.CLAY.apply(osaka_type)}"
hint_msg = f"Did you mean: {hint_value} ~{Colours.CLAY.apply(osaka_type.name.lower())}"

raise OsakerSyntaxError(
"The type of the literal must be defined! For example: '\"Hello, World!\" ~nyan'\n"
Expand All @@ -103,70 +165,37 @@ def __parse_define(self, tokens: List[Token], index: int):

type_define_token = next_token

# TODO: Catch the value error here.
type_ = self.types[type_define_token.value]

self._globals[variable_token.value] = type_(literal_token.value)

def __parse_delete(self, tokens: List[Token], index: int):
tokens: Generator[Token] = iter(tokens[index + 1:])

name_token = self.__parse_name(
tokens_after_operator = tokens,
error_message = "A name must be given for the Ayumu object " \
"you are trying to delete from memory after ':3'. \nFor example: ':3 !print'."
)

if name_token.value not in self._globals:
raise OsakerError(
f"'{name_token.value}' is not present in memory! Maybe you already deleted it?"
)

del self._globals[name_token.value]

def __parse_inspect(self, tokens: List[Token], index: int):
tokens: Generator[Token] = iter(tokens[index + 1:])

name_token = self.__parse_name(
tokens_after_operator = tokens,
error_message = "A name must be given for the Ayumu object " \
"you are trying to delete from memory after ':3'. \nFor example: ':3 !print'."
)

if name_token.value in self._globals:
ayumu_object_value = self._globals[name_token.value]

literal_representation = Colours.ORANGE.apply(f'"{ayumu_object_value}"')

if isinstance(ayumu_object_value, int):
literal_representation = Colours.BLUE.apply(ayumu_object_value)

osaka_type = self.__reverse_types[
self.__guess_literal_type(ayumu_object_value)
]
try:
osaka_type = OsakaType.from_osaka_type_string(type_define_token.value)

print(
">>", f"{Colours.BLUE.apply(name_token.value)} <-- {literal_representation} ~{Colours.CLAY.apply(osaka_type)}"
except ValueError as e:
raise OsakerSyntaxError(
f"Uhhhh, that type ('{type_define_token.value}') doesn't exist bro! Error: {e}"
)

def __parse_name(self, tokens_after_operator: Generator[Token], error_message: str) -> Token:
next_token = next(tokens_after_operator, None)

if next_token is None or not next_token.type == "NAME":
raise OsakerSyntaxError(error_message)

return next_token
return osaka_type

def __guess_literal_type(self, literal: str) -> type:

try:
int(literal)
return int
except ValueError:
except (TypeError, ValueError):
pass

return str

def __cast_correct_type_or_error(self, value: str, osaka_type: OsakaType) -> Any:
_type = osaka_type.value

try:
return _type(value)
except ValueError as e:
raise OsakerIncorrectTypeError(
f"An incorrect osaka type was cast! The type '{osaka_type.name}' " \
f"cannot cast upon the value '{short_str(value)}'! \nError: {e}"
)

def __format_hint(self, message: str) -> str:
face = random.choice(["(˶˃ ᵕ ˂˶) .ᐟ.ᐟ", "(˶ᵔ ᵕ ᵔ˶)"])

Expand Down

0 comments on commit 1f2ee8f

Please sign in to comment.