Senpai is an esoteric programming language that is inspired by anime girls. Don't ask why I made this.
Project description
Senpai: A dynamically-typed, Stack-Based Esolang
- For general info about the language, visit the esolang wiki page
- This document is about implementation-specific details
Implementation Features
- An implementation of the Senpai language purely interpreted in Python
- A simple Python API to create functions for the Senpai interpreter
- Many builtins that make the language easier to use that act as wrappers for Python classes
- An Earley parser, created with Lark
- A 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 with
pip install lark
- A probably slightly buggy interpreter.
Commandline Usage
- To use, use
python -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 file
Python API
If you want to see the library of functions introduced using this api, read lib/lib_docs.md
Basic Tutorial For Making Your Own Extension Modules
-
- Import
senpai_lang.pyutils
- Import
-
- Create a class that inherits off of
senpai_lang.pyutils.FuncBase
with a class attribute of the name of the function
- Create a class that inherits off of
-
- Create a
__init__
that inits thesuper()
with args ofself.name
and the function you want to wrap.
- Create a
-
- Instantiate a
PyModule
object with args of{name}
and theclass
of the command (not an instance of the class)
- Instantiate a
-
- Import the module from Senpai
- Example implementation of a wrapper for
os.system
import os
from senpai_lang.pyutils import FuncBase, PyModule
class System(FuncBase):
"""
Can take 2 or 1 argument
First 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 name
def __init__(self):
super().__init__(self.name, self.system)
@staticmethod
def system(*args):
if len(args) == 1:
os.system(*args)
else:
return os.system(args[0])
PyModule('os', [System]) # initialize module
NOTE: 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 Docs
FuncBase
-
def __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 Senpai- If
iter_results
isTrue
, when function is called, iterate over the return value ofself.function
and 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. - Updates
SenpaiInterpreter.builtins
with{self.name: self}
- Should probably not be instantiated manually unless you know what you are doing
-
def call(self, args, interpreter)
:- Pops the arguments from the top of the
interpreter
's current stack and callsself.function
with the unpacked version ofargs
as arguments. - Should probably not be called explicitely unless you know exactly what you are doing.
- Pops the arguments from the top of the
-
self.interpreter
: the interpreter that is calling the function. Only defined when the function is called.
PyModule
def __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 in
self.functions
and adds them to the builtins of theSenpaiInterpreter
class and logs imports.
SenpaiInterpreter
These are the useful attributes for making modules. If you want to know more methods and attributes of the SenpaiInterpreter
, look at the source code. Most of the methods in there interpret the AST. SenpaiInterpreter
objects should generally not be instantiated manually. If you really need to, the SenpaiInterpreter
class 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
: AStackHolder
object that holds the stacks.
StackHolder
A dictionary that holds the {name: Stack([items])}
that also holds the name of the current stack.
StackHolder
objects should generally not be instantiated manually. The StackHolder
class is located in senpai_lang.src.classes.StackHolder
-
def __init__(self, current_stack, **kwargs)
:- Creates a new
StackHolder
initialized with a current stack name ofcurrent_stack
, and contains the dictionary of**kwargs
. The dictionary should have values ofStack
objects.
- Creates a new
-
self.current_stack_name
: The name of the current stack -
self.current_stack
: AStack
object that represents the current stack of the interpreter. -
def switch_stack(self, name)
: Switches the current stack to be the stack namedname
if it exists. If not, creates a stack namedname
initialized with an emptyStack()
Stack
A class that inherits off of collections.deque
that represents a stack in the Senpai language. Stack
objects should generally not be instantiated manually.
def rot2(self)
: Performs a Senpairot2
operation on the stack (swaps the top 2 items).
def rot3(self)
: Performs a Senpairot3
operation on the stack.
Embedding the Interpreter in Python Applications (If you really want to) (Why would you?)
-
- Import
senpai_lang.src.classes.SenpaiInterpreter
andsenpai_lang.src.parser.parser
- Import
-
- Regret all of your life decisions.
-
- Call
parser.parse(code)
to get the Tree
- Call
-
- Instantiate the
SenpaiInterpreter
with the Tree as an argument
- Instantiate the
-
- Enjoy
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.