3030###########
3131
3232import ast
33- from typing import Any , List
33+ from typing import (
34+ Any ,
35+ List ,
36+ Final ,
37+ final ,
38+ )
3439
3540
3641#############
3742# CONSTANTS #
3843#############
3944
40- DIGITS : List [int ] = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ]
41- DIGITS_AS_STRINGS : List [str ] = ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "0" ]
45+ DIGITS_AS_STRINGS : Final [List [str ]] = ["1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "0" ]
4246
4347
44- ##############
45- # MAIN LEXER #
46- ##############
48+ #################
49+ # LEXER HELPERS #
50+ #################
4751
4852
4953class LexerToken :
54+ """
55+ Represents a token for the lexer.
56+ """
57+
5058 def __init__ (self , token_type : Any , value : Any ) -> None :
59+ """Initializes a new token.
60+
61+ :param token_type: Type of the token.
62+ :param value: Value of the token
63+ """
64+
5165 self .type = token_type
5266 self .value = value
5367
54- def __str__ (self ) -> str :
55- return "{" + self .type + ":'" + self .value + "'}"
56-
5768 def __repr__ (self ) -> str :
58- return "{" + self .type + ":'" + self .value + "'}"
69+ """Returns the representation of the token.
70+
71+ :return: String representation of the token.
72+ """
73+
74+ return (
75+ "{" + self .type + ":'" + self .value + "'}"
76+ ) # TODO (ElBe): Remove manual string formatting
5977
6078
6179class LexerError (BaseException ):
80+ """
81+ Represents an error while lexing.
82+ """
83+
6284 def __init__ (self , description : str , line : int , column : int ) -> None :
63- self .desc = description
85+ """Initializes a lexing error.
86+
87+ :param description: Description of the error.
88+ :param line: Line the error occurred in.
89+ :param column: Column the error occurred in.
90+ """
91+
92+ self .description = description
6493 self .line = line
6594 self .column = column
6695
67- def __str__ ( self ) -> str :
68- return (
69- str ( self . desc )
70- + " in line "
71- + str ( self . line )
72- + ", column "
73- + str ( self . column )
74- )
96+ super (). __init__ (
97+ f" { self . description } in line { self . line } , column { self . column } "
98+ ) # TODO (ElBe): Change it to not be a subclass of BaseException
99+
100+
101+ ####################
102+ # MAIN LEXER CLASS #
103+ ####################
75104
76105
77106class Lexer :
107+ """
108+ Represents a lexer object.
109+ """
110+
78111 def __init__ (self , text : str ):
79112 self .text = text
80113 self .separators = [" " , "\t " , "\n " ]
81- self .double_marks = {
82- "==" : "EQUAL" ,
83- "++" : "COUNT_UP" ,
84- "--" : "COUNT_DOWN"
85- }
114+ self .double_marks = {"==" : "EQUAL" , "++" : "COUNT_UP" , "--" : "COUNT_DOWN" }
86115 self .marks = {
87116 ";" : "END_CMD" ,
88117 "=" : "SET" ,
@@ -101,7 +130,9 @@ def __init__(self, text: str):
101130 "-" : "SUBTRACT" ,
102131 "*" : "MULTIPLY" ,
103132 "/" : "DIVIDE" ,
104- "%" : "STRING_FORMATTER" ,
133+ "%" : "MODULO" ,
134+ "//." : "CHILD" , # Duplicate, needs escaping
135+ "," : "SEPERATOR" ,
105136 }
106137 self .keywords = {
107138 "class" : "CLASS" ,
@@ -117,15 +148,22 @@ def __init__(self, text: str):
117148 "continue" : "CONTINUE" ,
118149 }
119150 self .base_types = [
120- "string" , # and str
121- "int" , # and integer
122- "float" ,
123- "complex" ,
124- "list" , # and array
125- "dict" , # and dictionary
151+ "any" ,
152+ "array" ,
126153 "bool" ,
154+ "complex" ,
155+ "dict" ,
156+ "dictionary" ,
127157 "dynamic" ,
128- "None" , # CONST, can't be changed
158+ "float" ,
159+ "int" ,
160+ "integer" ,
161+ "list" ,
162+ "str" ,
163+ "string" ,
164+
165+ "None" ,
166+ "Null" ,
129167 ]
130168
131169 self .tokens = []
@@ -150,24 +188,11 @@ def validate_integer(string: str) -> bool:
150188 if string [0 ] == "-" :
151189 string = string [1 :]
152190 for char in string :
153- valid = valid and char in [
154- "0" ,
155- "1" ,
156- "2" ,
157- "3" ,
158- "4" ,
159- "5" ,
160- "6" ,
161- "7" ,
162- "8" ,
163- "9" ,
164- ]
191+ valid = valid and char in DIGITS_AS_STRINGS
165192
166193 return valid
167194
168- def gettoken (
169- string : str , line : int , column : int
170- ) -> LexerToken | None :
195+ def gettoken (string : str , line : int , column : int ) -> LexerToken | None :
171196 if string in list (self .keywords .keys ()):
172197 return LexerToken (self .keywords [string ], string )
173198 elif len (string ) > 0 and string [0 ] == "_" :
@@ -189,7 +214,7 @@ def gettoken(
189214 else :
190215 raise LexerError ("Unrecognized Pattern: '" + string + "'" , line , column )
191216
192- def repl (ar ): # What's that?
217+ def replace_none (ar ): # What's that?
193218 n = []
194219 for el in ar :
195220 if el is not None :
@@ -234,7 +259,7 @@ def repl(ar): # What's that?
234259 self .tokens .append (
235260 LexerToken (
236261 self .double_marks [self .text [index : index + 2 ]],
237- self .text [index : index + 2 ],
262+ self .text [index : index + 2 ],
238263 )
239264 )
240265 buffer = ""
@@ -251,7 +276,7 @@ def repl(ar): # What's that?
251276 buffer += self .text [index ]
252277
253278 index += 1
254- self .tokens = repl (self .tokens )
279+ self .tokens = replace_none (self .tokens )
255280 return self .tokens
256281
257282
0 commit comments