from Interpreter.Repo import Repo from Interpreter.Utils import Utils from Models.Interpreter.Error import Error from Models.Interpreter.Token import Token from Models.Language.Class import Class from Models.Language.Func import Func from Models.Language.Lib import Lib class Parser: def __init__(self, repo: Repo, utils: Utils) -> None: self.__repo = repo self.__utils = utils # runtime representation self.__lib = None self.__class = None self.__func = None # helpers self.__tokens = [] # reset each line self.__i = 0 # for loop index self.__token_storage = [] self.__is_start_lib = False self.__is_start_class = False self.__is_start_func = False self.__is_public = False def parse(self, toks: list) -> None: self.__tokens = toks # self.__repo.output_tokens(toks) # output if len(toks) > 0: tokens = [] for t in toks: tokens.append({t.value: t.type}) # print(tokens) self.__check() # output if len(self.__repo.ast) > 1: print('___') for a_lib in self.__repo.ast: print(a_lib.name) for a_class in a_lib.ast: print(a_class.name, a_class.access) for a_funcs in a_class.ast: print(a_funcs.name, a_funcs.return_type, a_funcs.access) print('___') # print(self.__repo.ast, '\n') """ parser helpers """ def __get_next_token(self) -> Token: if len(self.__tokens) > self.__i + 1: return self.__tokens[self.__i + 1] else: return Token('EOL', 'EOL') def __get_last_token(self) -> Token: if len(self.__tokens) >= self.__i - 1: return self.__tokens[self.__i - 1] else: return Token('EOL', 'EOL') def __get_token_by_i_dif(self, delta: int) -> Token: return self.__tokens[self.__i + delta] def __is_scope_started(self) -> bool: return self.__is_start_lib or self.__is_start_class or self.__is_start_func def __is_only_func_started(self) -> bool: return not self.__is_start_lib and not self.__is_start_class and self.__is_start_func """ token checks """ def __check(self): # check tokens for self.__i in range(0, len(self.__tokens)): tok = self.__tokens[self.__i] if not self.__is_scope_started() and tok.type == 'keyword': self.__check_keyword(tok) elif tok.type == 'type' or tok.type in self.__repo.types: pass elif not self.__is_scope_started() and tok.type in self.__repo.var_types: pass elif tok.type == 'format_char': self.__check_format_char(tok) elif not self.__is_scope_started() and tok.type == 'expr_char': pass elif not self.__is_scope_started() and tok.type == 'bool_expr_char': self.__check_name(tok) elif tok.type == 'name': self.__check_name(tok) else: self.__utils.error(Error(2.9, f'{tok.type}: {tok.value}')) def __check_keyword(self, tok: Token) -> None: if tok.value == 'lib': self.__is_start_lib = True elif tok.value == 'class': self.__is_start_class = True elif tok.value == 'func': self.__is_start_func = True elif tok.value == 'public': next = self.__get_next_token() if next.type == 'keyword' and (next.value == 'class' or next.value == 'func'): self.__is_public = True else: if next.type == 'EOL': self.__utils.error(Error(2.8)) else: self.__utils.error(Error(2.9, next.value)) def __check_format_char(self, tok: Token) -> None: if tok.value == '{': # token in storage must be name! if len(self.__token_storage) > 0 and self.__token_storage[0].type == 'name': # lib if self.__is_start_lib and not self.__is_start_class and not self.__is_start_func: self.__lib = Lib(self.__token_storage[0].value) self.__token_storage = [] self.__is_start_lib = False # class elif not self.__is_start_lib and self.__is_start_class and not self.__is_start_func: access = '' if self.__is_public: access = 'public' self.__is_public = False self.__class = Class(self.__token_storage[0].value, access=access) self.__token_storage = [] self.__is_start_class = False # func elif not self.__is_start_lib and not self.__is_start_class and self.__is_start_func: access = '' if len(self.__token_storage) > 1 and self.__token_storage[1].type == 'type': if self.__is_public: access = 'public' self.__is_public = False self.__func = Func(self.__token_storage[0].value, self.__token_storage[1].value, access=access) self.__token_storage = [] self.__is_start_func = False else: self.__utils.error(Error(3.7)) else: self.__utils.error(Error(2.9, f'{tok.type}: {tok.value}')) elif not self.__is_scope_started() and tok.value == '}': if self.__lib is not None and self.__class is None and self.__func is None: self.__repo.ast.append(self.__lib) self.__lib = None elif self.__lib is not None and self.__class is not None and self.__func is None: self.__lib.ast.append(self.__class) self.__class = None elif self.__lib is not None and self.__class is not None and self.__func is not None: self.__class.ast.append(self.__func) self.__func = None else: self.__utils.error(Error(2.9, f'{tok.type}: {tok.value}')) elif self.__is_only_func_started() and (tok.value == '(' or tok.value == ')'): pass elif not self.__is_scope_started() and tok.value in self.__repo.format_chars: pass elif tok.value == ':': if self.__is_only_func_started(): next = self.__get_next_token() if next.type == 'type': self.__token_storage.append(next) else: self.__utils.error(Error(3.7)) else: self.__utils.error(Error(2.9, f'{tok.type}: {tok.value}')) def __check_name(self, tok: Token) -> None: if self.__is_start_lib or self.__is_start_class or self.__is_start_func: if len(self.__token_storage) == 0: self.__token_storage.append(tok) else: self.__utils.error(Error(2.9, f'{tok.type}: {tok.value}'))