├── README.md ├── bin └── 🔑++ ├── examples ├── fibonacci.liooooon ├── fizzbuzz.liooooon ├── hello_world.liooooon └── inspiration.liooooon └── src ├── ast.txt └── 🔑++.py /README.md: -------------------------------------------------------------------------------- 1 | `#DJKHALED` 2 | `#WETHEBEST` 3 | 4 | An emoji-based programming language designed to satisfy a curiosity around language-parsing and inspired by the idiolect of DJ Khaled. Designed over a few days at Swarthmore College. 5 | 6 | Other programming languages, they don't want you to win. That's why we're bringing you :key:++, the key to more success. 7 | 8 | They don't want you to code your way to more success. We do. They don't want you to code with 🔥emoji. We do. They don't want you always have another one. We do. Another one. 9 | 10 | And guess what? We've changed – a lot. 11 | 12 | ![:key:++](https://i.ytimg.com/vi/GNtRgxJJyVw/maxresdefault.jpg) 13 | 14 | Welcome to 🔑++, the programming language for winners and champions. We the best. 15 | 16 | ## Hello World 17 | ``` 18 | 🔥 "Hello World" 19 | ``` 20 | 21 | 22 | ## Fizz My Buzz 23 | 24 | ``` 25 | they don't want you to fizzbuzz max 26 | 27 | 🔑 n 0 28 | 29 | ride wit me 30 | if n % 3 == 0 and n % 5 == 0: 31 | 🔥 "FizzBuzz" 32 | elif n % 3 == 0: 33 | 🔥 "Fizz" 34 | elif n % 5 == 0: 35 | 🔥 "Buzz" 36 | else: 37 | 🔥 n 38 | 39 | if n >= max: 40 | you played yourself 41 | 42 | another one 43 | 44 | major 🔑 👍 45 | 46 | 🙏 47 | ``` 48 | 49 | ## Running 🔑++ locally 50 | 51 | In order to run 🔑++ on your local machine, you'll want to set up an alias so you can run code from anywhere. 52 | 53 | Add the following code to your `~/.profile` or `~/.bash_profile` (check out [StackOverflow](http://stackoverflow.com/a/8967864/4283301) for more information). 54 | 55 | ``` 56 | alias 🔑++="PATH_TO_DIRECTORY/🔑++/bin/🔑++" 57 | ``` 58 | 59 | You can change the alias if you'd prefer not to type emojis – we recommend "key++". Then you can just run 60 | 61 | ``` 62 | $> 🔑++ examples/hello_world.liooooon 63 | Hello world - WE THE BEST! 64 | ``` 65 | 66 | ## Name 67 | This language is called :key:++ because it's the key to more success, and another one. 68 | 69 | ## Syntax 70 | 71 | 72 | #### Boilerplate 73 | All :key:++ programs must begin with the following two-line comment: 74 | 75 | ``` 76 | #DJKHALED 77 | #WETHEBEST 78 | ``` 79 | 80 | 81 | #### Built-in types 82 | :key:++ naturally supports integers, floats, and strings. Booleans are `👍`, true, and `👎`, false. 83 | 84 | :key:++ accepts all standard operators, `+`, `-`, `*`, `\`, `%`, `**`, etc. Anything you could find in Python ;) 85 | 86 | ``` 87 | 1 88 | 3.14 89 | 👍 90 | "another one" 91 | ``` 92 | 93 | #### Printing 94 | To print a value, simply prefix it with `🔥`. 95 | 96 | ``` 97 | 🔥 3.14 98 | 🔥 "another one" 99 | ``` 100 | 101 | 102 | #### Assigning variables 103 | :key:++ uses the following notation for assigning variable values: 104 | 105 | ``` 106 | 🔑 x 1 107 | ``` 108 | 109 | You can read this as "The key to x is 1". The right term can include operators, so `🔑 x x + 1` will assign the value `x + 1` to `x`. 110 | 111 | #### Functions 112 | Function definitions begin with `they don't want you to [name] [args]` and are closed with `🙏`. To specify the return value, use `major 🔑 [optional value]`. :key:++ does not yet support anonymous functions. 113 | 114 | An example implementation of Fibonacci is below: 115 | 116 | ``` 117 | they don't want you to fibonacci n 118 | 119 | 🔑 acc1 0 120 | 🔑 acc2 1 121 | 122 | ride wit me 123 | 🔑 temp acc2 124 | 🔑 acc2 acc2 + acc1 125 | 🔑 acc1 temp 126 | 🔑 n n - 1 127 | 128 | if n < 1: 129 | you played yourself 130 | another one 131 | 132 | major 🔑 acc1 133 | 🙏 134 | ``` 135 | 136 | 137 | #### Loops 138 | Don't play yourself. :key:++ makes it easy to write code and easy to call `another one`. All :key:++ loops are initialized with the tag `ride wit me` and default behavior is always `another one`. 139 | 140 | ``` 141 | ride wit me 142 | ... 143 | another one 144 | ``` 145 | 146 | #### Breaks 147 | To exit a loop use the command `you played yourself`. Thus we can write a traditional loop as follows: 148 | 149 | ``` 150 | ride wit me 151 | [...] 152 | if [condition]: 153 | you played yourself 154 | another one 155 | ``` 156 | 157 | #### Importing modules 158 | DJ Khaled has the best fans in the world. You can access local Python libraries via `fanluv [libname]`. 159 | 160 | 161 | ## Next Steps 162 | 163 | We're currently working on implementing struct support in :key:++. 164 | 165 | We are also working on O'Khaled, a JIT compiler for 🔑++. 166 | 167 | 168 | ## Who did this? 169 | 170 | Good question. Razi Shaban and Alec Pillsbury put this project together after a late-night brainstorming session. Hope you unlock more success 171 | 172 | ## Isn't this just a blah blah python 173 | 174 | Yeah, yeah, whatever. Another one. 175 | -------------------------------------------------------------------------------- /bin/🔑++: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | root=$(dirname -- "$0")/.. 3 | exec python3 -- "$root/src/🔑++.py" "$@" -------------------------------------------------------------------------------- /examples/fibonacci.liooooon: -------------------------------------------------------------------------------- 1 | #DJKHALED 2 | #WETHEBEST 3 | 4 | 5 | they don't want you to fibonacci n 6 | 7 | 🔑 acc1 0 8 | 🔑 acc2 1 9 | 10 | ride wit me 11 | 🔑 temp acc2 12 | 🔑 acc2 acc2 + acc1 13 | 🔑 acc1 temp 14 | 🔑 n n - 1 15 | 16 | if n < 1: 17 | you played yourself 18 | another one 19 | 20 | 21 | major 🔑 acc1 22 | 🙏 23 | 24 | 25 | # def fibonacci(n): 26 | # acc1 = 0 27 | # acc2 = 1 28 | 29 | # while True: 30 | # temp = acc2 31 | # acc2 = acc2 + acc1 32 | # acc1 = temp 33 | # n = n - 1 34 | 35 | # if n < 1: 36 | # break 37 | 38 | # return acc1 39 | 40 | 41 | # Module(body=[ 42 | # FunctionDef(name='fibonacci', 43 | # args=arguments(args=[Name(id='n', ctx=Param())], vararg=None, kwarg=None, defaults=[]), 44 | # body=[ 45 | # Assign(targets=[Name(id='acc1', ctx=Store())], value=Num(n=0)), 46 | # Assign(targets=[Name(id='acc2', ctx=Store())], value=Num(n=1)), 47 | # While( 48 | # test=Name(id='True', ctx=Load()), 49 | # body=[ 50 | # Assign(targets=[Name(id='temp', ctx=Store())], value=Name(id='acc2', ctx=Load())), 51 | # Assign(targets=[Name(id='acc2', ctx=Store())], value=BinOp(left=Name(id='acc2', ctx=Load()), op=Add(), right=Name(id='acc1', ctx=Load()))), 52 | # Assign(targets=[Name(id='acc1', ctx=Store())], value=Name(id='temp', ctx=Load())), 53 | # Assign(targets=[Name(id='n', ctx=Store())], value=BinOp(left=Name(id='n', ctx=Load()), op=Sub(), right=Num(n=1))) 54 | # ], 55 | # orelse=[]), 56 | # If( 57 | # test=Compare(left=Name(id='n', ctx=Load()), ops=[Lt()], comparators=[Num(n=1)]), 58 | # body=[Break()], 59 | # orelse=[]), 60 | # Return(value=Name(id='acc1', ctx=Load()))], decorator_list=[]) 61 | # ]) -------------------------------------------------------------------------------- /examples/fizzbuzz.liooooon: -------------------------------------------------------------------------------- 1 | #DJKHALED 2 | #WETHEBEST 3 | 4 | they don't want you to fizzbuzz max 5 | 6 | 🔑 n 0 7 | 8 | ride wit me 9 | if n % 3 == 0 and n % 5 == 0: 10 | 🔥 "FizzBuzz" 11 | elif n % 3 == 0: 12 | 🔥 "Fizz" 13 | elif n % 5 == 0: 14 | 🔥 "Buzz" 15 | else: 16 | 🔥 n 17 | 18 | if n >= max: 19 | you played yourself 20 | another one 21 | 22 | major 🔑 👍 23 | 24 | 🙏 25 | 26 | # def fizzbuzz(max): 27 | # n = 0 28 | # while True: 29 | # if n % 3 == 0 and n % 5 == 0: 30 | # print("FizzBuzz") 31 | # elif n % 3 == 0: 32 | # print("Fizz") 33 | # elif n % 5 == 0: 34 | # print("Buzz") 35 | # else: 36 | # print(n) 37 | # if n >= max: 38 | # break 39 | # n = n + 1 40 | # return True 41 | 42 | 43 | # Module(body=[ 44 | # FunctionDef(name='fizzbuzz', args=arguments(args=[Name(id='max', ctx=Param())], vararg=None, kwarg=None, defaults=[]), 45 | # body=[ 46 | # Assign(targets=[Name(id='n', ctx=Store())], value=Num(n=0)), 47 | # While(test=Name(id='True', ctx=Load()), 48 | # body=[ 49 | # If(test=BoolOp(op=And(), values=[Compare(left=BinOp(left=Name(id='n', ctx=Load()), op=Mod(), right=Num(n=3)), ops=[Eq()], comparators=[Num(n=0)]), Compare(left=BinOp(left=Name(id='n', ctx=Load()), op=Mod(), right=Num(n=5)), ops=[Eq()], comparators=[Num(n=0)])]), 50 | # body=[Print(dest=None, values=[Str(s='FizzBuzz')], nl=True)], 51 | # orelse=[ 52 | # If(test=Compare(left=BinOp(left=Name(id='n', ctx=Load()), op=Mod(), right=Num(n=3)), ops=[Eq()], comparators=[Num(n=0)]), 53 | # body=[Print(dest=None, values=[Str(s='Fizz')], nl=True)], 54 | # orelse=[ 55 | # If(test=Compare(left=BinOp(left=Name(id='n', ctx=Load()), op=Mod(), right=Num(n=5)), ops=[Eq()], comparators=[Num(n=0)]), 56 | # body=[Print(dest=None, values=[Str(s='Buzz')], nl=True)], orelse=[Print(dest=None, values=[Name(id='n', ctx=Load())], nl=True)])])]), 57 | # If(test=Compare(left=Name(id='n', ctx=Load()), ops=[GtE()], comparators=[Name(id='max', ctx=Load())]), 58 | # body=[Break()], orelse=[]), 59 | # Assign(targets=[Name(id='n', ctx=Store())], value=BinOp(left=Name(id='n', ctx=Load()), op=Add(), right=Num(n=1)))], orelse=[]), 60 | # Return(value=Name(id='True', ctx=Load()))] 61 | # , decorator_list=[] 62 | # )]) 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/hello_world.liooooon: -------------------------------------------------------------------------------- 1 | #DJKHALED 2 | #WETHEBEST 3 | 4 | 🔥 "Hello world - WE THE BEST!" -------------------------------------------------------------------------------- /examples/inspiration.liooooon: -------------------------------------------------------------------------------- 1 | #DJKHALED 2 | #WETHEBEST 3 | # 4 | # 5 | # https://codeshare.io/wzilS 6 | # 7 | # inspiration.liooooon 8 | # Some keys to success – 🔑++ implementations of fibonacci 9 | # and fizzbuzz; breakfast talk and 10 | # 11 | # 12 | fanluv math 13 | fanluv string 14 | 15 | they don't want you to fibonacci n 16 | 17 | 🔑 acc1 0 18 | 🔑 acc2 1 19 | 20 | ride wit me 21 | 🔑 temp acc2 22 | 🔑 acc2 acc2 + acc1 23 | 🔑 acc1 temp 24 | 🔑 n n - 1 25 | 26 | if n < 1: 27 | you played yourself 28 | another one 29 | 30 | major 🔑 acc1 31 | 🙏 32 | 33 | 34 | they don't want you to fizzbuzz max 35 | 36 | 🔑 n 0 37 | 38 | ride wit me 39 | if n % 3 == 0 and n % 5 == 0: 40 | 🔥 "FizzBuzz" 41 | if n % 3 == 0: 42 | 🔥 "Fizz" 43 | if n % 5 == 0: 44 | 🔥 "Buzz" 45 | else: 46 | 🔥 n 47 | 48 | if n >= max: 49 | you played yourself 50 | 51 | another one 52 | 53 | major 🔑 👍 54 | 55 | 🙏 56 | 57 | 🔥 "30th Fibonacci number: " 58 | 🔥 fibonacci vibes 30 59 | 60 | #breakfast talk 61 | # 🔑 turkey_bacon 62 | # 🔑 egg_whites 63 | # 🔑 water 64 | #you smart 65 | 66 | 67 | #🔑 to success is breakfast (turkey_bacon=👍, 68 | # egg_whites=👍, 69 | # water=👍) 70 | 71 | 72 | 73 | #🙅 no 74 | 75 | -------------------------------------------------------------------------------- /src/ast.txt: -------------------------------------------------------------------------------- 1 | ast 2 | 3 | 4 | #DJKHALED ::= boilerplate 5 | #WETHEBEST ::= boilerplate 6 | 7 | 8 | _x_ ::= import _x_ 9 | 10 | <👍> ::= True 11 | <👎> ::= False 12 | 13 | _x_ args ::= def _x_(args): 14 | 15 | 🙏 ::= end of function 16 | 17 | 18 | <🔑> _x_ _y_ ::= _x_ = _y_ 19 | 20 | 21 | 22 | _body_ 23 | if _cond_ 24 | 25 | 26 | _x_ ::= return _x_ 27 | 28 | <🔥> ::= print 29 | 30 | 31 | _x_ talk ::= struct 32 | 🔑 var 33 | you smart 34 | -------------------------------------------------------------------------------- /src/🔑++.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | # 5 | # Welcome to 🔑++, the programming language they don't want you to use. 6 | # For more information about language functionality, check out 7 | # https://github.com/rrshaban/keyplusplus 8 | # 9 | # 10 | 11 | from __future__ import print_function 12 | 13 | import sys 14 | import ast 15 | import re 16 | 17 | # These are the regular expressions that define the language. As of now, 18 | # they include multi-line regexes, which might require hacking newlines. 19 | k = { 20 | "boilerplate" : r"^#DJKHALED\n#WETHEBEST", 21 | "import" : r"fanluv (?P\w+?)\b", 22 | "def" : r"they don't want you to (?P\w*?) (?P[\w ]*)\n (?P.*?)🙏", 23 | "=" : r"🔑 (?P\w*) (?P.*)", 24 | "loops" : r"ride wit me(?P.*?)another one", 25 | "break" : r"you played yourself", 26 | "return" : r"major 🔑 (?P\w*?)", 27 | "print" : r"🔥 (?P.+)", 28 | "true" : r"(?P👍)", 29 | "false" : r"(?P👎)", 30 | "struct" : r"(?P\w*?) talk(?P.*)you smart", 31 | "fields" : r"(🔑 [\w_]*$)+", 32 | "function" : r"(?P\w+) vibes (?P[\w ]*)\n", 33 | } 34 | 35 | def replace(p): 36 | # Python for 🔑++ 37 | # TODO: structs and fields remain to be implemented 38 | 39 | subs = [ 40 | (k["true"], r"True"), 41 | (k["false"], r"False"), 42 | (k["import"], r"import \g"), 43 | (k["return"], r"return \g"), 44 | (k["="], r"\g = \g"), 45 | (k["function"], r"\g(\g)"), 46 | (k["print"], r"print(\g)"), 47 | (k["break"], r"break"), 48 | ] 49 | 50 | for pattern, replacement in subs: 51 | p = re.sub(pattern, replacement, p) 52 | 53 | p = re.sub(k["loops"], r"while True:\n \g", p, 54 | flags=re.DOTALL) 55 | p = re.sub(k["def"], r"def \g(\g):\n \g", p, 56 | flags=re.DOTALL) 57 | 58 | return p 59 | 60 | def parse_v2(program): 61 | 62 | # check for boilerplate 63 | if not re.match(k["boilerplate"], program): 64 | raise SyntaxError("You played yourself. #DJKHALED #WETHEBEST") 65 | 66 | return ast.parse(replace(program)) 67 | 68 | def main(): 69 | 70 | if len(sys.argv) < 2: 71 | raise IOError(''' 72 | Congratulations, you played yourself. You must pass the 🔑++ a file to run: 73 | 74 | e.g. 🔑++ hello.liooooon 75 | ''') 76 | 77 | try: 78 | f = open(sys.argv[1], 'r') 79 | program = f.read() 80 | exec(compile(parse_v2(program), filename="<🔑++>", mode="exec")) 81 | except IOError: 82 | print("Could not open {}. You played yourself.".format(sys.argv[1])) 83 | 84 | if __name__ == '__main__': 85 | main() 86 | 87 | --------------------------------------------------------------------------------