cclang/src/Interpreter/Parser.py
2020-05-25 16:36:44 +02:00

207 lines
7.2 KiB
Python

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}'))