commit f1f1743ddb7b6a5a6d5ed4e608b7cfccca287e55 Author: niansa Date: Thu Apr 9 23:44:06 2020 +0200 Initial commit diff --git a/__pycache__/errors.cpython-37.pyc b/__pycache__/errors.cpython-37.pyc new file mode 100644 index 0000000..ec7c6d2 Binary files /dev/null and b/__pycache__/errors.cpython-37.pyc differ diff --git a/__pycache__/intern.cpython-37.pyc b/__pycache__/intern.cpython-37.pyc new file mode 100644 index 0000000..eec237f Binary files /dev/null and b/__pycache__/intern.cpython-37.pyc differ diff --git a/__pycache__/rstrings.cpython-37.pyc b/__pycache__/rstrings.cpython-37.pyc new file mode 100644 index 0000000..b04ae20 Binary files /dev/null and b/__pycache__/rstrings.cpython-37.pyc differ diff --git a/__pycache__/rtypes.cpython-37.pyc b/__pycache__/rtypes.cpython-37.pyc new file mode 100644 index 0000000..570dfdc Binary files /dev/null and b/__pycache__/rtypes.cpython-37.pyc differ diff --git a/cli.py b/cli.py new file mode 100755 index 0000000..ba05b9a --- /dev/null +++ b/cli.py @@ -0,0 +1,25 @@ +#! /usr/bin/env python3 +import sys +from intern import main_class + +if len(sys.argv) == 1: # CLI loop + main = main_class() + while True: + print(">>> ", end="", flush=True) + commandstr = input() + res = main.get_rstring(main.run_command(commandstr), errorsonly=False) + if res != None: + print(res) +else: # File execution loop + main = main_class() + if sys.argv[1] == "-c": + del sys.argv[1] + if len(sys.argv[1]) == 1: + sys.exit(1) + with open(sys.argv[1], mode="r") as f: + for line in f: + if line[-1] == "\n": + line = line[:-1] + cmdres = main.get_rstring(main.run_command(line), errorsonly=True) + if cmdres: + print(cmdres) diff --git a/errors.py b/errors.py new file mode 100644 index 0000000..bef5d08 --- /dev/null +++ b/errors.py @@ -0,0 +1,4 @@ +class nochsuchcmd: pass +class badarguments: pass +class nosuchmodule: pass +class nosuchvariable: pass diff --git a/intern.py b/intern.py new file mode 100644 index 0000000..df74cb6 --- /dev/null +++ b/intern.py @@ -0,0 +1,127 @@ +import sys, os +from types import ModuleType +import errors +import rtypes +from rstrings import rstrings + + +class environment_class: + def __init__(self): + self.variables = {} + self.catch = False +environment = environment_class() + +class main_class: + def __init__(self): + self.modules = {} + self.commands = {} + environment.evaluate = self.run_command + # Load and import modules + for module in os.listdir("modules"): + if module[-3:] == ".py" or module[-4:] == ".pyc": + self.import_module(f"modules/{module}") + + def is_error(self, robj): + try: + return robj.__name__ in errors.__dict__.keys() + except AttributeError: + return False + + def get_rstring(self, robj, errorsonly=True): + iserr = False + try: + if not "errorsonly" in self.__dict__.keys(): + self.errorsonly = errorsonly + if isinstance(robj,type): + if self.is_error(robj): + iserr = True + if self.errorsonly and not self.is_error(robj): + return None + try: + return rstrings[robj.__name__] + except KeyError: + return "py." + robj.__name__ + else: + return robj + finally: + if environment.catch and iserr: + environment.catch = False + print("An exception was catched:", self.get_rstring(robj)) + sys.exit(1) + + def import_module(self, path): + with open(path) as file: + modcode = file.read() + mod = ModuleType(path) + exec(modcode, mod.__dict__) + return mod.adder(self.add_module) + + def add_module(self, module_class): + modulename = module_class.__name__ + self.modules[modulename] = module_class(environment) + for command in self.modules[modulename].commands: + self.commands[command] = self.modules[modulename] + + def run_command(self, commandstr): + try: commandstr, _ = commandstr.split("#", 1) # Split off comments + except ValueError: pass + commandstr = commandstr.lstrip() + if commandstr == "": # Empty command (does nothing) + return + elif commandstr.startswith("~"): # Variable + try: + return environment.variables[commandstr[1:]] + except KeyError: + return errors.nosuchvariable + else: # Actual command + try: command, argsstr = commandstr.split(" ", 1) + except ValueError: command, argsstr = (commandstr, "") + try: commandsplit = command.split(".", 1) + except ValueError: commandsplit = [command] + # Get module to parse command + if len(commandsplit) == 1: # Non-exact command + try: + module = self.commands[command] + except KeyError: + return errors.nochsuchcmd + else: # Exact command + try: + module = self.modules[commandsplit[0]] + except KeyError: + return errors.nosuchmodule + command = commandsplit[1] + if not command in self.commands.keys(): + return errors.nochsuchcmd + # Split arguments if required + argsstr += "," + args = [] + if argsstr != ",": + currarg = "" + instring = False + arginstring = False + charig = False + skipall = False + for char in argsstr: + if skipall: + continue + elif char == '"' and not charig: + instring = not instring + if currarg == "": + arginstring = True + elif char == "#" and not charig and not instring: + skipall = True + elif char == ',' and not charig and not instring: + if len(currarg) != 0 and currarg[0] == "$" and not arginstring: + currarg = self.get_rstring(self.run_command(currarg[1:])) + args.append(currarg) + currarg = "" + arginstring = False + elif char == "\\" and not charig: + charig = True + else: + currarg += char + charig = False + else: + pass + # Run command + return module.processor(command, args) diff --git a/modules/__pycache__/builtin.cpython-37.pyc b/modules/__pycache__/builtin.cpython-37.pyc new file mode 100644 index 0000000..6ea14af Binary files /dev/null and b/modules/__pycache__/builtin.cpython-37.pyc differ diff --git a/modules/builtin.py b/modules/builtin.py new file mode 100644 index 0000000..76ab4ad --- /dev/null +++ b/modules/builtin.py @@ -0,0 +1,122 @@ +import sys +import errors +import rtypes + + +class builtin: + def __init__(self, environ): + self.commands = { + "ret": self.cmd_ret, + "catch": self.cmd_catch, + "exit": self.cmd_exit, + "print": self.cmd_print, + "input": self.cmd_input, + "set": self.cmd_set, + "del": self.cmd_del, + "eval": self.cmd_eval, + "cmp": self.cmd_cmp, + "lower": self.cmd_lower + } + self.environ = environ + + def processor(self, command, args): + try: + return self.commands[command](args) + except KeyError: + return errors.nochsuchcmd + + def cmd_ret(self, args): + return " ".join(args) + + def cmd_catch(self, args): + if args == []: + self.environ.catch = not self.environ.catch + else: + if args[0].lower() == "true": + self.environ.catch = True + elif args[0].lower() == "false": + self.environ.catch = False + else: + return errors.badarguments + + def cmd_exit(self, args): + try: + sys.exit(int(args[0])) + except ValueError: + return errors.badarguments + except IndexError: + return errors.badarguments + + def cmd_print(self, args, nonline=False): + for arg in args: + print(arg, end="") + if not nonline: + print() + return rtypes.success + + def cmd_input(self, args): + self.cmd_print(args, nonline=True) + return input() + + def cmd_set(self, args): + if len(args) != 2: + return errors.badarguments + self.environ.variables[args[0]] = args[1] + return rtypes.success + + def cmd_del(self, args): + # Check if variable exists + for arg in args: + if not arg in self.environ.variables.keys(): + return errors.nosuchvariable + # Actually do that stuff + for arg in args: + del self.environ.variables[arg] + return rtypes.success + + def cmd_lower(self, args): + return str(args[0].lower()) + + def cmd_cmp(self, args): + # Check + try: + action, var1, var2, *commands = args + if action == "equal": + matches = str(var1) == str(var2) + elif action == "nonequal": + matches = str(var1) != str(var2) + elif action == "bigger": + matches = float(var1) > float(var2) + elif action == "smaller": + matches = float(var1) < float(var2) + elif action in ["isnum", "isnotnum"]: + try: + float(var1) + float(var2) + matches = True + except ValueError: + matches = False + if action == "isnotnum": + matches = not matches + else: + return errors.badarguments + if commands == []: + return matches + except ValueError: + return errors.badarguments + # Evaluate list of commands + if matches: + for command in commands: + lastres = self.environ.evaluate(command) + return lastres + else: + return rtypes.fail + + def cmd_eval(self, args): + for command in args: + lastres = self.environ.evaluate(command) + return lastres + + +def adder(registerer): + registerer(builtin) diff --git a/modules/math.py b/modules/math.py new file mode 100644 index 0000000..186a033 --- /dev/null +++ b/modules/math.py @@ -0,0 +1,81 @@ +import errors +import rtypes + + +class math: + def __init__(self, environ): + self.commands = { + "add": self.cmd_add, + "sub": self.cmd_sub, + "mul": self.cmd_mul, + "div": self.cmd_div + } + + def processor(self, command, args): + try: + return self.commands[command](args) + except KeyError: + return errors.nochsuchcmd + + def cmd_add(self, args): + try: + if args[0] == "asint": + asint = True + args = args[1:] + else: + asint = False + result = 0 + for arg in args: + result += float(arg) + if asint: result = int(result) + return result + except ValueError: + return errors.badarguments + + def cmd_sub(self, args): + try: + if args[0] == "asint": + asint = True + args = args[1:] + else: + asint = False + result = float(args[0]) + for arg in args[1:]: + result -= float(arg) + if asint: result = int(result) + return result + except ValueError: + return errors.badarguments + + def cmd_mul(self, args): + try: + if args[0] == "asint": + asint = True + args = args[1:] + else: + asint = False + result = 1 + for arg in args: + result *= float(arg) + if asint: result = int(result) + return result + except ValueError: + return errors.badarguments + + def cmd_div(self, args): + try: + if args[0] == "asint": + asint = True + args = args[1:] + else: + asint = False + result = float(args[0]) + for arg in args[1:]: + result /= float(arg) + if asint: result = int(result) + return result + except ValueError: + return errors.badarguments + +def adder(registerer): + registerer(math) diff --git a/rstrings.py b/rstrings.py new file mode 100644 index 0000000..2ffdcca --- /dev/null +++ b/rstrings.py @@ -0,0 +1,8 @@ +rstrings = { + "success": "Success", + "fail": "Failed", + "nochsuchcmd": "No such command", + "nosuchmodule": "No such module", + "nosuchvariable": "No such variable", + "badarguments": "Bad arguments" + } diff --git a/rtypes.py b/rtypes.py new file mode 100644 index 0000000..63de9a2 --- /dev/null +++ b/rtypes.py @@ -0,0 +1,2 @@ +class success: pass +class fail: pass diff --git a/test.pil b/test.pil new file mode 100644 index 0000000..c256a5a --- /dev/null +++ b/test.pil @@ -0,0 +1,16 @@ +# Enable error catching +catch True +# Initialise stuff +set wasword,was +# Get input from user +set errnonum,Whatever you typed in... It's definitely not a number!!! +set name,$input "Name: " +cmp equal,$~name,,"print What? That person has no name???",exit 1 +set current year,$input "Current year: " +cmp isnotnum,$~current year,0,print $~errnonum,exit 2 +set birth year,$input "Year of birth: " +cmp isnotnum,$~birth year,0,print $~errnonum,exit 3 +# Check if birth year is before current year +cmp smaller,$~current year,$~birth year,"print Will ,$~name, be born in the future?","set yesno,$input Yes/No?: ","cmp equal,$lower $~yesno,no,exit 4","cmp nonequal,$lower $~yesno,yes,print I give you up... Bye!,exit 4","set wasword,will be" +# Print result +print $~name, ,$~wasword, born in ,$~current year,",", so I guess he is ,$"sub asint,$~current year,$~birth year", Years old!