From fa2a42dcc88a0bb2022bc5b56f10ccd159bc52eb Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Wed, 23 Sep 2020 19:38:14 +0200 Subject: [PATCH] [DevState] Improved Parsing for AST Lib, Class, Func, Var, Call --- doc/ast_rules.txt | 44 +- doc/ast_test.json | 64 +++ doc/todo.txt | 2 + src/First.bl | 2 +- src/Interpreter/Interpreter.py | 29 +- src/Interpreter/Lexer.py | 4 + src/Interpreter/Parser.py | 401 +++++++++++++++++- src/Interpreter/Repo.py | 89 ++-- .../AbstractSyntaxTree/AbstractSyntaxTree.py | 88 +++- src/Models/Interpreter/Datatypes.py | 24 +- src/Models/Token/TokenValueTypes.py | 98 ++--- 11 files changed, 664 insertions(+), 181 deletions(-) create mode 100644 doc/ast_test.json create mode 100644 doc/todo.txt diff --git a/doc/ast_rules.txt b/doc/ast_rules.txt index 612f115..b86ebd4 100644 --- a/doc/ast_rules.txt +++ b/doc/ast_rules.txt @@ -1,40 +1,6 @@ -LibraryDefinition: - IsPublic: - Name: - -ClassDefinition: - IsPublic: - Name: - Instructions: - -FunctionDefinition: - IsPublic: - Name: - Arguments: - ReturnType: - Instructions: - -VariableDefinition: - IsPublic: - Name: - Type: - Value: - IsAbleToBeEmpty: - -FunctionCall: - Function: - Arguments: - -Assignment: - Target: - Value: - -Operation: - Type: <+, -, *, /> - Arguments: - -Value: - Value: <1-9, '', true/false> - Type: - +operation: number <+, -, *, /> number +lib def: lib Name { +class def: class Name { +func def: func Name(arg: type<, more args>) { +var def: var Name: type<= value>; \ No newline at end of file diff --git a/doc/ast_test.json b/doc/ast_test.json new file mode 100644 index 0000000..f06c395 --- /dev/null +++ b/doc/ast_test.json @@ -0,0 +1,64 @@ +{ + "libraries": [ + { + "is_public": "True", + "name": "Main", + "classes": [ + { + "is_public": "False", + "name": "Program", + "variables": [ + { + "is_public": "False", + "name": "test", + "type": "bool", + "value": "false" + }, + { + "is_public": "False", + "name": "test2", + "type": "Program2", + "value": "empty" + }, + { + "is_public": "False", + "name": "test3", + "type": "Program2", + "value": {} + } + ], + "functions": [ + { + "is_public": "False", + "name": "Main", + "args": [], + "return_type": "empty", + "instructions": [ + { + "is_public": "False", + "name": "hallo", + "type": "any", + "value": "empty" + } + ] + }, + { + "is_public": "False", + "name": "isTrue", + "args": [ + { + "is_public": "False", + "name": "value", + "type": "bool", + "value": "empty" + } + ], + "return_type": "bool", + "instructions": [] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/doc/todo.txt b/doc/todo.txt new file mode 100644 index 0000000..57b3f5f --- /dev/null +++ b/doc/todo.txt @@ -0,0 +1,2 @@ +Todo: + - parse function \ No newline at end of file diff --git a/src/First.bl b/src/First.bl index adc44ae..a034ffd 100644 --- a/src/First.bl +++ b/src/First.bl @@ -8,7 +8,7 @@ public lib Main { class Program { var test: bool = false; var test2: Program2 = empty; - var test3: Program2 = Test(); + var test3: Program2 = Test(34); func Main(): empty { #func Main { diff --git a/src/Interpreter/Interpreter.py b/src/Interpreter/Interpreter.py index 0830d37..ea3169c 100644 --- a/src/Interpreter/Interpreter.py +++ b/src/Interpreter/Interpreter.py @@ -1,9 +1,12 @@ +from typing import Optional + from Interpreter.Validator import Validator from Interpreter.Lexer import Lexer # from Interpreter.Parser_Old import Parser from Interpreter.Parser import Parser from Interpreter.Repo import Repo from Interpreter.Utils import Utils +from Models.AbstractSyntaxTree.AbstractSyntaxTree import AbstractSyntaxTree class Interpreter: @@ -22,12 +25,34 @@ class Interpreter: :return: """ tokens = [] + ast: Optional[AbstractSyntaxTree] = None if self.__repo.is_error is None: tokens = self.__lexer.tokenize(line_str) if self.__repo.is_error is None: - self.__parser.parse(tokens) + ast = self.__parser.parse(tokens) + + """ print('#####\n') + if ast is not None: + for lib in ast.libraries: + print('lib', lib.name) + for cl in lib.classes: + print('class', cl.name) + for var in cl.variables: + print('cl var', var.name) + + for func in cl.functions: + print('func', func.name) + for arg in func.args: + print('func arg', arg.name) + + for var in func.variables: + print('func var', var.name) + + for ins in func.instructions: + print('ins', ins) + """ # if self.__repo.is_error is None: - # self.__validator.validate(self.__repo.AST) + # self.__validator.validate(self.__repo.AST) diff --git a/src/Interpreter/Lexer.py b/src/Interpreter/Lexer.py index 628cb1f..21bc554 100644 --- a/src/Interpreter/Lexer.py +++ b/src/Interpreter/Lexer.py @@ -89,6 +89,10 @@ class Lexer: # end of number elif not c.isdigit() and c != '.' and is_number: self.__add_tok(tokens, word, UnresolvedTokenTypes.Number) + local_tokens = self.tokenize(c) + for local_token in local_tokens: + tokens.append(local_token) + word = '' is_number = False diff --git a/src/Interpreter/Parser.py b/src/Interpreter/Parser.py index b87833e..7c9e4bb 100644 --- a/src/Interpreter/Parser.py +++ b/src/Interpreter/Parser.py @@ -1,8 +1,14 @@ -from typing import List, Optional +from typing import List, Optional, Union from Interpreter.Repo import Repo from Interpreter.Utils import Utils +from Models.AbstractSyntaxTree.AbstractSyntaxTree import LibraryDefinitionNode, ClassDefinitionNode, AbstractSyntaxTree, \ + FunctionDefinitionNode, VariableDefinitionNode, CallDefinitionNode, ValueNode, ASTElement +from Models.Interpreter.Datatypes import Datatypes +from Models.Interpreter.Error import Error, ErrorCodes from Models.Token.Token import Token +from Models.Token.TokenTypes import TokenTypes +from Models.Token.TokenValueTypes import Keywords, FormatCharacters, ExpressionCharacters class Parser: @@ -11,16 +17,399 @@ class Parser: self.__repo = repo self.__utils = utils - self.__next_is_public = False - + self.__ast: AbstractSyntaxTree = AbstractSyntaxTree() + self.__saved_tokens: List[Token] = [] self.__expected_tokens: List[Token] = [] - self.__ast: Optional[None] = None + # for validation if type is created + self.__is_saving_type = False + self.__is_saving_value = False + self.__is_saving_call = False + self.__is_end = False + + self.__saved_ast_elements: List[ASTElement] = [] + + def parse(self, tokens: List[Token]) -> AbstractSyntaxTree: + self.__is_end = False - def parse(self, tokens: List[Token]) -> None: if len(tokens) > 0: toks = [] for tok in tokens: toks.append({tok.type.name, tok.value}) - print(toks) + print(self.__repo.line_number, toks) + + for i in range(0, len(tokens)): + token = tokens[i] + + self.__check_for_expected_tokens(token) + + # keywords + if token.type == TokenTypes.Keyword: + if token.value == Keywords.Public.value: + self.__saved_tokens.append(token) + print('save public') + self.__add_expected_token(TokenTypes.Keyword, Keywords.Library.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Class.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Function.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Variable.value) + + elif token.value == Keywords.Library.value: + self.__saved_tokens.append(token) + print('save lib') + self.__add_expected_token(TokenTypes.Name) + + elif token.value == Keywords.Class.value: + self.__saved_tokens.append(token) + print('save class') + self.__add_expected_token(TokenTypes.Name) + + elif token.value == Keywords.Function.value: + self.__saved_tokens.append(token) + print('save function') + self.__add_expected_token(TokenTypes.Name) + + elif token.value == Keywords.Variable.value: + self.__saved_tokens.append(token) + print('save var') + self.__add_expected_token(TokenTypes.Name) + + # names + elif token.type == TokenTypes.Name: + if self.__is_saving_variable() and self.__is_saving_value: + self.__save_name(token) + if self.__is_saving_variable(): + self.__is_saving_call = True + + # names could be variable types, validation check in evaluator + elif self.__is_saving_variable() and self.__is_saving_type: + self.__save_type(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) + + elif self.__is_saving_variable(): + self.__save_name(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Colon.value) + + elif self.__is_saving_function(): + self.__save_name(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) + + elif self.__is_saving_library() or self.__is_saving_class(): + self.__save_name(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Brace.value) + + # format chars + elif token.type == TokenTypes.Format_Character: + if token.value == FormatCharacters.Left_Brace.value: + if self.__is_saving_library(): + self.__save_library() + + elif self.__is_saving_class(): + self.__save_class() + + elif token.value == FormatCharacters.Colon.value: + if self.__is_saving_variable(): + self.__is_saving_type = True + self.__add_expected_token(TokenTypes.Type) + self.__add_expected_token(TokenTypes.Name) + + elif token.value == FormatCharacters.Semicolon.value: + self.__end_line() + + elif token.value == FormatCharacters.Left_Parenthesis.value: + self.__add_expected_token(TokenTypes.Name) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Right_Parenthesis.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.This.value) + self.__add_expected_token(TokenTypes.Name) + self.__add_expected_token(TokenTypes.Empty) + self.__add_expected_token(TokenTypes.Number) + self.__add_expected_token(TokenTypes.String) + self.__add_expected_token(TokenTypes.Bool) + + if self.__is_saving_call: + self.__saved_tokens.append(token) + + elif token.value == FormatCharacters.Right_Parenthesis.value: + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Colon.value) + + if self.__is_saving_call: + self.__saved_tokens.append(token) + self.__save_call() + self.__is_saving_call = False + + # expr chars + elif token.type == TokenTypes.Expression_Character: + if token.value == ExpressionCharacters.Equal.value: + self.__is_saving_value = True + self.__add_expected_token(TokenTypes.Bool) + self.__add_expected_token(TokenTypes.Number) + self.__add_expected_token(TokenTypes.String) + self.__add_expected_token(TokenTypes.Empty) + self.__add_expected_token(TokenTypes.Name) + self.__add_expected_token(TokenTypes.Keyword, Keywords.This.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Input.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Range.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Length.value) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) + self.__add_expected_token(TokenTypes.Type, Datatypes.Empty.value) + + # types + elif token.type == TokenTypes.Type: + if self.__is_saving_variable() and self.__is_saving_value: + self.__save_value(token) + + elif self.__is_saving_variable(): + self.__save_type(token) + + # values + elif token.type == TokenTypes.Bool or token.type == TokenTypes.Number or token.type == TokenTypes.String: + if self.__is_saving_call: + self.__saved_tokens.append(token) + + elif self.__is_saving_value: + self.__save_value(token) + + return self.__ast + + """ + Utils + """ + + def __save_name(self, token: Token): + self.__saved_tokens.append(token) + print('save name') + + def __add_expected_token(self, token_type: TokenTypes, value: str = ''): + self.__expected_tokens.append(Token(token_type, value)) + + def __check_for_expected_tokens(self, token: Token): + error_token: Optional[Token] = None + is_error = True + + for expected_token in self.__expected_tokens: + if self.__is_end or token.type != expected_token.type or expected_token.value != '' and token.value != expected_token.value: + error_token = token + else: + is_error = False + + if error_token is not None and is_error: + self.__utils.error(Error(ErrorCodes.Unexpected, f'{error_token.type.name} {error_token.value}')) + + self.__expected_tokens = [] + + def __end_line(self): + if self.__is_saving_variable(): + self.__save_variable() + + self.__is_end = True + self.__expected_tokens = [] + self.__is_saving_type = False + self.__is_saving_value = False + + """ + Library + """ + + def __is_saving_library(self) -> bool: + found = False + for token in self.__saved_tokens: + if token.type == TokenTypes.Keyword and token.value == Keywords.Library.value: + found = True + + return found + + def __save_library(self) -> None: + is_public = False + name_token: Optional[Token] = None + + for token in self.__saved_tokens: + if token.type == TokenTypes.Name: + name_token = token + elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: + is_public = True + + if name_token is not None: + self.__ast.libraries.append(LibraryDefinitionNode(is_public, name_token.value)) + self.__saved_tokens = [] + self.__add_expected_token(TokenTypes.Keyword, Keywords.Public.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Class.value) + print('saved library') + + """ + Class + """ + + def __is_saving_class(self) -> bool: + found = False + for token in self.__saved_tokens: + if token.type == TokenTypes.Keyword and token.value == Keywords.Class.value: + found = True + + return found + + def __save_class(self) -> None: + is_public = False + name_token: Optional[Token] = None + + for token in self.__saved_tokens: + if token.type == TokenTypes.Name: + name_token = token + elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: + is_public = True + + if name_token is not None: + self.__ast.libraries[len(self.__ast.libraries) - 1].classes.append(ClassDefinitionNode(is_public, name_token.value)) + self.__saved_tokens = [] + self.__add_expected_token(TokenTypes.Keyword, Keywords.Public.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Variable.value) + self.__add_expected_token(TokenTypes.Keyword, Keywords.Function.value) + print('saved class') + + """ + Call + """ + def __save_call(self) -> None: + name_token: Optional[Token] = None + args: List[ValueNode] = [] + remove_tokens = [] + is_call = False + + for i in range(0, len(self.__saved_tokens)): + token = self.__saved_tokens[i] + last_token: Optional[Token] = None + if i-1 > 0: + last_token = self.__saved_tokens[i-1] + + if token.type == TokenTypes.Name and last_token is not None and last_token.type == TokenTypes.Format_Character and last_token.value == FormatCharacters.Left_Parenthesis.value: + pass + + if token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Left_Parenthesis.value and last_token is not None and last_token.type == TokenTypes.Name: + name_token = last_token + remove_tokens.append(last_token) + remove_tokens.append(token) + is_call = True + elif is_call and token.type == TokenTypes.Format_Character and token.value == FormatCharacters.Right_Parenthesis.value: + remove_tokens.append(token) + elif is_call and token.type == TokenTypes.Bool or token.type == TokenTypes.Number or token.type == TokenTypes.String: + args.append(ValueNode(token.value, Datatypes[token.type.name])) + remove_tokens.append(token) + + if name_token is not None: + call = CallDefinitionNode(name_token.value) + call.args = args + self.__saved_ast_elements.append(call) + + for token in remove_tokens: + self.__saved_tokens.remove(token) + + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) + print('saved call') + + """ + Function + """ + + def __is_saving_function(self) -> bool: + found = False + for token in self.__saved_tokens: + if token.type == TokenTypes.Keyword and token.value == Keywords.Function.value: + found = True + + return found + + def __save_function(self) -> None: + is_public = False + name_token: Optional[Token] = None + return_type: Optional[Token] = None + + for token in self.__saved_tokens: + if token.type == TokenTypes.Name: + name_token = token + elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: + is_public = True + elif token.type == TokenTypes.Type: + return_type = token + + if name_token is not None and return_type is not None: + self.__ast.libraries[len(self.__ast.libraries) - 1].classes[len(self.__ast.libraries) - 1].functions.append( + FunctionDefinitionNode(is_public, name_token.value, Datatypes[return_type.value])) + self.__saved_tokens = [] + print('saved function') + + """ + Variable + """ + + def __is_saving_variable(self) -> bool: + found = False + for token in self.__saved_tokens: + if token.type == TokenTypes.Keyword and token.value == Keywords.Variable.value: + found = True + + return found + + def __save_type(self, token: Token) -> None: + self.__saved_tokens.append(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) + self.__add_expected_token(TokenTypes.Expression_Character, ExpressionCharacters.Equal.value) + self.__is_saving_type = False + print('save type') + + def __save_variable(self): + is_public = False + name_token: Optional[Token] = None + datatype: Optional[Token] = None + value: Optional[Union[str, Token, CallDefinitionNode]] = None + + reset_saved_ast = False + + for token in self.__saved_tokens: + if token.type == TokenTypes.Name and name_token is None: + name_token = token + elif token.type == TokenTypes.Keyword and token.value == Keywords.Public.value: + is_public = True + elif token.type == TokenTypes.Type or name_token is not None and token.type == TokenTypes.Name: + datatype = token + + value = Token(TokenTypes.Empty, TokenTypes.Empty.value) + + for saved_ast_element in self.__saved_ast_elements: + if isinstance(saved_ast_element, CallDefinitionNode): + value = saved_ast_element + reset_saved_ast = True + + if reset_saved_ast: + self.__saved_ast_elements = [] + + if name_token is not None and datatype is not None and value is not None: + if not isinstance(value, CallDefinitionNode): + value = value.value + + if datatype.type == TokenTypes.Name: + variable = VariableDefinitionNode(is_public, name_token.value, datatype.value, value) + else: + variable = VariableDefinitionNode(is_public, name_token.value, Datatypes[str(datatype.value).capitalize()], value) + + if len(self.__ast.libraries) > 0: + lib = self.__ast.libraries[len(self.__ast.libraries) - 1] + if len(lib.classes) > 0: + cl = lib.classes[len(lib.classes) - 1] + if len(cl.functions) == 0: + cl.variables.append(variable) + else: + cl.functions[len(cl.functions) - 1].variables.append(variable) + + self.__saved_tokens = [] + print('saved variable') + + """ + Value + """ + + def __save_value(self, token: Token): + self.__saved_tokens.append(token) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Left_Parenthesis.value) + self.__add_expected_token(TokenTypes.Format_Character, FormatCharacters.Semicolon.value) + self.__is_saving_value = False + print('save value') diff --git a/src/Interpreter/Repo.py b/src/Interpreter/Repo.py index ad7c131..29e12d8 100644 --- a/src/Interpreter/Repo.py +++ b/src/Interpreter/Repo.py @@ -11,62 +11,63 @@ class Repo: # interpreter self.keywords = [ # define keywords - Keywords.Library, - Keywords.Class, - Keywords.Function, - Keywords.Variable, - Keywords.Use, - Keywords.From, + Keywords.Library.value, + Keywords.Class.value, + Keywords.Function.value, + Keywords.Variable.value, + Keywords.Use.value, + Keywords.From.value, # builtin functions - Keywords.Output, - Keywords.Input, - Keywords.Length, - Keywords.Range, - Keywords.Exit, + Keywords.Output.value, + Keywords.Input.value, + Keywords.Length.value, + Keywords.Range.value, + Keywords.Exit.value, # normal keywords - Keywords.If, - Keywords.ElseIf, - Keywords.Else, - Keywords.Continue, - Keywords.If, - Keywords.Return, + Keywords.If.value, + Keywords.ElseIf.value, + Keywords.Else.value, + Keywords.Continue.value, + Keywords.If.value, + Keywords.Return.value, # loops - Keywords.While, - Keywords.For, + Keywords.While.value, + Keywords.For.value, # access - Keywords.Public + Keywords.Public.value, + Keywords.This.value ] self.datatypes = [ - Datatypes.strings.value[Datatypes.Empty.value], - Datatypes.strings.value[Datatypes.Any.value], - Datatypes.strings.value[Datatypes.Number.value], - Datatypes.strings.value[Datatypes.String.value], - Datatypes.strings.value[Datatypes.Bool.value], - Datatypes.strings.value[Datatypes.List.value], - Datatypes.strings.value[Datatypes.Dict.value] + Datatypes.Empty.value, + Datatypes.Any.value, + Datatypes.Number.value, + Datatypes.String.value, + Datatypes.Bool.value, + Datatypes.List.value, + Datatypes.Dict.value ] self.format_chars = [ - FormatCharacters.chars.value[FormatCharacters.Left_Brace.value], - FormatCharacters.chars.value[FormatCharacters.Right_Brace.value], - FormatCharacters.chars.value[FormatCharacters.Left_Parenthesis.value], - FormatCharacters.chars.value[FormatCharacters.Right_Parenthesis.value], - FormatCharacters.chars.value[FormatCharacters.Left_Bracket.value], - FormatCharacters.chars.value[FormatCharacters.Right_Bracket.value], - FormatCharacters.chars.value[FormatCharacters.Semicolon.value], - FormatCharacters.chars.value[FormatCharacters.Colon.value], - FormatCharacters.chars.value[FormatCharacters.Comma.value], - FormatCharacters.chars.value[FormatCharacters.Point.value] + FormatCharacters.Left_Brace.value, + FormatCharacters.Right_Brace.value, + FormatCharacters.Left_Parenthesis.value, + FormatCharacters.Right_Parenthesis.value, + FormatCharacters.Left_Bracket.value, + FormatCharacters.Right_Bracket.value, + FormatCharacters.Semicolon.value, + FormatCharacters.Colon.value, + FormatCharacters.Comma.value, + FormatCharacters.Point.value ] self.expr_chars = [ - ExpressionCharacters.chars.value[ExpressionCharacters.Plus.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Minus.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Asterisk.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Slash.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Equal.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Caret.value] + ExpressionCharacters.Plus.value, + ExpressionCharacters.Minus.value, + ExpressionCharacters.Asterisk.value, + ExpressionCharacters.Slash.value, + ExpressionCharacters.Equal.value, + ExpressionCharacters.Caret.value ] self.bool_expr_chars = ['<', '>', '!', '!=', '==', '>=', '<=', '&&', '||'] - self.bool_values = [Booleans.Right, Booleans.Wrong] + self.bool_values = [Booleans.Right.value, Booleans.Wrong.value] # runtime self.is_error = None diff --git a/src/Models/AbstractSyntaxTree/AbstractSyntaxTree.py b/src/Models/AbstractSyntaxTree/AbstractSyntaxTree.py index ebbae78..a3ce81c 100644 --- a/src/Models/AbstractSyntaxTree/AbstractSyntaxTree.py +++ b/src/Models/AbstractSyntaxTree/AbstractSyntaxTree.py @@ -1,30 +1,92 @@ +from typing import List, Union + from Models.Interpreter.Datatypes import Datatypes -from Models.Token.Token import Token -from Models.Token.TokenTypes import TokenTypes from Models.Token.TokenValueTypes import ExpressionCharacters -class ValueNode: - def __init__(self, value: Token = 'empty', datatype: Token = Token(TokenTypes.Type, Datatypes.strings.value[Datatypes.Empty.value])): +class AbstractSyntaxTree: + + def __init__(self): + self.libraries: List[LibraryDefinitionNode] = [] + + +class ASTElement: + + def __init__(self): + pass + + +class ValueNode(ASTElement): + def __init__(self, value: str, datatype: Datatypes): + super().__init__() self.value = value self.type = datatype -class BinaryOperationNode: - def __init__(self, left: Token, op_token: Token, right: Token): +class BinaryOperationNode(ASTElement): + def __init__(self, left: str, op_token: str, right: str): + super().__init__() self.left = left self.op_token = op_token self.right = right self.operation_chars = [ - ExpressionCharacters.chars.value[ExpressionCharacters.Plus.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Minus.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Asterisk.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Slash.value], - ExpressionCharacters.chars.value[ExpressionCharacters.Caret.value] + ExpressionCharacters.Plus.value, + ExpressionCharacters.Minus.value, + ExpressionCharacters.Asterisk.value, + ExpressionCharacters.Slash.value, + ExpressionCharacters.Caret.value ] def eval(self): - if self.op_token.value not in self.operation_chars: - return eval(f'{self.left.value} {self.op_token.value} {self.right.value}') + if self.op_token in self.operation_chars: + return eval(f'{self.left} {self.op_token} {self.right}') + +class LibraryDefinitionNode(ASTElement): + + def __init__(self, is_public: bool, name: str): + super().__init__() + self.is_public = is_public + self.name = name + self.classes: List[ClassDefinitionNode] = [] + + +class ClassDefinitionNode(ASTElement): + + def __init__(self, is_public: bool, name: str): + super().__init__() + self.is_public = is_public + self.name = name + self.variables: [VariableDefinitionNode] = [] + self.functions: List[FunctionDefinitionNode] = [] + + +class CallDefinitionNode(ASTElement): + + def __init__(self, name: str): + super().__init__() + self.name = name + self.args: List[ValueNode] = [] + + +class FunctionDefinitionNode(ASTElement): + + def __init__(self, is_public: bool, name: str, return_type: Datatypes): + super().__init__() + self.is_public = is_public + self.name = name + self.args: List[VariableDefinitionNode] = [] + self.return_type = return_type + self.variables: [VariableDefinitionNode] = [] + self.instructions: List[ASTElement] = [] + + +class VariableDefinitionNode(ASTElement): + + def __init__(self, is_public: bool, name: str, datatype: Union[str, Datatypes], value: Union[str, CallDefinitionNode]): + super().__init__() + self.is_public = is_public + self.name = name + self.datatype = datatype + self.value = value diff --git a/src/Models/Interpreter/Datatypes.py b/src/Models/Interpreter/Datatypes.py index d22a649..65177be 100644 --- a/src/Models/Interpreter/Datatypes.py +++ b/src/Models/Interpreter/Datatypes.py @@ -3,20 +3,10 @@ from enum import Enum class Datatypes(Enum): - Empty = 0 - Any = 1 - Number = 2 - String = 3 - Bool = 4 - List = 5 - Dict = 6 - - strings = [ - 'empty', - 'any', - 'number', - 'string', - 'bool', - 'list', - 'dict' - ] + Empty = 'empty' + Any = 'any' + Number = 'number' + String = 'string' + Bool = 'bool' + List = 'list' + Dict = 'dict' diff --git a/src/Models/Token/TokenValueTypes.py b/src/Models/Token/TokenValueTypes.py index 570e15d..70dc45b 100644 --- a/src/Models/Token/TokenValueTypes.py +++ b/src/Models/Token/TokenValueTypes.py @@ -1,82 +1,62 @@ from enum import Enum -class Keywords: +class Keywords(Enum): # define keywords - Library: str = 'lib' - Class: str = 'class' - Function: str = 'func' - Variable: str = 'var' - Use: str = 'use' - From: str = 'from' + Library = 'lib' + Class = 'class' + Function = 'func' + Variable = 'var' + Use = 'use' + From = 'from' # builtin functions - Output: str = 'output' - Input: str = 'input' - Length: str = 'length' - Range: str = 'range' - Exit: str = 'exit' + Output = 'output' + Input = 'input' + Length = 'length' + Range = 'range' + Exit = 'exit' # normal keywords - If: str = 'if' - ElseIf: str = 'elseif' - Else: str = 'else' - Continue: str = 'continue' - In: str = 'in' - Return: str = 'return' + If = 'if' + ElseIf = 'elseif' + Else = 'else' + Continue = 'continue' + In = 'in' + Return = 'return' # loops - While: str = 'while' - For: str = 'for' + While = 'while' + For = 'for' # access - Public: str = 'public' + Public = 'public' + This = 'this' -class Booleans: +class Booleans(Enum): Right = 'true' Wrong = 'false' class ExpressionCharacters(Enum): - Plus = 0 - Minus = 1 - Asterisk = 2 - Slash = 3 - Equal = 4 - Caret = 5 - - chars = [ - '+', - '-', - '*', - '/', - '=', - '^' - ] + Plus = '+' + Minus = '-' + Asterisk = '*' + Slash = '/' + Equal = '=' + Caret = '^' class FormatCharacters(Enum): - Left_Brace = 0 - Right_Brace = 1 - Left_Parenthesis = 2 - Right_Parenthesis = 3 - Left_Bracket = 4 - Right_Bracket = 5 - Semicolon = 6 - Colon = 7 - Comma = 8 - Point = 9 + Left_Brace = '{' + Right_Brace = '}' + Left_Parenthesis = '(' + Right_Parenthesis = ')' + Left_Bracket = '[' + Right_Bracket = ']' + Semicolon = ';' + Colon = ':' + Comma = ',' + Point = '.' - chars = [ - '{', - '}', - '(', - ')', - '[', - ']', - ';', - ':', - ',', - '.' - ]