Package: senpai-lang
Senpai: A dynamically-typed, Stack-Based EsolangFor general info about the language, visit theesolang wiki pageThis document is about implementation-specific detailsImplementation FeaturesAn implementation of the Senpai language purely interpreted in PythonA simple Python API to create functions for the Senpai interpreterMany builtins that make the language easier to use that act as wrappers for Python classesAn Earley parser, created withLarkA 100x slower than Python run speed (Yeah, I'm sorry)Only a single dependency outside of the Python standard library (Lark) that can be installed withpip install larkA probably slightly buggy interpreter.Commandline UsageTo use, usepython -m senpai_lang [commands]Commands-h,--help: View the help for the commandline arguments-i,--infile: The input file with the Senpai code to interpret-d,--debugfile: The file to write to for verbose logging. The log tracks almost everything the intepreter does down to the expression.-tb,--pytraceback: Disable the custom except hook and enable normal Python traceback. Should be used for reporting bugs with the intepreter.-w,--wiki: Visit the wiki page for the Senpai language-ps,--printstack: Print the execution time, variables, stacks, and builtins of the program after running the filePython APIIf you want to see the library of functions introduced using this api, readlib/lib_docs.mdBasic Tutorial For Making Your Own Extension ModulesImportsenpai_lang.pyutilsCreate a class that inherits off ofsenpai_lang.pyutils.FuncBasewith a class attribute of the name of the functionCreate a__init__that inits thesuper()with args ofself.nameand the function you want to wrap.Instantiate aPyModuleobject with args of{name}and theclassof the command (not an instance of the class)Import the module from SenpaiExample implementation of a wrapper foros.systemimportosfromsenpai_lang.pyutilsimportFuncBase,PyModuleclassSystem(FuncBase):"""Can take 2 or 1 argumentFirst argument is always the command to execute.Second argument can be anything,Second argument if it exists returns the value os.system"""name='cmd'# allows for overriding by the module namedef__init__(self):super().__init__(self.name,self.system)@staticmethoddefsystem(*args):iflen(args)==1:os.system(*args)else:returnos.system(args[0])PyModule('os',[System])# initialize moduleNOTE: A function's return value is pushed onto the current stack and all arguments to the function are destroyed in the process of calling the function.Full Python API DocsFuncBasedef __init__(self, name, function, iter_results=False)self.name: The name that the function will be referred to by calling from Senpaiself.function: The function that gets called from SenpaiIfiter_resultsisTrue, when function is called, iterate over the return value ofself.functionand push each item in the iterable on top of stack in reverse order such that the top item on the stack is the first item in the iterable.UpdatesSenpaiInterpreter.builtinswith{self.name: self}Should probably not be instantiated manually unless you know what you are doingdef call(self, args, interpreter):Pops the arguments from the top of theinterpreter's current stack and callsself.functionwith the unpacked version ofargsas arguments.Should probably not be called explicitely unless you know exactly what you are doing.self.interpreter: the interpreter that is calling the function. Only defined when the function is called.PyModuledef __init__(self, name, functions, rename_funcs=True)self.name: the name of the moduleself.functions: an iterable of all of the classes for functions in the modulerename_funcs(self.rename): IfTrue(should almost always be), add the name of the module followed by an underscore (module_function) before the name of all the functions in the module. Should beTrue(or omitted) in almost all cases.Instantiates all of the classes inself.functionsand adds them to the builtins of theSenpaiInterpreterclass and logs imports.SenpaiInterpreterThese are the useful attributes for making modules. If you want to know more methods and attributes of theSenpaiInterpreter, look at the source code. Most of the methods in there interpret the AST.SenpaiInterpreterobjects should generally not be instantiated manually. If you really need to, theSenpaiInterpreterclass is located in senpai_lang.src.classes.SenpaiInterpreter.SenpaiInterpreter.builtins: All of the Python functions added to the interpreter.self.vars: The variables held by the interpreter. It is a dictionary that holds{name: object}.self.stacks: AStackHolderobject that holds the stacks.StackHolderA dictionary that holds the{name: Stack([items])}that also holds the name of the current stack.StackHolderobjects should generally not be instantiated manually. TheStackHolderclass is located insenpai_lang.src.classes.StackHolderdef __init__(self, current_stack, **kwargs):Creates a newStackHolderinitialized with a current stack name ofcurrent_stack, and contains the dictionary of**kwargs. The dictionary should have values ofStackobjects.self.current_stack_name: The name of the current stackself.current_stack: AStackobject that represents the current stack of the interpreter.def switch_stack(self, name): Switches the current stack to be the stack namednameif it exists. If not, creates a stack namednameinitialized with an emptyStack()StackA class that inherits off ofcollections.dequethat represents a stack in the Senpai language.Stackobjects should generally not be instantiated manually.def rot2(self): Performs a Senpairot2operation on the stack (swaps the top 2 items).def rot3(self): Performs a Senpairot3operation on the stack.Embedding the Interpreter in Python Applications (If youreallywant to) (Why would you?)Importsenpai_lang.src.classes.SenpaiInterpreterandsenpai_lang.src.parser.parserRegret all of your life decisions.Callparser.parse(code)to get the TreeInstantiate theSenpaiInterpreterwith the Tree as an argumentEnjoy