Improved parser to handle names and classes
This commit is contained in:
parent
ff025bdc7f
commit
b11ec9003e
@ -11,6 +11,8 @@ from lexer.model.token import Token
|
|||||||
from parser.abc.ast import AST
|
from parser.abc.ast import AST
|
||||||
from parser.abc.parser_abc import ParserABC
|
from parser.abc.parser_abc import ParserABC
|
||||||
from runtime.abc.runtime_service_abc import RuntimeServiceABC
|
from runtime.abc.runtime_service_abc import RuntimeServiceABC
|
||||||
|
from runtime.model.error import Error
|
||||||
|
from runtime.model.error_codes_enum import ErrorCodesEnum
|
||||||
|
|
||||||
|
|
||||||
class Application(ApplicationABC):
|
class Application(ApplicationABC):
|
||||||
@ -55,17 +57,18 @@ class Application(ApplicationABC):
|
|||||||
|
|
||||||
def _read_file(self, file: str):
|
def _read_file(self, file: str):
|
||||||
if not os.path.isfile(file):
|
if not os.path.isfile(file):
|
||||||
raise FileNotFoundError
|
self._runtime.error(Error(ErrorCodesEnum.FileNotFound))
|
||||||
# self.__utils.runtime_error(Error(ErrorCodes.FileNotFound))
|
|
||||||
|
|
||||||
if not file.endswith('.ccl'):
|
if not file.endswith('.ccl'):
|
||||||
raise Exception('Wrong file type')
|
self._runtime.error(Error(ErrorCodesEnum.WrongFileType))
|
||||||
# self.__utils.runtime_error(Error(ErrorCodes.WrongFileType))
|
|
||||||
|
|
||||||
|
|
||||||
|
self._runtime.file = file
|
||||||
f = open(file, 'r', encoding='utf-8').readlines()
|
f = open(file, 'r', encoding='utf-8').readlines()
|
||||||
for i in range(0, len(f)):
|
for i in range(0, len(f)):
|
||||||
self._runtime.line_count = i + 1
|
self._runtime.line_count = i + 1
|
||||||
self._interpret(f[i])
|
self._interpret(f[i])
|
||||||
|
self._runtime.file = ''
|
||||||
|
|
||||||
def configure(self): pass
|
def configure(self): pass
|
||||||
|
|
||||||
|
@ -9,4 +9,6 @@ class ASTTypesEnum(Enum):
|
|||||||
|
|
||||||
LibraryDeclaration = 'library_declaration'
|
LibraryDeclaration = 'library_declaration'
|
||||||
ClassDeclaration = 'class_declaration'
|
ClassDeclaration = 'class_declaration'
|
||||||
|
FuncDeclaration = 'func_declaration'
|
||||||
|
VariableDeclaration = 'variable_declaration'
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from typing import Optional, Tuple
|
||||||
from parser.abc.ast import AST
|
from parser.abc.ast import AST
|
||||||
from parser.abc.parser_abc import ParserABC
|
from parser.abc.parser_abc import ParserABC
|
||||||
from parser.model.ast_types_enum import ASTTypesEnum
|
from parser.model.ast_types_enum import ASTTypesEnum
|
||||||
@ -26,8 +27,43 @@ class ParserService(ParserABC):
|
|||||||
Keywords.This.value,
|
Keywords.This.value,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def _parse_name(self, tokens: List[Token]) -> Tuple[AST, Token]:
|
||||||
|
""" Parses names
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tokens (List[Token]): Tokens from lexer
|
||||||
|
|
||||||
|
AST:
|
||||||
|
Program
|
||||||
|
<name>
|
||||||
|
Program.Test
|
||||||
|
<name> <.> <name>
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
AST: Name AST
|
||||||
|
"""
|
||||||
|
name = ''
|
||||||
|
last_token: Optional[Token] = None
|
||||||
|
for i in range(0, tokens.count()):
|
||||||
|
token = tokens[i]
|
||||||
|
|
||||||
|
if i == tokens.count() and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Point:
|
||||||
|
self._runtime.error(Error(ErrorCodesEnum.Unexpected), FormatCharacters.Point.value)
|
||||||
|
|
||||||
|
if token.type == TokenTypes.Name or token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Point.value:
|
||||||
|
name += token.value
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
last_token = token
|
||||||
|
|
||||||
|
return (AST(ASTTypesEnum.Name, name, self._runtime.line_count, self._runtime.line_count), last_token)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_library_or_class(self, tokens: List[Token], cls=False) -> AST:
|
def _parse_library_or_class(self, tokens: List[Token], cls=False) -> AST:
|
||||||
""" Handles library declaration
|
""" Parses library or class declarations
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tokens (List[Token]): Tokens from lexer
|
tokens (List[Token]): Tokens from lexer
|
||||||
@ -39,35 +75,47 @@ class ParserService(ParserABC):
|
|||||||
<access> <lib, class> <name> <end>
|
<access> <lib, class> <name> <end>
|
||||||
public lib Main {}
|
public lib Main {}
|
||||||
<access> <lib, class> <name> <end> <end>
|
<access> <lib, class> <name> <end> <end>
|
||||||
|
public lib Main.Test {
|
||||||
|
<access> <lib, class> <name> <.> <name> <end> <end>
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AST: Library or class AST
|
AST: Library or class AST
|
||||||
"""
|
"""
|
||||||
end = None
|
end = None
|
||||||
ast = List(AST)
|
ast = List(AST)
|
||||||
for i in range(0, tokens.count()):
|
i = 0
|
||||||
|
while i < tokens.count():
|
||||||
token: Token = tokens[i]
|
token: Token = tokens[i]
|
||||||
|
|
||||||
# if line contains }
|
# if line contains }
|
||||||
if token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Right_Brace.value:
|
if token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Right_Brace.value:
|
||||||
end = self._runtime.line_count
|
end = self._runtime.line_count
|
||||||
|
|
||||||
elif i == tokens.count()-1 and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Left_Brace.value:
|
elif i == tokens.count()-1 and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Left_Brace.value:
|
||||||
break
|
break
|
||||||
|
|
||||||
elif i == tokens.count()-1:
|
elif i == tokens.count()-1:
|
||||||
self._runtime.error(
|
self._runtime.error(Error(ErrorCodesEnum.Expected, FormatCharacters.Left_Brace.value))
|
||||||
Error(ErrorCodesEnum.Expected, FormatCharacters.Left_Brace.value))
|
|
||||||
|
|
||||||
if i == 0 and token.type == TokenTypes.Keyword and token.value in self._access_keywords:
|
elif i == 0 and token.type == TokenTypes.Keyword and token.value in self._access_keywords:
|
||||||
ast.append(AST(ASTTypesEnum.Access, token.value,
|
ast.append(AST(ASTTypesEnum.Access, token.value, self._runtime.line_count, self._runtime.line_count))
|
||||||
self._runtime.line_count, self._runtime.line_count))
|
|
||||||
|
|
||||||
if i <= 1 and token.type == TokenTypes.Keyword and token.value == Keywords.Library.value:
|
elif i <= 1 and token.type == TokenTypes.Keyword and token.value == Keywords.Library.value and not cls:
|
||||||
ast.append(AST(ASTTypesEnum.Keyword, token.value,
|
ast.append(AST(ASTTypesEnum.Keyword, token.value, self._runtime.line_count, self._runtime.line_count))
|
||||||
self._runtime.line_count, self._runtime.line_count))
|
|
||||||
|
|
||||||
if i >= 1 and token.type == TokenTypes.Name:
|
elif i <= 1 and token.type == TokenTypes.Keyword and token.value == Keywords.Class.value and cls:
|
||||||
ast.append(AST(ASTTypesEnum.Name, token.value,
|
ast.append(AST(ASTTypesEnum.Keyword, token.value, self._runtime.line_count, self._runtime.line_count))
|
||||||
self._runtime.line_count, self._runtime.line_count))
|
|
||||||
|
elif i >= 1 and token.type == TokenTypes.Name:
|
||||||
|
name, last_token = self._parse_name(tokens.skip(i))
|
||||||
|
i = tokens.index(last_token)
|
||||||
|
ast.append(name)
|
||||||
|
ast.append(AST(ASTTypesEnum.Name, token.value, self._runtime.line_count, self._runtime.line_count))
|
||||||
|
|
||||||
|
else:
|
||||||
|
self._runtime.error(Error(ErrorCodesEnum.Unexpected, token.value))
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
return AST(ASTTypesEnum.LibraryDeclaration if not cls else ASTTypesEnum.ClassDeclaration, ast, self._runtime.line_count, end)
|
return AST(ASTTypesEnum.LibraryDeclaration if not cls else ASTTypesEnum.ClassDeclaration, ast, self._runtime.line_count, end)
|
||||||
|
|
||||||
@ -92,6 +140,12 @@ class ParserService(ParserABC):
|
|||||||
Returns:
|
Returns:
|
||||||
AST: Library or class AST
|
AST: Library or class AST
|
||||||
"""
|
"""
|
||||||
|
end = None
|
||||||
|
ast = List(AST)
|
||||||
|
for i in range(0, tokens.count()):
|
||||||
|
token: Token = tokens[i]
|
||||||
|
|
||||||
|
return AST(ASTTypesEnum.VariableDeclaration, ast)
|
||||||
|
|
||||||
def create_ast(self, tokens: List[Token]) -> List[AST]:
|
def create_ast(self, tokens: List[Token]) -> List[AST]:
|
||||||
self._ast = List(AST)
|
self._ast = List(AST)
|
||||||
@ -103,6 +157,6 @@ class ParserService(ParserABC):
|
|||||||
self._ast.append(self._parse_library_or_class(tokens, True))
|
self._ast.append(self._parse_library_or_class(tokens, True))
|
||||||
|
|
||||||
elif tokens.where(lambda t: t.type == TokenTypes.Keyword and t.value == Keywords.Variable.value).count() > 0:
|
elif tokens.where(lambda t: t.type == TokenTypes.Keyword and t.value == Keywords.Variable.value).count() > 0:
|
||||||
self._ast.append(self._parse_variable(tokens, True))
|
self._ast.append(self._parse_variable(tokens))
|
||||||
|
|
||||||
return self._ast
|
return self._ast
|
||||||
|
@ -19,6 +19,13 @@ class RuntimeServiceABC(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def line_count(self, line_count: int): pass
|
def line_count(self, line_count: int): pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file(self) -> str:
|
||||||
|
return self._file
|
||||||
|
@file.setter
|
||||||
|
def file(self, value: str):
|
||||||
|
self._file = value
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def input(self, prefix: str) -> str: pass
|
def input(self, prefix: str) -> str: pass
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ class RuntimeService(RuntimeServiceABC):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._line_count = 0
|
self._line_count = 0
|
||||||
|
self._file = ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def line_count(self) -> int:
|
def line_count(self) -> int:
|
||||||
@ -16,6 +17,13 @@ class RuntimeService(RuntimeServiceABC):
|
|||||||
def line_count(self, line_count: int):
|
def line_count(self, line_count: int):
|
||||||
self._line_count = line_count
|
self._line_count = line_count
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file(self) -> str:
|
||||||
|
return self._file
|
||||||
|
@file.setter
|
||||||
|
def file(self, value: str):
|
||||||
|
self._file = value
|
||||||
|
|
||||||
def input(self, prefix: str) -> str:
|
def input(self, prefix: str) -> str:
|
||||||
return Console.read_line(prefix)
|
return Console.read_line(prefix)
|
||||||
|
|
||||||
@ -24,12 +32,17 @@ class RuntimeService(RuntimeServiceABC):
|
|||||||
|
|
||||||
def error(self, error: Error) -> None:
|
def error(self, error: Error) -> None:
|
||||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||||
|
if self._file is not None:
|
||||||
|
Console.write_line(f'Error in {self._file} line {self._line_count}\n{error.message}')
|
||||||
|
else:
|
||||||
Console.write_line(f'Error in line {self._line_count}\n{error.message}')
|
Console.write_line(f'Error in line {self._line_count}\n{error.message}')
|
||||||
Console.color_reset()
|
Console.color_reset()
|
||||||
|
Console.write_line()
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
def runtime_error(self, error: Error) -> None:
|
def runtime_error(self, error: Error) -> None:
|
||||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||||
Console.write_line(f'{error.message}', 'red')
|
Console.write_line(f'{error.message}', 'red')
|
||||||
Console.color_reset()
|
Console.color_reset()
|
||||||
|
Console.write_line()
|
||||||
exit()
|
exit()
|
||||||
|
Loading…
Reference in New Issue
Block a user