Rotary

Rotary is a compiled programming language inspired by Meta's Hack and Nadeo's ManiaScript. It is based, not on practicality, but on *vibes*, but without falling into esoteric languages territory.

<entrypoint>main<=
    define string mystring = "Welcome to Rotary!"
    print mystring
    exit 0
=>
            

Downloads

Coming soon...


Concepts


Compilation pipeline

Rotary's compilation pipeline works in two steps:

  1. Your file is read by the Rotary compiler and it writes to an assembly file bearing the same name as your .rotary file, only with '.asm' appended.
  2. The assembly file is to be assembled with fasm(flat assembler)

Defining variables

To define a variable, use the define keyword, followed by the type, the name, the equal sign, and the value.

    define string hworld = "Hello world!"
  

Types

Function context

The function context defines how the function needs to be treated by the Rotary compiler.


Function declaration

To declare a function in Rotary, you need a context, a function name, an opening sign, and a closing sign.

<entrypoint>main<=
    print "Welcome to Rotary!"
    exit 0
=>
  

Here, <entrypoint> is the context; it defines that the function, main, is the program's starting function. <= indicates the beginning of the function, and > indicates its end. Please note that if multiple entrypoints are defined, only the last one will be considered as the entrypoint for the program. Also please note that, although a function may call another function or even an assembly function, it may not call an entrypoint.


Indentation

Rotary has some rules around indenting.


Name-following, repeating, and esoteric function declarations

Function declaration in Rotary is at first very forgiving regarding to how you order your functions. Take for example these two totally valid function declarations:

1. Classical function declaration
<entrypoint>main<=
    print "Welcome to Rotary!"
    exit 0
=>
  
2. Name-following function declaration
    print "Welcome to Rotary!"
    exit 0
<entrypoint>main<=
=>
  

The catch? Doing this breaks variable decoration in the intermediary assembly file. Therefore, due to ordering conflicts during the first stage of the compiling pipeline, of these three following examples, only two are valid:

1. Valid name-following function declaration
    print "Welcome to Rotary!"
    exit 0
<entrypoint>main<=
=>

---

Compiles to:
format PE console
entry main

section '.text' code executable
_main:
    cinvoke printf, 'Welcome to Rotary'
    invoke ExitProcess, 0
[...]
  
2. Invalid name-following function declaration
    define string mystring = "Welcome to Rotary!"
    print mystring
    exit 0
<entrypoint>main<=
=>

---

Compiles to:
format PE console
entry main

section '.text' code executable
_main:
    push __mystring ; should be __main_mystring
    call [printf]
    pop ecx
    invoke ExitProcess, 0

section '.data' data readable
__main_mystring db 'Welcome to Rotary!',0
[...]
  
3. Valid classical function declaration
<entrypoint>main<=
    define string mystring = "Welcome to Rotary!"
    print mystring
    exit 0
=>

---

Compiles to:
format PE console
entry main

section '.text' code executable
_main:
    push __main_mystring ; should be __main_mystring
    call [printf]
    pop ecx
    invoke ExitProcess, 0

section '.data' data readable
__main_mystring db 'Welcome to Rotary!',0
[...]
  

There is, however, an exception to this type of function declaration; assembly functions cannot be declared after assembly instructions as it sets a flag within the compiler regarding whether or not it should be compiling the code it sees or let it pass through as assembly.

1. Valid assembly function declaration
This is valid; when it is not told to let lines pass through as assembly, the compiler checks the first token of the line. Since, in this case, it is told to let pass by the assembly context, it doesn't check if cinvoke is a function in Rotary.
<assembly>myFunc<=
    cinvoke printf, "Welcome to assembly from Rotary!"
=>
2. Invalid assembly function declaration
This is invalid; as the compiler checks for the first token, it sees that "cinvoke" is indeed not a proper Rotary function and halts.
    cinvoke printf, "Welcome to assembly from Rotary!"
<assembly>myFunc<=
=>

Another fun side effect of Rotary's compiler ordering is the ability to recontextualise functions

A valid function called "myFunc".
This creates an assembly function called "myFunc". Everything up to the second function declaration is passed through as assembly. Then it is just considered to be a normal function. When the entrypoint recontextualisation hits, the function, which at this point has had both passed-through and compiled code, is considered the entrypoint of the program.
<assembly>myFunc<=
[...]
<function>myFunc<=
[...]
<entrypoint>myFunc<=
=>

To avoid ordering conflicts whilst using function declaration, be sure to always keep names consistent between multideclarations and to always declare your function at least once before defining your first local variable within it.


Examples


Big "Hello, world!"

<entrypoint>main<=
    test
    print "Welcome to Rotary!"
    exit 0
=>

<function>test<=
    define string hworld = "Hello world!"
    print hworld
    print "Welcome to Rotary!"
    asmtest
    return
=>

<assembly>asmtest<=
    cinvoke printf,"Welcome to assembly from Rotary!"
    ret
=>
  

< back to ~safariminer
< back to tilde.town