├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── BFL.keg ├── Codepage.txt ├── Coherse.py ├── Graphical.py ├── Guide.md ├── Information_noblank.pdf ├── Keg.py ├── KegLib.py ├── KegStrings.py ├── Keg_Nums.py ├── ListTest.py ├── New Specs.txt ├── OldKeg.py ├── Pagecomp.py ├── Parse.py ├── README.md ├── StackTest.py ├── Stackd.py ├── StringF.py ├── T.py ├── TranspiledTests.py ├── Word_List.py ├── docs ├── BFL.keg └── words.txt ├── examples ├── 99bottles.keg ├── 99bottles2.keg ├── 99new.keg ├── Abutnota.keg ├── Add.keg ├── Addition.keg ├── Decr.keg ├── ExclusiveTest.keg ├── Facrecursion.keg ├── Factorial9.keg ├── FactorialReg.keg ├── Function.keg ├── Function_Test.keg ├── InclusiveTest.keg ├── Numbersplit.keg ├── Printwloop ├── README.md ├── Shifting.keg ├── StringFormat.keg ├── Truth.keg ├── WhileLoop.keg ├── WhileLoop_Cond.keg ├── brake.keg ├── cat.keg ├── deadfish.keg ├── deadfish2.keg ├── factorial.keg ├── fizzbuzz.keg ├── fizzbuzz2.keg ├── hello.keg ├── quine.keg └── quine2.keg ├── preprocess.py └── uncompress.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /BFL.keg: -------------------------------------------------------------------------------- 1 | #Keg's BFL --> Built-In-Function-Library, Written in 100% Keg 2 | #A 3 | @AV *|!&⅀&/ƒ# 4 | #B 5 | # 6 | #C 7 | # 8 | #D 9 | # 10 | #E 11 | # 12 | #F 13 | # 14 | #G 15 | # 16 | #H 17 | # 18 | #I 19 | # 20 | #J 21 | # 22 | #K 23 | # 24 | #L 25 | # 26 | #M 27 | @MC2|®N®R©N¡©R¡©N©R-¡*/ƒ# 28 | @MM2|:":'$<⊙^__ƒ# 29 | # 30 | #N 31 | # 32 | #O 33 | # 34 | #P 35 | # 36 | #Q 37 | # 38 | #R 39 | # 40 | #S 41 | @S0|`@N|[];`ƒ 42 | # 43 | #T 44 | # 45 | #U 46 | # 47 | #V 48 | # 49 | #W 50 | # 51 | #X 52 | # 53 | #Y 54 | # 55 | #Z -------------------------------------------------------------------------------- /Codepage.txt: -------------------------------------------------------------------------------- 1 | ϧ∑¿∂•ɧ÷¡Ëė≬ƒß‘“„«®©ëλº√₳¬≤Š≠≥Ėπ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ø¶ 2 | ⊂½‡™±¦→←↶↷✏█↗↘□²ⁿ║ṡ⟰⟱⟷ℤℝ⅍℠א∀≌᠀⊙᠈⅀ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ☭⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⯑①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅↫🄂🄃🄄🄅🄆🄇🄈🄉🄊 3 | -------------------------------------------------------------------------------- /Coherse.py: -------------------------------------------------------------------------------- 1 | #Coherse.py 2 | 3 | import textwrap 4 | 5 | code_page = "set me in Keg.py" 6 | 7 | class char(): 8 | def __init__(self, what): 9 | self.v = str(what) 10 | 11 | def __str__(self): 12 | return self.v 13 | 14 | def __int__(self): 15 | return _ord(self.v) 16 | 17 | def split_list(list_obj: list, n: int) -> list: 18 | return [list_obj[i:i+n] for i in range(0, len(list_obj), n)] 19 | 20 | def sub_strings(source: str, subtractant: str) -> str: 21 | result = source 22 | if len(subtractant) == 1: 23 | return source.replace(subtractant, "", 1) 24 | for char in subtractant: 25 | result = sub_strings(result, char) 26 | return result 27 | 28 | def multiply(lhs: str, rhs: str) -> list: 29 | result = [] 30 | for char in lhs: 31 | for char_2 in rhs: 32 | result.append(char + char_2) 33 | return result 34 | 35 | def list_mult(lhs: list, rhs: str) -> list: 36 | result = [] 37 | for item in lhs: 38 | result.append(operate(item, rhs, "*")) 39 | return result 40 | 41 | def list_divide(lhs: list, rhs: str) -> list: 42 | result = [] 43 | for item in lhs: 44 | result.append(operate(item, rhs, "/")) 45 | return result 46 | 47 | def special_divide(lhs: list, rhs: list) -> list: 48 | result = [] 49 | for item in lhs: 50 | for item_1 in rhs: 51 | result += operate(item, item_1, "/") 52 | return result 53 | 54 | 55 | relations = {"Number": { 56 | "Number": ["x + y", "x - y", "x * y", "x / y", "x % y"], 57 | "Character": ["x + _ord(y.v)", "x - _ord(y.v)", 58 | "x * _ord(y.v)", "x / _ord(y.v)", 59 | "x % _ord(y.v)"], 60 | "String": ["str(x) + y", "str(x).replace(y, '')", 61 | "y * x", "textwrap.wrap(y, x)", 62 | "textwrap.wrap(y, x)[-1]"], 63 | "Stack": ["y + [x]", "y.remove(x)", "y * x", 64 | "split_list(y, x)", "split_list(y, x)[-1]"] 65 | }, 66 | 67 | "Character": { 68 | 69 | "Number": ["y + _ord(x.v)", "_ord(x.v) - y", 70 | "y * _ord(x.v)", "_ord(x.v) / y", 71 | "_ord(x.v) % y"], 72 | 73 | "Character" : ["_ord(x.v) + _ord(y.v)", 74 | "_ord(x.v) - _ord(y.v)", 75 | "_ord(x.v) * _ord(y.v)", 76 | "_ord(x.v) / _ord(y.v)", 77 | "_ord(x.v) % _ord(y.v)"], 78 | 79 | "String" : ["x.v + y", "y.replace(x.v, '')", 80 | "y * _ord(x.v)", "y.split(x.v)", 81 | "y.split(x.v)[-1]"], 82 | 83 | "Stack" : ["y + [x.v]", "y.remove(x.v)", "y * _ord(x.v)", 84 | "split_list(y, _ord(x.v))", 85 | "split_list(y, _ord(x.v))[-1]"] 86 | }, 87 | 88 | "String": { 89 | "Number" : ["x + str(y)", "sub_strings(x, str(y))", "x * y", 90 | "textwrap.wrap(x, y)", "textwrap.wrap(x, y)[-1]"], 91 | "Character" : ["x + y.v", "sub_strings(x, y.v)", 92 | "x * _ord(y.v)", "x.split(y.v)", 93 | "x.split(y.v)[-1]"], 94 | 95 | "String": ["x + y", "sub_strings(x, y)", "multiply(x, y)", 96 | "x.split(y)", "x.split(y)[-1]" ], 97 | 98 | "Stack": ["y + [x]", "y.remove(x)", "list_mult(y, x)", 99 | "list_divide(y, x)", "list_divide(y, x)[-1]" ] 100 | }, 101 | 102 | "Stack": { 103 | "Number": ["x + [y]", "x.remove(y)", "x * y", 104 | "split_list(x, y)", "split_list(x, y)[-1]"], 105 | 106 | "Character": ["x + [y.v]", "x.remove(y.v)", "x * _ord(y.v)", 107 | "split_list(x, _ord(y.v))", 108 | "split_list(x, _ord(y.v))[-1]"], 109 | 110 | "String": ["x + [y]", "x.remove(y)", "list_mult(x, y)", 111 | "list_divide(x, y)", "list_divide(x, y)[-1]"], 112 | 113 | "Stack": ["x + y", "list(set(x) - set(y))", 114 | "[list(pair) for pair in zip(x, y)]", 115 | "special_divide(x, y)", "special_divide(x, y)[-1]"]} 116 | } 117 | 118 | 119 | second = { 120 | "Number" : { 121 | "Number" : ["x < y", "x > y", "x <= y", "x >= y", "x == y", "x != y", 122 | "x < y and x > 0"], 123 | "Character" : ["x < _ord(y.v)", "x > _ord(y.v)", "x <= _ord(y.v)", 124 | "x >= _ord(y.v)", "x == _ord(y.v)", "x != _ord(y.v)", 125 | "x < _ord(y.v) and x > 0"], 126 | "String" : ["str(x) < y", "str(x) > y", "str(x) <= y", "str(x) >= y", 127 | "str(x) == y", "str(x) != y", 128 | "str(x) < y and str(x) > '0'"], 129 | "Stack": ["1", "1", "1", "1", "1", "1", "1"] 130 | }, 131 | "Character" : { 132 | "Number": ["_ord(x.v) < y", "_ord(x.v) > y", "_ord(x.v) <= y", 133 | "_ord(x.v) >= y", "y == _ord(x.v)", "y != _ord(x.v)", 134 | "_ord(x.v) < y and y > 0"], 135 | "Character" : ["_ord(x.v) < _ord(y.v)", "_ord(x.v) > _ord(y.v)", 136 | "_ord(x.v) <= _ord(y.v)", "_ord(x.v) >= _ord(y.v)", 137 | "_ord(x.v) == _ord(y.v)", "_ord(x.v) != _ord(y.v)", 138 | "_ord(x.v) < _ord(y.v) and _ord(x.v) > 0"], 139 | "String": ["x.v < y", "x.v > y", "x.v <= y", "x.v >= y", "x.v == y", 140 | "x.v != y", 141 | "x.v < y and x.v > '0'"], 142 | "Stack": ["1", "1", "1", "1", "1", "1", "1"] 143 | }, 144 | 145 | "String" : { 146 | "Number" : ["str(y) > x", "str(y) < x", "str(y) >= x", "str(y) <= x", 147 | "str(y) == x", "str(x) != y", 148 | "str(y) > x and y > '0'"], 149 | "Character" : ["y.v > x", "y.v < x", "y.v >= x", "y.v <= x", "y.v == x", 150 | "y.v != x", 151 | "y.v > x and y.v < '0'"], 152 | "String" : ["x < y", "x > y", "x <= y", "x >= y", "x == y", "x != y", 153 | "x < y and x > 0"], 154 | "Stack": ["1", "1", "1", "1", "1", "1", "1"] 155 | }, 156 | 157 | "Stack" : { 158 | #TODO: Replace everything here with something more reasonable 159 | "Number" : ["1", "1", "1", "1", "1", "1", "1"], 160 | "Character": ["1", "1", "1", "1", "1", "1", "1"], 161 | "String": ["1", "1", "1", "1", "1", "1", "1"], 162 | "Stack": ["1", "1", "1", "1", "1", "1", "1"], 163 | } 164 | } 165 | 166 | def _type(item): 167 | if type(item) in [float, int]: 168 | return "Number" 169 | 170 | if type(item) == char: 171 | return "Character" 172 | 173 | if type(item) == str: 174 | return "String" 175 | return "Stack" 176 | 177 | def operate(lhs, rhs, op): 178 | from Stackd import Stack 179 | tLhs, tRhs = _type(lhs), _type(rhs) 180 | choices = relations[tLhs][tRhs] 181 | expr = choices["+-*/%".index(op)] 182 | x, y = lhs, rhs 183 | 184 | if type(lhs) is Stack: 185 | x = eval(str(lhs)) 186 | if type(rhs) is Stack: 187 | y = eval(str(rhs)) 188 | 189 | z = eval(expr) 190 | if type(z) is list: 191 | z = Stack(z) 192 | return z 193 | 194 | 195 | def do_compare(lhs, rhs, op): 196 | tLhs, tRhs = _type(lhs), _type(rhs) 197 | choices = second[tLhs][tRhs] 198 | expr = choices["<>≤≥=≠≬".index(op)] 199 | x, y = lhs, rhs 200 | 201 | return 1 if eval(expr) else 0 202 | 203 | def _ord(character): 204 | if str(character) in code_page: 205 | return code_page.index(str(character)) 206 | return ord(character) 207 | 208 | def _chr(i): 209 | if code_page: 210 | if i == 10: 211 | return "\n" 212 | if 0 < i < 256: 213 | return code_page[i] 214 | return chr(i) 215 | else: 216 | return chr(i) 217 | -------------------------------------------------------------------------------- /Graphical.py: -------------------------------------------------------------------------------- 1 | import Keg, tkinter 2 | 3 | class Textbox(): 4 | def __init__(self, root, width, height, args): 5 | self.frame = tkinter.Frame(root, width=width, height=height) 6 | self.width, self.height = width, height 7 | 8 | self.widget = tkinter.Text(self.frame, args) 9 | self.widget.pack(expand=tkinter.YES, fill=tkinter.BOTH) 10 | 11 | def place(self, *args, **kwargs): 12 | self.frame.place(*args, **kwargs) 13 | self.frame.place_configure(width=self.width, height=self.height) 14 | self.frame.config(bd=1, relief="solid", highlightbackground="#ffffff") 15 | 16 | def grun(): 17 | Keg.stack = [] 18 | Keg.register = None 19 | Keg.comment = False 20 | Keg.escape = False 21 | Keg.printed = False 22 | Keg.grun(codebox.widget.get("1.0", tkinter.END), prepop.get()) 23 | 24 | root = tkinter.Tk() 25 | root.geometry('800x600') 26 | 27 | codebox = Textbox(root, 800, 300, {'height': '300', 'width': '800'}) 28 | codebox.place(x=0, y=0) 29 | 30 | submit = tkinter.Button(root, text="Run Program", command=grun) 31 | submit.place(x=0, y=301) 32 | 33 | tkinter.Label(root, text="Values to prepopulate stack").place(x=0, y=330) 34 | prepop = tkinter.Entry(root, width=50) 35 | prepop.place(x=0, y=350) 36 | -------------------------------------------------------------------------------- /Guide.md: -------------------------------------------------------------------------------- 1 | # A Guide to Keg's Raw Source 2 | 3 | Hello, Traveller! I see you are inspecting the source code for Keg (otherwise, you probably wouldn't be reading this). To an outsider, this may seem like a huge mess of files -- and it kind of is. But, don't fear, for I shall (hopefully) enlighten you about what each file does and how they all interact, bringing you inside the Keg experience! 4 | 5 | ## Keg.py vs OldKeg.py: Which One do I Use? 6 | 7 | The first thing you may have noticed about this repo is that there are _two_ interpreters: `Keg.py` and `OldKeg.py`. This is because of the change from Keg being an interpreted language to a transpiled language (i.e. Keg is converted to Python and `exec()` is called on the resulting code). Contained within `Keg.py` is the shiny new transpiler, which has _probably_ fewer bugs than `OldKeg.py`. Consequently, it is recommended that you use `Keg.py` to run your Keg programs, as it is the program that is now maintained. 8 | 9 | `OldKeg.py` contains the old interpreter, which, although being the cornerstone of the Keg language for most of the previous year (2018-2019), is somewhat buggy as well as hard to maintain. Indeed, fixing bugs and making everything work when what was really happening was hidden away in abstracted layers of "Tokens" just wasn't working anymore. 10 | 11 | In summary, use `Keg.py` if you want a smooth execution of your program and use `OldKeg.py` if you are feeling adventurous. 12 | 13 | ## The Keg Chain 14 | 15 | This section will attempt to explain how the transpiler turns Keg source code into tokens and then into python through exploring the different files involved in the process. 16 | 17 | ### preprocess.py 18 | 19 | This is the very first file that Keg source code flows through in order to be turned into a readable output. In here, sequences found within the Standard Sequence Library (SSL) are injected into places defined by the `₳` keyword. It takes input into `process()` as a string and returns another string filled with SSL sequences. 20 | 21 | However, there is another process occurring here: `balance_strings`: in order to allow for programs to have strings autocompleted, string symbols (the backtick, `¶‘“«„`) are matched in a LIFO manner. This has to be done somewhere before the next step (uncompressing of strings), meaning that is has to be done here. 22 | 23 | ### uncompress.py 24 | 25 | This is the second file that Keg source code flows through in the pipeline of execution. Within `uncompress.py`, the code goes through `Uncompress()` first, which turns every single string contained in the source and turns it into the standard string (the backtick string), while substituting String Compression Codes (SCCs) with words found in Keg's dictionary. Strings are passed to `to_standard()` in order to make `Uncompress()` modular. 26 | 27 | ### Parse.py 28 | 29 | This is the most important part of the execution pipeline: here, source code (at this point, still a string) is turned into mini tokens ready for the transpiler to turn into Python. It was this functionality that took me the longest to complete, as there was lots of testing, retesting, breakage of everything and more. What's important to note here is that without this file, nothing would work. 30 | 31 | ### Keg.py (or OldKeg.py) 32 | 33 | Now that the code has been turned into tokens, it is ready for transpilation/interpretation. In `Keg.py`, the tokens are systematically turned into Python statements that `exec()` can use. In `OldKeg.py`, the tokens are interpreted line by line. 34 | 35 | That concludes the Keg chain. It's not much, I know, but I feel that's all that is needed for an understanding of how the pipeline works. 36 | 37 | # MORE COMING SOON # 38 | -------------------------------------------------------------------------------- /Information_noblank.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyxal/Keg/b1a923f4dc35e7362f050d00e80baad74e8bc81b/Information_noblank.pdf -------------------------------------------------------------------------------- /Keg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import sys #Used for file parsing 4 | import Parse #Used for Keg source parsing 5 | import uncompress #Used for uncompressing Keg strings 6 | import preprocess #Used for expanding preprocessor cues 7 | import Stackd #The main data type of Keg 8 | 9 | '''Constants Section''' 10 | '''The following lines will define all the commands and place them into 11 | more readable/modular constants''' 12 | 13 | #Built-ins 14 | 15 | LENGTH = "!" 16 | DUPLICATE = ":" 17 | POP = "_" 18 | PRINT_CHR = "," 19 | PRINT_INT = "." 20 | INPUT = "?" 21 | R_SHIFT = '"' 22 | L_SHIFT = "'" 23 | RANDOM = "~" 24 | REVERSE = "^" 25 | SWAP = "$" 26 | 27 | DESCRIPTIONS = { 28 | LENGTH: "Push the length of the stack", 29 | DUPLICATE: "Duplicate the top of stack", 30 | POP: "Pop the top of stack", 31 | PRINT_CHR: "Print the top of stack, calling _ord(top)", 32 | PRINT_INT: "Print the top of stack, as is", 33 | INPUT: "Get input from user", 34 | L_SHIFT: "Left shift stack", 35 | R_SHIFT: "Right shift stack", 36 | RANDOM: "Push a random number between -inf and inf", 37 | REVERSE: "Reverse the stack", 38 | SWAP: "Swap the top two items on stack" 39 | } 40 | 41 | #Unofficial built-in functions 42 | #Note: Most of these are from myu-sername/A̲̲/User:A, so go check out their 43 | #repos/esolang account/code golf userpage and upvote their answers 44 | 45 | IOTA = "Ï" 46 | DECREMENT = ";" 47 | SINE = "§" 48 | APPLY_ALL = "∑" 49 | NICE_INPUT = "¿" 50 | 51 | DESCRIPTIONS[IOTA] = "Replaces the top of stack with all items from [top->0]" 52 | DESCRIPTIONS[DECREMENT] = "Decrement the top of stack" 53 | DESCRIPTIONS[SINE] = "sin(top)" 54 | DESCRIPTIONS[APPLY_ALL] = "Preprocess as (!;| --> Apply to all stack" 55 | DESCRIPTIONS[NICE_INPUT] = "Peform nice input" 56 | 57 | #Some Reg commands not by Btup but by JonoCode9374 58 | EXCLUSIVE_RANGE = "∂" 59 | INCLUSIVE_RANGE = "•" 60 | GENERATE_RANGE = "ɧ" 61 | NUMBER_SPLIT = "÷" 62 | FACTORIAL = "¡" 63 | EMPTY = "ø" 64 | PRINT_ALL = "Ω" 65 | NOT = "¬" 66 | AND = ("⒄", "⟑") #This is what a temp code page looks like when a more certain page is added 67 | OR = ("⒅", "⟇" ) 68 | PREDEFINED_CONSTANT = "λ" 69 | PI = "π" 70 | HALVE_TOP = "½" #math(stack, "/") 71 | INCREMENT = ("⑨", "؛") 72 | DOUBLE = "⑵" #dobule the top of stack 73 | NEGATE = "±" #*-1 74 | ONE_ON_X = ("⑱", "⅟") #1/tos 75 | ROUND = ("⑲", "𝚪") #uses round function 76 | WHILE_STUFF = ("⑳", "↬") #Preprocesses as {!| 77 | INCREMENT_REGISTER = ("⑹", "ꜛ") 78 | DECREMENT_REGISTER = ("⑺", "ꜜ") 79 | PUSH_REGISTER_NO_EMPTY = ("⑻", "⅋") 80 | X_TO_BASE = "⬥" # Huh, whould'a thought it'd take a code golf challenge to force me to finally implement this? 81 | 82 | 83 | #Keg+ Section 84 | PUSH_N_PRINT = "ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ" 85 | for n in range(127234, 127243): PUSH_N_PRINT += chr(n) 86 | #NOTE: Don't go trying to print PUSH_N_PRINT in IDLE... 87 | #Tkinter doesn't like some of the characters 88 | 89 | ALPHA_MAP = "abcdefghijklmnopqrstuvwxyz1234567890" 90 | 91 | 92 | INTEGER_SCAN = "‡" 93 | TO_INT, TO_FLOAT, TO_STRING, TO_STACK, TO_CHAR = "ℤℝ⅍℠ⁿ" 94 | UPPER, LOWER, TOGGLE = "⟰⟱⟷" 95 | SQUARE_OPERATOR = "²" 96 | STRING_INPUT = "᠀" 97 | ALL_TRUE = "∀" 98 | ALL_EQUAL = "≌" 99 | SUMMATE = "⅀" 100 | EVAL_EXEC = "ß" 101 | END_SWITCH = "™" 102 | MULTILINE_INPUT = "᠈" 103 | MAP = ("⑷", "£") #will be £. closed with » 104 | MAP_CLOSE = ("⑸", "»") #As aforementioned, will be » 105 | 106 | VARIABLE_SET = "©" 107 | VARIAGE_GET = "®" 108 | 109 | PERFORM_INDEX = "⊙" 110 | INFINITY = "א" 111 | RANDOM_INSTRUCTION = "⯑" #Chooses an instruction from 112 | #all avaliable commands and puts it in. 113 | 114 | DIV_MOD = ("①", "‰") 115 | EQUAL_TYPES = ("②", "≡") 116 | FIND_POS = "③" 117 | PRINT_RAW_NO_POP = "④" 118 | FUNCTION_MODIFIERS = "⑤⑥⑦⑧" 119 | PRINT_NICE_NO_POP = "⑩" 120 | TO_PERCENTAGE = "⑪" 121 | ITEM_IN = "⊂" 122 | 123 | EMPTY_STRING, SPACE_STRING = "⑫⑬" 124 | SORT_STACK = "⑭" 125 | SINGULAR_SCC = "⑮" 126 | POP_ITEM = "⑯" #Takes the TOS and removes all instances of TOS 127 | FILTER_BY = "⑰" #Takes a keg-string and pops all items not matching condition 128 | 129 | LENGTH_TOP, REVERSE_TOP = "⑴⑶" 130 | 131 | REGISTER_AUG_ADD, REGISTER_AUG_SUB, REGISTER_AUG_MULT, REGISTER_AUG_DIV = \ 132 | "⑼⑽⑾⑿" 133 | 134 | REGISTER_SET, REGISTER_LENGTH, REGISTER_REVERSE = "⒀⒁⒂" 135 | TRUTHY = "⒃" 136 | 137 | #'Keywords' 138 | 139 | COMMENT = "#" 140 | BRANCH = "|" 141 | ESCAPE = "\\" 142 | REGISTER = "&" 143 | STRING = "`" 144 | FUNCTION = "@" 145 | 146 | DESCRIPTIONS[COMMENT] = "Standard line comment" 147 | DESCRIPTIONS[BRANCH] = "Switch to the next part of the structure" 148 | DESCRIPTIONS[ESCAPE] = "Push the code page value of the next character" 149 | DESCRIPTIONS[STRING] = "Push an uncompressed string" 150 | DESCRIPTIONS[FUNCTION] = "Start/Call the given function" 151 | 152 | #Operators 153 | MATHS = "+-*/%Ë" 154 | CONDITIONAL = "<>=≬≤≠≥" 155 | NUMBERS = "0123456789" 156 | 157 | DESCRIPTIONS[MATHS] = "Pop x and y, and push y {0} x" 158 | DESCRIPTIONS[CONDITIONAL] = "Pop x and y, and push y {0} x" 159 | DESCRIPTIONS[NUMBERS] = "Push {0}" 160 | 161 | #Whitespace 162 | TAB = "\t" 163 | NEWLINE = "\n" 164 | 165 | #Code page - Special to Keg 166 | unicode = "ϧ∑¿∂•ɧ÷¡Ëė≬ƒß‘“" 167 | unicode += "„«®©ëλº√₳¬≤Š≠≥Ėπ" 168 | unicode += " !\"#$%&'()*+,-./" 169 | unicode += "0123456789:;<=>?" 170 | unicode += "@ABCDEFGHIJKLMNO" 171 | unicode += "PQRSTUVWXYZ[\\]^_" 172 | unicode += "`abcdefghijklmno" 173 | unicode += "pqrstuvwxyz{|}~ø" 174 | unicode += "¶\n\t⊂½‡™±¦→←↶↷" 175 | unicode += "✏█↗↘□²ⁿ║ṡ⟰⟱⟷" 176 | unicode += "ℤℝ⅍℠א∀≌᠀⊙᠈⅀" 177 | unicode += "ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ" #push'n'print 178 | unicode += "☭" #I don't know what this'll do. But it looks cool 179 | unicode += "⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯"#drawing 180 | unicode += "⯑" #Do something random 181 | unicode += "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅↫" 182 | 183 | 184 | for n in range(127234, 127243): unicode += chr(n) 185 | args = None 186 | 187 | '''Transpiler Helpers''' 188 | 189 | def balance(source: str) -> str: 190 | ''' 191 | 192 | Takes: source [str] 193 | Does: Balances any unclosed brackets and replaces any escaped brackets with 194 | an expression that evaluates to the ordinal value of the bracket. This is 195 | because it was too hard to have literal brackets in the source and have 196 | them escaped like other characters. 197 | Returns: str 198 | 199 | "abc" -> "abc" 200 | "(+" -> "(+)" 201 | "{[{[" -> "{[{[]}]}" 202 | "\{" -> "z1-" 203 | 204 | ''' 205 | 206 | brackets = [] #This is kind of equivalent to the loops list found commonly 207 | #in Python BF interpreters. 208 | mapping = {"{" : "}", "[" : "]", "(" : ")", "": "", "⑷": "⑸"} 209 | alt_brackets = {"{" : "z1+", "}" : "z3+", "(" : "85*", 210 | ")" : "85*1+", "[" : "Z1+", 211 | "]" : "Z3+", "⑷" : "25*25**2*56*+1+", 212 | "⑸" : "25*25**2*56*+2+"} 213 | 214 | escaped = False #Whether or not there is currently an escape sequence 215 | string_mode = False #Whether or not I'm currently in a string 216 | 217 | result = "" 218 | for char in source: 219 | 220 | if string_mode: 221 | if escaped: 222 | result += char 223 | escaped = False 224 | continue 225 | 226 | elif char == "\\": 227 | escaped = True 228 | result += char 229 | continue 230 | else: 231 | if char == "`": 232 | string_mode = False 233 | result += char 234 | continue 235 | if escaped: #Either escape the bracket or keep the escape 236 | if char in alt_brackets: 237 | result += alt_brackets[char] 238 | else: 239 | result += "\\" + char 240 | escaped = False 241 | continue 242 | 243 | elif char == "\\": 244 | escaped = True 245 | continue 246 | 247 | elif char == "`": 248 | string_mode = True 249 | 250 | 251 | if char in "[({⑷": 252 | brackets.append(char) 253 | 254 | elif char in "])}⑸": 255 | for i in range(len(brackets)): #Close an open bracket 256 | if mapping[brackets[i]] == char: 257 | brackets[i] = "" 258 | break 259 | 260 | result += char 261 | 262 | if brackets: 263 | for char in reversed(brackets): #Close all brackets 264 | result += mapping[char] 265 | 266 | return result 267 | 268 | def tab_format(string: str) -> str: 269 | ''' 270 | Takes: string [str] 271 | Does: Formats the line with tabs at the start. This also happens to 272 | recursively format lines within for|while loops/if stmts/functions, which 273 | is nice. 274 | Returns: str 275 | 276 | 277 | "abc" -> " abc\n" 278 | 279 | ''' 280 | result = "" 281 | for line in string.rstrip().split("\n"): 282 | result += " " + line + "\n" 283 | return result 284 | 285 | '''Actual Transpiler''' 286 | 287 | def transpile(source: str, stack="stack", lvl=0): 288 | ''' 289 | Takes: source [str], stack (default="stack") [str] 290 | Does: This is the primary function here, as it does the actual transpilation 291 | of Keg programs. Without it, there would be no Keg. It first of all parses 292 | the source into a list of tokens as defined in `Parse.py`. It then goes 293 | through and turns these tokens into python. 294 | Returns: str 295 | 296 | ''' 297 | 298 | if type(source) is str: 299 | source = Parse.parse(source) 300 | 301 | 302 | if args and args.reversetokens: 303 | source = source[::-1] 304 | 305 | comment = False #Whether or not the transpiler is parsing a comment 306 | escaped = False #Whether or not the transpiler needs to use escape() 307 | 308 | #Wow, this feels odd. Normally, this would be the interpreter part, but now, 309 | #it's just a transpiler. I.e. There would normally be variables here getting 310 | #ready for the interpreting that would be about to happen, but not this time 311 | 312 | result = "" 313 | tabs = "" 314 | #The variable storing the end result 315 | for Token in source: 316 | name, command = Token.name, Token.data 317 | #print(name, command) 318 | #^^ used only for debugging while working on the Transpiler 319 | 320 | 321 | #Deal with comments and potential escaped characters first 322 | if comment == True: 323 | if command == NEWLINE: #End of Comment 324 | comment = False 325 | continue 326 | 327 | if name == Parse.CMDS.ESC: 328 | escape = False 329 | result += f"character(stack, '{command}')\n" 330 | continue 331 | 332 | if name == Parse.CMDS.STRING: 333 | import KegStrings #Allow for the usage of object strings 334 | item = KegStrings.obj_str_extract("`" + command + "`") 335 | if type(item) != str: #The object is an object string 336 | if type(item) is list: #this is generally raw python. 337 | result += f"{stack}.push(Stack({item}))" 338 | else: 339 | result += f"{stack}.push({item})" 340 | else: #It isn't an object string 341 | result += f"iterable({stack}, \"" + command + "\")" 342 | 343 | 344 | #Now, keywords and structures 345 | elif command == COMMENT: 346 | comment = True 347 | 348 | elif command == BRANCH: 349 | continue 350 | 351 | elif command == ESCAPE: 352 | escaped = True 353 | 354 | elif command == REGISTER: 355 | result += f"register({stack})" 356 | 357 | elif name == Parse.CMDS.IF: 358 | 359 | ''' 360 | 361 | [ifTrue|ifFalse] --> 362 | 363 | if bool(stack.pop()): 364 | ifTrue 365 | else: 366 | ifFalse 367 | 368 | [ifTrue] --> 369 | 370 | if bool(stack.pop()): 371 | ifTrue 372 | 373 | [|ifFalse] --> 374 | 375 | if bool(stack.pop()): 376 | pass 377 | else: 378 | ifFalse 379 | ''' 380 | 381 | result += f"if bool({stack}.pop()):\n" 382 | if Token.data[0] == "": 383 | result += tab_format("pass") 384 | else: 385 | result += tab_format(transpile(command[0], stack)) 386 | 387 | if Token.data[1]: 388 | result += "\nelse:\n" 389 | result += tab_format(transpile(command[1], stack)) 390 | 391 | elif name == Parse.CMDS.FOR: 392 | 393 | ''' 394 | 395 | (count|code) --> 396 | 397 | count 398 | for _ in loop_eval(stack.pop()): 399 | code 400 | 401 | 402 | (code) --> 403 | 404 | length(stack) 405 | for _ in loop_eval(stack.pop()): 406 | code 407 | 408 | ''' 409 | 410 | result += transpile(Token.data[0]) 411 | result += f"\nfor _ in loop_eval({stack}.pop()):" 412 | result += "\n" 413 | 414 | 415 | 416 | if Token.data[1] == "": 417 | result += tab_format("pass") 418 | else: 419 | result += tab_format(transpile(Token.data[1])) 420 | 421 | elif name == Parse.CMDS.WHILE: 422 | 423 | ''' 424 | {condition|code} --> 425 | 426 | for expr in condition: eval(expr) 427 | while stack.pop(): 428 | code 429 | for expr in condition: eval(expr) 430 | 431 | 432 | {code} --> 433 | 434 | while 1: 435 | code 436 | 437 | ''' 438 | 439 | if Token.data[0]: 440 | template = "for expr in {0}: eval(expr)\n" 441 | 442 | functions = [] #Transpile all functions into a nice list 443 | for function in transpile(Token.data[0]).split("\n"): 444 | functions.append(function) 445 | 446 | 447 | result += template.format(functions) 448 | result += f"while {stack}.pop():\n" 449 | else: 450 | result += "while 1:\n" 451 | 452 | if not Token.data[1]: 453 | result += tab_format("pass") 454 | else: 455 | result += tab_format(transpile(Token.data[1])) 456 | result += "\n" 457 | 458 | if Token.data[0]: 459 | result += tab_format(template.format(functions)) 460 | 461 | elif name == Parse.CMDS.FUNCTION: 462 | if command[0] == 1: 463 | #Function call 464 | result += command[1] + f"({stack})" 465 | else: 466 | result += "def " + command[0]["name"] + f"({stack}):\n" 467 | result += " temp = Stack()" 468 | if command[0]["number"] == "!": 469 | result += f"\n temp = {stack}.copy()" 470 | else: 471 | result += "\n for _ in range(" + str(command[0]["number"]\ 472 | ) + "): " 473 | result += f"temp.push({stack}.pop())" 474 | result += "\n" + tab_format(transpile(command[1], "temp")) 475 | result += f"\n for item in temp: {stack}.push(item)" 476 | 477 | elif name == Parse.CMDS.VARIABLE: 478 | if command[1] == "set": 479 | result += f"var_set({stack}, '{command[0]}')" 480 | 481 | else: 482 | result += f"var_get({stack}, '{command[0]}')" 483 | 484 | elif name == Parse.CMDS.SWITCH: 485 | result += f"\nSWITCH_VARIABLE{lvl} = {stack}.pop()\n" 486 | result += "for _ in range(1):\n" 487 | for case in command: 488 | if "default" in case: 489 | default = case[0][:] 490 | result += tab_format("else: \n") 491 | result += tab_format(tab_format(\ 492 | f"{stack}.push(SWITCH_VARIABLE{lvl})")) 493 | result += tab_format(tab_format(transpile(default, lvl=lvl+1))) 494 | result += tab_format(tab_format("\nbreak\n")) 495 | else: 496 | result += tab_format(transpile([case[0]], lvl=lvl+1) + "\n") 497 | result += tab_format(f"{stack}.push(SWITCH_VARIABLE{lvl})") 498 | result += tab_format(f"comparative({stack}, '=')") 499 | result += tab_format(f"if bool({stack}.pop()):\n") 500 | result += tab_format(tab_format(transpile(case[1:], lvl=lvl+1))) 501 | result += tab_format(tab_format("\nbreak\n")) 502 | 503 | 504 | elif name == Parse.CMDS.MAP: 505 | result += f"keg_map({stack}, {command})" 506 | 507 | #Handle all functions (built-in) 508 | elif command == LENGTH: 509 | if args and args.lengthpops: 510 | result += f"length({stack}, True)" 511 | else: 512 | result += f"length({stack})" 513 | 514 | elif command == DUPLICATE: 515 | result += f"duplicate({stack})" 516 | 517 | elif command == POP: 518 | result += f"pop_top({stack})" 519 | 520 | elif command == PRINT_CHR: 521 | result += f"nice({stack}); printed = True" 522 | 523 | elif command == PRINT_INT: 524 | result += f"raw({stack}); printed = True" 525 | 526 | elif command in [L_SHIFT, R_SHIFT]: 527 | result += f"shift({stack}, '" + ["left", "right"]\ 528 | [[L_SHIFT, R_SHIFT].index(command)]+ "')" 529 | 530 | elif command == REVERSE: 531 | result += f"reverse({stack})" 532 | 533 | elif command == RANDOM: 534 | result += f"random({stack})" 535 | 536 | elif command == SWAP: 537 | result += f"swap({stack})" 538 | 539 | elif command == INPUT: 540 | result += f"Input({stack})" 541 | 542 | #Now, for Reg's commands 543 | elif command == IOTA: 544 | result += f"iota({stack})" 545 | 546 | elif command == DECREMENT: 547 | result += f"decrement({stack})" 548 | 549 | elif command == SINE: 550 | result += f"sine({stack})" 551 | 552 | elif command == NICE_INPUT: 553 | result += f"nice_input({stack})" 554 | 555 | elif command == EXCLUSIVE_RANGE: 556 | result += f"excl_range({stack})" 557 | 558 | elif command == INCLUSIVE_RANGE: 559 | result += f"incl_range({stack})" 560 | 561 | elif command == GENERATE_RANGE: 562 | result += f"smart_range({stack})" 563 | 564 | elif command == NUMBER_SPLIT: 565 | result += f"item_split({stack})" 566 | 567 | elif command == FACTORIAL: 568 | result += f"factorial({stack})" 569 | 570 | elif command == STRING_INPUT: 571 | result += f"string_input({stack})" 572 | 573 | elif command in INCREMENT: 574 | result += f"increment({stack})" 575 | 576 | elif command == DOUBLE: 577 | result += f"double({stack})" 578 | 579 | elif command == NEGATE: 580 | result += f"negate({stack})" 581 | 582 | elif command in ONE_ON_X: 583 | result += f"reciprocal({stack})" 584 | 585 | elif command in ROUND: 586 | result += f"keg_round({stack})" 587 | 588 | elif command in FILTER_BY: 589 | result += f"keg_filter({stack})" 590 | 591 | elif command == NOT: 592 | result += f""" 593 | 594 | if bool({stack}.pop()): 595 | {stack}.push(0) 596 | else: 597 | {stack}.push(1) 598 | """ 599 | 600 | elif command in AND: 601 | result += f""" 602 | ___lhs, ___rhs = {stack}.pop(), {stack}.pop() 603 | if bool(___lhs) and bool(___rhs): 604 | {stack}.push(1) 605 | else: 606 | {stack}.push(0) 607 | """ 608 | 609 | elif command in OR: 610 | result += f""" 611 | ___lhs, ___rhs = {stack}.pop(), {stack}.pop() 612 | if bool(___lhs) or bool(___rhs): 613 | {stack}.push(1) 614 | else: 615 | {stack}.push(0) 616 | """ 617 | 618 | #Now, operators. 619 | elif command in MATHS: 620 | if command == "Ë": 621 | result += f"exponate({stack})" 622 | else: 623 | result += f"maths({stack}, '" + command + "')" 624 | 625 | elif command in CONDITIONAL: 626 | result += f"comparative({stack}, '{command}')" 627 | 628 | elif command in NUMBERS: 629 | result += f"integer({stack}, " + command + ")" 630 | 631 | elif command == HALVE_TOP: 632 | result += f"halve_top({stack})" 633 | 634 | 635 | 636 | #Whitespace 637 | elif command == TAB: 638 | continue 639 | 640 | elif command == NEWLINE: 641 | if args and args.ignorenewlines: 642 | pass 643 | else: 644 | result += f"integer({stack}, 10)" 645 | 646 | #Keg+ 647 | 648 | elif command in PUSH_N_PRINT: 649 | result += f"print('{ALPHA_MAP[PUSH_N_PRINT.index(command)]}', end='')" 650 | 651 | elif command in [TO_INT, TO_FLOAT, TO_STRING, TO_STACK, TO_CHAR]: 652 | result += f"try_cast({stack}, '{command}')" 653 | 654 | elif command == SQUARE_OPERATOR: 655 | result += f"square({stack})" 656 | 657 | elif command == ALL_TRUE: 658 | result += f"all_true{stack}" 659 | 660 | elif command == ALL_EQUAL: 661 | result += f"all_equal({stack})" 662 | 663 | elif command == UPPER: 664 | result += f"case_switch({stack}, 'upper')" 665 | 666 | elif command == LOWER: 667 | result += f"case_switch({stack}, 'lower')" 668 | 669 | elif command == X_TO_BASE: 670 | result += f"int2base({stack})" 671 | 672 | elif command == TOGGLE: 673 | result += f"case_switch({stack}, 'toggle')" 674 | 675 | elif command == SUMMATE: 676 | result += f"summate({stack})" 677 | 678 | elif command == EMPTY: 679 | result += f"empty({stack})" 680 | 681 | elif command == PRINT_ALL: 682 | result += f"print_all({stack})" 683 | 684 | elif command == EVAL_EXEC: 685 | result += f"keg_exec({stack})" 686 | 687 | elif name == Parse.CMDS.INTEGER: 688 | result += f"integer({stack}, {command})" 689 | 690 | elif command == PERFORM_INDEX: 691 | result += f"perform_index({stack})" 692 | 693 | elif command == MULTILINE_INPUT: 694 | result += f"multiline({stack})" 695 | 696 | elif command in PRINT_RAW_NO_POP: 697 | result += f"raw({stack}, True)" 698 | 699 | elif command in PRINT_NICE_NO_POP: 700 | result += f"nice({stack}, True)" 701 | 702 | elif command in TO_PERCENTAGE: 703 | result += f"to_percentage({stack})" 704 | 705 | elif command in EMPTY_STRING: 706 | result += f"iterable({stack}, \"\")" 707 | 708 | elif command in SPACE_STRING: 709 | result += f"iterable({stack}, \" \")" 710 | 711 | elif command in LENGTH_TOP: 712 | result += f"length_top({stack})" 713 | 714 | elif command in REVERSE_TOP: 715 | result += f"reverse_top({stack})" 716 | 717 | elif command in POP_ITEM: 718 | result += f"pop_item({stack})" 719 | 720 | elif command in SORT_STACK: 721 | result += f"sort_stack({stack})" 722 | 723 | elif command in INCREMENT_REGISTER: 724 | result += f"increment_register({stack})" 725 | 726 | elif command in DECREMENT_REGISTER: 727 | result += f"decrement_register({stack})" 728 | 729 | elif command in PUSH_REGISTER_NO_EMPTY: 730 | result += f"register_dont_empty({stack})" 731 | 732 | elif command in REGISTER_AUG_ADD: 733 | result += f"register_aug_assign({stack}, '+')" 734 | 735 | elif command in REGISTER_AUG_SUB: 736 | result += f"register_aug_assign({stack}, '-')" 737 | 738 | elif command in REGISTER_AUG_MULT: 739 | result += f"register_aug_assign({stack}, '*')" 740 | 741 | elif command in REGISTER_AUG_DIV: 742 | result += f"register_aug_assign({stack}, '/')" 743 | 744 | elif command in REGISTER_SET: 745 | result += f"set_register_dont_empty({stack})" 746 | 747 | elif command in REGISTER_LENGTH: 748 | result += f"register_length({stack})" 749 | 750 | elif command in REGISTER_REVERSE: 751 | result += f"reverse_register({stack})" 752 | 753 | elif command in TRUTHY: 754 | result += f"truthify({stack})" 755 | 756 | 757 | 758 | #Default case 759 | 760 | else: 761 | result += f"character({stack}, '" + command + "')" 762 | 763 | result += ("\n") 764 | 765 | return result.rstrip("\n") 766 | 767 | if __name__ == "__main__": 768 | '''print(unicode) 769 | ''' 770 | 771 | 772 | 773 | if len(sys.argv) > 1: 774 | import argparse 775 | parser = argparse.ArgumentParser() 776 | parser.add_argument("file", help="The location of the Keg file to open") 777 | parser.add_argument('-ex', '--explain', 778 | help="Explains given source", action='store_true') 779 | parser.add_argument("-cm", "--compiled", 780 | help="Shows the compiled code", action='store_true') 781 | 782 | #Custom Keg flags 783 | #-hd --head : prints only the head of the stack upon finishing 784 | 785 | parser.add_argument("-hd", "--head", 786 | help="Only prints the top item", 787 | action='store_true') 788 | 789 | #-no --newoutput : prints everything 'as-is'/no conversion of ints to 790 | #chars 791 | 792 | parser.add_argument("-no", "--newoutput", 793 | help="Prints everything 'as-is'", 794 | action='store_true') 795 | 796 | #-hr --headraw : prints only the top of stack raw 797 | 798 | parser.add_argument("-hr", "--headraw", 799 | help="Only prints the top item raw", 800 | action='store_true') 801 | 802 | #-rr --reverseraw : reverse then perform -hr 803 | 804 | parser.add_argument("-rr", "--reverseraw", 805 | help="Reverse stack then -rr", 806 | action='store_true') 807 | 808 | #-rn --reversenice : reverse then perform -hd 809 | 810 | parser.add_argument("-rn", "--reversenice", 811 | help="Reverse stack then -rd", 812 | action='store_true') 813 | 814 | #-ir --inputraw : implicit input uses ? not ¿ 815 | 816 | parser.add_argument("-ir", "--inputraw", 817 | help="Make implicit input _not_ evaluate everything", 818 | action='store_true') 819 | 820 | #-oc --outputcharacters : Output everything as characters if possible 821 | parser.add_argument("-oc", "--outputcharacters", 822 | help="Output _everything_ as characters if possible", 823 | action='store_true') 824 | 825 | #-lp --lengthpops : Length pops if the stack has 0 items 826 | parser.add_argument("-lp", "--lengthpops", 827 | help="Length (!) pops if the stack has 0 items", 828 | action='store_true') 829 | 830 | #-in --ignorenewlines : newlines DON'T push 10 831 | 832 | parser.add_argument("-in", "--ignorenewlines", 833 | help="newlines DON'T push 10", 834 | action='store_true') 835 | 836 | #-pr --printregister : print the register instead of the stack 837 | parser.add_argument("-pr", "--printregister", 838 | help="print the register instead of the stack at EOE", 839 | action='store_true') 840 | 841 | #-rR --registerraw : print the register instead of the stack 842 | parser.add_argument("-rR", "--registerraw", 843 | help="print the register instead of the stack at EOE", 844 | action='store_true') 845 | 846 | 847 | #-pn --printnewlines : printing puts a newline between outputs 848 | parser.add_argument("-pn", "--printnewlines", 849 | help="printing puts a newline between outputs", 850 | action='store_true') 851 | 852 | #-rt --reversetokens : reverse token order 853 | 854 | parser.add_argument("-rt", "--reversetokens", 855 | help="reverse token order internally", 856 | action='store_true') 857 | 858 | 859 | #-rs --reversestack : reverse stack before outputting 860 | 861 | parser.add_argument("-rs", "--reversestack", 862 | help="reverse stack before outputting implicitly", 863 | action='store_true') 864 | 865 | #-v --version : Prints when the interpreter was last updated 866 | 867 | parser.add_argument("-v", "--version", 868 | help="Prints when the interpreter was last updated", 869 | action='store_true') 870 | 871 | # -b --bytes : Treats input file as raw bytes 872 | parser.add_argument("-b", "--bytes", 873 | help="This is mainly for SBCS purposes and to show that there truly is a codepage.", 874 | action='store_true') 875 | 876 | args = parser.parse_args() 877 | file_location = args.file 878 | 879 | if args.explain: 880 | source = open(file_location, encoding="utf-8").read().strip("\n") 881 | i = 0 882 | for char in source: 883 | if char in DESCRIPTIONS: 884 | print(" "*i + char + " "*(len(source) - i) + "#", 885 | DESCRIPTIONS[char]) 886 | else: 887 | print(" "*i + char + " "*(len(source) - i) + "#", 888 | "Push", char, "onto the stack") 889 | i += 1 890 | exit() 891 | 892 | elif args.version: 893 | print("Keg Last Updated On: Wednesday 15 January 2020") 894 | 895 | else: 896 | file_location = input("Enter the file location of the Keg program: ") 897 | args = 0 898 | 899 | if args.bytes: 900 | source = open(file_location, "rb").read() 901 | source = uncompress.keg_to_utf8(code) 902 | else: 903 | source = open(file_location, encoding="utf-8").read() 904 | 905 | 906 | 907 | code = source 908 | code_page = "" 909 | import string 910 | unicode_set = set(unicode) - set(string.printable) 911 | if any([char in unicode_set for char in source]): 912 | code_page = unicode 913 | 914 | #print(code_page) 915 | import KegLib, Coherse 916 | Stackd.code_page = code_page 917 | KegLib.code_page = code_page 918 | Coherse.code_page = code_page 919 | 920 | code = preprocess.process(code); #print("After preprocess:", code) 921 | code = preprocess.balance_strings(code); 922 | code = uncompress.Uncompress(code); #print("After uncom:", code) 923 | code += "\t" 924 | 925 | header = """ 926 | from KegLib import * 927 | from Stackd import Stack 928 | stack = Stack() 929 | printed = False 930 | """ 931 | 932 | footer = "" 933 | if args and args.inputraw: 934 | Stackd.input_raw = True 935 | 936 | if args and args.printnewlines: 937 | KegLib.seperator = "\n" 938 | 939 | #Conditionally determine the footer 940 | 941 | if args and args.reversestack: 942 | footer = "\nreverse(stack)\n" 943 | 944 | if args and args.head: 945 | footer += """ 946 | if not printed: 947 | nice(stack) 948 | """ 949 | 950 | elif args and args.newoutput: 951 | footer += """ 952 | if not printed: 953 | for item in stack[::-1]: 954 | if type(item) in [str, KegLib.Coherse.char]: 955 | nice(stack) 956 | else: 957 | raw(stack)""" 958 | 959 | elif args and args.headraw: 960 | footer += """ 961 | if not printed: 962 | raw(stack) 963 | """ 964 | 965 | elif args and args.reverseraw: 966 | footer += """ 967 | if not printed: 968 | reverse(stack) 969 | raw(stack) 970 | """ 971 | 972 | elif args and args.reversenice: 973 | footer += """ 974 | if not printed: 975 | reverse(stack) 976 | nice(stack) 977 | """ 978 | 979 | elif args and args.outputcharacters: 980 | footer += """ 981 | if not printed: 982 | for item in stack: 983 | if type(item) in [int, float]: 984 | print(chr(int(item)), end="") 985 | else: 986 | print(str(item), end="") 987 | """ 988 | 989 | elif args and args.printregister: 990 | footer += """ 991 | if not printed: 992 | register(stack) 993 | nice(stack) 994 | 995 | """ 996 | elif args and args.registerraw: 997 | footer += """ 998 | if not printed: 999 | register(stack) 1000 | raw(stack) 1001 | 1002 | """ 1003 | 1004 | else: 1005 | footer += """ 1006 | 1007 | if not printed: 1008 | printing = "" 1009 | for item in stack: 1010 | if type(item) in [Stack, list]: 1011 | printing += str(item) 1012 | 1013 | elif type(item) is str: 1014 | printing += custom_format(item) 1015 | elif type(item) == Coherse.char: 1016 | printing += item.v 1017 | 1018 | elif item < 10 or item > 256: 1019 | printing += str(item) 1020 | else: 1021 | printing += chr(item) 1022 | print(printing, end="") 1023 | """ 1024 | #print(code, balance(code)) 1025 | code = transpile(balance(code)) 1026 | if args and args.compiled: 1027 | import sys 1028 | sys.stderr.write("-----\nTranspiled Code:") 1029 | full = header + code + footer 1030 | sys.stderr.write(full) 1031 | sys.stderr.write("-----\n") 1032 | 1033 | 1034 | #First, load the BFL 1035 | 1036 | import os 1037 | 1038 | prepend = os.path.dirname(__file__) 1039 | source = open(prepend + "/docs/BFL.keg", encoding="utf-8").read() 1040 | exec(header + transpile(source)) 1041 | 1042 | 1043 | 1044 | if code.strip(): 1045 | exec(header + code + footer) 1046 | else: 1047 | try: 1048 | print(input()) 1049 | except: 1050 | pass 1051 | -------------------------------------------------------------------------------- /KegLib.py: -------------------------------------------------------------------------------- 1 | '''KegLib - Powering the transpilation of Keg since 2019''' 2 | 3 | import Coherse 4 | from Coherse import char 5 | from Stackd import Stack 6 | 7 | _register = None 8 | variables = {} 9 | code_page = "" 10 | function_list = [] 11 | seperator = "" 12 | inputs = Stack() 13 | 14 | # BASIC STACK PUSHING 15 | 16 | def character(stack, letter): 17 | stack.push(char(letter)) 18 | 19 | def integer(stack, number): 20 | stack.push(number) 21 | 22 | def iterable(stack, item): 23 | stack.push(item) 24 | 25 | # Coherse.py handles mathematics, so no need to define here 26 | # But still: 27 | 28 | def maths(stack, operator, debug=False): 29 | rhs, lhs = stack.pop(), stack.pop() #Sorry about the switched sides, But 30 | #that's the way it has to be in order 31 | #for maths to work as expected. 32 | if debug: 33 | print("DEBUG: in maths:", lhs, rhs, operator) 34 | print("DEBUG:", Coherse.operate(lhs, rhs, operator)) 35 | stack.push(Coherse.operate(lhs, rhs, operator)) 36 | 37 | # LOGIC 38 | 39 | def comparative(stack, operator): 40 | rhs, lhs = stack.pop(), stack.pop() 41 | result = Coherse.do_compare(lhs, rhs, operator) 42 | stack.push(result) 43 | 44 | 45 | # BUILT-IN FUNCTIONS 46 | 47 | def length(stack, pop_if_empty=False): 48 | if pop_if_empty: 49 | if len(stack) == 0: 50 | stack.push(stack.pop()) 51 | stack.push(len(stack)) 52 | 53 | def reverse(stack): 54 | length(stack) 55 | stack.pop() 56 | stack._Stack__stack.reverse() #Lazy moment, using Python built-ins 57 | 58 | def swap(stack): 59 | stack[-1], stack[-2] = stack[-2], stack[-1] #Welcome to python, how may I 60 | #help you? 61 | 62 | def duplicate(stack): 63 | temp = stack.pop() #Can't use stack.push(stack[-1]) because then implicit 64 | #input doesn't get a chance to work 65 | 66 | stack.push(temp); stack.push(temp) 67 | 68 | def shift(stack, direction): 69 | if direction == "left": 70 | stack.push(stack[0]) 71 | del stack[0] 72 | else: 73 | stack._Stack__stack.insert(0, stack.pop()) #Wow, reeeal cryptic 74 | #Legit just put the last item at position 0 75 | 76 | def nice(stack, keep=False): 77 | #This takes the top of the stack and prints it "nicely" 78 | #i.e. str() but even nicer. Also, implements some other rules a standard 79 | #call to a fn like str() might not handle 80 | 81 | item = stack.pop() 82 | if type(item) is int: 83 | print(_chr(item), 84 | end=seperator) #Preserve Keg's ability to print integers as chars 85 | 86 | elif type(item) is float: 87 | print(item, 88 | end=seperator) #I mean, floats can't really be conv'd to chars, can they? 89 | 90 | elif type(item) is char: 91 | print(item.v, end=seperator) #Because python doesn't have a char type. 92 | 93 | elif type(item) is Stack: 94 | print(*[x for x in item], end=seperator) 95 | 96 | else: 97 | print(custom_format(item), end=seperator) 98 | 99 | if keep: 100 | stack.push(item) 101 | 102 | 103 | def raw(stack, keep=False): 104 | #Like nice(), but Keg's version of repr() 105 | 106 | item = stack.pop() 107 | if type(item) is int: 108 | print(item, 109 | end=seperator) #Integers are printed as integers 110 | 111 | elif type(item) is float: 112 | print(item, 113 | end=seperator) #Floats -> Floats 114 | 115 | elif type(item) is char: 116 | print(_ord(item.v), end=seperator) #Char -> Integer 117 | 118 | elif type(item) is Stack: 119 | print(repr(stack), end=seperator) #I actually made a repr() fn for Stacks 120 | 121 | else: 122 | print("`" + custom_format(item) + "`", end=seperator) #Makes quines possible 123 | 124 | if keep: 125 | stack.push(item) 126 | 127 | def Input(stack): 128 | #This is the first of many input functions. 129 | #"Why are there more than one input function though?" 130 | #Well, because ?¿᠀ and implict input. That's why. 131 | 132 | #This one is "take input and push as ord" 133 | item = input() 134 | if item: 135 | for Char in reversed(item): 136 | stack.push(char(Char)) 137 | inputs.push(item) 138 | else: 139 | item = inputs.pop() 140 | inputs.push(item) 141 | if type(item) is str: 142 | for Char in reversed(item): 143 | stack.push(char(Char)) 144 | else: 145 | stack.push(item) 146 | shift(inputs, "R") 147 | 148 | #See you soon with another input fn! 149 | 150 | def random(stack): 151 | #Welcome to big_boy and small_boy 152 | import Keg_Nums, random 153 | stack.push(random.randint(Keg_Nums.small_boy, Keg_Nums.big_boy)) 154 | 155 | def pop_top(stack): 156 | stack.pop() 157 | 158 | def register(stack): 159 | global _register 160 | if _register is not None: 161 | stack.push(_register) 162 | _register = None 163 | else: 164 | _register = stack.pop() 165 | #print("In KegLib, _register equals", _register) 166 | 167 | # FOR-LOOP HELPER 168 | def loop_eval(expr): 169 | if type(expr) in [float, int]: 170 | return range(int(expr)) 171 | if type(expr) is char: 172 | return range(ord(expr.v)) 173 | return expr 174 | 175 | def condition_eval(expr_list, stack): 176 | for expr in expr_list: 177 | eval(expr) 178 | 179 | return stack.pop() 180 | 181 | 182 | 183 | # REG EXTENSION 184 | 185 | def iota(stack): 186 | try_cast(stack, 'ℤ') 187 | k = stack.pop() 188 | 189 | for i in range(k, -1, -1): 190 | stack.push(i) 191 | 192 | def sine(stack): 193 | import math 194 | x = stack.pop() 195 | stack.push(math.sin(x)) #I FOUND x EVERYONE!!!!! 196 | 197 | def decrement(stack): 198 | item = stack.pop() 199 | stack.push(Coherse.operate(item, 1, "-")) 200 | 201 | def increment(stack): 202 | item = stack.pop() 203 | stack.push(Coherse.operate(item, 1, "+")) 204 | 205 | def nice_input(stack): 206 | #As aforementioned, round 2 of input has arrived. 207 | #This one is "take input and best guess what it is the user wants" 208 | 209 | temp = input() 210 | 211 | try: 212 | if type(eval(temp)) is float: 213 | temp = float(temp) 214 | elif type(eval(temp)) is int: 215 | temp = int(temp) 216 | elif type(eval(temp)) is list: 217 | temp = Stack(eval(temp)) 218 | elif type(eval(temp)) is str: 219 | temp = temp 220 | else: 221 | for char in reversed(temp): 222 | stack.push(char) 223 | return 224 | except: 225 | temp = temp 226 | 227 | if temp: 228 | stack.push(temp) 229 | inputs.push(temp) 230 | else: 231 | item = inputs.pop() 232 | inputs.push(item) 233 | stack.push(item) 234 | shift(inputs, "R") 235 | 236 | #Float > Integer > List > String 237 | 238 | def excl_range(stack): 239 | query = stack.pop() 240 | x, y = stack.pop(), stack.pop() 241 | values = [to_integer(x), to_integer(y)] 242 | start, stop = sorted(values) 243 | range_object = range(start, stop) 244 | if to_integer(query) in range_object: 245 | stack.push(1) 246 | else: 247 | stack.push(0) 248 | 249 | def incl_range(stack): 250 | query = stack.pop() 251 | x, y = stack.pop(), stack.pop() 252 | values = [to_integer(x), to_integer(y)] 253 | start, stop = sorted(values) 254 | range_object = range(start, stop + 1) 255 | if to_integer(query) in range_object: 256 | stack.push(1) 257 | else: 258 | stack.push(0) 259 | 260 | def smart_range(stack): 261 | x, y = stack.pop(), stack.pop() 262 | values = [to_integer(x), to_integer(y)] 263 | start, stop = sorted(values) 264 | range_object = range(start, stop + 1) 265 | for item in range_object: 266 | stack.push(item) 267 | 268 | def to_integer(item): 269 | return _ord(item.v) if type(item) is char else int(item) 270 | 271 | def item_split(stack): 272 | item = stack.pop() 273 | _type = type(item) 274 | if _type is int: 275 | for number in str(item): 276 | stack.push(int(number) if number in "0123456789" else number) 277 | 278 | elif _type is float: 279 | for number in str(item): 280 | stack.push(int(number) if number in "0123456789" else number) 281 | elif _type is char: 282 | for number in str(_ord(item.v)): 283 | stack.push(int(number)) 284 | else: 285 | for value in item: 286 | stack.push(value) 287 | 288 | def factorial(stack): 289 | number = stack.pop() 290 | import math 291 | try: 292 | result = math.factorial(number) 293 | except Exception as e: 294 | result = "" #A whole lot of who knows what? 295 | stack.push(result) 296 | 297 | def empty(stack): 298 | stack.clear() 299 | #Yes, it really is that simple. 300 | 301 | def print_all(stack): 302 | for item in stack: 303 | nice(stack) 304 | 305 | def not_top(stack): 306 | item = stack.pop() 307 | stack.push(0 if item else 1) 308 | 309 | def pi(stack): 310 | import math 311 | stack.push(math.pi) 312 | 313 | def halve_top(stack): 314 | item = stack.pop() 315 | stack.push(Coherse.operate(item, 2, "/")) 316 | 317 | def double(stack): 318 | item = stack.pop() 319 | stack.push(Coherse.operate(item, 2, "*")) 320 | 321 | def negate(stack): 322 | item = stack.pop() 323 | stack.push(Coherse.operate(item, -1, "*")) 324 | 325 | #Keg+ Functions 326 | 327 | def convert(stack, _type): 328 | item = stack.pop() 329 | try: 330 | item = _type(item) 331 | except: 332 | pass 333 | stack.push(item) 334 | 335 | def case_switch(stack, how): 336 | string = stack.pop() 337 | if type(string) is not str: 338 | stack.push(string) 339 | return 340 | if how == "upper": stack.push(string.upper()) 341 | elif how == "lower": stack.push(string.lower()) 342 | else: stack.push(string.swapcase()) 343 | 344 | def square(stack): 345 | item = stack.pop() 346 | stack.push(Coherse.operate(item, item, "*")) 347 | 348 | def string_input(stack): 349 | #The third and final method of input: string input 350 | item = input() 351 | if item: 352 | stack.push(item) 353 | inputs.push(item) 354 | else: 355 | item = inputs.pop() 356 | inputs.push(item) 357 | stack.push(item) 358 | shift(inputs, "R") 359 | 360 | def all_true(stack): 361 | if all(stack): 362 | stack.push(1) 363 | else: 364 | stack.push(0) 365 | 366 | def all_equal(stack): 367 | equal = 1 368 | last = None 369 | for item in stack: 370 | if last is None: 371 | last = item 372 | continue 373 | else: 374 | if item != last: 375 | equal = 0 376 | break 377 | stack.push(equal) 378 | 379 | def summate(stack): 380 | x = len(stack) - 1 381 | for n in range(x): 382 | maths(stack, "+") 383 | 384 | 385 | def var_set(stack, name): 386 | variables[name] = stack.pop() 387 | 388 | def var_get(stack, name): 389 | stack.push(variables[name]) 390 | 391 | def custom_format(source): 392 | #Using the © format 393 | #first space after a © doesn't count and is removed. 394 | 395 | result = "" 396 | temp = "" 397 | escaped = False 398 | var_mode = False 399 | 400 | import string 401 | 402 | for char in source: 403 | if escaped: 404 | escaped = False 405 | result += char 406 | continue 407 | 408 | elif char == "\\": 409 | escaped = True 410 | result += char 411 | continue 412 | 413 | if var_mode: 414 | if char in string.ascii_letters: 415 | temp += char 416 | continue 417 | 418 | else: 419 | result += to_string(variables.get(temp, '©' + temp)) 420 | temp = "" 421 | var_mode = False 422 | if char == " ": 423 | continue 424 | 425 | if char == "©": 426 | var_mode = True 427 | continue 428 | 429 | result += char 430 | 431 | if var_mode: 432 | result += to_string(variables.get(temp, '©' + temp)) 433 | return result 434 | 435 | def to_string(item): 436 | if type(item) in [float, int]: 437 | return str(item) 438 | 439 | if type(item) == char: 440 | return str(_ord(item.v)) 441 | 442 | if type(item) == str: 443 | return item 444 | return str(item) 445 | 446 | def _ord(character): 447 | if str(character) in code_page: 448 | return code_page.index(str(character)) 449 | return ord(character) 450 | 451 | def _chr(i): 452 | if code_page: 453 | if i == 10: 454 | return "\n" 455 | if 0 < i < 256: 456 | return code_page[i] 457 | return chr(i) 458 | else: 459 | return chr(i) 460 | 461 | def try_cast(stack, what_type): 462 | INTEGER, FLOAT, STRING, STACK, CHARACTER = "ℤℝ⅍℠ⁿ" 463 | if what_type == INTEGER: 464 | item = stack.pop() 465 | try: 466 | item = int(item) 467 | except: 468 | pass 469 | stack.push(item) 470 | 471 | elif what_type == FLOAT: 472 | item = stack.pop() 473 | try: 474 | item = float(item) 475 | except: 476 | pass 477 | stack.push(item) 478 | 479 | elif what_type == STRING: 480 | stack.push(str(stack.pop())) 481 | 482 | elif what_type == CHARACTER: 483 | item = stack.pop() 484 | if Coherse._type(item) == "Number": 485 | stack.push(_chr(int(item))) 486 | elif Coherse._type(item) == "Character": 487 | stack.push(item) 488 | elif Coherse._type(item) == "String": 489 | stack.push(char(item[0])) 490 | elif Coherse._type(item) == "Stack": 491 | stack.push(try_cast(item, CHARACTER)) 492 | 493 | def keg_exec(big_stack): 494 | import Keg 495 | code = big_stack.pop() 496 | code = Keg.balance(code) 497 | code = Keg.transpile(code) 498 | 499 | 500 | header = f""" 501 | from KegLib import * 502 | from Stackd import Stack 503 | stack = Stack() 504 | """ 505 | 506 | footer = """ 507 | for item in stack: 508 | big_stack.push(item) 509 | """ 510 | 511 | exec(header + code + footer) 512 | 513 | def item_in(stack): 514 | query = stack.pop() 515 | 516 | if query in stack: 517 | stack.push(1) 518 | else: 519 | stack.push(0) 520 | 521 | def perform_index(stack): 522 | position = stack.pop() 523 | stack.push(stack.index([position])) 524 | 525 | def multiline(stack): 526 | temp = 1 527 | while temp: 528 | temp = input() 529 | for Char in temp: 530 | stack.push(char(Char)) 531 | stack.push("\n") 532 | stack.pop() 533 | 534 | def exponate(stack): 535 | power = stack.pop() 536 | base = stack.pop() 537 | result = base 538 | 539 | if type(power) in [float, int] and type(base) in [float, int]: 540 | stack.push(pow(base, power)) 541 | else: 542 | for n in loop_eval(Coherse.operate(power, 1, "-")): 543 | base = Coherse.operate(base, result, "*") 544 | 545 | stack.push(base) 546 | 547 | def to_percentage(stack): 548 | item = stack.pop() 549 | stack.push(Coherse.operate(item, 100, "/")) 550 | 551 | def reciprocal(stack): 552 | item = stack.pop() 553 | stack.push(Coherse.operate(1, item, "/")) 554 | 555 | def keg_round(stack): 556 | item = stack.pop() 557 | if type(item) in [int, float]: 558 | stack.push(round(item)) 559 | else: 560 | stack.push(item) 561 | 562 | def length_top(stack): 563 | item = stack.pop() 564 | if type(item) in [int, float]: 565 | stack.push(len(str(item))) 566 | else: 567 | stack.push(len(item)) 568 | 569 | def reverse_top(stack): 570 | item = stack.pop() 571 | if type(item) is int: 572 | if item < 0: 573 | item = int(str(item)[::-1][:-1]) * -1 574 | else: 575 | item = int(str(item)[::-1]) 576 | 577 | elif type(item) is float: 578 | if item < 0: 579 | item = float(str(item)[::-1][:-1]) * -1 580 | else: 581 | item = float(str(item)[::-1]) 582 | else: 583 | item = item[::-1] 584 | 585 | stack.push(item) 586 | 587 | def pop_item(stack): 588 | item = stack.pop() 589 | for i in range(len(stack)): 590 | temp = stack.pop() 591 | if not Coherse.do_compare(item, temp, '='): 592 | stack.push(temp) 593 | 594 | def sort_stack(stack): 595 | stack._Stack__stack.sort() 596 | 597 | def increment_register(stack): 598 | register(stack) 599 | integer(stack,1) 600 | maths(stack, "+") 601 | register(stack) 602 | 603 | def decrement_register(stack): 604 | register(stack) 605 | integer(stack,1) 606 | maths(stack, "-") 607 | register(stack) 608 | 609 | def register_dont_empty(stack): 610 | register(stack) 611 | duplicate(stack) 612 | register(stack) 613 | 614 | def register_aug_assign(stack, operator): 615 | register(stack) 616 | maths(stack, operator) 617 | register(stack) 618 | 619 | def set_register_dont_empty(stack): 620 | _register = stack.pop() 621 | 622 | def register_length(stack): 623 | register_dont_empty(stack) 624 | length_top(stack) 625 | 626 | def reverse_register(stack): 627 | register_dont_empty(stack) 628 | reverse_top(stack) 629 | 630 | def keg_map(stack, functions): 631 | import Keg 632 | for i in range(len(stack)): 633 | small = Stack([stack[i]]) 634 | code = Keg.balance(functions) 635 | code = Keg.transpile(code) 636 | 637 | header = f""" 638 | from KegLib import * 639 | from Stackd import Stack 640 | stack = small 641 | """ 642 | 643 | exec(header + code) 644 | stack[i] = smart_summate(small) 645 | 646 | 647 | def smart_summate(stack): 648 | if all(map(lambda x : type(x) in [float, int], stack)): 649 | return stack.pop() 650 | 651 | if all(map(lambda x : type(x) == char, stack)): 652 | return "".join([c.v for c in stack]) 653 | return str(stack) 654 | 655 | def truthify(stack): 656 | temp = stack.pop() 657 | if bool(temp): 658 | stack.push(1) 659 | else: 660 | stack.push(0) 661 | 662 | def keg_filter(stack): 663 | import Keg 664 | 665 | code = stack.pop() 666 | code = Keg.balance(code) 667 | code = Keg.transpile(code) 668 | 669 | final = Stack() 670 | 671 | header = f""" 672 | from KegLib import * 673 | from Stackd import Stack 674 | stack = item 675 | """ 676 | 677 | for i in range(len(stack)): 678 | item = Stack([stack[i]]) 679 | temp = stack[i] 680 | exec(header + code) 681 | if bool(item.pop()): 682 | final.push(temp) 683 | 684 | stack._Stack__stack = final._Stack__stack 685 | 686 | # https://stackoverflow.com/a/2267446/9363594 687 | 688 | 689 | def int2base(stack): 690 | 691 | import string 692 | digs = string.digits + string.ascii_letters 693 | 694 | base = stack.pop() 695 | x = stack.pop() 696 | 697 | if x < 0: 698 | sign = -1 699 | elif x == 0: 700 | stack.push(digs[0]) 701 | else: 702 | sign = 1 703 | 704 | x *= sign 705 | digits = [] 706 | 707 | while x: 708 | digits.append(digs[int(x % base)]) 709 | x = int(x // base) 710 | 711 | if sign < 0: 712 | digits.append('-') 713 | 714 | digits.reverse() 715 | 716 | stack.push(''.join(digits)) 717 | -------------------------------------------------------------------------------- /KegStrings.py: -------------------------------------------------------------------------------- 1 | #Object strings 2 | ''' There are four types of object strings: 3 | - (N)ew Object 4 | - (C)onvert Type 5 | - (M)ethod 6 | - (P)ython code 7 | 8 | This are in the form of 9 | 10 | `@[Letter]|[Information];` 11 | 12 | 13 | `N` object strings can create: 14 | 15 | - Stacks (`@N|[]`, `@N|[1, 2, 3];`) 16 | - Strings (`@N|"";`) 17 | - Files (`@N|file(addr);`) 18 | - Websocket Instances (`@N|https://addr;") 19 | - Other objects (`@N|obj`) 20 | 21 | `C` object strings can: 22 | 23 | - Convert one type to another 24 | - Actually, that's it 25 | - `@C|t;` t = type to convert 26 | 27 | `M` object strings can: 28 | 29 | - Call functions of the objects on the stack 30 | 31 | `P` object strings can: 32 | - Run raw python 33 | ''' 34 | 35 | def obj_str_extract(string): 36 | 37 | import re 38 | pobj = re.compile(r"`@(?P[NCMP])\|(?P.+);`") 39 | mobj = pobj.match(string) 40 | 41 | if mobj: 42 | str_type, obj_data = mobj.groups() 43 | if str_type == "N": #New Object 44 | return eval(obj_data) 45 | 46 | if str_type == "C": 47 | return obj_data 48 | 49 | if str_type == "P": 50 | exec(obj_data) 51 | 52 | else: 53 | return string 54 | 55 | 56 | 57 | 58 | if __name__ == "__main__": 59 | print(obj_str_extract("`09;`")) 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Keg_Nums.py: -------------------------------------------------------------------------------- 1 | #Keg nums 2 | 3 | big_boy = int("9"*3234) 4 | big_boy *= big_boy * big_boy 5 | big_boy += 21 6 | small_boy = -big_boy 7 | -------------------------------------------------------------------------------- /ListTest.py: -------------------------------------------------------------------------------- 1 | list_obj = [] 2 | def f(n): 3 | x = list_obj 4 | for i in range(n): 5 | x.append(i) 6 | 7 | print(list_obj) 8 | f(9) 9 | print(list_obj) 10 | -------------------------------------------------------------------------------- /New Specs.txt: -------------------------------------------------------------------------------- 1 | ! Push the length of the stack 2 | @ Start function 3 | # Start a comment 4 | $ Swap the top two items 5 | % Pop x, y, push y % x 6 | ^ Reverse the stack 7 | & Store/Push a value in/from the register 8 | * Pop x, y, push y * x 9 | () For loop 10 | [] If statement 11 | {} While loop 12 | : Duplicate top 13 | ; End function 14 | " Right shift 15 | ' Left shift 16 | < Less than 17 | > Greater than 18 | , Print nice 19 | . Print raw 20 | ? Take input 21 | / Pop x, y, push y / x 22 | \ Escape next character 23 | ~ Push random number (-inf, +inf) 24 | - Push x, y, push y - x 25 | _ Pop top of stack 26 | + Push x, y, push y + x 27 | = Equals 28 | a-Z Push character literal 29 | 0-9 Push numeric literal 30 | ` Start normal string 31 | ¬ Logical not 32 | ≠ Not Equals 33 | ≤ Less than or equal to 34 | ≥ Greater than or equal to 35 | ‹› List 36 | ° Pop list, pos, push list[pos] 37 | • Pop list, pos, val, list[pos] = val 38 | œ Apply operator to all of stack 39 | £™ Map the expression to the top item iteratively 40 | ƒ™ Map the expression to the whole stack iteratively 41 | §™ Switch statement 42 | ® Set variable 43 | © Get variable 44 | ß Binary List 45 | ⟨™ Zip map 46 | ⸤ Min of zip Map 47 | ⸢ Max of zip Map 48 | 𐊗 Base ten 49 | 𐊂 Base 2 50 | ∑ Summate the stack 51 | ∨ Max of the stack/item 52 | ∧ Min of the stack/item 53 | ∆ Increment 54 | ▽ Decrement 55 | Ṙ range(1, n + 1) [1, n] 56 | Ṛ range(0, n + 1) [0, n] 57 | Ṟ range(a, b) [a, b] 58 | ṙ range(1, n) [1, n) 59 | ṛ range(0, n) [0, n) 60 | ṟ range(a, b) [a, b) 61 | ⚁ mod 2 62 | ⊡ space string 63 | ″ empty string 64 | ¢ map but keep original as input 65 | § pairwise map 66 | Ω print all 67 | ² square top 68 | 𐊖 sort stack 69 | 𐊜 uniquify 70 | ⊐ wrap in List 71 | … flatten 72 | ẕ is integer 73 | ℤ to integer 74 | ¡ factorial 75 | ø prefixes of t.o.s 76 | ± negate 77 | € sub-sum a list 78 | fi filter a list 79 | ⁄ loop variable 80 | ˛ Empty string 81 | ¯ Item in the list 82 | λ Predefined constant 83 | 𐊏 Loop variable 84 | ⊕ Increment 85 | ⊖ Decrement 86 | -------------------------------------------------------------------------------- /OldKeg.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import Parse 3 | from Stackd import Stack 4 | import Stackd 5 | import Keg_Nums 6 | import uncompress 7 | import preprocess 8 | #Just a nice little error. Very helpful I know 9 | 10 | class Bruh(Exception): 11 | def __init__(self, msg): 12 | print("I can't believe you've done this...") 13 | #All built-in functions 14 | LENGTH = "!" 15 | DUPLICATE = ":" 16 | POP = "_" 17 | PRINT_CHR = "," 18 | PRINT_INT = "." 19 | INPUT = "?" 20 | L_SHIFT = '"' 21 | R_SHIFT = "'" 22 | RANDOM = "~" 23 | REVERSE = "^" 24 | SWAP = "$" 25 | 26 | DESCRIPTIONS = { 27 | LENGTH: "Push the length of the stack", 28 | DUPLICATE: "Duplicate the top of stack", 29 | POP: "Pop the top of stack", 30 | PRINT_CHR: "Print the top of stack, calling _ord(top)", 31 | PRINT_INT: "Print the top of stack, as is", 32 | INPUT: "Get input from user", 33 | L_SHIFT: "Left shift stack", 34 | R_SHIFT: "Right shift stack", 35 | RANDOM: "Push a random number between -inf and inf", 36 | REVERSE: "Reverse the stack", 37 | SWAP: "Swap the top two items on stack" 38 | } 39 | 40 | #Unofficial built-in functions 41 | #Note: Most of these are from Btup/A__/User:A, so go check out their 42 | #repos/esolang account/code golf userpage and upvote their answers 43 | 44 | IOTA = "Ï" 45 | DECREMENT = ";" 46 | SINE = "§" 47 | APPLY_ALL = "∑" 48 | NICE_INPUT = "¿" 49 | 50 | DESCRIPTIONS[IOTA] = "Replaces the top of stack with all items from [top->0]" 51 | DESCRIPTIONS[DECREMENT] = "Decrement the top of stack" 52 | DESCRIPTIONS[SINE] = "sin(top)" 53 | DESCRIPTIONS[APPLY_ALL] = "Preprocess as (!;| --> Apply to all stack" 54 | DESCRIPTIONS[NICE_INPUT] = "Peform nice input" 55 | 56 | #Some Reg commands not by Btup but by JonoCode9374 57 | EXCLUSIVE_RANGE = "∂" 58 | INCLUSIVE_RANGE = "•" 59 | GENERATE_RANGE = "ɧ" 60 | GENERATE_RANGE_0 = "ø" 61 | NUMBER_SPLIT = "÷" 62 | FACTORIAL = "¡" 63 | EMPTY = "ø" 64 | PRINT_ALL = "Ω" 65 | '''Remind me to create descriptions later''' 66 | 67 | # Keg+ Section 68 | 69 | DIV_MOD = "①" 70 | 71 | 72 | #'Keywords' 73 | 74 | COMMENT = "#" 75 | BRANCH = "|" 76 | ESCAPE = "\\" 77 | REGISTER = "&" 78 | STRING = "`" 79 | FUNCTION = "@" 80 | 81 | DESCRIPTIONS[COMMENT] = "Standard line comment" 82 | DESCRIPTIONS[BRANCH] = "Switch to the next part of the structure" 83 | DESCRIPTIONS[ESCAPE] = "Push the code page value of the next character" 84 | DESCRIPTIONS[STRING] = "Push an uncompressed string" 85 | DESCRIPTIONS[FUNCTION] = "Start/Call the given function" 86 | 87 | #Operators 88 | MATHS = "+-*/%Ë" 89 | CONDITIONAL = "<>=≬" 90 | NUMBERS = "0123456789" 91 | 92 | DESCRIPTIONS[MATHS] = "Pop x and y, and push y {0} x" 93 | DESCRIPTIONS[CONDITIONAL] = "Pop x and y, and push y {0} x" 94 | DESCRIPTIONS[NUMBERS] = "Push {0}" 95 | 96 | #Whitespace 97 | TAB = "\t" 98 | ALT_TAB = " " 99 | NEWLINE = "\n" 100 | 101 | #Structures 102 | START = "start" 103 | END = "end" 104 | BODY = "body" 105 | 106 | #Code page 107 | 108 | unicode = "ϧ∑¿∂•ɧ÷¡Ëė≬ƒß‘“" 109 | unicode += "„«®©ëλº√₳¬≤Š≠≥Ėπ" 110 | unicode += " !\"#$%&'()*+,-./" 111 | unicode += "0123456789:;<=>?" 112 | unicode += "@ABCDEFGHIJKLMNO" 113 | unicode += "PQRSTUVWXYZ[\\]^_" 114 | unicode += "`abcdefghijklmno" 115 | unicode += "pqrstuvwxyz{|}~ø" 116 | unicode += "¶\n\t⊂½‡™±¦→←↶↷" 117 | unicode += "✏█↗↘□²ⁿ║ṡ⟰⟱⟷" 118 | unicode += "ℤℝ⅍℠א∀≌᠀⊙᠈⅀" 119 | unicode += "ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ" #push'n'print 120 | unicode += "☭" #I don't know what this'll do. But it looks cool 121 | unicode += "⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯"#drawing 122 | unicode += "⯑" #Do something random 123 | unicode += "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇" 124 | 125 | 126 | for n in range(127234, 127243): unicode += chr(n) 127 | 128 | #Variables 129 | main_stack = Stack() 130 | functions = {} 131 | register = None #The register used 132 | comment = False #Whether or not in a comment 133 | escape = False #Escape next character? 134 | printed = False #Used to determine whether or not to do implicit printing 135 | pushed = False #Used to determine whether or not to implicit cat 136 | 137 | def keg_input(stack): 138 | global pushed; pushed = True 139 | temp = input() 140 | for char in reversed(temp): 141 | stack.push(_ord(char)) 142 | 143 | def generate_range(*args): 144 | low, high = sorted(args[:2]) 145 | if "e" in args: 146 | low += 1 147 | else: 148 | high += 1 149 | return range(low, high) 150 | 151 | def _ord(char): 152 | if char in code_page: 153 | return code_page.find(char) 154 | return ord(char) 155 | 156 | def _chr(integer): 157 | if integer > 0 and integer < len(code_page): 158 | return code_page[integer] 159 | return chr(integer) 160 | 161 | def _eval(expr, stack=main_stack): 162 | #Evaluate the given expression as Keg code 163 | temp = Stack() 164 | for Token in Parse.parse(expr): 165 | #print(Token.name, Token.data, temp) 166 | if Token.name not in [Parse.CMDS.CMD, Parse.CMDS.NOP, 167 | Parse.CMDS.ESC]: 168 | raise Bruh("""You can't just go placing forbidden characters in 169 | expressions and expect to get away with it.""") 170 | 171 | else: 172 | if Token.name == Parse.CMDS.ESC: 173 | temp.push(_ord(Token.data)) 174 | elif Token.data in NUMBERS: 175 | temp.push(int(Token.data)) 176 | 177 | elif Token.data in MATHS: 178 | x, y = temp.pop(), temp.pop() 179 | op = Token.data 180 | if op == MATHS[-1]: 181 | op = "**" 182 | 183 | temp.push(eval(f"y{op}x")) 184 | 185 | elif Token.data in CONDITIONAL: 186 | lhs, rhs = temp.pop(), temp.pop() 187 | op = Token.data 188 | if op == "=": 189 | op = "==" 190 | elif op == "≬": 191 | op = "> 0 and lhs <" 192 | 193 | result = eval(f"lhs{op}rhs") 194 | if result: 195 | temp.push(1) 196 | else: 197 | temp.push(0) 198 | 199 | elif Token.data == LENGTH: 200 | temp.push(len(stack)) 201 | 202 | elif Token.data == DUPLICATE: 203 | item = temp.pop() 204 | temp.push(item) 205 | temp.push(item) 206 | 207 | elif Token.data == RANDOM: 208 | temp.push(random.randint(Keg_Nums.small_boy, 209 | Keg_Nums.big_boy)) 210 | 211 | elif Token.data == POP: 212 | temp.push(stack.pop()) 213 | 214 | elif Token.data == NEWLINE: 215 | temp.push(10) 216 | 217 | elif Token.data == TAB: 218 | continue 219 | 220 | elif Token.data in "#|@": 221 | raise Bruh("You can't just do that in the expression " + expr) 222 | 223 | #Start of Reg's extra commands 224 | elif Token.data == IOTA: 225 | k = temp[-1] 226 | temp.pop() 227 | 228 | for i in range(k, -1, -1): 229 | temp.push(i) 230 | 231 | elif Token.data == EXCLUSIVE_RANGE: 232 | 233 | _range = generate_range(temp.pop(), temp.pop(), "e") 234 | query = temp.pop() 235 | if query in _range: 236 | temp.push(1) 237 | else: 238 | temp.push(0) 239 | 240 | elif Token.data == INCLUSIVE_RANGE: 241 | _range = generate_range(temp.pop(), temp.pop()) 242 | query = temp.pop() 243 | 244 | if query in _range: 245 | temp.push(1) 246 | else: 247 | temp.push(0) 248 | 249 | elif Token.data == GENERATE_RANGE: 250 | _range = generate_range(temp.pop(), temp.pop()) 251 | for item in _range: 252 | temp.push(item) 253 | elif Token.data == GENERATE_RANGE_0: 254 | _range = generate_range(0, temp.pop()) 255 | for item in _range: 256 | temp.push(item) 257 | 258 | elif Token.data == DECREMENT: 259 | temp[-1] -= 1 260 | 261 | elif Token.data == SINE: 262 | temp.push(math.sin(temp.pop())) 263 | 264 | elif Token.data == NUMBER_SPLIT: 265 | item = str(temp.pop()) 266 | for thing in item: 267 | temp.push(int(thing)) 268 | 269 | elif Token.data == FACTORIAL: 270 | temp.push(math.factorial(temp.pop())) 271 | 272 | elif Token.data == DIV_MOD: 273 | quot, remainder = divmod(temp.pop(), temp.pop()) 274 | temp.push(quot) 275 | temp.push(remainder) 276 | 277 | else: 278 | temp.push(_ord(Token.data)) 279 | return temp[0] 280 | 281 | #Bracket balancer 282 | def balance(source): 283 | brackets = [] 284 | mapping = {"{" : "}", "[" : "]", "(" : ")", "": ""} 285 | alt_brackets = {"{" : "z1-", "}" : "z3+", "(" : "85*", 286 | ")" : "85*1+", "[" : "Z1+", 287 | "]" : "Z3+"} 288 | 289 | escaped = False 290 | 291 | 292 | result = "" 293 | for char in source: 294 | if escaped: 295 | if char in alt_brackets: 296 | result += alt_brackets[char] 297 | else: 298 | result += char 299 | escaped = False 300 | continue 301 | 302 | elif char == "\\": 303 | escaped = True 304 | result += char 305 | continue 306 | 307 | if char in "[({": 308 | brackets.append(char) 309 | 310 | elif char in "])}": 311 | for i in range(len(brackets)): 312 | if mapping[brackets[i]] == char: 313 | brackets[i] = "" 314 | break 315 | 316 | 317 | 318 | result += char 319 | 320 | 321 | if brackets: 322 | for char in reversed(brackets): 323 | result += mapping[char] 324 | 325 | return result 326 | 327 | def run(source, master_stack, sub_stack=None): 328 | global register, comment, escape, printed, pushed 329 | code = source 330 | stack = Stack() 331 | do_repush = False #Indicate whether or not sub needs to push its contents 332 | #back onto master_stack 333 | 334 | if sub_stack is None: 335 | stack = master_stack 336 | else: 337 | stack = sub_stack 338 | do_repush = True 339 | 340 | 341 | for Tkn in code: 342 | cmd = Tkn.data 343 | print(Tkn, stack, register) 344 | 345 | #Handle effect of comments and escape chars first 346 | if comment: 347 | if cmd == NEWLINE: 348 | comment = False 349 | continue 350 | 351 | if Tkn.name == Parse.CMDS.ESC: 352 | #print(cmd, _ord(cmd)) 353 | escape = False 354 | stack.push(_ord(cmd)) 355 | continue 356 | 357 | #Now, do all the functions 358 | if cmd == LENGTH: 359 | stack.push(len(stack)) 360 | 361 | elif cmd == DUPLICATE: 362 | temp = stack.pop() 363 | stack.push(temp) 364 | stack.push(temp) 365 | 366 | elif cmd == POP: 367 | stack.pop() 368 | 369 | elif cmd == PRINT_CHR: 370 | #print(stack, stack.pop(), stack) 371 | print(_chr(stack.pop()), end="") 372 | printed = True 373 | 374 | elif cmd == PRINT_INT: 375 | print(stack.pop(), end="") 376 | printed = True 377 | 378 | elif cmd == L_SHIFT: 379 | stack.push(stack[0]) 380 | del stack[0] 381 | 382 | elif cmd == R_SHIFT: 383 | stack._Stack__stack.insert(0, stack.pop()) 384 | 385 | elif cmd == REVERSE: 386 | if not stack: 387 | keg_input(stack) 388 | stack._Stack__stack.reverse() 389 | 390 | elif cmd == SWAP: 391 | stack[-1], stack[-2] = stack[-2], stack[-1] 392 | 393 | elif cmd == INPUT: 394 | keg_input(stack) 395 | pushed = True 396 | 397 | #Reg starts now 398 | 399 | elif cmd == IOTA: 400 | k = stack[-1] 401 | stack.pop() 402 | 403 | for i in range(k, -1, -1): 404 | stack.push(i) 405 | 406 | elif cmd == DECREMENT: 407 | stack.push(stack.pop() - 1) 408 | 409 | elif cmd == SINE: 410 | stack.push(math.sin(stack.pop())) 411 | continue 412 | 413 | elif cmd == NICE_INPUT: 414 | temp = input() 415 | if "." in temp: 416 | stack.push(float(temp)) 417 | elif temp.isnumeric() or (temp[0] == "-" and temp[1:].isnumeric()): 418 | stack.push(int(temp)) 419 | else: 420 | for char in reversed(temp): 421 | stack.push(_ord(char)) 422 | 423 | pushed = True 424 | 425 | elif cmd == EXCLUSIVE_RANGE: 426 | _range = generate_range(stack.pop(), stack.pop(), "e") 427 | query = stack.pop() 428 | if query in _range: 429 | stack.push(1) 430 | else: 431 | stack.push(0) 432 | 433 | elif cmd == INCLUSIVE_RANGE: 434 | _range = generate_range(stack.pop(), stack.pop()) 435 | query = stack.pop() 436 | if query in _range: 437 | stack.push(1) 438 | else: 439 | stack.push(0) 440 | 441 | elif cmd == GENERATE_RANGE: 442 | _range = generate_range(stack.pop(), stack.pop()) 443 | for item in _range: 444 | stack.push(item) 445 | 446 | elif cmd == GENERATE_RANGE_0: 447 | _range = generate_range(0, stack.pop()) 448 | for item in _range: 449 | stack.push(item) 450 | 451 | elif cmd == NUMBER_SPLIT: 452 | temp = str(stack.pop()) 453 | for thing in temp: 454 | stack.push(int(thing)) 455 | 456 | elif cmd == FACTORIAL: 457 | stack.push(math.factorial(stack.pop())) 458 | 459 | #Next step, keywords 460 | 461 | elif cmd == COMMENT: 462 | comment = True 463 | 464 | elif cmd == BRANCH: 465 | continue 466 | 467 | elif cmd == ESCAPE: 468 | escape = True 469 | #print("ESCCAPE") 470 | 471 | elif cmd == REGISTER: 472 | if register is None: 473 | register = stack.pop() 474 | else: 475 | stack.push(register) 476 | register = None 477 | 478 | #Now, structures 479 | elif Tkn.name == Parse.CMDS.IF: 480 | condition = stack.pop() 481 | if condition: 482 | run(Parse.parse(Tkn.data[0]), stack) 483 | else: 484 | run(Parse.parse(Tkn.data[1]), stack) 485 | 486 | elif Tkn.name == Parse.CMDS.FOR: 487 | n = _eval(Tkn.data[0], stack) 488 | 489 | for q in range(int(n)): 490 | run(Parse.parse(Tkn.data[1]), stack) 491 | 492 | elif Tkn.name == Parse.CMDS.WHILE: 493 | condition = Tkn.data[0] 494 | while _eval(condition): 495 | run(Parse.parse(Tkn.data[1]), stack) 496 | 497 | elif Tkn.name == Parse.CMDS.FUNCTION: 498 | if Tkn.data[0] == 1: 499 | function_name, number_params = Tkn.data[1],\ 500 | int(functions[function_name]["number"]) 501 | 502 | function_stack = Stack() 503 | for _ in range(number_params): 504 | function_stack.push(master_stack.pop()) 505 | 506 | run(Parse.parse(functions[function_name]["body"]), 507 | stack, function_stack) 508 | 509 | else: 510 | function_name, number_params = Tkn.data[0]["name"],\ 511 | int(Tkn.data[0]["number"]) 512 | 513 | functions[function_name] = { 514 | "number" : number_params, 515 | "body" : Tkn.data[1] 516 | } 517 | 518 | #Now, operators 519 | elif cmd in MATHS: 520 | x, y = stack.pop(), stack.pop() 521 | temp = cmd 522 | if cmd == "Ë": 523 | temp = "**" 524 | 525 | stack.push(eval(f"y{temp}x")) 526 | 527 | elif cmd in CONDITIONAL: 528 | lhs, rhs = stack.pop(), stack.pop() 529 | temp = cmd 530 | if cmd == "=": 531 | temp = "==" 532 | 533 | elif cmd == "≬": 534 | temp = "> 0 and lhs <" 535 | 536 | result = eval(f"rhs{temp}lhs") 537 | 538 | if result: 539 | stack.push(1) 540 | else: 541 | stack.push(0) 542 | 543 | elif cmd in NUMBERS: 544 | stack.push(int(cmd)) 545 | 546 | elif Tkn.name == Parse.CMDS.STRING: 547 | stack.push(Tkn.data) 548 | 549 | #Keg+ 550 | 551 | elif Tkn.data == DIV_MOD: 552 | quot, remainder = divmod(stack.pop(), stack.pop()) 553 | stack.push(quot) 554 | stack.push(remainder) 555 | 556 | #Whitespace 557 | elif cmd == TAB: 558 | continue 559 | 560 | elif cmd == NEWLINE: 561 | stack.push(10) 562 | 563 | else: 564 | stack.push(_ord(cmd)) 565 | 566 | if do_repush: 567 | for item in stack: 568 | master_stack.push(item) 569 | 570 | 571 | if __name__ == "__main__": 572 | if len(sys.argv) > 1: 573 | import argparse 574 | parser = argparse.ArgumentParser() 575 | parser.add_argument("file", help="The location of the Keg file to open") 576 | parser.add_argument('-ex', '--explain', action='store_true', 577 | help="Explains given source") 578 | args = parser.parse_args() 579 | file_location = args.file 580 | 581 | if args.explain: 582 | source = open(file_location, encoding="utf-8").read().strip("\n") 583 | i = 0 584 | for char in source: 585 | if char in DESCRIPTIONS: 586 | print(" "*i + char + " "*(len(source) - i) + "#", 587 | DESCRIPTIONS[char]) 588 | else: 589 | print(" "*i + char + " "*(len(source) - i) + "#", 590 | "Push", char, "onto the stack") 591 | i += 1 592 | exit() 593 | 594 | else: 595 | file_location = input("Enter the file location of the Keg program: ") 596 | 597 | source = open(file_location, "r").read() 598 | 599 | 600 | 601 | 602 | #Preprocess ∑ as (!;| 603 | 604 | code = "" 605 | code_page = "" 606 | import string 607 | unicode_set = set(unicode) - set(string.printable) 608 | if any([char in unicode_set for char in source]): 609 | code_page = unicode 610 | 611 | #print(code_page) 612 | 613 | Stackd.code_page = code_page 614 | 615 | e = False #escaped while preprocessing? 616 | for c in source: 617 | if e: 618 | e = False 619 | code += c 620 | continue 621 | elif c == "\\": 622 | code += c 623 | e = True 624 | continue 625 | 626 | if c == "∑": 627 | code += "(!;|" 628 | else: 629 | code += c 630 | code = preprocess.process(code); #print("After preprocess:", code) 631 | code = uncompress.Uncompress(code); #print("After uncom:", code) 632 | run(Parse.parse(balance(code)), main_stack) 633 | 634 | if not printed: 635 | printing = "" 636 | if not pushed: 637 | try: 638 | print(input()) 639 | except: 640 | pass 641 | for item in main_stack: 642 | if True: #type(item) is str or item < 10 or item > 256: 643 | printing += str(item) + " " 644 | 645 | else: 646 | printing += _chr(item) 647 | 648 | print(printing,end="") 649 | -------------------------------------------------------------------------------- /Pagecomp.py: -------------------------------------------------------------------------------- 1 | #utf-8 2 | chars = "0123456789" 3 | chars += "abcdefghij" 4 | chars += "klmnopqrst" 5 | chars += "uvwxyzABCD" 6 | chars += "EFGHIJKLMN" 7 | chars += "OPQRSTUVWX" 8 | chars += "YZ!@#$%^&*" 9 | chars += "()_+~[]{}:" 10 | chars += "<>?,./\"'¿" 11 | chars += "¿∂⊂ø®©ëλº√" 12 | chars += "₳¬≤Š≠≥Ėπ§∑" 13 | chars += "•™÷‡∞\t\n½±" 14 | chars += "¦ė≬ƒßɧË-=Ï¡" 15 | chars += "→←↶↷✏█↗↘□" 16 | chars += "²ⁿ║ṡ⟰⟱ ⟷" 17 | 18 | unicode = "ϧ∑¿∂•ɧ÷¡Ëė≬ƒß‘“" 19 | unicode += "„«®©ëλº√₳¬≤Š≠≥Ėπ" 20 | unicode += " !\"#$%&'()*+,-./" 21 | unicode += "0123456789:;<=>?" 22 | unicode += "@ABCDEFGHIJKLMNO" 23 | unicode += "PQRSTUVWXYZ[\\]^_" 24 | unicode += "`abcdefghijklmno" 25 | unicode += "pqrstuvwxyz{|}~ø" 26 | unicode += "¶\n\t⊂½‡™±¦→←↶↷" 27 | unicode += "✏█↗↘□²ⁿ║ṡ⟰⟱⟷" 28 | unicode += "ℤℝ⅍℠א∀≌᠀⊙᠈" 29 | 30 | 31 | for n in range(127234, 127243): unicode += chr(n) 32 | 33 | print(chars, len(chars)) 34 | print(len(unicode)) 35 | 36 | print(set(unicode) - set(chars)) 37 | -------------------------------------------------------------------------------- /Parse.py: -------------------------------------------------------------------------------- 1 | SQUARE = ["[", "]"] 2 | ROUND = ["(", ")"] 3 | CURLY = ["{", "}"] 4 | FUNCTION = ["@", "ƒ"] 5 | INTEGER_SCAN = "‡" 6 | SWITCH = ["¦", "™"] 7 | MAP = ["⑷", "⑸"] 8 | 9 | OPEN, CLOSE = "[({@¦⑷", "])}ƒ™⑸" 10 | 11 | 12 | class CMDS: 13 | CMD = "cmd" 14 | IF = "if" 15 | FOR = "for" 16 | WHILE = "while" 17 | NOP = "" 18 | FUNCTION = "function" 19 | ESC = "escape" 20 | STRING = "string" 21 | VARIABLE = "variable" 22 | INTEGER = "integer" 23 | SWITCH = "switch" 24 | MAP = "map" 25 | 26 | 27 | class Token(): 28 | def __init__(self, name, data): 29 | self.name = name 30 | self.data = data 31 | 32 | def __str__(self): 33 | return str(self.name) + " " + str(self.data) 34 | 35 | 36 | def parse(prog): 37 | temp, parts, structures, escaped = "", [], [], False 38 | string_mode, string = False, "" 39 | variable_mode, variable, call_set = False, "", "" 40 | integer_mode, number = False, "" 41 | #call_set will be whether or not to set the variable 42 | 43 | ast = [] 44 | #print(prog) 45 | for char in prog: 46 | # print(char, temp, parts, structures, [str(x) for x in ast]) 47 | 48 | if integer_mode: 49 | if char not in "0123456789": 50 | integer_mode = False 51 | if structures: 52 | temp += "‡" + number 53 | else: 54 | ast.append(Token(CMDS.INTEGER, number)) 55 | number = "" 56 | else: 57 | number += char 58 | continue 59 | 60 | if string_mode: 61 | if escaped: 62 | escaped = False 63 | string += char 64 | else: 65 | if char == "`": 66 | string_mode = False 67 | if structures: 68 | temp += "`" + string + "`" 69 | else: 70 | ast.append(Token(CMDS.STRING, string)) 71 | string = "" 72 | elif char == "\\": 73 | escaped = True 74 | string += char 75 | else: 76 | string += char 77 | continue 78 | 79 | if variable_mode: 80 | import string as STRING_MODULE 81 | if char not in STRING_MODULE.ascii_letters: 82 | variable_mode = False 83 | if structures: 84 | temp += {"call" : "©", "set" : "®"}[call_set] + variable 85 | else: 86 | ast.append(Token(CMDS.VARIABLE, [variable, call_set])) 87 | variable = "" 88 | call_set = "" 89 | 90 | else: 91 | variable += char 92 | continue 93 | 94 | if escaped: 95 | escaped = False 96 | if structures: 97 | temp += char 98 | else: 99 | ast.append(Token(CMDS.ESC, char)) 100 | continue 101 | 102 | elif char == "\\": 103 | escaped = True 104 | if structures: 105 | temp += char 106 | continue 107 | 108 | elif char == "‡": 109 | integer_mode = True 110 | continue 111 | 112 | elif char == "`": 113 | string_mode = True 114 | continue 115 | 116 | elif char == "®": 117 | variable_mode = True 118 | call_set = "set" 119 | continue 120 | 121 | elif char == "©": 122 | variable_mode = True 123 | call_set = "call" 124 | continue 125 | 126 | 127 | 128 | if char in OPEN and not string_mode: 129 | if structures: 130 | temp += char 131 | 132 | if char == SQUARE[0]: 133 | structures.append(CMDS.IF) 134 | 135 | elif char == ROUND[0]: 136 | structures.append(CMDS.FOR) 137 | 138 | elif char == CURLY[0]: 139 | structures.append(CMDS.WHILE) 140 | 141 | elif char == FUNCTION[0]: 142 | structures.append(CMDS.FUNCTION) 143 | 144 | elif char == SWITCH[0]: 145 | structures.append(CMDS.SWITCH) 146 | 147 | elif char == MAP[0]: 148 | structures.append(CMDS.MAP) 149 | 150 | elif char in CLOSE and not string_mode: 151 | struct = structures.pop() 152 | 153 | if len(structures) == 0: 154 | parts.append(temp) 155 | temp = "" 156 | if struct == CMDS.IF: 157 | if len(parts) == 0: 158 | ast.append(CMDS.NOP) 159 | 160 | elif len(parts) == 1: 161 | ast.append(Token(struct, [parts[0], 162 | CMDS.NOP])) 163 | 164 | elif len(parts) == 2: 165 | ast.append(Token(struct, [parts[0], 166 | parts[1]])) 167 | 168 | else: 169 | #raise SyntaxError("Too many if parts") 170 | ast.append(CMDS.NOP) 171 | 172 | parts = [] 173 | 174 | elif struct == CMDS.FOR: 175 | if len(parts) == 0: 176 | ast.append(CMDS.NOP) 177 | 178 | elif len(parts) == 1: 179 | ast.append(Token(struct, ["!", 180 | parts[0]])) 181 | 182 | elif len(parts) == 2: 183 | ast.append(Token(struct, [parts[0], 184 | parts[1]])) 185 | 186 | else: 187 | # raise SyntaxError("Too many for parts) 188 | ast.append(CMDS.NOP) 189 | parts = [] 190 | 191 | elif struct == CMDS.WHILE: 192 | if len(parts) == 0: 193 | ast.append(CMDS.NOP) 194 | 195 | elif len(parts) == 1: 196 | ast.append(Token(struct, ["1", 197 | parts[0]])) 198 | elif len(parts) == 2: 199 | ast.append(Token(struct, [parts[0], 200 | parts[1]])) 201 | else: 202 | # raise SyntaxError("Too many while parts) 203 | ast.append(CMDS.NOP) 204 | parts = [] 205 | 206 | elif struct == CMDS.FUNCTION: 207 | if len(parts) == 0: 208 | ast.append(CMDS.NOP) 209 | if len(parts) == 1: 210 | ast.append(Token(struct, [1, 211 | parts[0]])) 212 | 213 | elif len(parts) == 2: 214 | ast.append(Token(struct, [func(parts[0]), 215 | parts[1]])) 216 | else: 217 | # raise SyntaxError("Too many function parts) 218 | ast.append(CMDS.NOP) 219 | parts = [] 220 | 221 | elif struct == CMDS.SWITCH: 222 | if len(parts) == 0: 223 | ast.append(CMDS.NOP) 224 | else: 225 | switch_temp = [parse(part) for part in parts[:-1]] 226 | if parts[-1][0] == "║": 227 | default = parse(parts[-1]) 228 | switch_temp.append([default[:], "default"]) 229 | ast.append(Token(struct, switch_temp)) 230 | 231 | elif struct == CMDS.MAP: 232 | ast.append(Token(struct, "'" + parts[0] + "'")) 233 | parts = [] 234 | temp = "" 235 | 236 | else: 237 | temp += char 238 | 239 | elif char == "|" and len(structures) == 1: 240 | parts.append(temp) 241 | temp = "" 242 | 243 | elif char == "║": 244 | if len(structures) == 1 and structures[-1] == CMDS.SWITCH: 245 | default = True 246 | parts.append(temp) 247 | temp = "║" 248 | 249 | else: 250 | temp += char 251 | 252 | elif structures: 253 | temp += char 254 | else: 255 | ast.append(Token(CMDS.CMD, char)) 256 | 257 | if variable_mode: 258 | ast.append(Token(CMDS.VARIABLE, [variable, call_set])) 259 | return ast 260 | 261 | def func(source): 262 | if source.count(" ") == 1: 263 | name, n = source.split() 264 | 265 | else: 266 | n = "" 267 | j = len(source) - 1 268 | for i in range(len(source) - 1, -1, -1): 269 | if source[i] not in "0123456789": 270 | break 271 | n += source[i] 272 | j -= 1 273 | n = n[::-1] 274 | name = source[:j + 1] 275 | 276 | if n.isnumeric(): 277 | n = int(n) 278 | else: 279 | if n == "*": 280 | n = "!" 281 | else: 282 | n = 0 283 | 284 | return {"name": name, "number": n} 285 | 286 | if __name__ == "__main__": 287 | test = parse("`]`") 288 | print([str(x) for x in test]) 289 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Keg -- (Ke)yboard (G)olfed 2 | _Keg_ is a stack-based esolang with condensability as well as simplicity and readability in mind. It's main purpose is to be used for golfing, although it can be potentially used for other purposes. What makes this esolang different from others is that: 3 | 4 | * Alphanumerical characters are automatically pushed (no need to wrap them in quotation marks) 5 | * There are readable and intuitive `if` statements, `for` and `while` loops 6 | * The number of functions to remember is small 7 | * And much more 8 | 9 | ## A Few Conventions of This Document 10 | * `∆ ... ∆` in a code snippet means that the code in the `...` is optional 11 | * `>` in a code snippet means an input prompt 12 | * `>>>` in a code snippet means a command prompt 13 | 14 | ## Design Principles 15 | The main inspiration for _Keg_ comes from a want of an esolang where only symbols count as commands and everything else is pushed onto the stack as a literal. This is why there are only 12 functions, 7 'keywords' and 8 operators. As such, this system allows for shorter programs where strings are involved (_uncompressed_ strings in Keg are usually 1-2 bytes shorter than their counterparts in other languages). 16 | 17 | Another design feature of _Keg_ is the look of `if` statements, `for` loops and `while` loops. These **structures** take on the form of: 18 | 19 | B...B 20 | 21 | Where `B` is any of the three brackets (`(/)`, `[/]` or `{/}`) and `...` is any body of code 22 | 23 | ## The Basics 24 | Most tutorials show how to print the string `Hello, World!` , so that's what this tutorial will do as well. Here is a simple 21 byte program to achieve the goal. 25 | 26 | Hello\, World\!^(!|,) 27 | 28 | ### Explanation 29 | 30 | Hello #Push the characters "H", "e", "l", "l" and "o" to the stack 31 | \, #Escape the "," and push it to the stack 32 | World #Push the characters "W", "o", "r", "l" and "d" to the stack 33 | \! #Escape the "!" and push it to the stack 34 | ^ #Reverse the stack 35 | (!| #Start a for loop and set the count to the length of the stack 36 | , #Print the last item on the stack as a character 37 | ) 38 | 39 | In the above example, 6 new functions and keywords are introduced: 40 | 41 | `\` : Escapes the next command, and instead pushes it as a string (pushes its ascii value) 42 | `,` : Prints the last item on the stack as a character 43 | `!` : Pushes the length of the stack onto the stack 44 | `^` : Reverses the stack 45 | `(...)` : The for loop structure 46 | `|` : Used in structures to switch from one branch to the other. 47 | 48 | ### The Stack 49 | One of the most important parts of _Keg_ is the stack, which is where all operations are performed. A stack is a type of container (or list) where the last item in the container is the first item to be operated on (LIFO -- Last In First Out). In the following examples, the stack will be investigated. 50 | 51 | 3# [3] 52 | 4# [3, 4] 53 | +# [7] 54 | 55 | In the above example, the numbers `3` and `4` are pushed onto the stack, and are then added using the `+` operator. The way it works is that the `+` pops what will be called `x` and `y` off the stack (the first and second last item) and pushes `y` + `x` back onto the stack. Note that the order of `x` and `y` are important when using the `-` and `\` operators, as `x` - `y` doesn't equal `y` - `x` most of the time (as is the same with `x` / `y` and `y` / `x`). This can be seen in the following example: 56 | 57 | 34-.#Outputs -1 58 | 43-.#Outputs 1 59 | 34/.#Outputs 0.75 60 | 43/.#Outputs 1.333333333333 61 | 62 | _Note that the `.` function prints the last item on the stack as an integer._ 63 | 64 | ### Input and Output 65 | _Keg_ has two output functions and one input function. When taking input from the user, the next line from the Standard Input and push the ascii value of each character onto the stack. It will not push -1 anymore onto the stack to sigify the end of input (input as integers will be coming in a later version of _Keg_). Input is taken using the `?` command, as shown in the example program: 66 | 67 | ?(!|,) 68 | 69 | # > Example text 70 | # Example text 71 | 72 | The two output functions (`.` -- Print as integer and `,` -- Print as string) have already been detailed in other sections 73 | 74 | ## Program Flow 75 | ### `If` Statements 76 | As mentioned in the introduction, _Keg_ has a readable and intuative way of expressing `if` statements, `for` and `while` loops. The form of an `if` statement is: 77 | 78 | [...1 ∆| ...2∆] 79 | 80 | When an `if` statement is run, the last item on the stack is popped, and if it is non-zero, `...1` is executed. If there is a `|...2`, it is executed if the popped value is 0. 81 | 82 | ### `For` Loops 83 | The form of a `for` loop is: 84 | 85 | (∆...1|∆ ...2) 86 | 87 | When a `for` loop is run, if `...1` is present, it will be evaluated as used as the number of times the loop will be run (if it isn't given, the length of the stack will be used). `...2` is the body of the `for` loop, which will be executed. 88 | 89 | ### `While` Loops 90 | The form of a `while` loop is: 91 | 92 | { ∆...1|∆ ...2} 93 | 94 | When a `while` loop is run, `...1` (if given) will be the condition of the loop (if it isn't present, `1` will be used as the condition of the loop) and `...2` will be executed until the given condition is false. 95 | 96 | ## User Defined Functions 97 | One of the special features of _Keg_ is user-defined functions, which are defined using the following form: 98 | 99 | @name ∆n∆ | ...@ 100 | 101 | Where: 102 | `name` = the name of the function (note that it needs to be one full word, and that it can't contain any `@`'s) 103 | `n` = the number of items popped from the stack 104 | `...` = the body of the function 105 | 106 | If `n` isn't present, no items will be popped from the stack, and all code in the function will be applied to the main stack 107 | 108 | ## Special Bits 109 | 110 | * If nothing is printed during the run of the program, the whole stack will be joined together (stringified, with values less than 10 or greater than 256 being treated as integers) and printed 111 | 112 | * Closing brackets can be left out of programs, and will be auto-completed in a LIFO matter 113 | 114 | * There is also implicit input. If you use `^` and `:` on an empty stack, one line of input will be taken. 115 | 116 | * The next edit of the interpreter does not have -1's being pushed to the input. 117 | 118 | ## Example Programs 119 | 120 | ### Hello World, Further Golfed 121 | 122 | Hello\, World\! 123 | 124 | ### Cat Program 125 | 126 | ^ 127 | 128 | ### Fizzbuzz Program 129 | 130 | 0(d|1+:35*%0=[ zzubzziF(9|,)|:5%0=[ zzuB(5|,)|:3%0=[ zziF(5|,)|:. ,]]]) 131 | 132 | ### 99 Bottles of Beer Program 133 | 134 | c&(c|&:.& bottles of beer on the wall\, ^(!|,)&:.& bottles of beer\.91+^(!|,)Take one down\, pass it around\, ^(!|,)&1-&&:.& bottles of beer on the wall\.91+^(!|,)) 135 | 136 | ### Quine 137 | 138 | Q 139 | 140 | _This can be any series of alphabetical letters_ 141 | 142 | ## Command Glossary 143 | If the `^` or `:` commands tried to operate on an empty stack, an input will be taken (for shorter programs). 144 | 145 | |Command|Description|Usage|Notes| 146 | |------------|-------------|-------|-------| 147 | | `!` | Pushes the length of the stack onto the stack | `!` | | 148 | | `:` | Duplicates the last item on the stack | `:` | | 149 | | `_` | Removes the last item on the stack | `_` | | 150 | | `,` | Prints the last item on the stack as a character | `,` | | 151 | | `.` | Prints the last item on the stack as an integer | `.` | | 152 | | `?` | Gets input from the user | `?` | | 153 | | `'` | Left shifts the stack | `'` | | 154 | | `"` | Right shifts the stack | `"` | | 155 | | `~` | Pushes a random number onto the stack | `~` | The number will be between 0 and 32767 | 156 | | `^` | Reverses the stack | `^` | | 157 | | `$` | Swaps the top two items on the stack | `$` | | 158 | | `#` | Starts a comment | `#` | | 159 | | `\|` | Branches to the next section of a structure | `B...\|...B`| `B` is any one bracket type | 160 | | `\` | Escapes the next command, and pushes it as a string | `\` | | 161 | | `&` | Gets/sets the register value | `&` | | 162 | | `@` | Define/call a function | `@ name ∆n∆ \| ...@` | | 163 | | `+` | Pops `x` and `y` and pushes `y` + `x` | `+` | | 164 | | `-` | Pops `x` and `y` and pushes `y` - `x` | `-` | | 165 | | `*` | Pops `x` and `y` and pushes `y` * `x` | `*` | | 166 | | `/` | Pops `x` and `y` and pushes `y` / `x` | `/` | Divison by zero gives an error | 167 | | `%` | Pops `x` and `y` and pushes `y` % `x` | `%` | Divison by zero gives an error | 168 | | `<` | Pops `x` and `y` and pushes `y` < `x` | `<` | | 169 | | `>` | Pops `x` and `y` and pushes `y` > `x` | `>` | | 170 | | `=` | Pops `x` and `y` and pushes `y` == `x` | `=` | | 171 | | `0-9` | Pushes the given integer onto the stack | `` | | 172 | | `a-z, A-Z` | Pushes the ascii value of the given character onto the stack | `` | | 173 | 174 | ## Extended command glossary 175 | These commands are added to Keg in order to make Keg programs shorter. These instructions can be implemented in Keg quite easily. These are NOT part of the official Keg. (From A__) 176 | 177 | |Command|Description|Usage|Notes&Implementation| 178 | |-------|-----------|-----|--------------------| 179 | |`Ï`| Replaces the top of stack with all items from `top to 0`|`Ï`| this is under EASCII, of course;
```(:\|:1-)```| 180 | |`;`| Decrement the top of the stack | `;` | `1-` | 181 | |`Ë`| Exponentation |`Ë`| `# Unknown`| 182 | |`§`| Sine function |`§`| `# Unknown` | 183 | |`¿`| Nice input | `¿`| Tries to eval as Float > Integer > List > String| 184 | |`∂`| Exclusive range | `∂` | Pops `x`, `y` and `z` and pushes `z in range(y, x)`| 185 | |`•`| Inclusive range | `•` | Pops `x`, `y` and `z` and pushes `z in range(y, x + 1)`| 186 | |`ɧ`| Generate range | `ɧ` | Pops `x` and `y` and pushes `range(y, x + 1)`| 187 | |`÷`| Item split | `÷`| Splits the top of stack into seperate parts| 188 | |`¡`| Factorial| `¡` | Takes the factorial of the top of the stack| 189 | |`ø`| Empties the stack |`ø`|None| 190 | |`Ω`|Prints the entire stack|`Ω`|None| 191 | |`∑`|Apply to all the stack|`∑`|Preprocesses to `(!;|`| 192 | |`¬`|Logically nots the top of the stack|`¬`|None| 193 | |`½`|Halves the top of the stack|`½`|None| 194 | 195 | ## Keg+ Extension 196 | 197 | | Command | Description | Usage | Notes | Implemented? | 198 | |---------|-----------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------------------|--------------| 199 | | `‡` | Reads the source code until a non-number character is found | `‡` | Non-number character means that it isn't a valid float/integer | No | 200 | | `ℤℝ⅍℠ⁿ` | Converts the top of the stack to the desired type (integer, float, stack, string, character respectively) | `` | | Yes | 201 | | `⟰⟱⟷` | Takes the top of the stack and uppercases it, lowercases it or togglecases it respectively | `` | Doesn't do anything to non-strings | Yes | 202 | | `²` | Squares the top of the stack | `²` | Performs `top * top` | Yes | 203 | | `᠀` | Take input as a string | `᠀` | | Yes | 204 | | `∀` | Pushes 1 if everything on the stack is true, otherwise 0 | `∀` | Doesn't pop things from the stack | Yes | 205 | | `≌` | Like above, but if everything is the same | `≌` | | Yes | 206 | | `⅀` | Summates the entire stack | `⅀` | Pretty much just `∑+)` | Yes | 207 | | `ß` | Takes the top of the stack and executes it as Keg code | `ß` | | Kind of | 208 | | `©` | Get the value of a variable | `©name` | `name` has to only contain letters | Yes | 209 | | `®` | Set the value of a variable to the top of the stack (popping it) | `®name` | Same as above | Yes | 210 | -------------------------------------------------------------------------------- /StackTest.py: -------------------------------------------------------------------------------- 1 | stack = [] 2 | def something(x, s=stack): 3 | s.append(x) 4 | -------------------------------------------------------------------------------- /Stackd.py: -------------------------------------------------------------------------------- 1 | #Stackd library for Keg 2 | 3 | def _ord(char): 4 | if char in code_page: 5 | return code_page.find(char) 6 | return ord(char) 7 | 8 | code_page = "Set me in Keg.py" 9 | input_raw = False #Set me in Keg.py using flags 10 | 11 | class Stack: 12 | def __init__(self, iterable=()): 13 | if iterable: 14 | self.__stack = list(iterable) 15 | self.stacks = self.__stack.copy() 16 | else: 17 | self.__stack = [] 18 | self.stacks = [self.__stack] 19 | 20 | self.level = 0 21 | self.inputs = [] 22 | 23 | def __len__(self): 24 | return len(self.__stack) 25 | 26 | def __setitem__(self, index, value): 27 | self.__stack[index] = value 28 | 29 | def __getitem__(self, index): 30 | return self.__stack[index] 31 | 32 | def __delitem__(self, what): 33 | del self.__stack[what] 34 | 35 | def push(self, value): 36 | self.__stack.append(value) 37 | 38 | def pop(self): 39 | if self.__stack: 40 | return self.__stack.pop() 41 | try: 42 | temp = input() 43 | except: 44 | return None 45 | 46 | if input_raw: 47 | from Coherse import char 48 | for Char in reversed(temp): 49 | self.__stack.append(char(Char)) 50 | return self.__stack.pop() 51 | 52 | try: 53 | if type(eval(temp)) is float: 54 | temp = float(temp) 55 | elif type(eval(temp)) is int: 56 | temp = int(temp) 57 | elif type(eval(temp)) is list: 58 | temp = Stack(eval(temp)) 59 | elif type(eval(temp)) is str: 60 | for Char in reversed(temp): 61 | self.__stack.append(Char) 62 | return self.__stack.pop() 63 | except: 64 | temp = temp 65 | 66 | self.inputs.append(temp) 67 | return temp 68 | 69 | def __repr__(self): 70 | return str(self.__stack) 71 | 72 | def clear(self): 73 | self.__stack.clear() 74 | 75 | def index(self, *pos_list): 76 | #Iteratively index the stack 77 | 78 | temp = self.__stack 79 | for indx in pos_list: 80 | temp = temp[indx] 81 | 82 | return temp 83 | 84 | def __str__(self): 85 | return "".join([str(item) for item in self.__stack]) 86 | 87 | 88 | if __name__ == "__main__": 89 | x = Stack([1, 2, 3, [4, 5, [6, 7, 8]]]) 90 | print(x.index(3, 2, 2)) 91 | -------------------------------------------------------------------------------- /StringF.py: -------------------------------------------------------------------------------- 1 | def custom_format(source): 2 | #Using the © format 3 | #first space after a © doesn't count and is removed. 4 | 5 | result = "" 6 | temp = "" 7 | escaped = False 8 | var_mode = False 9 | 10 | import string 11 | 12 | for char in source: 13 | if escaped: 14 | escaped = False 15 | result += char 16 | continue 17 | 18 | elif char == "\\": 19 | escaped = True 20 | result += char 21 | continue 22 | 23 | if var_mode: 24 | if char in string.ascii_letters: 25 | temp += char 26 | continue 27 | 28 | else: 29 | result += variables.get(temp, '©' + temp) 30 | temp = "" 31 | var_mode = False 32 | if char == " ": 33 | continue 34 | 35 | if char == "©": 36 | var_mode = True 37 | continue 38 | 39 | result += char 40 | 41 | if var_mode: 42 | result += variables.get(temp, '©' + temp) 43 | return result 44 | 45 | 46 | -------------------------------------------------------------------------------- /T.py: -------------------------------------------------------------------------------- 1 | from KegLib import * 2 | from Stackd import Stack 3 | stack = Stack() 4 | printed = False 5 | _register = None 6 | character(stack, 'c') 7 | register(stack) 8 | character(stack, 'd') 9 | 10 | for _ in loop_eval(stack.pop()): 11 | register(stack) 12 | duplicate(stack) 13 | raw(stack) 14 | register(stack) 15 | character(stack, ' ') 16 | character(stack, 'b') 17 | character(stack, 'o') 18 | character(stack, 't') 19 | character(stack, 't') 20 | character(stack, 'l') 21 | character(stack, 'e') 22 | character(stack, 's') 23 | character(stack, ' ') 24 | character(stack, 'o') 25 | character(stack, 'f') 26 | character(stack, ' ') 27 | character(stack, 'b') 28 | character(stack, 'e') 29 | character(stack, 'e') 30 | character(stack, 'r') 31 | character(stack, ' ') 32 | character(stack, 'o') 33 | character(stack, 'n') 34 | character(stack, ' ') 35 | character(stack, 't') 36 | character(stack, 'h') 37 | character(stack, 'e') 38 | character(stack, ' ') 39 | character(stack, 'w') 40 | character(stack, 'a') 41 | character(stack, 'l') 42 | character(stack, 'l') 43 | integer(stack, 44) 44 | character(stack, ' ') 45 | reverse(stack) 46 | length(stack) 47 | 48 | for _ in loop_eval(stack.pop()): 49 | nice(stack) 50 | 51 | register(stack) 52 | duplicate(stack) 53 | raw(stack) 54 | register(stack) 55 | character(stack, ' ') 56 | character(stack, 'b') 57 | character(stack, 'o') 58 | character(stack, 't') 59 | character(stack, 't') 60 | character(stack, 'l') 61 | character(stack, 'e') 62 | character(stack, 's') 63 | character(stack, ' ') 64 | character(stack, 'o') 65 | character(stack, 'f') 66 | character(stack, ' ') 67 | character(stack, 'b') 68 | character(stack, 'e') 69 | character(stack, 'e') 70 | character(stack, 'r') 71 | integer(stack, 46) 72 | integer(stack, 9) 73 | integer(stack, 1) 74 | maths(stack, '+') 75 | reverse(stack) 76 | length(stack) 77 | 78 | for _ in loop_eval(stack.pop()): 79 | nice(stack) 80 | 81 | character(stack, 'T') 82 | character(stack, 'a') 83 | character(stack, 'k') 84 | character(stack, 'e') 85 | character(stack, ' ') 86 | character(stack, 'o') 87 | character(stack, 'n') 88 | character(stack, 'e') 89 | character(stack, ' ') 90 | character(stack, 'd') 91 | character(stack, 'o') 92 | character(stack, 'w') 93 | character(stack, 'n') 94 | integer(stack, 44) 95 | character(stack, ' ') 96 | character(stack, 'p') 97 | character(stack, 'a') 98 | character(stack, 's') 99 | character(stack, 's') 100 | character(stack, ' ') 101 | character(stack, 'i') 102 | character(stack, 't') 103 | character(stack, ' ') 104 | character(stack, 'a') 105 | character(stack, 'r') 106 | character(stack, 'o') 107 | character(stack, 'u') 108 | character(stack, 'n') 109 | character(stack, 'd') 110 | integer(stack, 44) 111 | character(stack, ' ') 112 | reverse(stack) 113 | length(stack) 114 | 115 | for _ in loop_eval(stack.pop()): 116 | nice(stack) 117 | 118 | register(stack) 119 | integer(stack, 1) 120 | maths(stack, '-') 121 | register(stack) 122 | register(stack) 123 | duplicate(stack) 124 | raw(stack) 125 | register(stack) 126 | character(stack, ' ') 127 | character(stack, 'b') 128 | character(stack, 'o') 129 | character(stack, 't') 130 | character(stack, 't') 131 | character(stack, 'l') 132 | character(stack, 'e') 133 | character(stack, 's') 134 | character(stack, ' ') 135 | character(stack, 'o') 136 | character(stack, 'f') 137 | character(stack, ' ') 138 | character(stack, 'b') 139 | character(stack, 'e') 140 | character(stack, 'e') 141 | character(stack, 'r') 142 | character(stack, ' ') 143 | character(stack, 'o') 144 | character(stack, 'n') 145 | character(stack, ' ') 146 | character(stack, 't') 147 | character(stack, 'h') 148 | character(stack, 'e') 149 | character(stack, ' ') 150 | character(stack, 'w') 151 | character(stack, 'a') 152 | character(stack, 'l') 153 | character(stack, 'l') 154 | integer(stack, 46) 155 | integer(stack, 9) 156 | integer(stack, 1) 157 | maths(stack, '+') 158 | reverse(stack) 159 | length(stack) 160 | 161 | for _ in loop_eval(stack.pop()): 162 | nice(stack) 163 | 164 | 165 | 166 | if not printed: 167 | printing = "" 168 | for item in stack: 169 | if type(item) in [str, Stack]: 170 | printing += item 171 | elif type(item) is Coherse.char: 172 | printing += item.v 173 | 174 | elif item < 10 or item > 256: 175 | printing += str(item) 176 | else: 177 | printing += chr(item) 178 | print(printing) 179 | -------------------------------------------------------------------------------- /TranspiledTests.py: -------------------------------------------------------------------------------- 1 | from KegLib import * 2 | from Stackd import Stack 3 | stack = Stack() 4 | printed = False 5 | Input(stack) 6 | condition = condition_eval(["length(stack)", "integer(stack, 1)", "maths(stack, '-')"], stack) 7 | print(condition) 8 | while condition: 9 | nice(stack); printed = True 10 | condition = 1 11 | 12 | integer(stack, 10) 13 | 14 | if not printed: 15 | printing = "" 16 | for item in stack: 17 | if type(item) in [str, Stack]: 18 | printing += item 19 | elif type(item) is Coherse.char: 20 | printing += item.v 21 | 22 | elif item < 10 or item > 256: 23 | printing += str(item) 24 | else: 25 | printing += chr(item) 26 | print(printing) 27 | -------------------------------------------------------------------------------- /Word_List.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | def generate_list(): 4 | words = list() 5 | import os 6 | prepend = os.path.dirname(__file__) 7 | source = open(prepend + "/docs/words.txt", encoding="utf-8").readlines() 8 | 9 | for word in source: 10 | if len(word) <= 3: 11 | continue 12 | if len(words) >= 61000: 13 | continue 14 | if word.startswith("#!comment:"): 15 | continue 16 | 17 | if all([x in "ABCDEFFGHIJKLMNOPQRSTUVWXYZ" for x in word]): 18 | continue 19 | 20 | words.append(word.strip("\n")) 21 | return words 22 | -------------------------------------------------------------------------------- /docs/BFL.keg: -------------------------------------------------------------------------------- 1 | #Keg's BFL --> Built-In-Function-Library, Written in 100% Keg 2 | #A 3 | @AV *|!&⅀&/ƒ# 4 | #B 5 | # 6 | #C 7 | # 8 | #D 9 | # 10 | #E 11 | # 12 | #F 13 | # 14 | #G 15 | # 16 | #H 17 | # 18 | #I 19 | # 20 | #J 21 | # 22 | #K 23 | # 24 | #L 25 | # 26 | #M 27 | @MC2|®N®R©N¡©R¡©N©R-¡*/ƒ# 28 | @MM2|:":"<[_|'_]ƒ# 29 | @MP1|:;¡²$%ƒ# 30 | # 31 | #N 32 | # 33 | #O 34 | # 35 | #P 36 | # 37 | #Q 38 | # 39 | #R 40 | # 41 | #S 42 | @S0|`@N|[];`ƒ 43 | # 44 | #T 45 | # 46 | #U 47 | # 48 | #V 49 | # 50 | #W 51 | # 52 | #X 53 | # 54 | #Y 55 | # 56 | #Z -------------------------------------------------------------------------------- /examples/99bottles.keg: -------------------------------------------------------------------------------- 1 | c&(d|&:.& bottles of beer on the wall\, ^(!|,)&:.& bottles of beer\.91+^(!|,)Take one down\, pass it around\, ^(!|,)&1-&&:.& bottles of beer on the wall\.91+^(!|,)) -------------------------------------------------------------------------------- /examples/99bottles2.keg: -------------------------------------------------------------------------------- 1 | c&(c|&:.& bottle&:&1=[|s] of beer on the wall\, ^(,)&:.& bottle&:&1=[|s] of beer\.\ 2 | ^(,)Take one down\, pass it around\, ^(,)&1-:&[&:.&|no more] bottle&:&1=[|s] of beer on the wall\.\ 3 | ^(,)) 4 | -------------------------------------------------------------------------------- /examples/99new.keg: -------------------------------------------------------------------------------- 1 | #99-bottles rewritten 2 | c&(c|&:.&¶ u_;of o⒁;on the 47;¶,\,, ,&:.&¶ u_;of beer.¶,&1-&`\n7Ʀ; one 0];, 2 ; it 1⬬;, `,&:.&¶ u_;of o⒁;on the 47;\n¶,) -------------------------------------------------------------------------------- /examples/Abutnota.keg: -------------------------------------------------------------------------------- 1 | Ȧ -------------------------------------------------------------------------------- /examples/Add.keg: -------------------------------------------------------------------------------- 1 | + -------------------------------------------------------------------------------- /examples/Addition.keg: -------------------------------------------------------------------------------- 1 | 123∑+) -------------------------------------------------------------------------------- /examples/Decr.keg: -------------------------------------------------------------------------------- 1 | 4; -------------------------------------------------------------------------------- /examples/ExclusiveTest.keg: -------------------------------------------------------------------------------- 1 | bzb•. -------------------------------------------------------------------------------- /examples/Facrecursion.keg: -------------------------------------------------------------------------------- 1 | #Factorial w/ recursion 2 | @factorial 1|:1<[_1|:;@factorialƒ*]ƒ# 3 | ¿@factorialƒ. 4 | -------------------------------------------------------------------------------- /examples/Factorial9.keg: -------------------------------------------------------------------------------- 1 | ¿ï_∑*). -------------------------------------------------------------------------------- /examples/FactorialReg.keg: -------------------------------------------------------------------------------- 1 | azɧ -------------------------------------------------------------------------------- /examples/Function.keg: -------------------------------------------------------------------------------- 1 | @t1|::++ƒ8@tƒ. -------------------------------------------------------------------------------- /examples/Function_Test.keg: -------------------------------------------------------------------------------- 1 | @K0|Lolƒ@Kƒ -------------------------------------------------------------------------------- /examples/InclusiveTest.keg: -------------------------------------------------------------------------------- 1 | azb• -------------------------------------------------------------------------------- /examples/Numbersplit.keg: -------------------------------------------------------------------------------- 1 | ¿÷ -------------------------------------------------------------------------------- /examples/Printwloop: -------------------------------------------------------------------------------- 1 | zziF∑,) -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | File Guide 2 | 3 | |File|Description|Author| 4 | |----|-----------|------| 5 | |99bottles.keg| A 'cheating' version of the 99 bottles of beer program|JonoCode9374| 6 | |99bottles2.keg|A more proper solution to the 99 bottles of beer program|A_ee| 7 | |99new.keg|An example of string compression to print 99 bottles of beer program|JonoCode9374| 8 | |Abutnota.keg|A solution to [this](https://codegolf.stackexchange.com/questions/90349/the-letter-a-without-a/) challenge|JonoCode9374| 9 | |Add.keg|A test of implict input via addition|JonoCode9374| 10 | |Addition.keg|A test of the 'apply to all' keyword (`∑`)|JonoCode9374| 11 | |brake.keg|No clue what this does. Just ignore it|JonoCode9374| 12 | |cat.keg|A simple 'cat' solution (print the given input to stdout)|A_ee| 13 | |deadfish.keg|A deadfish interpreter in Keg|A_ee| 14 | |deadfish2.keg|An alternate deadfish interpreter|A_ee| 15 | |Decr.keg|A test of the decrement function (`;`)|JonoCode9374| 16 | |ExclusiveTest.keg|A test of exclusive ranges (`•`)|JonoCode9374| 17 | |Facrecursion.keg|Finds the factorial of a given number using recursive functions|JonoCode9374| 18 | |factorial.keg|Finds the factorial of a given number using a for-loop|A_ee| 19 | |Factorial9.keg|Finds the factorial of a given number using iota and apply-to-all|JonoCode9374| 20 | |FactorialReg.keg|This was _supposed_ to be a test of Reg's factorial command, but it isn't. Ignore this file|JonoCode9374| 21 | |fizzbuzz.keg|A simple fizzbuzz solution|JonoCode9374| 22 | |fizzbuzz2.keg|An improved fizzbuzz solution|A_ee| 23 | |Function_Test.keg|No clue what this does. Just ignore it|JonoCode9374| 24 | |Function.keg|An example function and it's call (triples the given input)|JonoCode9374| 25 | |hello.keg|Uncompressed Hello World program|JonoCode9374| 26 | |InclusiveTest.keg|Suppossed to be a test of inclusive ranges but it isn't. Ignore this file|JonoCode9374| 27 | |Numbersplit.keg|Testing the item split command (`÷`)|JonoCode9374| 28 | |Printwloop.keg|Another test of the apply-to-all keyword|JonoCode9374| 29 | |quine.keg|A proper Keg quine. Prints it's own source|UnrelatedString| 30 | |quine2.keg|An alternate Keg quine|GuyJoKing| 31 | |Shifting.keg|A test of stack shifting|JonoCode9374| 32 | |StringFormat.keg|A test of string formatting|JonoCode9374| 33 | |Truth.keg|An implementation of a truth machine|A_ee| 34 | |WhileLoop_Cond.keg|A file to see if the transpiler works|JonoCode9374| 35 | |WhileLoop.keg|A simple empty while loop|JonoCode9374| 36 | -------------------------------------------------------------------------------- /examples/Shifting.keg: -------------------------------------------------------------------------------- 1 | ' -------------------------------------------------------------------------------- /examples/StringFormat.keg: -------------------------------------------------------------------------------- 1 | #String formatting test 2 | `Hello ©name`᠀®name 3 | _©name, 4 | -------------------------------------------------------------------------------- /examples/Truth.keg: -------------------------------------------------------------------------------- 1 | ?\1=[{1.}|_0] 2 | -------------------------------------------------------------------------------- /examples/WhileLoop.keg: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /examples/WhileLoop_Cond.keg: -------------------------------------------------------------------------------- 1 | ?{!1-|,} 2 | -------------------------------------------------------------------------------- /examples/brake.keg: -------------------------------------------------------------------------------- 1 | ab< -------------------------------------------------------------------------------- /examples/cat.keg: -------------------------------------------------------------------------------- 1 | ? -------------------------------------------------------------------------------- /examples/deadfish.keg: -------------------------------------------------------------------------------- 1 | 0&{&:&\@4*=[&_0&]&:&0<[&_0&] \>\>25*,,,,?:o=[&:.&]:i=[&1+&]:d=[&1-&]:s=[&:*&]} 2 | -------------------------------------------------------------------------------- /examples/deadfish2.keg: -------------------------------------------------------------------------------- 1 | 0&{&:&ÿ1+=[&_0&]&:&0<[&_0&] \>\>\ 2 | ,,,,?:o=[&:.&]:i=[&1+&]:d=[&1-&]:s=[&:*&]} 3 | -------------------------------------------------------------------------------- /examples/factorial.keg: -------------------------------------------------------------------------------- 1 | ?^_(\0-")^(!1-|91+*+):&&:&(:|&:&*&1-&)$/. 2 | -------------------------------------------------------------------------------- /examples/fizzbuzz.keg: -------------------------------------------------------------------------------- 1 | 0(d|1+:35*%0=[ zzubzziF(9|,)|:5%0=[ zzuB(5|,)|:3%0=[ zziF(5|,)|:. ,]]]) -------------------------------------------------------------------------------- /examples/fizzbuzz2.keg: -------------------------------------------------------------------------------- 1 | 0{1+:�%0=[ zzubzziF(9|,)|:5%0=[ zzuB(5|,)|:3%0=[ zziF(5|,)|:. ,]]]} 2 | -------------------------------------------------------------------------------- /examples/hello.keg: -------------------------------------------------------------------------------- 1 | Hello\, World\! -------------------------------------------------------------------------------- /examples/quine.keg: -------------------------------------------------------------------------------- 1 | \^\(\\\\\,\:\&\^\&\^\,\)\^\#^(\\,:&^&^,)^# 2 | -------------------------------------------------------------------------------- /examples/quine2.keg: -------------------------------------------------------------------------------- 1 | HBZLTXJMIC(":,48*-)# 2 | -------------------------------------------------------------------------------- /preprocess.py: -------------------------------------------------------------------------------- 1 | #The Keg Preprocessor 2 | STRING_CHARS = "`¶“‘«„" 3 | 4 | def process(string): 5 | final = "" 6 | string_mode = [False, ""] 7 | escaped = False 8 | comment = False 9 | ssl_reference = [False, ""] 10 | 11 | for char in string: 12 | if string_mode[0]: 13 | if escaped: 14 | final += char 15 | escaped = False 16 | continue 17 | 18 | elif char == "\\": 19 | escaped = True 20 | final += char 21 | continue 22 | else: 23 | if char == string_mode[1]: 24 | string_mode = [False, ""] 25 | final += char 26 | continue 27 | 28 | if char in STRING_CHARS: 29 | string_mode = [True, char] 30 | final += char 31 | continue 32 | 33 | if escaped: 34 | final += char 35 | escaped = False 36 | continue 37 | 38 | if char == "\\": 39 | escaped = True 40 | final += char 41 | continue 42 | 43 | if char == "₳": 44 | ssl_reference = [True, ""] 45 | continue 46 | 47 | if char == "\n" and comment: 48 | comment = False 49 | 50 | if ssl_reference[0] and len(ssl_reference[1]) != 2: 51 | ssl_reference[1] += char 52 | if len(ssl_reference[1]) == 2: 53 | ssl_reference[0] = False 54 | if ssl_reference[1] in ssls: 55 | final += ssls[ssl_reference[1]] 56 | else: 57 | final += f"" 58 | ssl_reference[1] = "" 59 | continue 60 | 61 | if char == "∑": 62 | final += "(!;|" 63 | continue 64 | 65 | if char == "⑳": 66 | final += "{!|" 67 | continue 68 | 69 | if char == "#": 70 | comment = True 71 | 72 | final += char 73 | return final 74 | 75 | 76 | def balance_strings(source): 77 | symbol = "" 78 | string_mode = False 79 | escaped = False 80 | 81 | alt_strings = {"`" : "834**", "¶" : "882**", 82 | "‘" : "27*", "“" : "35*", 83 | "«" : "25*7+", "„" : "82*"} 84 | 85 | 86 | 87 | 88 | result = "" 89 | for char in source: 90 | if escaped: 91 | if char in alt_strings: 92 | if string_mode: 93 | result += "\\" + char 94 | else: 95 | result += alt_strings[char] 96 | else: 97 | result += "\\" + char 98 | escaped = False 99 | continue 100 | 101 | elif char == "\\": 102 | escaped = True 103 | continue 104 | 105 | elif string_mode: 106 | if char == symbol: 107 | symbol = None 108 | string_mode = False 109 | 110 | result += char 111 | continue 112 | 113 | elif char in alt_strings: 114 | string_mode = True 115 | symbol = char 116 | result += char 117 | 118 | else: 119 | result += char 120 | 121 | 122 | if symbol: 123 | result += symbol 124 | 125 | return result 126 | 127 | ssls = { 128 | "0a" : "`0123456789abcdefghijklmnopqrstuvwxyz`", 129 | "0b" : "`0123456789`", 130 | "0c" : "`abcdefghijklmnopqrstuvwxyz`" 131 | } 132 | 133 | if __name__ == "__main__": 134 | assert process("₳0a") == "" 135 | assert process("₳0a₳0b") == "" 136 | assert process("a₳0b") == "a" 137 | assert process("a₳0bc") == "ac" 138 | assert process("m₳0em₳0E") == "mm" 139 | -------------------------------------------------------------------------------- /uncompress.py: -------------------------------------------------------------------------------- 1 | #utf-8 2 | #The Uncompressor 3 | from Word_List import * 4 | import KegStrings 5 | sccs = generate_list() 6 | 7 | chars = "0123456789" 8 | chars += "abcdefghij" 9 | chars += "klmnopqrst" 10 | chars += "uvwxyzABCD" 11 | chars += "EFGHIJKLMN" 12 | chars += "OPQRSTUVWX" 13 | chars += "YZ!@#$%^&*" 14 | chars += "()_+~[]{}:" 15 | chars += "<>?,./\"'¿" 16 | chars += "¿∂⊂ø®©ëλº√" 17 | chars += "₳¬≤Š≠≥Ėπ§∑" 18 | chars += "•™÷‡∞\t\n½±" 19 | chars += "¦ė≬ƒßɧË-=Ï¡" 20 | chars += "→←↶↷✏█↗↘□" 21 | chars += "²ⁿ║ṡ⟰⟱⟷" 22 | chars += "ℤℝ⅍℠א∀≌᠀⊙᠈⅀" 23 | chars += "ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ" #push'n'print 24 | chars += "☭" 25 | chars += "⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯" 26 | chars += "⯑" 27 | chars += "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆" 28 | chars += "↫" 29 | 30 | for n in range(127234, 127243): chars += chr(n) 31 | 32 | def _ord(char): 33 | if char in chars: 34 | return chars.find(char) 35 | return ord(char) + 256 36 | 37 | def numberToBase(n, b): #https://stackoverflow.com/a/28666223/9363594 38 | if n == 0: 39 | return [0] 40 | digits = [] 41 | while n: 42 | digits.append(int(n % b)) 43 | n //= b 44 | return digits[::-1] 45 | 46 | class STRINGS: 47 | STANDARD = "`" 48 | STANDARD_SPACED = "¶" 49 | SCC = "‘" 50 | SCC_SPACED = "“" 51 | SPECIAL = "„" 52 | SPECIAL_SPACED = "«" 53 | NONE = "" 54 | STRINGS = {STANDARD, STANDARD_SPACED, SCC, SCC_SPACED, SPECIAL, 55 | SPECIAL_SPACED} 56 | 57 | def Uncompress(source): 58 | parts = [] 59 | temp = "" 60 | string_type = STRINGS.NONE 61 | escaped = False 62 | 63 | for char in source: 64 | if escaped: 65 | temp += char 66 | escaped = False 67 | continue 68 | 69 | if string_type == STRINGS.NONE: 70 | if char in "`¶‘“„«": 71 | string_type = char 72 | parts.append(temp) 73 | temp = "" 74 | else: 75 | parts.append(char) 76 | 77 | elif char == string_type: 78 | import KegStrings 79 | item = KegStrings.obj_str_extract("`" + temp + "`") 80 | if type(item) != str: #The object is an object string 81 | parts.append("`" + temp + "`") 82 | else: 83 | parts.append("`" + to_standard(temp, string_type) + "`") 84 | string_type = STRINGS.NONE 85 | temp = "" 86 | 87 | elif char in STRINGS.STRINGS - {string_type}: 88 | temp += "\\" + char 89 | 90 | elif char in ["'", '"']: 91 | temp += "\\" + char 92 | 93 | elif char == "\\": 94 | temp += char 95 | escaped = True 96 | 97 | else: 98 | temp += char 99 | 100 | return "".join(parts) 101 | 102 | def to_standard(source, s_type): 103 | result = "" 104 | compression_code = "" 105 | escaped = False 106 | 107 | if type(KegStrings.obj_str_extract(source)) is not str: 108 | return source 109 | 110 | if s_type in [STRINGS.STANDARD, STRINGS.STANDARD_SPACED]: 111 | spaces = " " * [STRINGS.STANDARD, STRINGS.STANDARD_SPACED].index(s_type) 112 | for char in source: 113 | if escaped: 114 | compression_code += char 115 | escaped = False 116 | continue 117 | 118 | elif char == "\\": 119 | escaped = True 120 | continue 121 | 122 | if char == ";": 123 | result += f"{get_scc(compression_code)}{spaces}" 124 | compression_code = "" 125 | else: 126 | compression_code += char 127 | if len(compression_code) > 2: 128 | result += compression_code[0] 129 | compression_code = compression_code[1:] 130 | 131 | elif s_type in [STRINGS.SCC, STRINGS.SCC_SPACED]: 132 | spaces = " " * [STRINGS.SCC, STRINGS.SCC_SPACED].index(s_type) 133 | 134 | if len(source) % 2: source += " " 135 | codes = [source[i] + source[i + 1] for i in range(0, len(source), 136 | 2)] 137 | for code in codes: 138 | result += f"{get_scc(code)}{spaces}" 139 | 140 | elif s_type in [STRINGS.SPECIAL, STRINGS.SPECIAL_SPACED]: 141 | spaces = " " * [STRINGS.SPECIAL, STRINGS.SPECIAL_SPACED].index(s_type) 142 | codes, joins = source.split("|", 1) 143 | 144 | codes = [codes[i] + codes[i + 1] for i in range(0, len(codes), 145 | 2)] 146 | 147 | if len(joins) < len(codes): 148 | for _ in range(len(codes) - len(joins)): 149 | joins += " " 150 | 151 | for i in range(len(codes)): 152 | result += f"{get_scc(codes[i])}{joins[i]}{spaces}" 153 | 154 | 155 | 156 | if compression_code: 157 | result += compression_code 158 | 159 | if s_type in [STRINGS.STANDARD_SPACED, 160 | STRINGS.SCC_SPACED, 161 | STRINGS.SPECIAL_SPACED] and result[-1] == " ": 162 | result = result[:-1] 163 | 164 | return result 165 | 166 | def get_scc(code): 167 | index = _ord(code[1]) + (len(chars) * _ord(code[0])) 168 | return sccs[index] 169 | 170 | def keg_to_utf8(code): 171 | # Taken from the old 05AB1E interpreter 172 | processed_code = "" 173 | for c in code: 174 | processed_code += chars[c] 175 | 176 | return processed_code 177 | 178 | def utf8_to_keg(code): 179 | # Taken from the old 05AB1E interpreter 180 | processed_code = "" 181 | for c in code: 182 | processed_code += chr(chars.index(c)) 183 | 184 | return processed_code 185 | 186 | if __name__ == "__main__": 187 | while 1: 188 | term = input("Enter a search term: ") 189 | if term in sccs: 190 | x = sccs.index(term) 191 | numbers = numberToBase(x, 248) 192 | code = "".join([chars[i] for i in numbers]) 193 | print(code, numbers) 194 | else: 195 | print(-1) 196 | --------------------------------------------------------------------------------