StoryScriptorg/StoryScript

View on GitHub
storyscript/cachelogger.py

Summary

Maintainability
A
0 mins
Test Coverage
from langEnums import Types
from orjson import dumps as dumpsjson, loads as loadsjson
from .SymbolTable import SymbolTable
from .langParser import Parser


class CacheLogger:
    """
    # [EXAMPLE TARGET CACHE FILE LAYOUT] #

    [SOURCE]
    int a = 10
    print (a)
    [ENDSOURCE]

    [STARTCACHE]
    INT A 10
    PRINT A
    [ENDCACHE]

    If No source block:

    #NOSOURCE
    """

    def __init__(self, no_source=False):
        self.source_block = []
        self.no_source = no_source
        if self.no_source:
            self.source_block = ["#NOSOURCE"]
        self.cache_string = []

    def cache_var_declaration(self, vartype, name, value):
        # INT(TYPE) A(NAME) 5(VALUE)
        self.cache_string.append(f"{vartype} {name} {value}")

    def cache_var_set(self, varname, value):
        """Cache a Variable set"""
        self.cache_string.append(f"SET {varname} {value}")

    def cache_function_call(self, funcname, args):
        """Cache a Function call"""
        args = dumpsjson({"args": args})
        self.cache_string.append(f"CALL {funcname} {args}")

    def cache_function_define(self, funcname, args, content):
        """Cache a Function define"""
        jsoncontent = dumpsjson({"args": args, "content": content}).decode("utf-8")
        self.cache_string.append(
            f"FUNC {funcname} [|!STARTCONTENT!|] {jsoncontent} [|!ENDCONTENT!|]"
        )

    def cache_loopfor_loop(self, times, content):
        """Cache a loopfor loop"""
        jsoncontent = dumpsjson({"content": content})
        self.cache_string.append(
            f"LOOPFOR {times} [|!STARTCONTENT!|] {jsoncontent} [|!ENDCONTENT!|]"
        )

    def cache_ternary(self, condition, truecase, falsecase):
        jsoncontent = dumpsjson(
            {"condition": condition, "truecase": truecase, "falsecase": falsecase}
        )
        self.cache_string.append(f"TERNARY {jsoncontent}")

    def log_source(self, source):
        """Add source to the Source list."""
        if not self.no_source:
            self.source_block.append(source)

    @staticmethod
    def retrieve_source(file_name, as_raw=False):
        """Retrieve source from file specified"""
        with open(file_name, "r") as file:
            content = file.readlines()
            res = []
            is_in_source_block = False
            for i in content:
                if i == "#NOSOURCE\n":
                    return None
                if i == "[SOURCE]\n":
                    is_in_source_block = True
                    continue
                if i == "[ENDSOURCE]\n":
                    is_in_source_block = False
                    break
                if is_in_source_block:
                    res.append(i)

            if as_raw:
                return "".join(res)

            return res

    @staticmethod
    def retrieve_cache(file_name, as_raw=False):
        """Retrive a cache from a specified file"""
        with open(file_name, "r") as file:
            content = file.readlines()
            res = []
            is_in_cache_block = False
            for i in content:
                if i == "[STARTCACHE]\n":
                    is_in_cache_block = True
                    continue
                if i == "[ENDCACHE]\n":
                    is_in_cache_block = False
                    break
                if is_in_cache_block:
                    res.append(i)

            if as_raw:
                return "".join(res)

            return res

    def save_cache(self, file_name):
        """Write the stored cache into a file specified."""
        with open(file_name, "w") as file:
            if self.source_block == ["#NOSOURCE"]:
                file.write("#NOSOURCE\n\n")
                file.writelines(self.cache_string)
            else:
                file.write("[SOURCE]\n")
                file.writelines(self.source_block)
                file.write("[ENDSOURCE]\n\n[STARTCACHE]\n")
                file.writelines(self.cache_string)
                file.write("\n[ENDCACHE]\n")


class CacheParser:
    def __init__(self, symbol_table, parser=None):
        self.symbol_table = symbol_table
        self.parser = parser

        if parser is None:
            self.parser = Parser(symbol_table)

    @staticmethod
    def trim_string(string):
        outstr = ""
        in_string = False
        for i in string:
            if i == '"':
                in_string = bool(not in_string)
            if not in_string and i == " ":
                continue
            outstr.append(i)
        return outstr

    def parse_function(self, tc):
        funclist = self.symbol_table.get_all_function_name()
        if tc[1] == "print":
            res = self.parser.parse_string_list(tc[2:])
            if res.endswith('"'):
                res = res[:-1]
            if res.startswith('"'):
                res = res[1:]
            res = self.execute_cache(res)
            print(res)
        elif tc[1] == "input":
            return input(self.parser.parse_string_list(tc[2:]))
        if tc[1] in funclist:
            funcObj = self.symbol_table.get_function(tc[1])
            args = self.parser.parse_string_list(tc[2:])
            args = self.trim_string(args)
            args = args.split("[||]")
            argslen = len(args) - 1
            i = 0
            while i < argslen:
                varobj = funcObj[0][i]
                varobj = varobj.split()
                self.symbol_table.SetVariable(varobj[1], args[i], varobj[0])
                i += 1
            for i in funcObj[1]:
                self.execute_cache(i)
            i = 0
            while i < argslen:
                varobj = (funcObj[0][i]).split()
                self.symbol_table.DeleteVariable(varobj[1])
                i += 1

    def execute_cache(self, command):
        tc = command.split()
        varlist = self.symbol_table.get_all_variable_name()

        if tc[0] in [
            "int",
            "bool",
            "float",
            "list",
            "dictionary",
            "tuple",
            "const",
            "string",
            "dynamic",
        ]:
            # VARTYPE NAME VALUE:
            vartype = self.parser.parse_type_string(tc[0])
            is_keep_float = False
            if vartype == Types.Float:
                is_keep_float = True
            expr = self.execute_cache(self.parser.parse_string_list(tc[2:]))
            self.symbol_table.SetVariable(tc[1], expr, vartype)
        elif tc[0] == "TERNARY":
            content = loadsjson(self.parser.parse_string_list(tc[1:]))
            print(content)
        elif tc[0] == "SET":
            # SET VARNAME VALUE:
            vartype = self.symbol_table.get_variable_type(tc[1])
            is_keep_float = False
            if vartype == Types.Float:
                is_keep_float = True
            expr = self.parser.parse_expression(tc[2:], is_keep_float)
            self.symbol_table.SetVariable(tc[1], expr, vartype)
        elif tc[0] == "CALL":
            return self.parse_function(tc)
        if tc[0] == "FUNC":
            loadedcontent = loadsjson(self.parser.parse_string_list(tc[2:]))
            self.symbol_table.setFunction(
                tc[1], loadedcontent["data"], loadedcontent["args"]
            )
        elif tc[0] == "LOOPFOR":
            if tc[1] in varlist:
                tc[1] = self.symbol_table.GetVariable(tc[1])[1]
            times = int(tc[1])
            content = loadsjson(self.parser.parse_string_list(tc[3:-1]))
            loopcount = 0
            while loopcount < times:
                for i in content["content"]:
                    self.execute_cache(i)
                loopcount += 1
        else:
            if tc[0] in varlist:
                return self.symbol_table.GetVariable(tc[0])[1]
            return self.parser.parse_string_list(tc)


if __name__ == "__main__":
    cachelogger = CacheLogger()
    cachelogger.cache_var_declaration("int", "a", "10")
    cachelogger.log_source("int a = 10\n")
    cachelogger.save_cache("main_storyscript.stsc")
    print("Cache:", cachelogger.retrieve_cache("main_storyscript.stsc", as_raw=False))
    print("Source:", cachelogger.retrieve_source("main_storyscript.stsc", as_raw=False))

    symboltable = SymbolTable()
    cacheParser = CacheParser(symboltable)
    cacheParser.execute_cache("int a 10")
    cacheParser.execute_cache("CALL print a")
    cacheParser.execute_cache("CALL print CALL input prompt hehe >\t")
    cacheParser.execute_cache(
        'TERNARY {"condition":"a == 5","truecase":["print (\\"The conditions is true.\\")"], "falsecase":[""]}'
    )
    cacheParser.execute_cache(
        'LOOPFOR 10 [|!STARTCONTENT!|] {"content":["CALL print \\"tong\\""]} [|!ENDCONTENT!|]'
    )