cclang/src/Interpreter/Parser.py

191 lines
6.6 KiB
Python
Raw Normal View History

from Interpreter.Repo import Repo
from Interpreter.Utils import Utils
2020-05-24 17:56:15 +02:00
from Models.Interpreter.Error import Error
2020-05-23 13:40:51 +02:00
from Models.Interpreter.Token import Token
2020-05-24 17:56:15 +02:00
from Models.Language.AST.Class import Class
from Models.Language.AST.Func import Func
from Models.Language.AST.Lib import Lib
class Parser:
def __init__(self, repo: Repo, utils: Utils) -> None:
self.__repo = repo
self.__utils = utils
2020-05-24 17:56:15 +02:00
# 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:
2020-05-24 17:56:15 +02:00
self.__tokens = toks
2020-05-23 13:40:51 +02:00
# self.__repo.output_tokens(toks)
2020-05-24 17:56:15 +02:00
# 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.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 not self.__is_scope_started() and 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 == '{':
if len(self.__token_storage) > 0 and self.__token_storage[0].type == 'name':
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
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
elif not self.__is_start_lib and not self.__is_start_class and self.__is_start_func:
access = ''
if self.__is_public:
access = 'public'
self.__is_public = False
self.__func = Func(self.__token_storage[0].value, access=access)
self.__token_storage = []
self.__is_start_func = False
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
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}'))