-[[cw3:creeper_world_3|CW3 Home]]<- [[crpl:start|CRPL Home]]\\
====== CRPL - The Language ======
CRPL (**C**reeper **R**everse **P**olish **L**anguage) is a stack-based, Reverse Polish Notation language. There, now that we've said it, what does it mean?
CRPL programming is similar to programming a HP calculator or Forth language programming. If this is not something you have done, read on for a brief introduction to CRPL and stack-based programming. For a more detailed CRPL explanation, see the [[crpl:crpltutorial|Tutorial]].
Each CRPL instruction (term) uses one or more arguments that are on a "stack". The most recent argument on the stack will be used first. This is called LIFO (**L**ast **I**n, **F**irst **O**ut). In return, the instruction may also place new arguments on the stack as part of its output. These new arguments are first in line to be consumed by the next instruction to be executed.
You can place arguments on the stack by typing them, or executing an instruction that will push arguments on to the stack. For instance, you can type 2 4 5
and then these three numbers will be pushed onto the stack when your script executes.
As an illustration, imagine you want to add two of the numbers you entered above. The instruction to perform addition is **[[crpl:docs:add|add]]**. Either of these mini scripts will now perform the addition:
*2 4 5 add
*2 4 5
add
Both will read the two most recent arguments on the stack (4 and 5), add them and push the sum on to the stack. After the instruction has completed, there will be two numbers on the stack. The "2" from your original entry, and "9" - the sum of the two arguments added by the "add" instruction. The stack would now look like this:
2 9
You can find more commands and detailed explanations of them in the [[crpl:crplreference|CRPL Reference]]!
===== Comments =====
Adding comments makes code easier to understand, and sometimes helps the programmer or another reader to grasp complex pieces of logic. Also, after some time interval, it refreshes one's memory about exactly what a certain piece of code was intended to do.
Comments in CRPL can be either a whole line or a partial line. The comment terminates when a line ends.
Comments are indicated by the "hash" character (**#**),
# This is how we add two of the three numbers
# that are on the stack
# Below is code # Below is a comment
2 4 5 add # adds 4 and 5 to get 9
===== Stack Notation =====
Every CRPL operand takes zero or more arguments from a "stack", pushes zero or more operands onto the "stack, or does both. In order to diagram the number of arguments consumed or produced, the following notation is included in every description following:
* The term is defined by two dashes: %% -- %%
* Preceding the term are the arguments consumed from the stack.
* Following the term are the arguments pushed onto the stack.
For instance, the instruction to add two numbers are:
4 5 add
Stack notation to represent this will be:
4 5 -- 9
In general, if we do not know the exact values of the arguments, an indicator of the argument would be given. Thus if we know the add command takes two input arguments and produces one output argument, then we notate it like this
n1 n2 -- n3
**Note:** Unless explicitly noted otherwise, all instructions are destructive stack operations in that they will remove as many arguments as is required for their execution from the stack and replace those with the output from their execution. In the example above, the original two items on the stack have been replaced by their sum.
Likewise, note that the most recent item pushed on to the stack will also be the first item to be removed. This is referred to as LIFO (**L**ast **I**n, **F**irst **O**ut) processing.
The following convention is followed to represent items on the stack notation
|< 80% 15% >|
|b |**Boolean** ; nominally a 1 or a zero, representing True or False|
|i |**Integer** ; an integer. The CRPL run-time will, if possible, convert the argument to an integer.|
|n |**Term** ; a generic argument. Any term that will be accepted by the instruction. If possible, the CRPL run-time will attempt conversion between types.|
|f |**Float** ; a floating point value. If possible, the CRPL run-time will attempt conversion between types.|
|x, y |**Coordinate** ; an integer that represents a valid X- or Y-coordinate on the map.|
|L |**List** ; a list is capable of storing multiple values in an orderly system.|
|s |**String** ; a string of one or more text characters. If possible, numeric values will be converted at run-time.|
===== Warp Notation =====
An extra and optional operator to CRPL allows for a reversed order that you write some things in CRPL. It doesn't change a thing about the stack, or how CRPL works. It only gives you a syntax alternative that can make things easier to read in some cases.
This operator is the "warp" operator since it warps things around. In more technical terms, it allows for prefix notation. Take the following example:
3 4 add
This means to push 3 to the stack, push 4 to the stack, then to call "add". Add pops two items from the stack, adds them together, then pushes the result back. So stack notation for "add" is:
n1 n2 -- n3
This means two items on the stack before the operation, and one item on the stack afterwards.
This is all CRPL (or RPL, or forth...) standard stuff and the primary principle of the language. This remains unchanged and untouched.
Take a second example:
CurrentCoords GetCreeper 1 gt if
"Creeper Greater than 1" Trace
endif
This looks at the current coordinates, gets the creeper there, checks if it is greater than 1. If so, trace the string "Creeper Greater than 1" to the trace log. Because of the way the stack works, you have to push two coordinates to the stack first (CurrentCoords does that), then call GetCreeper. That takes two items from the stack, uses them as coordinates, then pushes the value of the creeper at that map location back to the stack. The number 1 is then pushed to the stack, and the "gt" call takes two items from the stack and does a "greater than" comparison between them. The result is either 0 (false) or 1 (true) and that is pushed back to the stack. Finally, the "if" statement pops the result of the "gt" call from the stack and then either allows execution to pass to the next statement, or jumps to the "endif".
Again, CRPL 101.
Now, introducing the Warp operator.
3 4 add
can become
add (3 4)
The open parenthesis "(" means to warp the previous command to the closing parenthesis ")" during compilation. There is no run time penalty for doing this since it is just a syntax trick. The compiler literally 'warps' "add" from before the 3 to after the 4 when this example is compiled.
This also means the same thing:
3 add(4)
Here, the "add" warps from before the 4 to after the 4, resulting in "3 4 add" which is the exact same thing as the first example.
Take the second example. It now can become:
if ( GetCreeper(CurrentCoords) gt (1) )
Trace ("Creeper Greater than 1")
endif
Notice that spaces before or after a warp operator ( which are parentheses) don't matter. You can put spaces, or you can bump the warp operator up right next to something else.
Note also that this syntax is totally optional and can be intermixed with standard RPL notation as seems appropriate. For instance, assignments still look better without warping.
7 ->x
This means to assign 7 to the variable "x". Or "seven goes into x".
So does this:
->x(7)
Like any language, you can write some really obfuscated code if you try ([[http://www.ioccc.org/years.html]]).
For instance take this clean piece of code:
CurrentCoords GetCreeper 1 gt if
CurrentCoords -10 SetCreeper
endif
Here it is in bizarro form:
endif(SetCreeper(-10(CurrentCoords(if(gt(1(GetCreeper(CurrentCoords))))))))
Here's the same code with just one oddball warp:
endif ( if (GetCreeper(CurrentCoords) gt (1))
SetCreeper(CurrentCoords -10)
)
===== Typographical conventions =====
**Note:** FIXME This has not yet been implemented. We intend to, but until then the following is merely a placeholder.
The following typographical conventions are used in this reference document:
|< 80% 15% >|
|Normal text |Used in most instances.|
|Instruction |Refers to a CRPL language element or instruction.|
|Argument |Refers to a an argument required for a CRPL instruction.|
|User |Refers text that should be replaces with user-supplied values.|
===== Creating CRPL Scripts =====
Any text editor can be used to edit CRPL files. However, syntax highlight and auto completion support files are provided for several available editors.
See how others created their maps! You can extract the CRPL scripts and custom images from any CW3 game file. The guide to [[examine map resources]] will show you how to retrieve these resources from other maps.
==== Notepad++ ====
Notepad++ can be obtained from here: [[https://notepad-plus-plus.org/]]
Make sure you download only from the official Notepad++ website to avoid malware. https://notepad-plus-plus.org/
* Once Notepad++ is installed you can add **syntax highlight** for the CRPL language. Currently there are two sample thems, one for the "normal (llisth) theme and one for the "dark" (Deep Black) theme.
* Light theme: [[crpl:crpl-syntax|crpl-syntax.xml]]
* Deep Black theme: [[crpl:crpl-syntax-deep-black.xml]]
* Download either (or both) of those files, then:
* Open Notepad++, select Language from the menu bar, click "Define Your Language", then "Import".
*You can add **keyword auto completion** to Notepad++ by download this file [[CRPL.xml]]
* To install into Notepad++ you need to copy CRPL.xml to the ''autoCompletion'' subdirectory of the Notepad++ install folder. (In older versions, Notepad++ v7.6.1 and earlier, you had to put the file in the ''plugins\APIs'' subdirectory of the intstall folder.) Then, restart Notepad++. Next, go to the Settings/Preferences menu in Notepad++. Click the "Backup/Auto-Completion" tab. Check the "Enable auto-completion on each input" checkbox, and make sure the "Function completion" radio button is selected.
* Alternatively, download this file [[https://drive.google.com/open?id=18U2nQ32AajOZESGKERYBtrNlS1YHjlmD|crpl.xml]] instead, which works for **keyword auto completion** as well, but also contains the input, output, and the description of each command.
* Use the same process to install as above. To see the description of the command, type the opening bracket "(" after the command you want to see help for. Then press Esc to dismiss the help, or click elsewhere in the code. Disclaimer: these hints were autogenerated from the wiki, so the formatting might not be the best.
* You can also create a keyboard shortcut to open the wiki of the current command you have your cursor on.
* In Notepad++, go into "Run -> Run", then type ''https://knucklecracker.com/wiki/doku.php?id=crpl:docs:$(CURRENT_WORD)'' into the input field and click "Save". After that, select a name (for example "Open CRPL Wiki") and a keyboard shortcut (for example Ctrl+Shift+H) and click OK, then just close the Run... dialog. After that, you should see your shortcut in the "Run" menu, and you can use it to open the current command (the one that your input cursor is currently on) in the wiki.
==== Visual Studio Code ====
Visual Studio Code can be obtained from here: [[https://code.visualstudio.com/]].
Features:
* Syntax Highlighting
* Looking stuff up on the wiki
* Syntactical diagnostics (making sure block delimiters match, $ parameters are at the start of the file, etc)
* Implements several VSCode features for named entities (variables/functions): go-to-definition, rename, and find references
* Checks to make sure variables are used (written to at least once and read from at least once)
Instructions:
* Download this *.vsix file: [[https://github.com/stellHex/crpl-vscode/releases/download/v0.3.0-beta/crpl-0.3.0.vsix]]
* In Visual Studio Code, Go to View -> Extensions.
* In the menu that opens, expand the more options menu in top right and press Install from VSIX, then point to the downloaded file.
* All files with the *.crpl extension will now automatically utilize the features above.
==== Sublime Text ====
Sublime Text can be obtained from here: [[https://www.sublimetext.com/3]].
Features include syntax highlighting and auto completion.
Instructions:
* In Sublime Text, go to Tools -> Command Palette.
* Type "Install Package Control" and hit Enter.
* Open the Command Palette again and type "Package Control: Install Package".
* In the menu that opens, type "CRPL", then select the Creeper Reverse Polish Language package.
* All files with the *.crpl extension should now use this package.
=====Translation Front-ends =====
* Forum user [[https://knucklecracker.com/forums/index.php?action=profile;u=6122 | Arin112]] (Discord: Arin112#8343) wrote a C-lookalike front-end translator that will produce xRPL code as output. There is a [[https://knucklecracker.com/forums/index.php?topic=31849.msg179146#msg179146 | reference to the translator (MplLang) on the forum]]. The source code and examples are on [[https://github.com/Arin112/mplLang | Github]].
* Discord user Redcrafter#7494 wrote a transpiler that translates Javascript to xRPL code. The source code and examples are on [[https://github.com/Redcrafter/crplJs | Github]].
Time permitting, this deserves a more complete treatment and probably a section of it's own.
\\
\\
=====Syntax Highlighting in the Wiki =====
Dokuwiki uses [[http://qbnz.com/highlighter/|GeSHi]] syntax highlighting.
Code examples can be highlighted using the `4rpl` code tag eg:
# --Volcano-- 5/13/2020 12:58:29 PM
$$POSX:154
$$POSZ:98
$$AMT:100
if (GetGameUpdateCount 3600 % eq0)
true ->erupting
endif
if (<-erupting)
@Erupt
endif
if (<-orbsHaveErupted ! GetUnitCount("sniper") 21 gte &&)
240 ->orbsErupting
true ->orbsHaveErupted
endif
if (<-orbsErupting)
@OrbsErupt
endif
:Erupt
if (<-eruptCount 60 % eq0)
do(2 -1)
do(2 -1)
AddCreeper(<-POSX I + <-POSZ J + <-AMT)
loop
loop
endif
<-eruptCount 1 + ->eruptCount
if (<-eruptCount 400 gte)
false ->erupting
0 ->eruptCount
endif
:OrbsErupt
V3(RandFloat 0.5 - 1 * 2 RandFloat 0.5 - 1 *) ->orbInitData{"velocity"}
CreateOrb(V3(154 randint(-1 2) + 15 98 randint(-1 2) +) <-orbInitData)
<-orbsErupting 1 - ->orbsErupting
:once
Table( "payload" 500
"bounce" true
"creeperdamps" false
"destroywhenstill" false
"destroywhendrytime" 60
"releaseondestroy" false) ->orbInitData