(Current) Version : 1.0.2
(Beta) Version : 2.0.0-beta.2
This esolang of mine is still in development, so expect alot of updates.
This is for the most part supposed to be a functional programming language.
To setup, see Install.md To run, see CLI.md
For a list of global variables and functions, see Globals.md
Jaiva files end in the .jiv
or .jaiva
or .jva
extension.
-
Get and Install (at least) Java 21 yeah this isn't a good start 💀 but this shit is amde in java so ye man. Download and install the latest JDK 21
-
Set Up Jaiva as a Global Command
Follow the instructions in Install.md to configure Jaiva so you can run thejaiva
command from anywhere on your system. -
CLI The basic command to run your file is
jaiva <filePath>
but CLI.md exists.
- Jaiva!
It's simple really, to start off with:
All lines (unless block open and close) must end in an exclamation mark. because why aren't you screaming your code.
maak a <- 10!
Single line comments start with an @
@ single line comment
And multi line comments open and close with the {
}
{
wus good shawty
- stfu
}
If you're using something like vscode and would like to document your variables or functions, you can use the following syntax
@* My lovely variable.
maak a <- 10!
<-
Is the basic assignment operator in this language. Any assignment you do is with this.
Accept for arrays, thats specifically <-|
(See Arrays)
And also for throwing errors, thats <==
(See Throw an error)
In terms of actual types, Jaiva doesnt have type syntax like Java or Typescript. This is a loosely typed language. However some functions do error when you do not provide the correct type, so keep that in mind.
This is just any integer or real number
They don't need any special format, you can just type the number out to use it
maak b <- 10!
maak c <- 9.321!
(also scientific notation is supported)
maak b <- 1e4! @ This gets parsed as 10000
even binary, hex and octal notation is supported! (it always gets parsed as an integer)
maak c <- 0b1010 @ Integer 10 in binary
maak d <- 0xA @ Integer 10 in hexadecimal
maak e <- 0c12 @ Integer 10 in Octal
true
and false
are supported, but so are aowa
(maps to false) and yebo
(maps to true). because come on now this is just cool.
They don't need any special format, you can just type the bool out to use it
maak b <- aowa!
Strings, stolen striaght from Java use "
(double quotes) to start and end a string.
These are the only characters for strings. No string literals or multi line strings because wtf dawg.
maak b <- "String"!
To get the length of a string use the ~
operator
maak b <- "let's gooo"!
khuluma(b~)! @ returns 10
-
Concatenation
"a" + "string"
returns"astring"
1 + "string"
returns"1string"
"string" + 1
returns"string1"
-
Substring (first occurance)
"string" - "tri"
returns"sing"
(removes the first occuramce of rhs from the lhs. Sometimes this dont work tho lol.)"string" - 2
returns"stri"
2 - "string"
returns"ring"
-
Multiplication
"String" * 3
returns"StringStringString"
-
Substring (all occurances)
"remove all es please" / "e"
returns"rmov all s plas"
(removes ALL occurences of rhs from the lhs. Sometimes this dont work too lol.)"Hello ong World" / 2
returns"Hello o"
(returns the substring in the range [0, (lhs' length)/rhs) )4 / "Hello ong World"
returns"lo ong World"
(returns the substring in the range [(rhs' length)/lhs, rhs.length-1) )And of course, you can compare strings to each other using
=
and!=
-
Contains
"string" ? "tri"
returnstrue
(checks if the left-hand string contains the right-hand string)"string" ? "xyz"
returnsfalse
To escape characters in a string use the $
symbol.
maak b <- "String$n"!
Table of escape characters
character | escape sequence |
---|---|
= |
$= |
, |
$, |
! |
$! |
@ |
$@ |
\n (new line) |
$n |
\t (tab) |
$t |
\r (carriage return) |
$r |
\b (backspace) |
$b |
\f (form feed) |
$f |
" (double qoutes) |
$" |
$ |
$$ |
This is a constant and value which is used to represent nothingness.
maak a <- idk! @ Using idk as a value
maak b! @ Creating a variable with no value assigns idk to it
maak c <- 10!
khuluma(a = idk)! @ true
khuluma(b = idk)! @ true
khuluma(c != idk)! @ true
kwenza func(t?) ->
khutla t!
<-
khuluma(func())! @ Prints idk, as the parameter t did not get a value.
Note
In the case of passing idk
into a function call, unless the paramter is marked as optional, you cannot pass idk
into a required parameter.
operation | operator |
---|---|
modulu | % |
power | ^ |
division | / |
multiplication | * |
addition | + |
subtraction | - |
unary minus | - |
is equal to (not double equals) | = |
is not equal to | != |
greater than (and equal to) | > >= |
less than (and equal to) | < <= |
logical AND | && |
logical OR | || |
Logical NOT (Negation) | ' |
bitwise AND | & |
bitwise OR | | |
braces for ordering | ( ) |
bitshift left | << |
bitshift right | >> |
hexshift left | <x |
hexshift right | >x |
Note
Where other languages use !
as logical NOT as a prefix to the expression. Jaiva uses '
as a logical NOT as a post
fix expression. Where a normal language would right !(var != 3)
in Jaiva the equivalent is (var != 3)'
All Operations follow this exact order:
- Exponentiation (Highest precedence)
- Division, Multiplcation, Modulo
- Addition, Subtraction
- Bit/Hex Shifts
- Bitwise Operators
- Comparisons
- Logical Operators (Lowest precedence)
Use (
braces)
to change the order however you wish.
Blocks are defined by the ->
and <~
symbols. The ->
symbol opens a block, and the <~
symbol closes it.
I think this is where jaiva deviates from normal programming languages, Especially since your usual {
}
is reserved for comments.
Note
You can have multiple blocks in a single line, but this is not recommended. It makes the code hard to read. (And i dont think i implemented or tested that case, ur crazy if u think im finna allow that )
Note
You can only have a block after like, an if, or a function and whatever, you cant just open an new arbitrary block in the middle of your code. This is a design choice, and i think it makes sense.
if (a = 10) ->
@ inner code
<~
In Jaiva you have array indexing with []
(See Arrays) and function calling with ()
(See Functions)
Naturally, you can make some code like this:
kwenza returnArray() ->
maak arr <-| 10, 39, returnArray, 4! @ Creates an array with values and at index 2, contains a reference to itself.
khutla arr!
<~
Instead of assigning each value returned to a variable, you can chain array indexing and function calls together, multiple times, in any order or any fashion
returnArray()[1]! @ holds 39
returnArray()[1 + 1]! @ ([1+1] becomes [2]) holds the referencing to itself, allowing it to call itself.
returnArray()[-1 + 3]()! @ ([-1+3] becomes [2]) returns the same array.
returnArray()[2]()[4/2]! @ ([4/2] becomes [2]) holds the exact same reference to itself, allowing infinite calls to itself
@ holds the exact same reference, every time.
returnArray()[2]()[2]()[2]()[2]()[2]()[2]()[2]()[2]!
One of my favourite examples is the infinity function
kwenza infinity() ->
khutla infinity!
<~
infinity()! @ Returns itself
infinity()()()()! @ Returns itself
infinity()()()()()()()()()()()()()()()()()()()()()()! @ Still returns itself.
Jaiva's Interpreter however will take a while to resolve this mess of code when the chaining gets absurdly long. But if you give it time it will work.
Alot of the keywords refer to words from South African languages, so if you happen to know one, you've got the advantage here's a cheat table though
keyword | meaning | use in jaiva | language origin | reference |
---|---|---|---|---|
maak | "make" | variable declaration keyword | Afrikaans | Variables |
aowa | "no" | false |
Sepedi | Bools |
yebo | "yes" | true |
Zulu | Bools |
if | - | conditional execution keyword | English | If Statements |
mara | "but" | keyword to start an else block |
Sesotho | Mara (else) |
kwenza | "does" | function definition keyword | Zulu | Functions |
khutla | "return" | function return keyword | Zulu | Functions |
colonize | - | loop constructs (for loop and for-each loop) | English | Colonize loops |
nikhil | - | while loop keyword | it's a name, not sure | Colonize loops |
zama zama | "try" | try block | Zulu (informal?) | Errror Handling |
cima | "turn off" | keyword to throw an error | Zulu | Throw an error |
chaai | "oh no" (subjective meaning) | catch block | lowkey dont know | Error Handling |
voetsek | "fuck off" | break keyword |
Afrikaans | Control flow |
nevermind | - | continue keyword |
English | Control flow |
with | - | keyword used to define for each loop along with colonize | English | Colonize loops |
tsea | "take" | keyword to import symbols from another file | Sepedi | Tsea |
idk | - | This is a special keyword, as it also acts as a value. (null) | English | idk |
however | - | (else keyword in a ternary) |
English | Ternary ifs |
Variables are scoped constructs.
See Globals for a list of global variables that are available to you.
maak (variable name) <- (value)!
Simple asf
maak a <- 20! @ number
maak var1 <- "string"! @ string
maak var5 <- aowa! @ boolean
maak f! @ define without a value.
Also a neat feature, since only a specifc set of chars are reserved, this allows for some weird variable names that is allowed.
Statement | Variable Name |
---|---|
maak a b <- 10! |
a b |
maak a b <- 100! (diferent from above) |
a b |
maak #b... <- 20! |
#b... |
maak \ <- 10! |
\ |
And more crazy combos you can come up with. if it doesnt result in a generic Java error, it's probably valid. Go wild.
maak a <- 20!
maak b <- 10!
maak c <- a + b! @ 30
maak a <- 20!
a <- 10!
a <- "string"!
You can reassign any type really. This shit aint type safe.
Arrays are 0-indexed. This isn't Lua afterall
Array literals do not exist. Sorry not sorry.
maak a <-| 20, 23, 56, 324, 354!
maak b <-|! @ Empty array.
Yknow. Then you can access elements of the array using the []
operator.
maak a <-| 20, 23, 56, 324, 354!
maak b <- a[0]! @ 20
To get the length of an array use the ~
operator.
maak a <-| 10, 23, 984!
khuluma(a~)! @ returns 3
Functions are scoped constructs.
See Globals for a list of global functions that are available to you.
Functions are defined using the kwenza
keyword, and return values using the khutla
keyword.
kwenza addition(param1, param2) ->
khutla (param1 + param2)!
<~
Just like any other language, you can call a function by just using the name of the function and passing in the parameters.
maak a <- 10!
maak b <- 20!
maak c <- addition(a, b)! @ 30
@ or
maak c <- addition(10, 20)! @ 30
Function parameters can take any type of variable, including arrays and other functions.
You can reference a function by excluding the parameter braces.
khuluma(additon)! @ This will print to the console, the function's defintion. So "addition(param1, param2)"
And you can pass this reference as a value anywhere you want really
(See Higher-Order Functions for passing function references in other functions)
maak new <- addition! @ This will mkae the variable new hold the reference to the function addition
khuluma(new(10, 10))! @ Now new can be used as a function, and will act exactly like addition
khuluma(new)! @ Printing new will give you the original function's declaration so "addition(param1, param2)"
And some more funky examples
kwenza anotherFunc() ->
khutla 10!
<-
maak t <- anotherFunc! @ This assigns t, the reference to anotherFunc
anotherFunc <- khuluma! @ This reassigns anotherFunc as a reference to khuluma
khuluma(t)! @ Print "anotherFunc()"
khuluma(t())! @ Prints 10
khuluma(anotherFunc) @ Prints "khuluma(msg, removeNewLn?)"
anotherFunc("hello")! @ Prints "hello" (Since this is just khuluma.)
In the case wehere you want to pass a function into another function, you will have to input F~
to the name of the parameter to explicity tell the interpreter that the shi u finna input should be treated as a function.
V~
is available for variables, but its not needed as without this typing, its always assumed to be a variable
kwenza function(F~ref) ->
khutla ref()!
<~
kwenza returnNum() ->
khutla 100!
<~
khuluma(function(returnNum))! @ prints 10
be careful when you start doing this though as when you start calling and chaining these, you loose variables in scopes since it doesnt know an shi.
In the case where you need certain arguments to be optional, stolen straight from typescript, all you gotta do is suffix the parameter name with ?
then it will not be required when calling the function.
kwenza function(param?) ->
khuluma(param = idk)! @ When a parameter is optional and it is not given,
@ It will be set to the type idk
<~
function()! @ prints true
function(10)! @ prints false
Warning
When a parameter is required, it CANNOT be set to idk or be empty in the parameters list of the function call. That's the whole point of a required parameter, that it is a value.
For if statements, if
is the keyword, and mara
is the else statement.
if (condition) ->
@ block to execute.
<~
maak variable <- 10!
if (variable != 100) ->
khuluma("Variable isn't 100")!
<~
if (condition) ->
@ block to execute
<~ mara ->
@ block to execute if the condition is false
<~
if (variable != 100) ->
khuluma("Variable is not 100")!
<~ mara ->
khuluma("It's 10")!
<~
Note
Other languages allow you to put a variable as a the condition to check for truthiness. We don't allow that here, check it against true or idk
Warning
You cannot put the mara keyword underneath the end of an if block, it HAS to be on the same line as the closing <~
symbol. This makes it easier for me lol.
if (condition) ->
@ block to execute
<~ mara if (condition) ->
@ another block.
<~
maak variable <- 10!
if (variable != 100) ->
khuluma("Variable is not 100")!
<~ mara if (variable = 10) ->
khuluma("Variable is 10")!
<~
You can chain as many mara if statements as you want, but this is not recommended. (It makes the code hard to read, and this language is already hard enough to read)
You can also nest if statements. because why not.
Warning
You can use a normal mara
block along with other mara if
blocks. However the mara
block must be the LAST block of the entire if chain.
This is your shorthand one line if statement that returns a value too.
This is the syntax
(condition) => (expression1) however (expression2)
Where if (condition)
returns true, it returns (expression1)
however if not, return (expression2)
.
(With or without braces)
(Yes including the however
keyword)
So you can do things like
maak control!
@* braces are added to make it more readable, you don't need them
maak a <- ((control = idk) => idk however 0xFFFF)!
Where if the variable control
is idk , thne variable a
will be set to idk too. Otherwise, it will be set to the integer 0xFFFF
And you can chain them
maak input <- mamela("enter a number")! @ Waits for number input fom the console.
kwenza clamp(number, min, max) ->
khutla (number > max => max however (number < min => min however number))!
<~
khuluma(clamp(input, 0, 50))!
Here we define a function clamp
which will... clamp, what'd you think, the given number to the given minimum value and maximum value.
Note
While it's not required to have braces around the expressions or condition. Just have them you maniac.
Warning
You cant have ternaries on new lines, they hve to be in the sam eline if you chain them unfortunately
Shoutout to Nikhil for this one.
Twitter
Instagram
YouTube @nikhil17 (probably idk)
Discord @Nikx17
nikhil (condition) ->
@ block to execute
<~
Where
condition
is the condition to check for the loop to continue. This is a boolean expression.
This ones a bit weird.
colonize (variable init) | (condition) | (increment) ->
@ block to execute
<~
Where
variable init
is the variable to use in the for loop, and the initial value.
condition
is the condition to check for the loop to continue. This is a boolean expression.
increment
is the increment to use for the loop. This can be a+
or a-
sign.
and the
|
is the separator between the three parts of the for loop.
colonize i <- 0 | i <= 10 | + ->
khuluma(i)! @ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
<~
colonize (variable name) with (array) ->
@ block
<~
Where
variable name
is the variable to use in the for loop, and the initial value.
array
is the array to loop through.
colonize word with reservedKeywords ->
khuluma(word)! @ prints all the reserved keywords
<~
For all loops, to forcefully exit a loop, use the voetsek
keyword.
nikhil (a = 10) ->
khuluma(a)! @ 10
voetsek! @ this will break out of the loop, stopping it.
<~
To skip to the next iteration of a loop, use the nevermind
keyword.
colonize i <- 0 | i <= 10 | + ->
if (i = 5) ->
nevermind! @ this will skip the rest of the loop and go to the next iteration.
<~
khuluma(i)! @ 0, 1, 2, 3, 4, 6, 7, 8, 9, 10
<~
Jaiva has error handling and throwing! This is done using 2 constructs.
Use the cima
keyword follwed by the <==
operator, then followed by the error message.
<==
is the assignment operator for errors. Literally not used anywhere else but for this.
cima <== (error message)!
maak a <- 10!
if (a = 10) ->
khuluma("a is 10")!
<~ mara ->
cima <== "a is not 10"! @ this will throw an error.
<~
The zama zama
keyword (both, one zama
won't work.) is used to define a try block, and the chaai
keyword is used to define a catch block.
The chaai
block is executed if an error is thrown in the zama zama
block.
Note
When in a chaai block, you have access to a special variable called
Warning
You cannot have a zama zama
block without a chaai
block. This is a design choice, and it makes sense.
Warning
You cannot put the chaai
keyword underneath the end of a zama zama
block, it HAS to be on the same line as the closing <~
symbol. This makes it easier for me lol.
zama zama ->
@ block of code to try
<~ chaai ->
@ block of code to execute if an error is thrown
<~
zama zama ->
khuluma(true + 1)!
<~ chaai ->
khuluma(error)!
<~
When in a chaai
block, Jaiva gives you access to a variable named "error"
which holds the error that ocurred in string form however if there already is a variable named error, it will increment the new error variable by 1.
zama zama ->
khuluma(idk - 1)! @ throws error
<~ chaai ->
zama zama ->
khuluma("an error bruh" - idk)! @ another error
<~ chaai ->
khuluma(error)! @ This is the (idk - 1) error
khuluma(error1)! @ This is this context's error (So the ("an error bruh" - idk) error)
<~
<~
Note
The way the code works, is it looks in it's current context for any variable which contains the exact word "error", so if you have like 4 variables named error, and you decide to open a chaai block, the name of the error variable will be "error4" (it counts the amount of current variables named error, and adds it to the variable name) Just keep this in mind This is defined in Interpreter.java on line 499
Everytime you open a block, you create a new scope. This means that any variables or functions you define in that block are not accessible outside of that block.
maak a <- 10!
maak b <- 20!
maak c <- 30!
if (a = 10) ->
maak d <- 40!
khuluma(d)! @ 40
kwenza addition(param1, param2) ->
khuluma(param1 + param2)!
<~
<~ mara ->
khuluma(d)! @ This will error, because d isn't defined in this scope.
khuluma(a)! @ 10. This works because a is defined in the global scope.
<~
addition(10, 20)! @ Will also error, because addition() is not defined in this scope.
Importing isn't that bad. Here's a simple import.
Say you have "file.jiv
" with the following code.
maak *a <- 10! @ Pre-pend * to the variable name to mark it as a exported variable.
kwenza *addition(param1, param2) -> @ Pre-pend * to the function name to mark it as a exported function.
khuluma(param1 + param2)!
<~
@ Note: Using the variables/functions are still normal. When using them you don't have to prepend the * to them. It's just simply a marker for the tokenizer to know that this variable/function is exported.
Then in your main file, you can import it like this.
tsea "file.jiv"! @ or you can have an absolute import.
khuluma(addition(a, 1))! @ 11
Or if you want to import a specific variable or function, you can do this.
tsea "file.jiv" <- addition!
Note
File paths are relative to the current working directory. So if you have a file in a different directory, you will have to use the full path to the file.
Note
You can also import files from the Jaiva library. Example to import the arrays files
tsea "jaiva/arrays"!
See Globals for a list of global variables and functions that are available to you, and others that you can import.
Note
Omitting the file extension is okay, however it will default to .jiv