multilingualprogramming 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. multilingualprogramming/__init__.py +74 -0
  2. multilingualprogramming/__main__.py +194 -0
  3. multilingualprogramming/codegen/__init__.py +12 -0
  4. multilingualprogramming/codegen/executor.py +215 -0
  5. multilingualprogramming/codegen/python_generator.py +592 -0
  6. multilingualprogramming/codegen/repl.py +489 -0
  7. multilingualprogramming/codegen/runtime_builtins.py +308 -0
  8. multilingualprogramming/core/__init__.py +12 -0
  9. multilingualprogramming/core/ir.py +29 -0
  10. multilingualprogramming/core/lowering.py +24 -0
  11. multilingualprogramming/datetime/__init__.py +11 -0
  12. multilingualprogramming/datetime/date_parser.py +190 -0
  13. multilingualprogramming/datetime/mp_date.py +210 -0
  14. multilingualprogramming/datetime/mp_datetime.py +153 -0
  15. multilingualprogramming/datetime/mp_time.py +147 -0
  16. multilingualprogramming/datetime/resource_loader.py +18 -0
  17. multilingualprogramming/exceptions.py +158 -0
  18. multilingualprogramming/imports.py +150 -0
  19. multilingualprogramming/keyword/__init__.py +13 -0
  20. multilingualprogramming/keyword/keyword_registry.py +249 -0
  21. multilingualprogramming/keyword/keyword_validator.py +59 -0
  22. multilingualprogramming/keyword/language_pack_validator.py +110 -0
  23. multilingualprogramming/lexer/__init__.py +11 -0
  24. multilingualprogramming/lexer/lexer.py +570 -0
  25. multilingualprogramming/lexer/source_reader.py +91 -0
  26. multilingualprogramming/lexer/token.py +54 -0
  27. multilingualprogramming/lexer/token_types.py +38 -0
  28. multilingualprogramming/numeral/__init__.py +11 -0
  29. multilingualprogramming/numeral/abstract_numeral.py +232 -0
  30. multilingualprogramming/numeral/complex_numeral.py +190 -0
  31. multilingualprogramming/numeral/fraction_numeral.py +165 -0
  32. multilingualprogramming/numeral/mp_numeral.py +243 -0
  33. multilingualprogramming/numeral/numeral_converter.py +151 -0
  34. multilingualprogramming/numeral/roman_numeral.py +301 -0
  35. multilingualprogramming/numeral/unicode_numeral.py +292 -0
  36. multilingualprogramming/parser/__init__.py +28 -0
  37. multilingualprogramming/parser/ast_nodes.py +459 -0
  38. multilingualprogramming/parser/ast_printer.py +677 -0
  39. multilingualprogramming/parser/error_messages.py +75 -0
  40. multilingualprogramming/parser/parser.py +1796 -0
  41. multilingualprogramming/parser/semantic_analyzer.py +689 -0
  42. multilingualprogramming/parser/surface_normalizer.py +282 -0
  43. multilingualprogramming/resources/datetime/eras.json +23 -0
  44. multilingualprogramming/resources/datetime/formats.json +32 -0
  45. multilingualprogramming/resources/datetime/months.json +150 -0
  46. multilingualprogramming/resources/datetime/weekdays.json +90 -0
  47. multilingualprogramming/resources/parser/error_messages.json +310 -0
  48. multilingualprogramming/resources/repl/commands.json +636 -0
  49. multilingualprogramming/resources/usm/builtins_aliases.json +731 -0
  50. multilingualprogramming/resources/usm/keywords.json +1063 -0
  51. multilingualprogramming/resources/usm/operators.json +532 -0
  52. multilingualprogramming/resources/usm/schema.json +34 -0
  53. multilingualprogramming/resources/usm/surface_patterns.json +1523 -0
  54. multilingualprogramming/unicode_string.py +140 -0
  55. multilingualprogramming/version.py +9 -0
  56. multilingualprogramming-0.2.0.dist-info/METADATA +350 -0
  57. multilingualprogramming-0.2.0.dist-info/RECORD +61 -0
  58. multilingualprogramming-0.2.0.dist-info/WHEEL +5 -0
  59. multilingualprogramming-0.2.0.dist-info/entry_points.txt +3 -0
  60. multilingualprogramming-0.2.0.dist-info/licenses/LICENSE +674 -0
  61. multilingualprogramming-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,243 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2022 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """Functions to handle numbers of multiple languages
8
+ """
9
+
10
+ from operator import invert, neg
11
+ from roman import toRoman
12
+ from multilingualprogramming.unicode_string import get_unicode_character_string
13
+ import multilingualprogramming.numeral.unicode_numeral as un
14
+ import multilingualprogramming.numeral.roman_numeral as rn
15
+ from multilingualprogramming.exceptions import (
16
+ MultipleLanguageCharacterMixError,
17
+ InvalidNumeralCharacterError,
18
+ DifferentNumeralTypeError
19
+ )
20
+
21
+
22
+ class MPNumeral:
23
+ """
24
+ Handling numerals in unicode-supported languages and
25
+ Roman numerals
26
+ """
27
+
28
+ def __init__(self, numstr: str):
29
+ self.numstr = numstr
30
+ self.num = None
31
+ try:
32
+ if rn.RomanNumeral.is_roman_numeral(numstr):
33
+ self.num = rn.RomanNumeral(numstr) # create a Roman numeral
34
+ self.numeral_type = "Roman"
35
+ else:
36
+ self.num = un.UnicodeNumeral(numstr) # create a Unicode numeral
37
+ self.numeral_type = "Unicode"
38
+ except (
39
+ MultipleLanguageCharacterMixError,
40
+ InvalidNumeralCharacterError,
41
+ ) as exception:
42
+ raise exception
43
+
44
+ def to_decimal(self):
45
+ """
46
+ Returns the number (Multilingual Numeral) associated with the number string
47
+ given by the user
48
+
49
+ return:
50
+ number: number associated with the number string
51
+ """
52
+ if self.num:
53
+ return self.num.to_decimal()
54
+ return None
55
+
56
+ def __str__(self):
57
+ """
58
+ Returns the original number string (Multilingual Numeral)
59
+
60
+ return:
61
+ numstr: original number string
62
+ """
63
+ return self.numstr
64
+
65
+ def __repr__(self):
66
+ """
67
+ Returns the representation (Multilingual numeral) of an instance
68
+
69
+ return:
70
+ reprstr: representation of an instance
71
+ """
72
+
73
+ def to_mp_numeral(self, number):
74
+ """
75
+ Returns the number (Multilingual Numeral) associated with the number string
76
+ given by the user
77
+
78
+ return:
79
+ mpnumeral: MPNumber associated with the number string
80
+ """
81
+ result = None
82
+ if self.numeral_type == "Roman":
83
+ result = toRoman(number)
84
+ else:
85
+ result = get_unicode_character_string(self.num.language_name, number)
86
+ return MPNumeral(result)
87
+
88
+ def _perform_operation(self, numeral, operation):
89
+ """
90
+ Helper function to perform arithmetic operations on MPNumeral objects.
91
+
92
+ Parameters:
93
+ numeral (MPNumeral): The numeral to operate with.
94
+ operation (function): The arithmetic operation to apply.
95
+
96
+ Returns:
97
+ MPNumeral: The result of the arithmetic operation.
98
+ """
99
+ if isinstance(numeral, MPNumeral) and self.numeral_type == numeral.numeral_type:
100
+ result = operation(self.to_decimal(), numeral.to_decimal())
101
+ return self.to_mp_numeral(result)
102
+ raise DifferentNumeralTypeError(operation.__name__)
103
+
104
+ def __add__(self, numeral):
105
+ """
106
+ Add a MPNumeral with a numeral or another MPNumeral.
107
+
108
+ Returns:
109
+ MPNumeral: The sum of the MPNumeral values.
110
+ """
111
+ return self._perform_operation(numeral, lambda x, y: x + y)
112
+
113
+ def __mul__(self, numeral):
114
+ """
115
+ Multiply a MPNumeral with a numeral or another MPNumeral.
116
+
117
+ Returns:
118
+ MPNumeral: The product of the MPNumeral values.
119
+ """
120
+ return self._perform_operation(numeral, lambda x, y: x * y)
121
+
122
+ def __lshift__(self, numeral):
123
+ """
124
+ Left-shifting of Multilingual numerals
125
+
126
+ return:
127
+ MPNumeral: returns the left shifted value
128
+ """
129
+ return self._perform_operation(numeral, lambda x, y: x << y)
130
+
131
+ def __rshift__(self, numeral):
132
+ """
133
+ Right-shifting of Multilingual numerals
134
+
135
+ return:
136
+ MPNumeral: returns the right shifted value
137
+ """
138
+ return self._perform_operation(numeral, lambda x, y: x >> y)
139
+
140
+ def __sub__(self, numeral):
141
+ """
142
+ Substraction of Multilingual numerals
143
+
144
+ return:
145
+ MPNumeral: returns the difference
146
+ """
147
+ return self._perform_operation(numeral, lambda x, y: x - y)
148
+
149
+ def __truediv__(self, numeral):
150
+ """
151
+ True division of Multilingual numerals
152
+
153
+ return:
154
+ MPNumeral: returns the value after true division
155
+ """
156
+ return self._perform_operation(numeral, lambda x, y: x / y)
157
+
158
+ def __floordiv__(self, numeral):
159
+ """
160
+ Floor division of Multilingual numerals
161
+
162
+ return:
163
+ MPNumeral: returns the value after floor division
164
+ """
165
+ return self._perform_operation(numeral, lambda x, y: x // y)
166
+
167
+ def __neg__(self):
168
+ """
169
+ Negation of Multilingual numerals
170
+
171
+ return:
172
+ MPNumeral: returns the negation
173
+ """
174
+ return MPNumeral(str(neg(self.to_decimal())))
175
+
176
+ def __pow__(self, numeral):
177
+ """
178
+ Power of Multilingual numerals
179
+
180
+ return:
181
+ MPNumeral: returns the power
182
+ """
183
+ return self._perform_operation(numeral, lambda x, y: x**y)
184
+
185
+ def __mod__(self, numeral):
186
+ """
187
+ Modulus of Multilingual numerals
188
+
189
+ return:
190
+ MPNumeral: returns the modulus value
191
+ """
192
+ return self._perform_operation(numeral, lambda x, y: x % y)
193
+
194
+ def __xor__(self, numeral):
195
+ """
196
+ XOR value of Multilingual numerals
197
+
198
+ return:
199
+ MPNumeral: returns the XOR value
200
+ """
201
+ return self._perform_operation(numeral, lambda x, y: x ^ y)
202
+
203
+ def __invert__(self):
204
+ """
205
+ Bitwise inversion value of Multilingual numerals
206
+
207
+ return:
208
+ MPNumeral: returns the bitwise-inverted value
209
+ """
210
+ result = invert(self.to_decimal())
211
+ if self.numeral_type == "Roman":
212
+ result = toRoman(result)
213
+ else:
214
+ result = get_unicode_character_string(self.num.language_name, result)
215
+ return MPNumeral(result)
216
+
217
+ def __or__(self, numeral):
218
+ """
219
+ OR value of Multilingual numerals
220
+
221
+ return:
222
+ MPNumeral: returns the OR value
223
+ """
224
+ return self._perform_operation(numeral, lambda x, y: x | y)
225
+
226
+ def convert_to(self, target_language):
227
+ """
228
+ Convert this numeral to a different script.
229
+
230
+ Only works for Unicode numerals.
231
+
232
+ Parameters:
233
+ target_language (str): Target language name (e.g., "ARABIC-INDIC")
234
+
235
+ Returns:
236
+ MPNumeral: A new MPNumeral in the target script
237
+ """
238
+ if self.numeral_type == "Unicode":
239
+ converted = self.num.convert_to(target_language)
240
+ return MPNumeral(str(converted))
241
+ raise DifferentNumeralTypeError(
242
+ "Cannot convert Roman numerals to another script"
243
+ )
@@ -0,0 +1,151 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2024 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """Functions for converting numerals between scripts and notations"""
8
+
9
+ from multilingualprogramming.numeral.unicode_numeral import UnicodeNumeral
10
+ from multilingualprogramming.unicode_string import (
11
+ get_unicode_character_string,
12
+ )
13
+
14
+
15
+ class NumeralConverter:
16
+ """
17
+ Utility class for converting numerals between scripts and formats.
18
+ """
19
+
20
+ # Unicode superscript digits for scientific notation
21
+ SUPERSCRIPT_MAP = {
22
+ "0": "\u2070",
23
+ "1": "\u00b9",
24
+ "2": "\u00b2",
25
+ "3": "\u00b3",
26
+ "4": "\u2074",
27
+ "5": "\u2075",
28
+ "6": "\u2076",
29
+ "7": "\u2077",
30
+ "8": "\u2078",
31
+ "9": "\u2079",
32
+ "-": "\u207b",
33
+ }
34
+
35
+ SUPERSCRIPT_REVERSE = {v: k for k, v in SUPERSCRIPT_MAP.items()}
36
+
37
+ @staticmethod
38
+ def convert(numeral, target_language):
39
+ """
40
+ Convert a UnicodeNumeral to a different script.
41
+
42
+ Parameters:
43
+ numeral (UnicodeNumeral): The numeral to convert
44
+ target_language (str): Target language name (e.g., "ARABIC-INDIC")
45
+
46
+ Returns:
47
+ UnicodeNumeral: A new numeral in the target script
48
+ """
49
+ return numeral.convert_to(target_language)
50
+
51
+ @staticmethod
52
+ def to_scientific(numeral, language=None):
53
+ """
54
+ Convert a numeral to scientific notation string.
55
+
56
+ Parameters:
57
+ numeral (UnicodeNumeral): The numeral to convert
58
+ language (str): Target language for output (default: same as input)
59
+
60
+ Returns:
61
+ str: Scientific notation string (e.g., "1.23×10³")
62
+ """
63
+ value = numeral.to_decimal()
64
+ lang = language or numeral.language_name or "DIGIT"
65
+
66
+ if value == 0:
67
+ zero = get_unicode_character_string(lang, 0)
68
+ return zero
69
+
70
+ # Calculate mantissa and exponent
71
+ negative = value < 0
72
+ abs_value = abs(value)
73
+
74
+ exponent = 0
75
+ mantissa = abs_value
76
+ if mantissa >= 10:
77
+ while mantissa >= 10:
78
+ mantissa /= 10
79
+ exponent += 1
80
+ elif 0 < mantissa < 1:
81
+ while mantissa < 1:
82
+ mantissa *= 10
83
+ exponent -= 1
84
+
85
+ # Format mantissa
86
+ if mantissa == int(mantissa):
87
+ mantissa = int(mantissa)
88
+
89
+ # Build the string
90
+ mantissa_val = -mantissa if negative else mantissa
91
+ if isinstance(mantissa_val, float):
92
+ # Round to avoid floating point artifacts
93
+ mantissa_val = round(mantissa_val, 10)
94
+
95
+ if exponent == 0:
96
+ return get_unicode_character_string(lang, mantissa_val)
97
+
98
+ mantissa_str = get_unicode_character_string(lang, mantissa_val)
99
+ ten_str = get_unicode_character_string(lang, 10)
100
+
101
+ # Build superscript exponent
102
+ exp_str = ""
103
+ for char in str(exponent):
104
+ exp_str += NumeralConverter.SUPERSCRIPT_MAP.get(char, char)
105
+
106
+ return f"{mantissa_str}\u00d7{ten_str}{exp_str}"
107
+
108
+ @staticmethod
109
+ def from_scientific(sci_str):
110
+ """
111
+ Parse a scientific notation string into a UnicodeNumeral.
112
+
113
+ Parameters:
114
+ sci_str (str): Scientific notation string (e.g., "1.23×10³")
115
+
116
+ Returns:
117
+ UnicodeNumeral: The parsed numeral
118
+ """
119
+ # Split on multiplication sign
120
+ if "\u00d7" in sci_str:
121
+ parts = sci_str.split("\u00d7", 1)
122
+ mantissa_str = parts[0]
123
+ base_exp_str = parts[1]
124
+ else:
125
+ # No scientific notation, just a plain number
126
+ return UnicodeNumeral(sci_str)
127
+
128
+ # Parse mantissa
129
+ mantissa_numeral = UnicodeNumeral(mantissa_str)
130
+ mantissa = mantissa_numeral.to_decimal()
131
+ lang = mantissa_numeral.language_name
132
+
133
+ # Parse exponent from superscript digits after the base
134
+ # Find where superscripts start
135
+ exp_chars = ""
136
+ base_chars = ""
137
+ for char in base_exp_str:
138
+ if char in NumeralConverter.SUPERSCRIPT_REVERSE:
139
+ exp_chars += NumeralConverter.SUPERSCRIPT_REVERSE[char]
140
+ else:
141
+ base_chars += char
142
+
143
+ exponent = int(exp_chars) if exp_chars else 0
144
+
145
+ # Calculate final value, rounding to avoid floating point artifacts
146
+ result = mantissa * (10 ** exponent)
147
+ result = round(result, 10)
148
+ if result == int(result):
149
+ result = int(result)
150
+
151
+ return UnicodeNumeral(get_unicode_character_string(lang, result))
@@ -0,0 +1,301 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2022 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """Functions to handle Roman numerals
8
+ """
9
+
10
+ from operator import invert, neg
11
+ from roman import fromRoman, toRoman
12
+ from multilingualprogramming.exceptions import (
13
+ InvalidNumeralCharacterError,
14
+ )
15
+ from multilingualprogramming.numeral.abstract_numeral import AbstractNumeral
16
+
17
+
18
+ class RomanNumeral(AbstractNumeral):
19
+ """
20
+ Handling Roman numerals
21
+ """
22
+
23
+ roman_numerals_list = [
24
+ "X",
25
+ "V",
26
+ "I",
27
+ "L",
28
+ "C",
29
+ "D",
30
+ "M",
31
+ "x",
32
+ "v",
33
+ "i",
34
+ "l",
35
+ "c",
36
+ "d",
37
+ "m",
38
+ "Ⅰ",
39
+ "Ⅱ",
40
+ "Ⅲ",
41
+ "Ⅳ",
42
+ "Ⅴ",
43
+ "Ⅵ",
44
+ "Ⅶ",
45
+ "Ⅷ",
46
+ "Ⅸ",
47
+ "Ⅹ",
48
+ "Ⅺ",
49
+ "Ⅻ,Ⅼ",
50
+ "Ⅽ",
51
+ "Ⅾ",
52
+ "Ⅿ",
53
+ "ↀ",
54
+ "ↁ",
55
+ "ↂ",
56
+ "ↇ",
57
+ "ↈ",
58
+ "ⅰ",
59
+ "ⅱ",
60
+ "ⅲ",
61
+ "ⅳ",
62
+ "ⅴ",
63
+ "ⅵ",
64
+ "ⅶ",
65
+ "ⅷ",
66
+ "ⅷ",
67
+ "ⅸ",
68
+ "ⅹ",
69
+ "ⅺ",
70
+ "ⅻ",
71
+ "ⅼ",
72
+ "ⅽ",
73
+ "ⅾ",
74
+ "ⅿ",
75
+ "ↅ",
76
+ "ↆ",
77
+ "Ↄ",
78
+ ]
79
+
80
+ @classmethod
81
+ def __verify_roman_characters__(cls, self, numstr: str):
82
+ """
83
+ Verify whether each character is a Roman character
84
+ """
85
+ for character in numstr:
86
+ if character not in self.roman_numerals_list:
87
+ raise InvalidNumeralCharacterError(
88
+ "Not a valid number, contains the character: " + character
89
+ )
90
+
91
+ @staticmethod
92
+ def is_roman_numeral(numstr: str) -> bool:
93
+ """
94
+ Verify whether each character is a Roman character
95
+ """
96
+ for character in numstr:
97
+ if character not in RomanNumeral.roman_numerals_list:
98
+ return False
99
+ return True
100
+
101
+ def __init__(self, numstr: str):
102
+ super().__init__(numstr)
103
+ self.numstr = numstr
104
+ self.__verify_roman_characters__(self, numstr)
105
+
106
+ def to_decimal(self):
107
+ """
108
+ Returns the number associated with the number string (Roman numeral)
109
+ given by the user
110
+
111
+ return:
112
+ number: number associated with the number string
113
+ """
114
+ return fromRoman(self.numstr)
115
+
116
+ @staticmethod
117
+ def get_roman_numerals() -> list:
118
+ """
119
+ Get list of Roman numerals
120
+ """
121
+ return RomanNumeral.roman_numerals_list
122
+
123
+ def set_roman_numerals(self, numerals: list):
124
+ """
125
+ Set list of Roman numerals
126
+ """
127
+ self.roman_numerals_list = numerals
128
+
129
+ def __str__(self):
130
+ """
131
+ Returns the original number string (Roman numeral)
132
+
133
+ return:
134
+ numstr: original number string
135
+ """
136
+ return self.numstr
137
+
138
+ def __repr__(self):
139
+ """
140
+ Returns the representation (Roman numeral) of an instance
141
+
142
+ return:
143
+ reprstr: representation of an instance
144
+ """
145
+ return f'RomanNumeral("{self.numstr}")'
146
+
147
+ def __add__(self, second):
148
+ """
149
+ Add a RomanNumeral with a numeral or another RomanNumeral
150
+
151
+ return:
152
+ RomanNumeral: returns the sum of a RomanNumeral
153
+ """
154
+ if isinstance(second, RomanNumeral):
155
+ return RomanNumeral(toRoman(self.to_decimal() + second.to_decimal()))
156
+ raise TypeError("Cannot substract a Roman numeral with a non-Roman numeral")
157
+
158
+ def __mul__(self, second):
159
+ """
160
+ Multiply a RomanNumeral with a numeral or another RomanNumeral
161
+
162
+ return:
163
+ RomanNumeral: multiplication of the two RomanNumeral values
164
+ """
165
+ if isinstance(second, RomanNumeral):
166
+ return RomanNumeral(toRoman(self.to_decimal() * second.to_decimal()))
167
+ raise TypeError("Cannot multiply a Roman numeral with a non-Roman numeral")
168
+
169
+ def __sub__(self, second):
170
+ """
171
+ Substraction of Roman Numerals
172
+
173
+ return:
174
+ AbstractNumeral: returns the difference
175
+ """
176
+ if isinstance(second, RomanNumeral):
177
+ return RomanNumeral(toRoman(self.to_decimal() - second.to_decimal()))
178
+ raise TypeError("Cannot substract a Roman numeral with a non-Roman numeral")
179
+
180
+ def __lshift__(self, second):
181
+ """
182
+ Left-shifting of Roman Numerals
183
+
184
+ return:
185
+ AbstractNumeral: returns the left shifted value
186
+ """
187
+ if isinstance(second, RomanNumeral):
188
+ return RomanNumeral(toRoman(self.to_decimal() << second.to_decimal()))
189
+ raise TypeError("Cannot left-shift a Roman numeral with a non-Roman numeral")
190
+
191
+ def __rshift__(self, second):
192
+ """
193
+ Right-shifting of Roman Numerals
194
+
195
+ return:
196
+ AbstractNumeral: returns the right shifted value
197
+ """
198
+ if isinstance(second, RomanNumeral):
199
+ return RomanNumeral(toRoman(self.to_decimal() >> second.to_decimal()))
200
+ raise TypeError("Cannot right-shift a Roman numeral with a non-Roman numeral")
201
+
202
+ def __truediv__(self, second):
203
+ """
204
+ True division of Roman Numerals
205
+
206
+ return:
207
+ AbstractNumeral: returns the value after true division
208
+ """
209
+ if isinstance(second, RomanNumeral):
210
+ return RomanNumeral(toRoman(self.to_decimal() / second.to_decimal()))
211
+ raise TypeError("Cannot divide a Roman numeral with a non-Roman numeral")
212
+
213
+ def __floordiv__(self, second):
214
+ """
215
+ Floor division of Roman Numerals
216
+
217
+ return:
218
+ AbstractNumeral: returns the value after floor division
219
+ """
220
+ if isinstance(second, RomanNumeral):
221
+ return RomanNumeral(toRoman(self.to_decimal() // second.to_decimal()))
222
+ raise TypeError("Cannot floor divide a Roman numeral with a non-Roman numeral")
223
+
224
+ def __neg__(self):
225
+ """
226
+ Negation of Roman Numerals
227
+
228
+ return:
229
+ AbstractNumeral: returns the negation
230
+ """
231
+ return RomanNumeral(toRoman(neg(self.to_decimal())))
232
+
233
+ def __pow__(self, second):
234
+ """
235
+ Power of Roman Numerals
236
+
237
+ return:
238
+ AbstractNumeral: returns the power
239
+ """
240
+ if isinstance(second, RomanNumeral):
241
+ return RomanNumeral(toRoman(self.to_decimal() ** second.to_decimal()))
242
+ raise TypeError(
243
+ "Cannot compute power of a Roman numeral with a non-Roman numeral"
244
+ )
245
+
246
+ def __mod__(self, second):
247
+ """
248
+ Modulus of Roman Numerals
249
+
250
+ return:
251
+ AbstractNumeral: returns the modulus value
252
+ """
253
+ if isinstance(second, RomanNumeral):
254
+ return RomanNumeral(toRoman(self.to_decimal() % second.to_decimal()))
255
+ raise TypeError(
256
+ "Cannot compute modulus of a Roman numeral with a non-Roman numeral"
257
+ )
258
+
259
+ def __xor__(self, second):
260
+ """
261
+ XOR value of Roman Numerals
262
+
263
+ return:
264
+ AbstractNumeral: returns the XOR value
265
+ """
266
+ if isinstance(second, RomanNumeral):
267
+ return RomanNumeral(toRoman(self.to_decimal() ^ second.to_decimal()))
268
+ raise TypeError(
269
+ "Cannot compute XOR of a Roman numeral with a non-Roman numeral"
270
+ )
271
+
272
+ def __invert__(self):
273
+ """
274
+ Bitwise inversion value of Roman Numerals
275
+
276
+ return:
277
+ AbstractNumeral: returns the bitwise-inverted value
278
+ """
279
+ return RomanNumeral(invert(toRoman(self.to_decimal())))
280
+
281
+ def __or__(self, second):
282
+ """
283
+ OR value of Roman Numerals
284
+
285
+ return:
286
+ AbstractNumeral: returns the OR value
287
+ """
288
+ if isinstance(second, RomanNumeral):
289
+ return RomanNumeral(toRoman(self.to_decimal() | second.to_decimal()))
290
+ raise TypeError(
291
+ "Cannot computer OR of a Roman numeral with a non-Roman numeral"
292
+ )
293
+
294
+ def __abs__(self):
295
+ """
296
+ Absolute value of Roman Numerals
297
+
298
+ return:
299
+ RomanNumeral: returns the absolute value
300
+ """
301
+ return RomanNumeral(toRoman(abs(self.to_decimal())))