Package: pickora
Pickora 🐰A small compiler that can convert Python scripts to pickle bytecode.RequirementsPython 3.8+No third-party modules are required.Quick StartInstallationUsing pip:$pipinstallpickoraFrom source:$gitclonehttps://github.com/splitline/Pickora.git
$cdPickora
$pythonsetup.pyinstallBasic UsageCompile from a string:$pickora-c'from builtins import print; print("Hello, world!")'-ooutput.pkl
$python-mpickleoutput.pkl# load the pickle bytecodeHello,world!
NoneCompile from a file:$echo'from builtins import print; print("Hello, world!")'>hello.py
$pickorahello.py# output compiled pickle bytecode to stdout directlyb'\x80\x04\x95(\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x8c\x05print\x93\x94\x94h\x01\x8c\rHello, world!\x85R.'Usageusage: pickora [-h] [-c CODE] [-p PROTOCOL] [-e] [-O] [-o OUTPUT] [-d] [-r]
               [-f {repr,raw,hex,base64,none}]
               [source]

A toy compiler that can convert Python scripts into pickle bytecode.

positional arguments:
  source                source code file

optional arguments:
  -h, --help            show this help message and exit
  -c CODE, --code CODE  source code string
  -p PROTOCOL, --protocol PROTOCOL
                        pickle protocol
  -e, --extended        enable extended syntax (trigger find_class)
  -O, --optimize        optimize pickle bytecode (with pickletools.optimize)
  -o OUTPUT, --output OUTPUT
                        output file
  -d, --disassemble     disassemble pickle bytecode
  -r, --run             run (load) pickle bytecode immediately
  -f {repr,raw,hex,base64,none}, --format {repr,raw,hex,base64,none}
                        output format, none means no output

Basic usage: `pickora samples/hello.py` or `pickora --code 'print("Hello, world!")' --extended`Supported SyntaxBasic Syntax (achived by only usingpickleopcodes)Basic types: int, float, bytes, string, dict, list, set, tuple, bool, NoneAssignment:val = dict_['x'] = obj.attr = 'meow'Augmented assignment:x += 1Named assignment:(x := 1337)Unpacking:a, b, c = 1, 2, 3Function call:f(arg1, arg2)Doesn't support keyword argument.Importfrom module import things(directly usingSTACK_GLOBALSbytecode)Macros (see below for more details)STACK_GLOBALGLOBALINSTOBJNEWOBJNEWOBJ_EXBUILDExtended Syntax (enabled by-e/--extendedoption)Note: All extended syntaxes are implemented by importing other built-in modules. So with this option will triggerfind_classwhen loading the pickle bytecode.Attributes:obj.attr(usingbuiltins.getattronly when you need to "load" an attribute)Operators (usingoperatormodule)Binary operators:+,-,*,/etc.Unary operators:not,~,+val,-valCompare:0 < 3 > 2 == 2 > 1(usingbuiltins.allfor chained comparing)Subscript:list_[1:3],dict_['key'](usingbuiltins.slicefor slice)Boolean operators (usingbuiltins.next,builtins.filter)and: usingoperator.not_or: usingoperator.truth(a or b or c)->next(filter(truth, (a, b, c)), c)(a and b and c)->next(filter(not_, (a, b, c)), c)Importimport module(usingimportlib.import_module)Lambdalambda x,y=1: x+yUsingtypes.CodeTypeandtypes.FunctionType[Known bug] If any global variables are changed after the lambda definition, the lambda function won't see those changes.MacrosThere are currently 4 macros available:STACK_GLOBAL,GLOBAL,INSTandBUILD.STACK_GLOBAL(modname: Any, name: Any)Example:function_name=input("> ")# > systemfunc=STACK_GLOBAL('os',function_name)# <built-in function system>func("date")# Tue Jan 13 33:33:37 UTC 2077Behaviour:PUSH modnamePUSH nameSTACK_GLOBALGLOBAL(modname: str, name: str)Example:func=GLOBAL("os","system")# <built-in function system>func("date")# Tue Jan 13 33:33:37 UTC 2077Behaviour:Simply write this piece of bytecode:f"c{modname}\n{name}\n"INST(modname: str, name: str, args: tuple[Any])Example:command=input("cmd> ")# cmd> dateINST("os","system",(command,))# Tue Jan 13 33:33:37 UTC 2077Behaviour:PUSH a MARKPUSHargsby orderRun this piece of bytecode:f'i{modname}\n{name}\n'BUILD(inst: Any, state: Any, slotstate: Any)stateis forinst.__setstate__(state)andslotstateis for setting attributes.Example:fromcollectionsimport_collections_abcBUILD(_collections_abc,None,{'__all__':['ChainMap','Counter','OrderedDict']})Behaviour:PUSHinstPUSH(state, slotstate)(tuple)PUSHBUILDFAQWhat is pickle?RTFM.Why?It's cool.Is it useful?No, not at all, it's definitely useless.So, is this garbage?Yep, it's cool garbage.Would it support syntaxes likeif/while/for?No. All pickle can do is just simply define a variable or call a function, so this kind of syntax wouldn't exist.But if you want to do things like:ans=input("Yes/No: ")ifans=='Yes':print("Great!")elifans=='No':exit()It's still achievable! You can rewrite your code like this:fromfunctoolsimportpartialcondition={'Yes':partial(print,'Great!'),'No':exit}ans=input("Yes/No: ")condition.get(ans,repr)()ta-da!For the loop syntax, you can try to usemap/starmap/reduceetc .And yes, you are right, it's functional programming time!