Skip to content
Richard DeSilvey edited this page Apr 2, 2021 · 105 revisions

Rowdy Wiki

Importing souces

You are able to import your own libraries by using the import keyword followed by a string "mylib.file". All libraries are in the bin directory along with Rowdy's core library rowdy.core For a file path bin/myLib/sourceFile you would simply import as import "myLib.sourceFile"

Data types

There are many data types Rowdy is going to support. The keywords for the data types are int double boolean long short byte bigint string Rowdy also gives the ability to cast data types as well using the as keyword followed by the datatype. Any expression can be cast.

print a as int
print (4 + 6) as int

But if you're not explicit Rowdy will cast for you but will cast as follows: Integer with Double, Result is Double Integer with Long, Result is Long Double with Long, Result is Long

Print and Read statements

print "Hello World\n";

The above statement will print to the console "Hello World" on it's own line.

There is also the helper ln which is a variable defined as ln = "\n"

read var1

The above statement will read from the keyboard and return the input when the user hits enter read var1, var2

Variables

All variables are dynamically typed. All variables are statically scoped within a function but if the function is anonymous or declared dynamic then all variables are dynamically scoped unless you use the keyword this.

func f1(){
  loop p: {
   v1 = 100 // Still belongs to the rest of the scope in f1 and not just the loop
   break
  }
  print v1, ln // v1 still exits even though we are no longer in the scope of the loop
}

Demo below shows the variables and their scope

func f1(v1){
  v1 = 100
  print v1, ln // 100
}
func f2() {
  v1 = 12
  print v1, ln // 12
  $f1(v1)
  print v1, ln // Still 12
}

func f3() {
  v5 = 10
  print v5, ln
  ff = func() {
    v5 = 23
    print v5, ln // 23
  }
  $ff() // 23, v5 still belongs to f3
  ff = func() {
    this.v5 = 100
    print v5 // 100
  }
  $ff()
  // ff will have it's own v5 now
  print v5 // still 23

  // You can also bind variables to dynamic functions with < >
  ff2 = func() <v5> {
    v5 = 555
    print v5 // 555
  }
  print v5 // 23
}

In order to make sure a variable is set or not you can use the built in function isset. isset is a function which returns a boolean. Unlike print or read which are statements and don't return anything.

func f1(v1){
  if (isset v1) {
    print v1, ln
  }
}

Another alternative to isset is the Null Default test which can be used in two different ways.

print is name ? // prints true if name is null or undefined
print is name ? "No Name" // prints 'No Name' if name is null or undefined otherwise the value of the name is printed

This kind of test can be helpful for functions that need values in their parameters

func addNums(a, b) { \\
 return (is a? 0) + (is b? 0)
}

print $addNums // prints 0 since no values are defined
print $addNums(3) // prints 3 because 3 + 0 = 3
print $addNums(3, 2) // prints 5

Variables can be declared as constant and will be immutable during the lifetime of Rowdy's execution

const a = 100 // a is forever immutable until Rowdy finishes

main function

Every Rowdy program must have a main function to run

func main(){
   // do something
}

Parameters come from the command prompt or shell when the interpreter is executed with a source file.

func main(p1, p2, p3){
   // do something
}

Program Execution

In a shell script or a shell use this command

java -jar rowdy.jar <program file name> <program parameters>
...
java -jar rowdy.jar change 5.16 10

You can also run rowdy without source files by just executing the jar This will place the interpreter in a continuous execution shell allowing you to enter one or more lines of code and execute them in real time. To terminate the current session type exit.

java -jar rowdy.jar

var1 = 100 ..
var2 = 400 ..
print var1, " ", var2
100 400


print "Hello!"
Hello!
exit

To tell rowdy not to execute the line right away place two .. after the line. When a line is entered without the two .. all the code is executed

f = func() { ..
 return "Multi line code" ..
} // <---- Not entering two .. terminates the entry of code and rowdy will build it, then execute it.
print $f(), ln
Multi line code

Control statements

Rowdy has two common control statements that every language has. ifs and loops except for switches

if (bool condition) {
   // Do Something
} else if {
   // Do Something else
} else {
   // if all false do this
}

Parenthesis are optional for the bool condition.

The loop below has a corresponding label or id which can be used to control the sequence with a break statement.

loop label: {
  print "Loop Forever?\n"
  break label; // Leave the loop 'label'
}
loop outer: {
print "Outer\n"
   loop inner: {
     print "Inner\n"
     break outer // Leave all the loops
   }
}

The labels are actually IDs initialized to 0 with the simple loop form loop x: {} You can change the value of the ID while iterating

loop x: {
  if (x >= 10) {break}
  x = x + 1
}

These loops are quite slow if you iterate over many times. If you find yourself needing a better loop you can import "rowdy.core" for the function forLoop(I, F, inc, callback) I is that initial value of the for loop, F is the value to iterate to. The mathematical inclusion is [I, F) or if I > F then it's [F, I]. inc is the increment value and finally the callback is the function that is the body of the loop. Rowdy won't check bounds or for infinite loops, be careful to pick the correct incremental value.

// i is the value for the loop
$forLoop(0, 100, 1, func(i) {
 print i, " " // prints out 0, 1, 2, ... , 99
})
$forLoop(100, 0, -1, func(i) {
 print i, " " // prints out 100, 99, 98, ... , 2, 1, 0
})

// the variable passed to the callback is optional
$forLoop(0, 100, 1, func() {
 print "." // prints 100 dots
})

This implementation is much faster and should be used instead of the built in loop

Functions

Each function is statically scoped if declared in a source file unless marked as dynamic. All anonymous functions are dynamic. Parameters passed to it are pass-by-value and variables can be statically bound to anonymous functions.

func myFunc (a, b){
   return a + b
}
c = 10
func myFunc (a, b) <c> { // bind a new `c` to this function
   c = 1
   return a + b + c
}

To call a function you need to use the $ in front of the function to tell rowdy to execute it.

print $ myfunc(1, 3), ln // Prints 4.0

If a function doesn't have a return statement that function will always return a null value, since all functions must return a value this is just the result if nothing is returned.

Functions can be assigned to variables and act as functions, this lets you setup callbacks

func func2(){
  print "Function 2\n"
}
func main(){
  func1 = func2
  $func1 // calls func2's code
}

Creating callbacks is also possible with anonymous functions

func service(callback){
  $callback("Hello World!")
}
func main(){
  $service(func (msg) {
    print "Callback: ", msg, ln
  })

  // Can also assign anonymous functions to variables
  anonymous = func (msg) {
    print "Hello ", msg, "!\n"
  }
  $anonymous("Anonymous")
}

Functions can recurse but functions like pow or exponentials are already built in.

Scope

Rowdy offers Dynamic and Static scope. By default functions that aren't anonymous are statically scoped unless explicitly specified with the keyword dynamic

dynamic func f1() {}

Anonymous functions are treated as dynamic unless the keyword this is used to tell rowdy that the scope is this function

a = 12
f = func () {
 this.a = 10
 print a // 10
} 
$f()
print a // 12

Same as above but made formally by binding a to the scope of f. This should be used in place of the keyword this because if f is passed into an object or class function and later executed Rowdy will complain that you are trying to execute an unsafe function for using the keyword this outside of a class.

f = func() <a> {
 a = 10
 print a // 10
}

$f
print a // 12

Depending on the scope if you are inside a class the keyword this points to the current instance of that object, otherwise the scope is the current instance of the function.

Arrays

Rowdy can build two types of arrays, a normal array or ArrayList in Java and a key-value HashMap. the keyword new is optional

// Build the array [0, 1, 2, 3]
myArray = new [0, 1, 2, 3] 
empty = new []

// When building arrays each parameter is an expression, even anonymous functions can be stored in arrays
myArray = new ["Some value", 10, (concat "This", " and ", "That")] 
functions = new [
       func () {
          print "f1"
       }, 
       func () {
          print "f2"
       }] 

To build a key-value map:

myMap = new {"key":"value", "function1": func () {print "func1"}} 
empty = new {}

To access these arrays or maps use the function $get from the rowdy.lists or the rowdy.core import

value = $get(fromArray, 0); // location 0
anotherValue = $get(fromMap, "Key")

You can also dereference the array or map

print fromArray[0], ln
print fromMap["key"], ln

fromArray[0] = "value" // can throw index out of bounds exception if the index is not within the bounds of the array
fromMap["new key"] = "Rowdy"

There are other built in functions to handle arrays and maps. import "rowdy.core" contains a whole set of basic functions to work on maps and lists.

list = $List() // returns an empty linked list data structure
map = $Map() // returns an empty map

$add(list, 100) // appends to the list, linked lists do best with this.
$set(list, 1, 23) // puts 23 at location 1, this is faster with ArrayLists and not linked lists
$remove(list, 0) // remove the element at location 0

$put(map, key, value)

$get(list, 0)
$get(map, key)

$size(list) // Returns the number of elements
$size(map) // Returns the number of keys

You can use a faster implementation of a for loop using forEach(list, callback)

$forEach(list, func(element) {
  // Do something with the element, can't remove them
})

String manipulation

The language comes with a few string statements that can be useful, such as concat, slice, and strcmp

print concat "These are ", "Concatenated", "\n"
print "These are ", "Concatenated", "\n" // Equivalent to the above line

str1 = "Hello "
str2 = "World!\n"
		
str3 = concat str1, str2
print str3

// Slicing Strings using slice from 'rowdy.core'
str4 = $slice(str3, 0, 5) // [0, 5)
$println(str4)

// Selection with variables
v1 = 0; v2 = 5;
str4 = $slice(str3, v1, v2) // [0, 5)
print ( concat str4, "\n" )

// rowdy core imports
$println( $strcmp("Hello", "World") == 0) // false
// or
$println( $equals("Hello", "World") // false
$println( $notEqual("Hello", "World") // true

$println($isEmpty("")) // true
$println($isNotEmpty("Hello")) // true

Arithmetic

Rowdy lets the user work on doubles and integers without having to explicitly cast the types. However, longs and doubles being worked on together need to be cast accordingly to avoid precision losses. If a variable is an integer and you add a double to the value the result will be a double unless explicitly cast to an integer. If a variable is a long and it's added or subtracted from an integer the result will be a long to avoid precision losses.

print 1 + 4 ^ (5 - 2), "\n" // Evaluates to 1 + 4 ^ 3 => 1 + 64 => 65.0
print (1 + 4) ^ (5 - 2), "\n" // Evaluates to 5 ^ 3 => 125.0
print 5 % 10 + 1 // Evaluates to 6.0

Rowdy has a built in function round which rounds up or down and truncates the rest based on the precision given to the method

v1 = 2.34432
v2 = round v1, 2 // v2 becomes 2.34

v1 = 67.457123123718263
v2 = round v1, 1 // v2 becomes 67.5
v2 = round v1, 9 // v2 becomes 67.457123124

Rowdy also allows numbers in strings to be worked on. Actually if Rowdy sees a string assigned to a variable it will try to first cast the string as a number, being a double, integer, or long.

var1 = "4.5" // Rowdy sees this as a double
print $type(var1)
Double

var1 = "1" + 4.5 - "5" // Rowdy computes this as 0.5

var1 = concat 1, 2, 0.5 // var1 becomes "120.5" which is then cast to a double

var1 = (concat 1, 2.33) - 0.33 // becomes 12.0

This functionality is used to easily convert strings to numbers and numbers to strings. Rowdy won't fail if the following occurs.

var1 = "Hello" + 12 // Double.NaN
print $type(var1) // Double

Runtime import

Another helpful import from rowdy.core is the runtime function. This function measures in milliseconds how long it took for a function to finish execution.

$println(concat "Took ", $runtime(program), " ms to finish")

// Since you can't pass parameters to the function being measured, yet, you can dynamically scope it like the following
iterations = 100000
$println(concat "Took ", $runtime(func () { 
 $forLoop(0, iterations, 1, func(x) {
  // Do something with x
 })
}, " ms to finish")

Object Oriented Programming

Rowdy offers the ability to create or define objects.

public class Person {
 construct(name, age) { 
  this.name = is name? "No Name"
  this.age = is age? 0
 }

 public:
  func rep() {
   return concat this.name, " is ", this.age
  }
}

func main() {
 p1 = new Person // defaults are used
 p2 = new Person("David", 33)
}

Above is a basic example of an object called Person which holds data about the person's name and age. Both member variables are defined in the constructor using the keyword this. All member variables have to be pointed to using the keyword this otherwise Rowdy will think you are looking for a variable in the current function. The rep function is an override for every object in Rowdy that allows you to return a string representation of the object exact behavior as toString in Java. In the constructor it's important to note that it's possible that a name and age aren't given so the Null Default tests are used to ensure each member variable is setup correctly with some form of data.

public class <name of class> { 
 construct() { // constructor is optional
 }

 public:
  a = 10 // these are evaluated first before the constructor is called
  // functions and members are defined here to be public
 private:
  // functions and members are defined here to be private
}

Native code for Rowdy

Rowdy offers the ability to write native Java code. The native keyword is used when defining a function that is implemented in native Java. Some of the functions in the rowdy.core import are implemented with Java.

In order to write native Java you need three main imports from Rowdy.

import rowdy.JavaHookin;
import rowdy.NativeJava;
import rowdy.RowdyInstance;

The JavaHookin annotation is used to tell Rowdy that this method is the function being defined in Rowdy. The rule here is the method name must match the name of the function being defined in Rowdy. For instance for the following

  @JavaHookin
  public static NativeJava List() {
    return (RowdyInstance instance, Object... params) -> {
      return new LinkedList<>();
    };
  }

The function in Rowdy would be defined as native func List() The only part that does not matter are the parameters. The method will be empty and the parameters, if any provided, will be passed into the lambda Object... params. The RowdyInstance instance parameter is the current instance of Rowdy that is running. Methods such as instance.setAsGlobal(idName, value); can be used to allocate a global variable with the given id name and the value. If there is a function being passed into one of the parameters you can use the built in feature of the Rowdy instance to setup the callback by doing the following.

BaseNode callback = (BaseNode) params[0];
BaseNode function = instance.buildAndAllocateCallBack(instance, callback);
List<Value> funcParams = new ArrayList<>();
try {
  instance.executeFunc(function, funcParams);
} catch (ConstantReassignmentException ex) {
}

After you're done build your project and include your built Jar in the directory of Rowdy under bin. You should also be able to see RowdyLib which is the library for some of the native Java code for the rowdy.core import.

That's pretty much it for wrapping a function call in Rowdy with native Java. This allows you to wrap already built methods and libraries for Rowdy and you can even have a native function in Rowdy call a native method in Java.

Java reflection

There's a native function called java that takes an object, the name of the method to call on that object, an array that describes the method's parameter types and the values for the parameters.

str1 = "hello" 
print $java(str1, "length"), ln
print $java(str1, "substring", ["java.lang.Integer", "java.lang.Integer"], 0, 2), ln

Although this is easier than writing native java code it isn't going to be the most efficient way of calling java code from Rowdy so if this is being called many times through the lifetime of your program it's best to wrap it as native java.