It's official. Keg is now a transpiled language, as interpreting it was just too hard. Here is a guide of how everything now works
graph TB
First[Preprocessor] --> Second
Second[Uncompressor] --> Third
Third[Parser] --> Fourth
Fourth[Translator] --> Fifth
Fifth[Execution] --> Output
Characters in the range of a-z
and A-Z
will be pushed as so:
letter()
As such, the program ABC
would be transpiled as:
A(); B(); C()
And Hello World
would become:
H(); e(); l(); l(); o(); space(); W(); o(); r(); l(); d()
This allows for letters to be redefined as macros if that makes sense. (More on that later)
Numbers in the range of 0-9
would follow as such:
0: zero()
1: one()
2: two()
3: three()
4: four()
5: five()
6: six()
7: seven()
8: eight()
9: nine()
Thenceforth, 89
would become:
eight(); nine()
Quite simple really:
+: add(stack.pop(), stack.pop())
-: minus(stack.pop(), stack.pop())
*: times(stack.pop(), stack.pop())
/: divide(stack.pop(), stack.pop())
%: modulo(stack.pop(), stack.pop())
I'mma start using a new way of writing these. All functions assume the parameters stack.pop(), stack.pop()
=: eq()
≠: nq()
>: gt()
<: lt()
≥: ge()
≤: le()
≬: g0()
These functions don't assume any parameters
!: length()
$: swap()
^: reverse()
:: duplicate()
": r_shift()
': l_shift()
,: nice()
.: raw()
?: _input()
~: random()
_: stack.pop()
Unlike all prior sections, this section shan't be so brief. Why? Because the humble [...|...]
isn't just a function you see.
The general form will become:
if bool(stack.pop):
...
else:
...
But what if there is only one section? (i.e. [...]
)
if bool(stack.pop()):
...
But what if there is an empty ifTrue
section but a filled ifFalse
section? (i.e. [|...]
)
if bool(stack.pop()):
pass
else:
...
Although maybe this is more appropriate:
if not bool(stack.pop()):
...
I mean, really, the only person bothering with this is those making transpilers.
These are a bit harder, as, well, Keg loops are a little different. Given the normal counted loop (no vars, integer as condition):
for _ in _loop_eval(stack.pop())
...
It is important to note that _loop_eval()
is defined as such:
def _loop_eval(expr):
if type(expr) in [int, chr]:
return range(expr)
else:
return expr
But what if there are three parts? (i.e. (count|var|code)
)
for var in _loop_eval(count):
code
But what if there isn't a loop condition?
length()
for _ in _loop_eval(stack.pop()):
...
While loops are pretty similar to for loops, but easier in a way:
while bool(stack.pop()):
...
But what if it is a post-test loop? (i.e. {...|P|...}
)
condition = True
while condition:
...
condition = bool(stack.pop())
The function @name n|...ƒ
turns into:
def name(stack):
temp = Stack()
for _ in range(n): temp.push(stack.pop())
...
for item in temp:
stack.push(item)
The function @name *|...ƒ
gets turned into:
def name(stack):
...
The function @name _|...ƒ
gets turned into:
def name(stack):
field = stack.pop()
if type(field) in [int, float]:
n = int(field)
elif type(field) is str and len(field) == 1:
n = _chr(field)
else:
n = len(field)
temp = Stack()
for _ in range(n):
temp.push(stack.pop())
...
for item in temp:
stack.push(item)
Escaping characters is an interesting problem:
stack.push("character")
or perhaps
escape(CHARACTER)
Comments aren't included in the transpiled program
Hmm. The register. Toggled with &
, it will be turned into:
register()
iota(stack)
sine(stack)
decrement(stack)
stack.push(_eval(_input()))
preprocesses as usual
Pop a
, b
and c
and generate a range from a
to b - 1
and return if c
is in that range.
def excl_range(stack):
query = stack.pop()
values = [stack.pop(), stack.pop()]
start, stop = sorted(values)
range_object = range(start, stop)
if query in range_object:
stack.push(1)
else:
stack.push(0)
Pop a
, b
and c
and generate a range from a
to b
and return if c
is in that range.
def incl_range(stack):
query = stack.pop()
values = [stack.pop(), stack.pop()]
start, stop = sorted(values)
range_object = range(start, stop + 1)
if query in range_object:
stack.push(1)
else:
stack.push(0)
Pop a
and b
and generate a smart, inclusive range:
def smart_range(stack):
values = [stack.pop(), stack.pop()]
start, stop = sorted(values)
range_object = range(start, stop + 1)
for item in range_object:
stack.push(item)
This is an interesting one, as it requires type checking: nonetheless, here is what it probably transpile to:
def item_split(stack):
item = stack.pop()
_type = type(item)
if _type is int:
for number in str(item):
stack.push(int(item))
elif _type is str and len(item) == 1:
for number in str(_ord(item)):
stack.push(int(item))
else:
for value in item:
stack.push(value)
def factorial(stack):
number = stack.pop()
import math
try:
result = math.factorial(number)
except Exception as e:
result = "" #A whole lot of who knows what?
stack.push(result)
def empty(stack):
stack.clear()
#Yes, it really is that simple.
def print_all(stack):
for item in stack:
print(item)
Now, for the big guns: it's Keg+ time! This stuff isn't exactly defined yet, so this is new even for me. This is coming out soon, but I figured I might as well incorporate it into here right now.
So I guess each section will have the transpiled code and then a little description of what in the actual fr*ck everything does.
Includes characters in the range of ȦƁƇƉƐƑƓǶȊȷǨȽƜƝǪǷɊƦȘȚȔƲɅƛƳƵ
Pushes the specified letter to the stack and immediately prints it -- really helpful for those pesky restricted source challenges!
print(character)
Yes. It really is that easy.
The ‡
keyword is the new integer scanning operator, meaning that it will read through the code until a non-integer/decimal character is found. This is more a pre-processing command, but will be transpiled as so:
def integer(stack, number):
stack.push(number)
The commands ℤℝ⅍℠
(int, float, list and str respectively) all transpile as such:
def convert(stack, _type):
item = stack.pop()
try:
item = _type(item)
except:
pass
stack.push(item)
The commands ⟰⟱⟷
represent uppercase, lowercase and switch case respectively:
def case_switch(stack, how):
string = stack.pop()
if type(string) is not string:
stack.push(string)
return
if how == "upper":
stack.push(string.upper())
elif how == "lower":
stack.push(string.lower())
else:
stack.push(string.swapcase())
²
is probably found in most golfing languages, and it will square the top of the stack.
def square(stack):
item = stack.pop()
stack.push(times(item, item))
᠀
will take input as a string, ready to be casted as anything it needs to be casted as:
def string_input(stack):
stack.push(input())
∀
returns 1
if all items on the big stack are "true"
def all_true(stack):
if all(stack):
stack.push(1)
else:
stack.push(0)
≌
pushes 1
if everything is the same (no popping)
def all_equal(stack):
equal = 1
last = None
for item in stack:
if last is None:
last = item
continue
else:
if item != last:
equal = 0
break
stack.push(equal)
⅀
does this
def summate(stack):
for item in stack:
stack.push(add(stack.pop(), stack.pop()))
Written with StackEdit.