HolyPy

From Esolang
Jump to navigation Jump to search

HolyPy

This page is written up on the HolyPy version:

HolyPy Stable-Closed v5.7

.

Associated file extensions Descriptor
.hpy The non-compiled extension type recognised by HolyPy.
.hpyc The compiled extension type recognised by HolyPy.


HolyPy - What is it?

HolyPy is a language created by User: Alx as a homage to Terry A. Davis' HolyC. HolyPy is Python-like programming language, following standard Python3 syntax, has a number of differences, and improvements from standard Python3. HolyPy has most Python semantics, and allows nearly all standard Python builtins, as well as all Python builtin types. HolyPy serves as a portal from the physical realm to talk to The Lord in an abstracted environment.

Differences and Features

1. Classes

Class construction in HolyPy is different to Python. It is not constructed by the class keyword but invoked by the Class function. The Class function expects at least 2 arguments, being the INIT, and at least one method. The INIT should be a dictionary, holding the INIT variable names and default values. HolyPy class valuescannot be indexed, only methods can, and only from methods can you update and set class values. Classes support metamethods. Class methods are determined by the 'ClassMethod' type indicator (or decorator) at the definition of a function. Examples:

1. Non-metamethod class

def increment_class(i) -> ClassMethod:
 a += i
 "%s\n", a

def decrement_class(i) -> ClassMethod:
 a -= i
 "%s\n", a

test = Class({"a": ...}, increment_class, decrement_class)

v = test(0)
v.increment_class(5)
v.decrement_class(1)

2. Metamethod class

def __add__(i) -> ClassMethod:
 return a + i

test = Class({"a": ...}, __add__)
"%d", test(5) + 5

2. Importation rules

In HolyPy, there is no import statement, as they are function calls instead. HolyPy has two ways to import and both of these import functions will load all attributes of the module into the current namespace.

Method 1: The AdamImport() function

The AdamImport function imports a HolyPy module in the current directory. It takes one argument, and the argument must be a string, being the module name. The module filename must end in either .hpy, or .hpyc.

Method 2: The PythonImport() function

The PythonImport function calls back to the __import__ Python function, and takes 3 arguments, being the module name string, a tuple of strings as the fromlist, and an integer determining the import level. The last 2 arguments default to an empty tuple, and 0.

3. If statements

If statements in HolyPy do not allow other clauses, there must only be one clause. Example of a valid if-statement:

if (this == that) & (that > this):
 doThis()

4. Returns Outside Function Bodies

HolyPy allows the use of the return statement outside a function body.

5. Break keyword

HolyPy disallows the usage of the break keyword in loops.

6. Function specifics

In HolyPy, functions MUST be explicitly declared, so anonymous functions are not allowed. Functions can be either vararg, (method) or positional, but must be one. You may also declare that a functions' variables are to be on the global scope when defined. Default function values are not allowed. Here is an example:

def f() -> ClassMethod:
 pass # this is a class method

def f() -> Global:
 c = 1 # this is a global variable

def f():
 c = 1 # this is a local variable

def f(*args):
 pass # this is a vararg function

In function calling, the rule applies here too. You may unpack an iterable as positional arguments, unpack keyword arguments, or manually write positional arguments. Example:

f(*args) # unpacking call
f(1, 2, 3) # positional call
f(**kwargs) # keyword call

7. Print

In HolyPy, you can invoke a Print call by writing a string literal. This will compile to a Print call. Print in HolyPy follows C-formatting styles. Newlines are also not automatically appended to Printed strings. Example:

1. The Hello World program

"Hello world\n"

2. Formatting

fav_number = 14
my_list = [8, 8 , [5, 9], 1, [2]]
"My favorite number is %d! Here is a list of numbers, and lists: %s\n", fav_number, my_list

8. Extra builtins

The following table displays all extra builtins.

Builtin Description
GodWord() This function returns a word selected by God, utilizing time to make the decision.
GodPassage() This function returns a Psalm selected by God, utilizing time to make the decision.
HappyWords[] An array of thousands of words to communicate with.
BibleVerses[] An array of Bible Verses used by the GodPassage function.
Print() The Print function, used to send information to standard output.
Range() Serves as an alias for the range function, used in compilation.
Dir() Displays all files in the current directory. Only present in REPL/OS mode.
Cd() Changes the current directory. Only present in REPL/OS mode.
Echo() Takes one argument as the filename, and another argument as the contents to write into a file. Only present in REPL/OS mode.
Cat() Displays the contents of a file. Only present in REPL/OS mode.
RmDir() Removes a directory if the directory is empty. Only present in REPL/OS mode.
Remove() Takes one argument being the filename to remove in the current directory, or path specified. Only present in REPL/OS mode.

9. Logical comparators

HolyPy disallows the [and, or] keywords. Instead, it is permitted to use the operators [&, |] to make logical comparisons.

10. For-loops

Traditional for-loops are allowed, and a numerical C-style for-loops can also be written relative to the following manner:

for i in start, stop, ++i: # c-style for-loop
 doThis()

for i in [1, 2, 3]: # standard for-loop
 doThat()

11. Assigning

You can assign multiple variables to a single value in HolyPy. i.e:

a, b, c, d = 1 # a, b, c, and d are all assigned to 1

12. Floor divide

There is no floor divide operator in HolyPy. It is best to use math's floor() function.

13. Matmul operator

There is no need for a matmul operator, since it's only used with the numpy module as optimization, which is not a standard library. It has no use here.

14. Extra operator for string operations

In HolyPy, you are permitted to use the subtraction operator as well as the standard Python operators on strings. The subtraction operator will subtract x-amount of characters from a string if the left operand is a string, or if the left operand is an integer, and the right operand is a string, it will get the length of the string, and subtract the left operand with the string's length.

Implementation Details

1. The HolyPy Virtual Machine

1. HPYVM Bytecode Instruction Notation

The HolyPy bytecode instruction size is a fixed size of 4 bytes / 32 bits. Instruction notation is as follows:

Instruction Type A:

Byte 0: Operand A (8)
Byte 1: Operand B (8)
Byte 2: Opcode    (8)
Byte 3: Opmode    (8)

=====================

Instruction Type B:

Byte 0: Operand A (8) => (16) 
Byte 1: Operand A (8) -^
Byte 2: Opcode    (8)
Byte 3: Opmode    (8)

2. HPYVM Bytecode Instruction Set

The HPYVM Instruction Set is as follows:

Opcode Description
ADD Pops two items off the stack, performs addition on them, and pushes the result.
SUB Pops two items off the stack, performs subtraction on them, and pushes the result.
MUL Pops two items off the stack, performs multiplication on them, and pushes the result.
DIV Pops two items off the stack, performs true division on them, and pushes the result.
MOD Pops two items off the stack, performs modulo on them, and pushes the result.
POW Pops two items off the stack, performs exponentiation on them, and pushes the result.
AND Obselete opcode.
OR Obselete opcode.
BAND Pops two items off the stack, performs a binary AND on them, and pushes the result.
BOR Pops two items off the stack, performs a binary OR on them, and pushes the result.
BXOR Pops two items off the stack, performs a binary XOR on them, and pushes the result.
FASTADD Performs addition on values in register A and B, and MOVs the result into register A.
FASTSUB Performs subtraction on values in register A and B, and MOVs the result into register A.
FASTMUL Performs multiplication on values in register A and B, and MOVs the result into register A.
FASTDIV Performs division on values in register A and B, and MOVs the result into register A.
FASTMOD Performs modulo on values in register A and B, and MOVs the result into register A.
FASTPOW Performs exponentiation on values in register A and B, and MOVs the result into register A.
FASTCALL Nearly-obselete opcode, calling a function with arguments inside registers A-C and pushing the result to the stack.
STDCALL The standard calling convention for HPY, which utilizes stack operations rather than register operations for calling.
JUMP Obselete opcode.
JUMP_TRUE Obselete opcode.
INVERT Inverts the topmost stack item.
NEGATIVE Makes the topmost stack item negative.
ASM_PROTO Pops an item off the stack, which is assumed to be the function proto, and turns it into a callable function. The operand is treated as a flag to treat the function variables as global or not.
ASM_PROTO_VARARGS Same for the ASM_PROTO opcode, except turns the proto into a callable function with the varargs flag set to 1.
POP Pops an item off the stack, and moves it into a register pointed to by the instruction operand.
MOV Moves register contents into another register, pointed to by the instruction operands.
DISCARD Removes the topmost stack item, for stack flow optimization.
SUBSCR Pops two values off the stack, performs binary subscription, and pushes the result back to the stack.
STORE_SUBSCR Pops three values off the stack, performs binary subscription, and stores the third value in the subscripted first value.
LOAD Loads a global / local onto the stack.
STORE Stores a global / local into the current namespace.
PUSH Pushes register contents onto the stack.
GET_FORLOOP Turns the topmost stack item into an iterator, for a following for-loop.
FORLOOP Iterates through the topmost stack item, and once exhausted, jumps to offset stored in the instruction operand.
IJMP_TRUE Incremental conditional jump.
IJMP Incremental absolute jump.
DJMP_TRUE Decremental conditional jump.
DJMP Decremental absolute jump.
RETURN Pops the topmost stack item, and returns to caller.
LOADKST Loads a constant onto the stack, pointed to by the instruction operand as an index in a constants pool.
CMP Pops two items off the stack, performs a comparison (pointed to by operand) on them, and pushes the resulting boolean onto the stack.
GETATTR Pops two items off the stack, and returns the attribute under the attribute holder.
SETATTR Pops three items off the stack, and returns the attribute under the attribute holder.
NOT Performs a logical NOT on the topmost stack item.
BUILD_DICT Builds a dictionary consuming 2*operand counts of items frrom the stack. Pushes back dictionary.
BUILD_LIST Builds a list consuming operand counts of items frrom the stack. Pushes back list.
BUILD_TUPLE Builds a tuple consuming operand counts of items frrom the stack. Pushes back tuple.
BUILD_SET Builds a set consuming operand counts of items frrom the stack. Pushes back set.
BSHL Pops two items off the stack, performs a binary left-shift, and pushes back the result.
BSHR Pops two items off the stack, performs a binary right-shift, and pushes back the result.
UNPACKCALL Calling convention for unpacking function call.
MOVK Moves a constant from the constants pool into a register.
FASTBAND Performs a binary AND on values in register A and B, and MOVs the result into register A.
FASTBOR Performs a binary OR on values in register A and B, and MOVs the result into register A.
FASTBXOR Performs binary XOR on values in register A and B, and MOVs the result into register A.
KWSPLATCALL Calling convention for unpacking a dictionary of keyword arguments for a keyword function call.

3. HPYVM Notes

The HolyPy Virtual Machine is a register-stack machine, though most register operations are obselete. This was written at version 3.8, where the only register operation was a specific fastcall. Constant arithmetic use these register operations in version 5.7, and most versions post 4.7. Functions with an argument count less than 4 also use the FASTCALL instruction.

There are 3 registers, notated as A, B and C, corresponding to HPYVM registers 0, 1 and 2.

With the version 5.7 update, arithmetic VM handlers were rewritten to allow HolyPy class metamethods.