Holy Java is a programming language made by me. It's similar to Java, but it can be run without a VM and is run within a wrapper application. It's mainly just a hobby project but it can be used to create some cool stuff.
Installation
Step 1: Download the Setup Installer Right Here (For now, Windows only) -
Holy Java Editor (This documentation is not done yet, reach out to me for help)
<
>
Prior knowledge of other languages would be beneficial here but not necessary.
Variables 101
Holy Java supports 4 primitive types: Strings, Floats, Integers and Booleans. Variables, regardless of their type, store data. Variables can be accessed by the name they are given upon creation. Along with their name, they can also be provided a value. This value can change throughout the applications lifetime, but sometimes the variable can go out of scope, and therefore can no longer be accessed. Variable names can begin with any letter or an at symbol. But can contain any character beyond the first.
Examples (This applies to all types): Creation: int a; (No value). Or int a = 7; (With value). Or int a = 7; int b = a; (Integer 'a' was defined and integer 'b' was given the value of variable 'a'). Reassigning: a = 9; (Can only be done once the variable has been created).
Variables - Strings
First up are strings. Strings are representations of text and they can be defined as such: string myString = "a random message"; Strings, like every other type, can be assigned to another string variable, provided that it has a value.
Variables - Integers
Integers are variables that hold 32 bit numeric values (32 bytes long. This means it is possible for an error to be thrown if the number is too long). These values, however, must be whole numbers. These can be created like the other types, but they begin with int (short for integer).
Variables - Floats
Floats (comes from the term "floating point"), very similarly to integers, hold numeric values. But unlike an integer, these values can be (not required to be) a decimal. They're created as such: float myFloat = 4.3454365456437245737357756869452453;
variables - Booleans
Booleans are perhaps the simplest primitive type. They contain two states: True, or False. boolmyBool = true; bool other = false;
Function Declarations
Functions (can also be referred to as methods) can be complicated but are very simple once understood. A function contains 4 main parts. They are: the Name, the Arguments, the Return Type, and the Block. ----------------------------------------------------------------------------------- The Name The Name is used in the same as in variables. ----------------------------------------------------------------------------------- The Arguments The Arguments are a group of variables that can be used inside the function. They cannot be defined in the declaration of the function, but instead they're set when the function is called. You can define as many arguments as needed (More on this later). ----------------------------------------------------------------------------------- The Return Type The Return Type is one of the 4 primitive types and this is used to set the type that the function may return (A return type is not necessary in every function). The return type also has a relative called the return value. The return value is what is returned and its type must match the return value. It is set at the end of the function as such: return 6; (Or any other value) ----------------------------------------------------------------------------------- The Block The Block is all of the code that runs when the function is called. The arguments defined can be used here but nowhere else. ----------------------------------------------------------------------------------- Example: Name Arguments Return Type func MyFunction(int age, string name) -> bool { return true; }
Calling a Function
Without function calls, functions would be useless. Function calls are used to run the code found inside the block of the function. A function is called as such: ----------------------------------------------------------------------------------- MyFunction(10, "Andrew"); Name Arguments ----------------------------------------------------------------------------------- The name must match the name as defined in the function declaration. And each argument passed in must match the type as defined, in the same order. The number of arguments passed in cannot exceed the amount defined. Each argument that was defined will then be set to the value that is passed in, and then the function block will run. If the function has a return value then calling that function may be used as an expression or a value. int ----------------------------------------------------------------------------------- There is only one built in function at the moment which is the Printf function. This is used to print a value to the screen. It does not return anything but its input can be any primitive type.
If statements
If statements are a very useful part of the language. They contain a block, just like a function does, but this block will only be executed if a certain condition is true. If statements can be used a such: ----------------------------------------------------------------------------------- if (11 > 10) {
} ----------------------------------------------------------------------------------- The above block will only run if 11 > 10 (which it is). The condition can be a wide range of things, as long as they end up in an either true or false output. If comparing two integers it would look like this: int a = 6; int b = a; ----------------------------------------------------------------------------------- if (a == b) { Printf("Yes"); } ----------------------------------------------------------------------------------- Notice the use of 2 equals signs. This is also the case for a few of the other comparison operators. They are: == > >= < <= != (This one returns true if the two values are not equal) ----------------------------------------------------------------------------------- Along with the if statement, there are also two other statements. They are the else statement and the else if statement. Else if statements are defined the exact same way as if statements, but they must follow an existing if statement and will only be checked if the if statement is false. You can have any number of them but they are checked in order until one works (or it runs out of them). else statements immediately follow either an if statement or an else if statement. There can only be one of them and it is run if everything above it fails. ----------------------------------------------------------------------------------- Example: if (12 != 4.6) { Printf("Weird"); } else if (12 == 12) { Printf(65467455457856); } else { Printf("All else failed"); }
Loops 101
There are 2 types of loops in Holy Java. They are: While loops and For Loops. Each loop has different parameters as to how many times it will run, but each loop contains a block that will execute.
For Loops
For loops have a bit of a weird syntax, but they are very useful. They are defined as such: ----------------------------------------------------------------------------- Run this and see what happens. for (int i = 0; i < 10; i++) { Printf(i); } ----------------------------------------------------------------------------------- As you could see in the example above, a for loop creates a variable that is set to a value and that can be used within the for loop. The second part of it is i < 10 (can be changed). This is the parameter that is checked before running the block. The third part is i++ (can be changed). This expression will be run at the end of every block cycle. The ++ part just means that the variable 'i' is incremented by 1.
While Loops
While loops are much simpler and have only two parts. The condition and the block. The condition is checked before each cycle and if it is true the block is executed. Unlike the for loop, the while loop does not create a variable that can be used inside the loop. But this can be added by just creating a variable outside and incrementing it each time. ----------------------------------------------------------------------------------- while (10 == 10) { Printf("THIS WILL RUN FOREVER!") } -----------------------------------------------------------------------------------
Classes
Classes are large structures that can be used to house different variables, functions and arrays. They are defined as such: ----------------------------------------------------------------------------------- class MyClass { string name2 = "fewihf";
func Funcg() -> string { return "Yes"; } }
MyClass myClass; Printf(myClass.Funcg()); ----------------------------------------------------------------------------------- A lot is happening in there but just think about it as the class holding everything and then you can call individual parts and access them. Before a class can be accessed, it must be instantiated by creating an instance of it. The line: MyClass myClass; Creates a variable with the name myClass that now refers to MyClass when it is called. It can now be used to access the items inside of the class. You may create as many instances of the same class as necessary, and they will all have their own respective values. ------------------------------------------------------------------ Advanced Classes While classes are plenty useful when used as shown above, there are also more advanced ways to use them. The first topic is on constructors. Constructors are similar to functions but are exclusive to classes. There can only be one. ---------------------------------------------------------------------------------- class MyClass { string name; MyClass(string param) { name = param; } } ---------------------------------------------------------------------------------- Notice how the name of the constructor matches the name of the class. This is mandatory. Constructors do not start with 'func', but besides that, they are identical to functions. They are called when the class is instantiated. The next topic is on static classes. Static classes are purely data classes and cannot be instantiated. All values within a static will be global to everyone in the file and will not need be instantiated in order to access any values within. ---------------------------------------------------------------------------------- static class MyStaticClass { string name = "Yes"; }
Printf(MyStaticClass.name); // The output would be 'Yes'. ----------------------------------------------------------------------------------
OOP - Inheritance
This is a continuation of classes as they are what inheritance applies to. Inheritance is the ability for class to have child classes that inherit and take values from the parent. For a class to be inherited from, it must be marked as abstract (Abstract classes can inherit from other abstract classes). Further classes can then inherit or 'extend' them. This gives the class all the values that the parent had. As many classes as need can extend the same parent, but a class can only extend one other class. Functions can act a bit different, if you wish. They, like classes, can be abstract (only in an abstract class). This removes their ability to have a block, but it allows all child classes that extend it to provide their own implementation of that function. Similar to abstract functions are virtual functions. Virtual functions are virtually the same, but they can have a default block. This block will be called if no other override is provided. ---------------------------------------------------------------------------------- abstract class MyAbstractClass { int age = 104;
abstract func MyFunc(); }
class MyClass extends MyAbstractClass { override func MyFunc() { Do Stuff } }
MyClass myClass; myClass.MyFunc(); ---------------------------------------------------------------------------------- When overriding a function, the override must match the definition of the function exactly. Same name, same arguments.
Arrays
Arrays are a data type that can hold a bunch of a single data type. They are created as such: ----------------------------------------------------------------------------------- Type Name Type Size string names = string[2]; Name Index Value names[0] = "Jimmy"; names[1] = "Andrew"; Printf(names[0]); Printf(names[1]); ----------------------------------------------------------------------------------- Arrays have a set size and you cannot set or get any values over that original size. To set a value in the array, type the name of the array and in braces type the index (All arrays start on 0). Then set the value. The value should match the array type. You can then get a value by typing the name and then the index in braces. Arrays in this sense are ordered.
Importing other holy java files
A language would be severely limited if not for the ability to separate a codebase across different files. Holy Java supports this, but in a slightly different way. The entry point to your application (Default: "Main.hjm") is run as the first script. There can be at most one Holy Java Main (.hjm) file. Any other Holy Java files must have the extension ".hj". Holy Java Main files act exactly the same as Holy Java files, except for the fact that they contain the lifecycle of your application. In other words, Holy Java files can import other Holy Java files, as well as the Holy Java Main file. And the Holy Java Main file can import other Holy Java Files. You import a file as such: ---------------------------------------------------------------------------------- include "PATH TO FILE" as file Printf(file::name); ---------------------------------------------------------------------------------- When including a file, you gain access to every value in the file. You also gain the option of importing the file into a namespace, or just importing the file into your file. The former will import the file into the specified namespace and then value can be accessed by typing the namespace, followed by double colons, and finally the name of the value. The ladder is a bit more dangerous as naming conflicts can arise. To solve this, you are able to prefix your include statement with either a '!' (Override all of your implementations with the same name with the ones from the namespace) or the '#' (Skip all implementations of the same name and keep your original implementations). Neither is required, but an error will be thrown if a naming conflict arises when not importing into a namespace.