From 9947c3260c9037c7847dbd280011e04dc5ae4a49 Mon Sep 17 00:00:00 2001 From: DaRubyMiner360 Date: Tue, 15 Feb 2022 17:06:25 -0500 Subject: [PATCH] Started working on enums. --- CHANGELOG.md | 4 +- doc/85_enums.md | 1 + error.py | 1 + examples/enums.para | 13 ++++ interpreter/env/builtins.py | 16 +++++ interpreter/env/globals.py | 1 + interpreter/interpreter.py | 14 +++- main.py | 6 +- std/__repl__.para | 2 - std/def.para | 55 +++++---------- std/io.para | 4 +- std/types/array.para | 5 ++ std/types/bool.para | 7 +- std/types/caseinsensitivedict.para | 31 +++++---- std/types/dict.para | 30 ++++----- std/types/enum.para | 67 +++++++++++++++++++ std/types/exceptions/interruptederror.para | 13 ++++ std/types/exceptions/notimplementederror.para | 13 ++++ std/types/float.para | 2 + std/types/func.para | 4 ++ std/types/int.para | 5 ++ std/types/num.para | 5 ++ std/types/object.para | 4 ++ std/types/str.para | 5 ++ util.py | 23 +++++-- 25 files changed, 247 insertions(+), 84 deletions(-) create mode 100644 doc/85_enums.md create mode 100644 examples/enums.para create mode 100644 std/types/enum.para create mode 100644 std/types/exceptions/interruptederror.para create mode 100644 std/types/exceptions/notimplementederror.para diff --git a/CHANGELOG.md b/CHANGELOG.md index b152eb9..b4f4b51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - Support for variables in the `catch` statement -- More errors +- More error messages - Complete requests HTTP library - Better interfacing with python code from ParaCode - The ability to use keyword arguments when calling a function - **kwargs (Keyword Arguments) +- More exceptions ## [2.1.0] - CURRENTLY UNRELEASED ### Added - Easy use of default parameters in functions - *args (Non-Keyword Arguments) - Complete regex support +- Enums ## [2.0.1] - 2021-10-18 ### Fixed diff --git a/doc/85_enums.md b/doc/85_enums.md new file mode 100644 index 0000000..fb9543a --- /dev/null +++ b/doc/85_enums.md @@ -0,0 +1 @@ +### Enums \ No newline at end of file diff --git a/error.py b/error.py index 6abc35f..ba74d97 100644 --- a/error.py +++ b/error.py @@ -20,6 +20,7 @@ class ErrorType(Enum): MultipleDefinition = auto() ArgumentError = auto() MacroExpansionError = auto() + InterruptedError = auto() class Error(): def __init__(self, type, location, message, filename, name="Exception"): diff --git a/examples/enums.para b/examples/enums.para new file mode 100644 index 0000000..11817ad --- /dev/null +++ b/examples/enums.para @@ -0,0 +1,13 @@ +let ExampleEnum = Enum.extend({ + name = 'ExampleEnum' + + instance = {} + + HELLO = 0 + WORLD = 1 +}); + +// interpreter.py: line 275 +// let v: ExampleEnum = ExampleEnum.new(ExampleEnum.HELLO); +let v: ExampleEnum = ExampleEnum.HELLO; +print(v.to_str()); diff --git a/interpreter/env/builtins.py b/interpreter/env/builtins.py index 027710f..794507d 100644 --- a/interpreter/env/builtins.py +++ b/interpreter/env/builtins.py @@ -1131,6 +1131,22 @@ def builtin_pyeval(arguments): return BasicValue(result) +def builtin_object_members(arguments): + target = arguments.arguments[0].extract_value() + + # members = {} + members = target.members.copy() + + # for key in target.members: + # if isinstance(target.members[key], BasicObject): + # members[key] = target.members[key].clone(parent_override=target) + # else: + # members[key] = target.members[key] + + members = [list(members.keys()), list(members.values())] + + return fixiter(members) + def builtin_object_new(arguments): interpreter = arguments.interpreter this_object = arguments.this_object diff --git a/interpreter/env/globals.py b/interpreter/env/globals.py index 6ae9e14..1253d4b 100644 --- a/interpreter/env/globals.py +++ b/interpreter/env/globals.py @@ -45,6 +45,7 @@ def __init__(self): ('Type', VariableType.Object, self.basic_type), ('Object', VariableType.Type, self.basic_object), ('Func', VariableType.Type, self.func_type), + ('__intern_object_members__', VariableType.Function, BuiltinFunction("__intern_object_members__", None, builtin_object_members)), ('__intern_object_patch__', VariableType.Function, BuiltinFunction("__intern_object_patch__", None, builtin_object_patch)), ('__intern_math_e__', VariableType.Function, BuiltinFunction("__intern_math_e__", None, builtin_math_e)), ('__intern_math_inf__', VariableType.Function, BuiltinFunction("__intern_math_inf__", None, builtin_math_inf)), diff --git a/interpreter/interpreter.py b/interpreter/interpreter.py index 103d876..0aaed37 100644 --- a/interpreter/interpreter.py +++ b/interpreter/interpreter.py @@ -67,6 +67,9 @@ def error(self, node, type, message, cont=False, name=None, classnames=None, obj elif type == ErrorType.ArgumentError: name = "Argument Error" classnames = ["Exception", "Argument Error"] + elif type == ErrorType.InterruptedError: + name = "Interrupted Error" + classnames = ["Exception", "InterruptedError"] elif type == ErrorType.MacroExpansionError: name = "Macro Expansion Error" classnames = ["Exception", "MacroExpansionError"] @@ -269,8 +272,15 @@ def assignment_typecheck(self, node, type_object, assignment_value): return False if not type_object.compare_type(assignment_type): - self.error(node, ErrorType.TypeError, 'Attempted to assign <{}> to a value of type <{}>'.format(type_object.friendly_typename, assignment_type.friendly_typename)) - return False + try: + # target_type_object = assignment_type.lookup_type(self.global_scope).extract_basicvalue() + # type_object + # assignment_type + # assignment_value + builtin_object_new(BuiltinFunctionArguments(interpreter=self, this_object=assignment_type, arguments=[type_object], node=node)) + except InterpreterError: + self.error(node, ErrorType.TypeError, 'Attempted to assign <{}> to a value of type <{}>'.format(type_object.friendly_typename, assignment_type.friendly_typename)) + return False return True diff --git a/main.py b/main.py index a8ae9c8..53d5288 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,14 @@ #!/bin/python3 +import sys + +# TODO: Implement version checker with `vermin --backport enum --no-parse-comments --versions .` + import os from ParaCode import ParaCode from parse.parser import Parser -import sys +# TODO: Move installDependencies.py and dataCounter.py's code here def main(): os.system("") diff --git a/std/__repl__.para b/std/__repl__.para index 31a0190..5925821 100644 --- a/std/__repl__.para +++ b/std/__repl__.para @@ -8,11 +8,9 @@ func tictactoe() { let sep_str = '\n' + (' ' * 22) + ('-' * 30) + '\n'; -io.write(sep_str); io.write_color(Console.RED, ' *** '); io.write_color(Console.BOLD, "Run `tictactoe();` to start a game of TicTacToe (built 100% in ParaCode!)"); io.write_color(Console.RED, ' *** '); io.write('\n'); io.write((' ' * 8) + 'Code in examples/ttt.para. More examples in that folder as well!'); -io.write(sep_str); io.write('\n'); diff --git a/std/def.para b/std/def.para index 078f73f..66808d1 100644 --- a/std/def.para +++ b/std/def.para @@ -7,6 +7,11 @@ __intern_object_patch__(Object, { func __eql__(self, other) { return __intern_default_compare__(self, other); } + + func members(self) { + let result = __intern_object_members__(self); + return Dict.new(result[0], result[1]); + } }); Type.patch({ @@ -15,6 +20,15 @@ Type.patch({ } }); +// These are only set so other code works fine before the actual io code gets run. +let io = Type.extend({ + func write(*args) {} + func read(*args) {} +}); +func print(message="", end="\n") { + io.write(message, end); +} + let pyimport = __intern_import_python__; @@ -32,6 +46,7 @@ import "std/types/caseinsensitivedict.para"; import "std/types/str.para"; import "std/types/range.para"; import "std/types/macro.para"; +import "std/types/enum.para"; import "std/types/exceptions/exception.para"; import "std/types/exceptions/argumenterror.para"; @@ -39,41 +54,5 @@ import "std/types/exceptions/doesnotexisterror.para"; import "std/types/exceptions/macroexpansionerror.para"; import "std/types/exceptions/multipledefinitionerror.para"; import "std/types/exceptions/typeerror.para"; - -// Type aliases -let object = Object; -let float = Float; -let type = Type; - -let array = Array; -let Arr = Array; -let arr = Array; - -let dict = Dict; -let Dictionary = Dict; -let dictionary = Dict; - -let caseinsensitivedict = CaseInsensitiveDict; -let CaseInsensitiveDictionary = CaseInsensitiveDict; -let caseinsensitivedictionary = CaseInsensitiveDict; -let InsensitiveDictionary = CaseInsensitiveDict; -let insensitivedictionary = CaseInsensitiveDict; - -let num = Num; -let number = Num; -let Number = Num; - -let int = Int; -let Integer = Int; -let integer = Int; - -let str = Str; -let String = Str; -let string = Str; - -let bool = Bool; -let Boolean = Bool; -let boolean = Bool; - -let Function = Func; -let function = Func; +import "std/types/exceptions/interruptederror.para"; +import "std/types/exceptions/notimplementederror.para"; diff --git a/std/io.para b/std/io.para index ecb1bda..f39ba1d 100644 --- a/std/io.para +++ b/std/io.para @@ -1,4 +1,4 @@ -let io = Type.extend({ +io = Type.extend({ func pyeval(self, *args) { return __intern_pyeval__(*args); } @@ -7,4 +7,4 @@ let io = Type.extend({ import "std/io/file.para"; import "std/io/console.para"; -let print = io.write; +// print = io.write; diff --git a/std/types/array.para b/std/types/array.para index 953fdee..7751189 100644 --- a/std/types/array.para +++ b/std/types/array.para @@ -175,3 +175,8 @@ let Array = Iterable.extend({ return self.len(); } }); + +// Type aliases +let array = Array; +let Arr = Array; +let arr = Array; diff --git a/std/types/bool.para b/std/types/bool.para index 284bf2b..7bf0362 100644 --- a/std/types/bool.para +++ b/std/types/bool.para @@ -11,7 +11,7 @@ let Bool = Num.extend({ func _invert(self, value) { return value.__not__(); } - + func __bool__(self) { return self._value; } @@ -45,3 +45,8 @@ let true = Bool.true; let True = Bool.true; let false = Bool.false; let False = Bool.false; + +// Type aliases +let bool = Bool; +let Boolean = Bool; +let boolean = Bool; diff --git a/std/types/caseinsensitivedict.para b/std/types/caseinsensitivedict.para index 4c5585c..c53cd28 100644 --- a/std/types/caseinsensitivedict.para +++ b/std/types/caseinsensitivedict.para @@ -200,21 +200,17 @@ let CaseInsensitiveDict = Dict.extend({ self._normal = Dict.new(self._normal[0], self._normal[1]); } - let result = [null, null]; + let result = null; for i in Range.new(0, self.len()) { if self._value[0][i].tolower() == aindex.tolower() { - let key = self._normal._value[0][i]; - let value = self._value[1][i]; - result = [key, value]; + result = self._value[1][i]; } else { - if i == self.len() - 1 && result == [null, null] { + if i == self.len() - 1 && result == null { let intIndex = self.len() - 1; if intIndex != -1 { - let key = self._normal._value[0][intIndex]; - let value = self._value[1][intIndex]; - result = [key, value]; + result = self._value[1][intIndex]; } } } @@ -230,21 +226,17 @@ let CaseInsensitiveDict = Dict.extend({ self._normal = Dict.new(self._normal[0], self._normal[1]); } - let result = [null, null]; + let result = null; for i in Range.new(0, self.len()) { if self._value[1][i] == aindex { - let key = self._normal._value[0][i]; - let value = self._value[1][i]; - result = [key, value]; + result = self._normal._value[0][i]; } else { - if i == self.len() - 1 && result == [null, null] { + if i == self.len() - 1 && result == null { let intIndex = self.len() - 1; if intIndex != -1 { - let key = self._normal._value[0][intIndex]; - let value = self._value[1][intIndex]; - result = [key, value]; + result = self._normal._value[0][intIndex]; } } } @@ -336,3 +328,10 @@ let CaseInsensitiveDict = Dict.extend({ return result; } }); + +// Type aliases +let caseinsensitivedict = CaseInsensitiveDict; +let CaseInsensitiveDictionary = CaseInsensitiveDict; +let caseinsensitivedictionary = CaseInsensitiveDict; +let InsensitiveDictionary = CaseInsensitiveDict; +let insensitivedictionary = CaseInsensitiveDict; diff --git a/std/types/dict.para b/std/types/dict.para index 65aef0b..117c2ac 100644 --- a/std/types/dict.para +++ b/std/types/dict.para @@ -119,6 +119,7 @@ let Dict = Iterable.extend({ // Constructor func __construct__(self, keys, values) { self._value = [keys, values]; + return self; } func setOrAppend(self, key, value) { @@ -177,21 +178,17 @@ let Dict = Iterable.extend({ } func atkey(self, aindex) { - let result = [null, null]; + let result = null; for i in Range.new(0, self.len()) { if self._value[0][i] == aindex { - let key = self._value[0][i]; - let value = self._value[1][i]; - result = [key, value]; + result = self._value[1][i]; } else { - if i == self.len() - 1 && result == [null, null] { + if i == self.len() - 1 && result == null { let intIndex = self.len() - 1; if intIndex != -1 { - let key = self._value[0][intIndex]; - let value = self._value[1][intIndex]; - result = [key, value]; + result = self._value[1][intIndex]; } } } @@ -203,21 +200,17 @@ let Dict = Iterable.extend({ func atvalue(self, aindex) { - let result = [null, null]; + let result = null; for i in Range.new(0, self.len()) { if self._value[1][i] == aindex { - let key = self._value[0][i]; - let value = self._value[1][i]; - result = [key, value]; + result = self._value[0][i]; } else { - if i == self.len() - 1 && result == [null, null] { + if i == self.len() - 1 && result == null { let intIndex = self.len() - 1; if intIndex != -1 { - let key = self._value[0][intIndex]; - let value = self._value[1][intIndex]; - result = [key, value]; + result = self._value[0][intIndex]; } } } @@ -315,3 +308,8 @@ let Dict = Iterable.extend({ return self._value[1]; } }); + +// Type aliases +let dict = Dict; +let Dictionary = Dict; +let dictionary = Dict; diff --git a/std/types/enum.para b/std/types/enum.para new file mode 100644 index 0000000..3a95e76 --- /dev/null +++ b/std/types/enum.para @@ -0,0 +1,67 @@ +let Enum = Num.extend({ + name = 'Enum' + + instance = { + _value = null + + func to_str(self) { + if self._value != null { + let v = self._value; + let str_result = self.type().to_str(); + + for member in self.values() { + if v == member[1] { + str_result += "." + member[0]; + } + } + + return str_result; + } + return self.type().to_str(); + } + + func __construct__(self, value=0) { + self._value = value; + + let valid = false; + for member in self.values() { + if value == member[1] { + valid = true; + } + } + + if !valid { + ArgumentError.new("Enum value is out of range!").raise(); + } + return self; + } + } + + func __get__(self) { + return self._value; + } + + func values(self) { + let result = Dictionary.new([], []); + + if self._value == null { + for member in self.members() { + if member[1].type() == Int { + result.append([member[0], member[1]]); + } + } + } + else { + for member in self.type().members() { + if member[1].type() == Int { + result.append([member[0], member[1]]); + } + } + } + + return result; + } +}); + +// Type aliases +let enum = Enum; diff --git a/std/types/exceptions/interruptederror.para b/std/types/exceptions/interruptederror.para new file mode 100644 index 0000000..4c14235 --- /dev/null +++ b/std/types/exceptions/interruptederror.para @@ -0,0 +1,13 @@ +let InterruptedError = Exception.extend({ + name = 'InterruptedError' + + instance = { + func raise(self) { + return raise(self, "Interrupted Error"); + } + } + + func __construct__(self, _message) { + self.message = _message; + } +}); diff --git a/std/types/exceptions/notimplementederror.para b/std/types/exceptions/notimplementederror.para new file mode 100644 index 0000000..e2babb1 --- /dev/null +++ b/std/types/exceptions/notimplementederror.para @@ -0,0 +1,13 @@ +let NotImplementedError = Exception.extend({ + name = 'NotImplementedError' + + instance = { + func raise(self) { + return raise(self, "Not Implemented Error"); + } + } + + func __construct__(self, _message) { + self.message = _message; + } +}); diff --git a/std/types/float.para b/std/types/float.para index fed34c5..3bef0a4 100644 --- a/std/types/float.para +++ b/std/types/float.para @@ -76,3 +76,5 @@ let Float = Num.extend({ return __intern_float_bitshiftleft__(self._value, other._value); } }); + +let float = Float; diff --git a/std/types/func.para b/std/types/func.para index deb4711..e9b9a86 100644 --- a/std/types/func.para +++ b/std/types/func.para @@ -11,3 +11,7 @@ Func.patch({ self._method(*args); } }); + +// Type aliases +let Function = Func; +let function = Func; diff --git a/std/types/int.para b/std/types/int.para index eadac92..ce4c097 100644 --- a/std/types/int.para +++ b/std/types/int.para @@ -87,3 +87,8 @@ let Int = Num.extend({ return __intern_int_bitshiftright__(self._value, other._value); } }); + +// Type aliases +let int = Int; +let Integer = Int; +let integer = Int; diff --git a/std/types/num.para b/std/types/num.para index 74b31b3..6b75193 100644 --- a/std/types/num.para +++ b/std/types/num.para @@ -31,3 +31,8 @@ let Num = Type.extend({ return self._value; } }); + +// Type aliases +let num = Num; +let number = Num; +let Number = Num; diff --git a/std/types/object.para b/std/types/object.para index ab89faa..82a6979 100644 --- a/std/types/object.para +++ b/std/types/object.para @@ -39,3 +39,7 @@ Object.patch({ return self.__compare__(other) != -1; } }); + +// Type aliases +let object = Object; +let type = Type; diff --git a/std/types/str.para b/std/types/str.para index fae7e2d..93b17bd 100644 --- a/std/types/str.para +++ b/std/types/str.para @@ -182,3 +182,8 @@ let Str = Array.extend({ return self.name; } }); + +// Type aliases +let str = Str; +let String = Str; +let string = Str; diff --git a/util.py b/util.py index 7cad7fe..2a42dfa 100644 --- a/util.py +++ b/util.py @@ -5,19 +5,32 @@ class LogColor(): Info = "\033[34m" Bold = "\033[1m" -def fixiter(values, make_basic_value=True): +def fixiter(values, make_basic_value=True, skip_null=False): from interpreter.basic_value import BasicValue + from interpreter.basic_object import BasicObject result = [] for value in values: if type(value) in [list, set, tuple]: result.append(fixiter(value)) else: - if make_basic_value: + if not isinstance(value, BasicValue) and make_basic_value: result.append(BasicValue(value)) else: - result.append(value) - if make_basic_value: + if isinstance(value, BasicObject): + if make_basic_value: + result.append(BasicValue(value.value)) + else: + result.append(value.value) + else: + result.append(value) + if not isinstance(result, BasicValue) and make_basic_value: return BasicValue(result) else: - return result + if isinstance(value, BasicObject): + if make_basic_value: + return BasicValue(result.value) + else: + return result.value + else: + return result