cclang/src/Interpreter/Parser.py
2020-09-17 19:33:52 +02:00

318 lines
12 KiB
Python

from typing import List, Optional
from termcolor import colored
from Interpreter.Repo import Repo
from Interpreter.Utils import Utils
from Models.AbstractSyntaxTree.Class import Class
from Models.AbstractSyntaxTree.Function import Function
from Models.AbstractSyntaxTree.Library import Library
from Models.AbstractSyntaxTree.Variable import Variable
from Models.Interpreter.Error import Error, ErrorCode
from Models.Interpreter.ExpressionCharacters import ExpressionCharacters
from Models.Interpreter.FormatCharacters import FormatCharacters
from Models.Interpreter.Keywords import Keywords
from Models.Interpreter.Token import Token
from Models.Interpreter.TokenTypes import TokenTypes
from Models.Interpreter.Types import Types
class Parser:
def __init__(self, repo: Repo, utils: Utils) -> None:
self.__repo = repo
self.__utils = utils
# library status
self.__is_creating_library = False
self.__is_saving_library = False
self.__library: Optional[Library] = None
# class status
self.__is_creating_class = False
self.__is_saving_class = False
self.__class: Optional[Class] = None
# function status
self.__is_creating_function = False
self.__is_creating_function_parameters = False
self.__is_saving_function = False
self.__function: Optional[Function] = None
# variable status
self.__is_creating_variable = False
self.__is_saving_variable = False
self.__variable: Optional[Variable] = None
# type status
self.__is_creating_type = False
self.__type: Optional[Types] = None
# common
self.__next_is_public = True
def parse(self, tokens: List[Token]) -> None:
"""
Creates abstract syntax tree from token list
:param tokens:
:return:
"""
# output
if len(tokens) == 0:
return None
output_tokens = []
for t in tokens:
output_tokens.append({t.value: t.type})
# print(output_tokens)
for i in range(0, len(tokens)):
token = tokens[i]
print(colored(f'>> {self.__utils.line_number}: {token.type} {token.value}', 'blue'))
""" error status checks """
# check if var name is valid
if i-1 >= 0 and self.__is_creating_variable and tokens[i-1].value == Keywords.Variable:
if token.type != TokenTypes.Name:
self.__utils.error(Error(ErrorCode.Unexpected, f'{token.type.name}: {token.value}'))
""" normal status checks """
# token is member of variable value
if self.__is_saving_variable and token.value != FormatCharacters.chars.value[FormatCharacters.Semicolon.value] and self.__variable is not None:
print(6, 'save variable value')
self.__variable.value.append(token)
# token type keyword
if token.type == TokenTypes.Keyword:
self.__check_token_keyword(tokens, i, token)
# token type format character
elif token.type == TokenTypes.Format_Character:
self.__check_token_format_character(token)
# token type expression character
elif token.type == TokenTypes.Expression_Character:
self.__check_token_expression_character(token)
# token type name
elif token.type == TokenTypes.Name:
self.__check_token_name(token)
# token type type
elif token.type == TokenTypes.Type:
self.__check_token_type(token)
""" validation function """
def __check_token_keyword(self, tokens: List[Token], i: int, token: Token) -> None:
if token.value == Keywords.Library:
# create library
self.__is_creating_library = True
self.__library = Library()
self.__set_is_public(self.__library)
print(1, 'create lib')
elif token.value == Keywords.Class:
# create class
self.__is_creating_class = True
self.__class = Class()
self.__set_is_public(self.__class)
print(2, 'create class')
elif token.value == Keywords.Function:
# create function
self.__is_creating_function = True
self.__function = Function()
self.__set_is_public(self.__function)
print(3, 'create function')
elif token.value == Keywords.Variable:
self.__is_creating_variable = True
self.__variable = Variable()
print(6, 'create variable')
elif token.value == Keywords.Public:
if self.__is_saving_function:
self.__utils.error(Error(ErrorCode.Unexpected, f'{token.type.name}: {token.value}'))
return
self.__next_is_public = True
print(0, 'Next is public')
elif self.__next_is_public:
if i - 1 > 0:
error_msg = f'{token.type.name}: {tokens[i - 1].value}'
else:
error_msg = 'keyword: public'
self.__utils.error(Error(ErrorCode.Unexpected, error_msg))
def __check_token_format_character(self, token: Token) -> None:
if token.value == FormatCharacters.chars.value[FormatCharacters.Left_Brace.value]:
if self.__is_creating_library:
# set status to save vars and funcs to library
self.__is_creating_library = False
self.__is_saving_library = True
print(1, 'status save lib')
elif self.__is_creating_class:
# set status to save vars and funcs to class
self.__is_creating_class = False
self.__is_saving_class = True
print(2, 'status save class')
elif self.__is_creating_function:
# set status to save vars and commands to function
self.__is_creating_function = False
self.__is_saving_function = True
print(3, 'status save function')
# check for type end
if self.__is_creating_type:
self.__check_for_type_end()
elif token.value == FormatCharacters.chars.value[FormatCharacters.Right_Brace.value]:
if self.__is_saving_function:
# save function to class
self.__is_saving_function = False
if self.__class is not None:
self.__class.functions.append(self.__function)
print(3, f'saved function {self.__function.name}')
else:
self.__utils.error(Error(ErrorCode.Unexpected, f'function: {self.__function.name}'))
self.__function = None
elif self.__is_saving_class:
# save class to library
self.__is_saving_class = False
if self.__library is not None:
self.__library.classes.append(self.__class)
print(2, f'saved class {self.__class.name}')
else:
self.__utils.error(Error(ErrorCode.Unexpected, f'class: {self.__class.name}'))
self.__class = None
elif self.__is_saving_library:
# save library to ast
self.__is_saving_library = False
self.__repo.AST.libs.append(self.__library)
print(1, f'saved lib {self.__library.name}')
self.__library = None
elif token.value == FormatCharacters.chars.value[FormatCharacters.Left_Parenthesis.value]:
if self.__is_creating_function:
self.__is_creating_function_parameters = True
print(4, 'create function parameters')
elif token.value == FormatCharacters.chars.value[FormatCharacters.Right_Parenthesis.value]:
if self.__is_creating_function:
self.__is_creating_function_parameters = False
self.__type = None
print(4, 'save function parameters')
# check for type end
if self.__is_creating_type:
self.__check_for_type_end()
elif token.value == FormatCharacters.chars.value[FormatCharacters.Colon.value]:
self.__check_create_type(token)
elif token.value == FormatCharacters.chars.value[FormatCharacters.Semicolon.value]:
if self.__is_creating_type:
self.__check_for_type_end()
if self.__is_saving_variable:
self.__is_saving_variable = False
self.__add_variable()
self.__variable = None
print(6, 'status saved variable')
elif self.__is_creating_variable:
self.__is_creating_variable = False
self.__is_saving_variable = True
self.__add_variable()
self.__variable = None
print(6, 'status saved variable')
def __check_token_expression_character(self, token: Token) -> None:
if token.value == ExpressionCharacters.chars.value[ExpressionCharacters.Equal.value]:
# check for type end
if self.__is_creating_type:
self.__is_creating_variable = False
self.__is_saving_variable = True
self.__check_for_type_end()
def __check_token_name(self, token: Token) -> None:
if self.__is_creating_type and self.__type is not None:
self.__type = token.value
print(5, 'save type')
elif self.__is_creating_variable and self.__variable is not None:
self.__variable.name = token.value
print(6, 'save variable name')
elif self.__is_creating_library:
# save library name
self.__library.name = token.value
print(1, 'lib name')
elif self.__is_creating_class:
# save class name
self.__class.name = token.value
print(2, 'class name')
elif self.__is_creating_function and not self.__is_creating_function_parameters:
# save function name
self.__function.name = token.value
print(3, 'function name')
def __check_token_type(self, token: Token) -> None:
if self.__is_creating_function and self.__function is not None and not self.__is_creating_function_parameters:
self.__function.return_type = Types(Types.strings.value.index(token.value))
print(3, 'save function type')
elif self.__is_creating_type:
self.__type = Types(Types.strings.value.index(token.value))
print(5, 'save type')
""" util functions """
def __set_is_public(self, ast_element):
if ast_element is not None and self.__next_is_public:
ast_element.is_public = True
self.__next_is_public = False
def __check_for_type_end(self):
# end status creating type
self.__is_creating_type = False
print(5, 'status saved type')
def __check_create_type(self, token: Token):
if self.__is_creating_function or self.__is_creating_function_parameters or self.__is_creating_variable:
self.__is_creating_type = True
print(5, 'create type')
else:
self.__utils.error(Error(ErrorCode.Unexpected, f'{token.type.name}: {token.value}'))
def __add_variable(self):
if len(self.__variable.value) == 0:
self.__variable.value.append(Token(TokenTypes.Empty, Types.strings.value[Types.Empty.value]))
if self.__type is not None:
self.__variable.type = self.__type
else:
self.__utils.error(Error(ErrorCode.Expected, f'type'))
if self.__is_saving_function and self.__function is not None:
self.__function.variables.append(self.__variable)
elif self.__is_saving_class and self.__class is not None:
self.__class.variables.append(self.__variable)
else:
self.__utils.error(Error(ErrorCode.Unexpected, f'variable: {self.__variable.name}'))