Added logic to handle lib & class declaration
This commit is contained in:
parent
793ca62ddd
commit
2b02341336
@ -1,12 +1,12 @@
|
||||
{
|
||||
"WorkspaceSettings": {
|
||||
"DefaultProject": "cc-lang",
|
||||
"DefaultProject": "cc-lang-interpreter",
|
||||
"Projects": {
|
||||
"cc-lang-interpreter": "src/cc_lang_interpreter/cc-lang-interpreter.json",
|
||||
"cc-lang": "src/cc_lang/cc-lang.json",
|
||||
"parser": "src/parser/parser.json",
|
||||
"lexer": "src/lexer/lexer.json",
|
||||
"runtime": "src/runtime/runtime.json",
|
||||
"cc-lang-interpreter": "src/cc_lang_interpreter/cc-lang-interpreter.json"
|
||||
"runtime": "src/runtime/runtime.json"
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,8 @@
|
||||
"LicenseName": "",
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"sh_cpl==2021.4.0.post2"
|
||||
"sh_cpl-core==2021.10.0.post1",
|
||||
"sh_cpl-query==2021.10.0.post1"
|
||||
],
|
||||
"PythonVersion": ">=3.9.2",
|
||||
"PythonPath": {
|
||||
|
@ -4,8 +4,11 @@ from cpl_core.application import ApplicationABC
|
||||
from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.console import Console
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_query.extension.list import List
|
||||
|
||||
from lexer.abc.lexer_abc import LexerABC
|
||||
from lexer.model.token import Token
|
||||
from parser.abc.ast import AST
|
||||
from parser.abc.parser_abc import ParserABC
|
||||
from runtime.abc.runtime_service_abc import RuntimeServiceABC
|
||||
|
||||
@ -22,15 +25,17 @@ class Application(ApplicationABC):
|
||||
self._path = config.get_configuration('p')
|
||||
|
||||
def _interpret(self, line: str):
|
||||
tokens = self._lexer.tokenize(line)
|
||||
ast = self._parser.create_ast(tokens)
|
||||
|
||||
tokens: List[Token] = self._lexer.tokenize(line)
|
||||
ast: List[AST] = self._parser.create_ast(tokens)
|
||||
|
||||
line.replace("\n", "").replace("\t", "")
|
||||
# Console.write_line(f'<{self._runtime.line_count}> LINE: {line}')
|
||||
Console.write_line(f'<{self._runtime.line_count}> LINE: {line}')
|
||||
# header, values = ['Type', 'Value'], []
|
||||
# tokens.for_each(lambda t: values.append([t.type, t.value]))
|
||||
# Console.table(header, values)
|
||||
|
||||
Console.write(ast, '\n')
|
||||
|
||||
def _console(self):
|
||||
i = 0
|
||||
while True:
|
||||
@ -62,8 +67,7 @@ class Application(ApplicationABC):
|
||||
self._runtime.line_count = i + 1
|
||||
self._interpret(f[i])
|
||||
|
||||
def configure(self):
|
||||
pass
|
||||
def configure(self): pass
|
||||
|
||||
def main(self):
|
||||
if self._path is None:
|
||||
|
@ -17,7 +17,7 @@
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"sh_cpl-core==2021.10.0.post1",
|
||||
"sh_cpl-query==2021.10.0"
|
||||
"sh_cpl-query==2021.10.0.post1"
|
||||
],
|
||||
"PythonVersion": ">=3.9.2",
|
||||
"PythonPath": {
|
||||
|
@ -23,8 +23,8 @@ class Startup(StartupABC):
|
||||
return config
|
||||
|
||||
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironment) -> ServiceProviderABC:
|
||||
services.add_singleton(RuntimeServiceABC, RuntimeService)
|
||||
services.add_singleton(LexerABC, LexerService)
|
||||
services.add_singleton(ParserABC, ParserService)
|
||||
services.add_singleton(RuntimeServiceABC, RuntimeService)
|
||||
|
||||
return services.build_service_provider()
|
||||
|
@ -16,7 +16,8 @@
|
||||
"LicenseName": "",
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"sh_cpl==2021.4.0.post2"
|
||||
"sh_cpl-core==2021.10.0.post1",
|
||||
"sh_cpl-query==2021.10.0.post1"
|
||||
],
|
||||
"PythonVersion": ">=3.9.2",
|
||||
"PythonPath": {
|
||||
|
@ -19,5 +19,8 @@ class Token:
|
||||
def value(self, value: str):
|
||||
self._value = value
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Token <Type: {self._type}> <Value: {self._value}>'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'Token: Type: {self._type}, Value: {self._value}'
|
||||
|
34
src/parser/abc/ast.py
Normal file
34
src/parser/abc/ast.py
Normal file
@ -0,0 +1,34 @@
|
||||
from typing import Optional, Union
|
||||
from cpl_query.extension.list import List
|
||||
from parser.model.ast_types_enum import ASTTypesEnum
|
||||
|
||||
|
||||
class AST():
|
||||
|
||||
def __init__(self, type: ASTTypesEnum, value: Union[str, List['AST']], start: Optional[int] = None, end: Optional[int] = None):
|
||||
self._type = type
|
||||
self._value = value
|
||||
self._start = start
|
||||
self._end = end
|
||||
|
||||
@property
|
||||
def type(self) -> ASTTypesEnum:
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def value(self) -> Union[str, List['AST']]:
|
||||
return self._value
|
||||
|
||||
@property
|
||||
def start(self) -> Optional[int]:
|
||||
return self._start
|
||||
|
||||
@property
|
||||
def end(self) -> Optional[int]:
|
||||
return self._end
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'AST <Type: {self._type}> <Value: {self._value}> <{self._start},{self._end}>'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'AST <Type: {self._type}> <Value: {self._value}> <{self._start},{self._end}>'
|
@ -1,7 +0,0 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class AST(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self): pass
|
@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_query.extension.list import List
|
||||
|
||||
from parser.abc.ast_abc import AST
|
||||
from parser.abc.ast import AST
|
||||
from lexer.model.token import Token
|
||||
|
||||
class ParserABC(ABC):
|
||||
|
1
src/parser/model/__init__.py
Normal file
1
src/parser/model/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# imports
|
12
src/parser/model/ast_types_enum.py
Normal file
12
src/parser/model/ast_types_enum.py
Normal file
@ -0,0 +1,12 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ASTTypesEnum(Enum):
|
||||
|
||||
Access = 'access'
|
||||
Keyword = 'keyword'
|
||||
Name = 'name'
|
||||
|
||||
LibraryDeclaration = 'library_declaration'
|
||||
ClassDeclaration = 'class_declaration'
|
||||
|
18
src/parser/model/class_ast.py
Normal file
18
src/parser/model/class_ast.py
Normal file
@ -0,0 +1,18 @@
|
||||
from parser.abc.ast import AST
|
||||
|
||||
from cpl_query.extension.list import List
|
||||
|
||||
|
||||
class ClassAST(AST):
|
||||
|
||||
def __init__(self):
|
||||
AST.__init__(self)
|
||||
self._body = List(AST)
|
||||
|
||||
@property
|
||||
def body(self) -> List['AST']:
|
||||
return self._body
|
||||
|
||||
@body.setter
|
||||
def body(self, value: List['AST']):
|
||||
self._body = value
|
18
src/parser/model/library_ast.py
Normal file
18
src/parser/model/library_ast.py
Normal file
@ -0,0 +1,18 @@
|
||||
from parser.abc.ast import AST
|
||||
|
||||
from cpl_query.extension.list import List
|
||||
|
||||
|
||||
class LibraryAST(AST):
|
||||
|
||||
def __init__(self):
|
||||
AST.__init__(self)
|
||||
self._body = List(AST)
|
||||
|
||||
@property
|
||||
def body(self) -> List['AST']:
|
||||
return self._body
|
||||
|
||||
@body.setter
|
||||
def body(self, value: List['AST']):
|
||||
self._body = value
|
8
src/parser/model/parser_state_enum.py
Normal file
8
src/parser/model/parser_state_enum.py
Normal file
@ -0,0 +1,8 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ParserStateEnum(Enum):
|
||||
|
||||
Default = 0
|
||||
Library = 1
|
||||
Class = 2
|
@ -16,7 +16,8 @@
|
||||
"LicenseName": "",
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"sh_cpl==2021.4.0.post2"
|
||||
"sh_cpl-core==2021.10.0.post1",
|
||||
"sh_cpl-query==2021.10.0.post1"
|
||||
],
|
||||
"PythonVersion": ">=3.9.2",
|
||||
"PythonPath": {
|
||||
|
@ -1,19 +1,108 @@
|
||||
from parser.abc.ast import AST
|
||||
from parser.abc.parser_abc import ParserABC
|
||||
from parser.model.ast_types_enum import ASTTypesEnum
|
||||
|
||||
from cc_lang.model.language_definition_classes import FormatCharacters, Keywords
|
||||
from cpl_core.console.console import Console
|
||||
from cpl_query.extension.list import List
|
||||
from lexer.model.token import Token
|
||||
from parser.abc.ast_abc import AST
|
||||
from parser.abc.parser_abc import ParserABC
|
||||
from lexer.model.token_types import TokenTypes
|
||||
from pynput.keyboard import Key
|
||||
from parser.model.parser_state_enum import ParserStateEnum
|
||||
from runtime.abc.runtime_service_abc import RuntimeServiceABC
|
||||
from runtime.model.error import Error
|
||||
from runtime.model.error_codes_enum import ErrorCodesEnum
|
||||
|
||||
|
||||
class ParserService(ParserABC):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
def __init__(self, runtime: RuntimeServiceABC):
|
||||
self._runtime = runtime
|
||||
|
||||
self._access_keywords = [
|
||||
Keywords.Public.value,
|
||||
Keywords.Private.value,
|
||||
Keywords.Static.value,
|
||||
Keywords.This.value,
|
||||
]
|
||||
|
||||
def _parse_library_or_class(self, tokens: List[Token], cls=False) -> AST:
|
||||
""" Handles library declaration
|
||||
|
||||
Args:
|
||||
tokens (List[Token]): Tokens from lexer
|
||||
|
||||
AST:
|
||||
lib Main {
|
||||
<lib, class> <name> <end>
|
||||
public lib Main {
|
||||
<access> <lib, class> <name> <end>
|
||||
public lib Main {}
|
||||
<access> <lib, class> <name> <end> <end>
|
||||
|
||||
Returns:
|
||||
AST: Library or class AST
|
||||
"""
|
||||
end = None
|
||||
ast = List(AST)
|
||||
for i in range(0, tokens.count()):
|
||||
token: Token = tokens[i]
|
||||
|
||||
# if line contains }
|
||||
if token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Right_Brace.value:
|
||||
end = self._runtime.line_count
|
||||
elif i == tokens.count()-1 and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Left_Brace.value:
|
||||
break
|
||||
elif i == tokens.count()-1:
|
||||
self._runtime.error(
|
||||
Error(ErrorCodesEnum.Expected, FormatCharacters.Left_Brace.value))
|
||||
|
||||
if i == 0 and token.type == TokenTypes.Keyword and token.value in self._access_keywords:
|
||||
ast.append(AST(ASTTypesEnum.Access, token.value,
|
||||
self._runtime.line_count, self._runtime.line_count))
|
||||
|
||||
if i <= 1 and token.type == TokenTypes.Keyword and token.value == Keywords.Library.value:
|
||||
ast.append(AST(ASTTypesEnum.Keyword, token.value,
|
||||
self._runtime.line_count, self._runtime.line_count))
|
||||
|
||||
if i >= 1 and token.type == TokenTypes.Name:
|
||||
ast.append(AST(ASTTypesEnum.Name, token.value,
|
||||
self._runtime.line_count, self._runtime.line_count))
|
||||
|
||||
return AST(ASTTypesEnum.LibraryDeclaration if not cls else ASTTypesEnum.ClassDeclaration, ast, self._runtime.line_count, end)
|
||||
|
||||
def _parse_variable(self, tokens: List[AST]) -> AST:
|
||||
""" Parses variable declarations
|
||||
|
||||
Args:
|
||||
tokens (List[Token]): Tokens from lexer
|
||||
|
||||
AST:
|
||||
var test: number;
|
||||
<var> <name> <type> <end>
|
||||
var test: number = 0;
|
||||
<var> <name> <type> <value | int, str, bool> <end>
|
||||
var test: number = test;
|
||||
<var> <name> <type> <name> <end>
|
||||
var test: number = TestClass();
|
||||
<var> <name> <type> <object-assign> <end>
|
||||
private var test: number = 0;
|
||||
<access> <var> <name> <type> <end>
|
||||
|
||||
Returns:
|
||||
AST: Library or class AST
|
||||
"""
|
||||
|
||||
def create_ast(self, tokens: List[Token]) -> List[AST]:
|
||||
for i in range(0, tokens.count()):
|
||||
prev_token = tokens[i-1] if i-1 > 0 else None
|
||||
token = tokens[i]
|
||||
next_token = tokens[i+1] if i+1 < tokens.count() else None
|
||||
|
||||
Console.write_line(token)
|
||||
self._ast = List(AST)
|
||||
|
||||
if tokens.where(lambda t: t.type == TokenTypes.Keyword and t.value == Keywords.Library.value).count() > 0:
|
||||
self._ast.append(self._parse_library_or_class(tokens))
|
||||
|
||||
elif tokens.where(lambda t: t.type == TokenTypes.Keyword and t.value == Keywords.Class.value).count() > 0:
|
||||
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:
|
||||
self._ast.append(self._parse_variable(tokens, True))
|
||||
|
||||
return self._ast
|
||||
|
@ -1,5 +1,10 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from cpl_core.console.console import Console
|
||||
from cpl_core.console.foreground_color_enum import ForegroundColorEnum
|
||||
|
||||
from runtime.model.error import Error
|
||||
|
||||
|
||||
class RuntimeServiceABC(ABC):
|
||||
|
||||
@ -13,3 +18,15 @@ class RuntimeServiceABC(ABC):
|
||||
@line_count.setter
|
||||
@abstractmethod
|
||||
def line_count(self, line_count: int): pass
|
||||
|
||||
@abstractmethod
|
||||
def input(self, prefix: str) -> str: pass
|
||||
|
||||
@abstractmethod
|
||||
def output(self, text: str): pass
|
||||
|
||||
@abstractmethod
|
||||
def error(self, error: Error): pass
|
||||
|
||||
@abstractmethod
|
||||
def runtime_error(self, error: Error): pass
|
||||
|
1
src/runtime/model/__init__.py
Normal file
1
src/runtime/model/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# imports
|
16
src/runtime/model/error.py
Normal file
16
src/runtime/model/error.py
Normal file
@ -0,0 +1,16 @@
|
||||
from runtime.model.error_codes_enum import ErrorCodesEnum
|
||||
|
||||
|
||||
class Error:
|
||||
|
||||
def __init__(self, code: ErrorCodesEnum, msg: str):
|
||||
self._code = code
|
||||
self._msg = code.value.format(msg)
|
||||
|
||||
@property
|
||||
def code(self) -> ErrorCodesEnum:
|
||||
return self._code
|
||||
|
||||
@property
|
||||
def message(self) -> str:
|
||||
return self._msg
|
21
src/runtime/model/error_codes_enum.py
Normal file
21
src/runtime/model/error_codes_enum.py
Normal file
@ -0,0 +1,21 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ErrorCodesEnum(Enum):
|
||||
|
||||
StartFailed = 'Start failed'
|
||||
FileNotFound = 'File not found'
|
||||
WrongFileType = 'Wrong file type'
|
||||
|
||||
Unknown = 'Unknown {}'
|
||||
Inaccessible = '{} inaccessible'
|
||||
Unexpected = 'Unexpected {}'
|
||||
Expected = 'Expected {}'
|
||||
|
||||
LibInLib = 'Lib in lib'
|
||||
LibInClass = 'Lib in class'
|
||||
LibInFunc = 'Lib in func'
|
||||
ClassInClass = 'Class in class'
|
||||
ClassInFunc = 'Class in func'
|
||||
FuncInLib = 'Func in lib'
|
||||
FuncInFunc = 'Func in func'
|
@ -16,7 +16,8 @@
|
||||
"LicenseName": "",
|
||||
"LicenseDescription": "",
|
||||
"Dependencies": [
|
||||
"sh_cpl==2021.4.0.post2"
|
||||
"sh_cpl-core==2021.10.0.post1",
|
||||
"sh_cpl-query==2021.10.0.post1"
|
||||
],
|
||||
"PythonVersion": ">=3.9.2",
|
||||
"PythonPath": {
|
||||
|
@ -1,4 +1,6 @@
|
||||
from cpl_core.console import Console, ForegroundColorEnum
|
||||
from runtime.abc.runtime_service_abc import RuntimeServiceABC
|
||||
from runtime.model.error import Error
|
||||
|
||||
|
||||
class RuntimeService(RuntimeServiceABC):
|
||||
@ -13,3 +15,21 @@ class RuntimeService(RuntimeServiceABC):
|
||||
@line_count.setter
|
||||
def line_count(self, line_count: int):
|
||||
self._line_count = line_count
|
||||
|
||||
def input(self, prefix: str) -> str:
|
||||
return Console.read_line(prefix)
|
||||
|
||||
def output(self, text: str) -> None:
|
||||
Console.write_line(f'> {text}')
|
||||
|
||||
def error(self, error: Error) -> None:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'Error in line {self._line_count}\n{error.message}')
|
||||
Console.color_reset()
|
||||
exit()
|
||||
|
||||
def runtime_error(self, error: Error) -> None:
|
||||
Console.set_foreground_color(ForegroundColorEnum.red)
|
||||
Console.write_line(f'{error.message}', 'red')
|
||||
Console.color_reset()
|
||||
exit()
|
||||
|
Loading…
Reference in New Issue
Block a user