FoxLang Discussion

FoxLang Discussion

This is a discussion post for suggestions and feature requests of a yet to be fully implemented plugin called FoxLang.


What is FoxLang?

FoxLang is a JVM-based programming and scripting language all in one package.
This idea occurred because of FoxGuard and the proposed FoxEdit, both of which needed some ability to have basic scripts.

The point of this language is to provide a straight-forward, Minecraft oriented scripting/programming system. This language should be easy enough for anyone to write basic scripts in, while still having an advanced feature set for those who really want to do whatever they want.

One thing to note before continuing on, when I reference to scripts, I am talking about the files containing the code written in the language. I am referring to such files as scripts, because most of the time that is what the will be.

We originally had just been lexing, parsing, and running a very basic scripting setup directly in Java when the script was run. There was a huge downside about this method though, and that was the length of time it took to to do said tasks. We then decided that it would be better if the language could directly interface with regular game and plugin code.

This meant that we were going to have to do one of two things:

  1. Make it even slower and use a hell of a lot of reflection to allow access of regular objects into the scripts
  2. We could make the language compile down into Java bytecode, in which case we still might need a little bit reflection, but overall anything that you could do in regular Java, could also be done in the scripts.

We have, after much discussion, decided to have all scripts compile directly down to bytecode (this also allows JIT to optimize code, which means it should run at the same fast speeds that Java does).
As of right now, we do not have a syntax nailed down, and that is part of why I have decided to finally write this post, to gather peoples opinions on it.

There are currently only a few limitations for the syntax that we have decided on.

  • There will be no indentation-based hierarchy. Sorry Python users. If people want to enter small scripts in the in-game chat, and we DID have an indentation-based syntax, it would be quite impossible to have anything more complex than a basic math expression.
  • For the same reason listed above, there will be semicolons to end a statement.

While this language will optimally be able to do anything, it is targeting two specific features: Math/Expression scripting, and direct Minecraft interfacing.


Questions

Things I would like peoples opinions on (although please feel free to let me know if you have any other ideas or opinions)

  • Nullability (Similar to Kotlin style)
  • Strictly or Weakly variable types (Weakly: type of object can change)
  • Inferred or defined variable types (Defined means you need to specify variable type)
  • Closures/Lambdas
  • Script argument handling
  • Tuples, Data Classes, etc
  • Compiled ahead of time, or at runtime
  • Script caching
  • Direct integration with plugins
  • Piping into scripts or scripts output piping into other scripts

How to help

  1. Comment below with ideas, suggestions, and opinions (in regards to syntax, features, etc.).
  2. Test out the occasional release (once I actually get my act together and put things in a useable way.
  3. If your more into the development side, here is the GitHub; please feel free to make a PR or issue.

Current Stats

  • Lexing 28900 tokens from raw code takes about 30 milliseconds.
  • Compiling currently takes about 5 milliseconds (although this currently is only basic generation: things like the header, constant pool, various lists and such. This doesnā€™t include the actual code logic)

P.S. Not really sure if this is the correct category for the postā€¦ Feel free to move it if itā€™s in the wrong place :slight_smile:

Snowie (d4rk)
FoxDenStudio

1 Like

It really depends how complex you want the compiler (or interpreter for that matter) to be. Having a type distinction for nulls is nice, but it adds a layer of complexity. Similarly, type inference is a nice developer feature, but can complicate the compiler in certain fashions.

Other than that, I think that having it slightly functional, with first class closures would be nice, tuples are a must for me, as are data classes. For compilation, the easiest option for people who want to write the scripts would be for them to be compiled when the plugin starts, and the resulting program representation in code to be cached (HashMap of String (fileName) to program representation for this), and reloaded when asked to with a certain command.

1 Like

If you want to do this for your own sake to learn how to design a language go ahead.

But if you are really doing this for the sake of creating a scripting language for foxedit and foxguard, unless you are able to have domain specific types/syntax that make things much less verbose / easier to learn, I see little benefit over using something people either already know how to use, i.e. javascript, java, etc.

@ryantheleach That was pretty much the entire point.

This language, while it could be used on its own, was purely planned to be used inside minecraft, and therefor a few of the features that we have so far planned, relate specifically with certain minecraft features. It is meant to be a language that has varying levels of difficulty, its layout should be easy enough that anyone with an ounce of logic should be able to right a very basic script (say for randomly generating blocks based off percentage or neighboring blocks. It should also have a lot more advanced features that make it able to be used to extend the Fox Suite plugins (and any other plugin really).

A lot of the DSL stuff will be more in the syntax then anything.
One of the ideas we had so far was something like this:

var region = FG.regions:first
region:blocks {
    type = Math.random(0,3) [ [[stone]],[[dirt]],[[grass]] ]
}

Now what this does (and of course the syntax is definitely NOT set in stone by any means):

First get the list of FoxGuard regions, and get the first one from that list.
Then, for each block in that region, run the following code:

  • Set the block type to one of three items, done by mapping a randomly generated number to the following map. The double square brackets imply that it is a block type.

Plus there is the fact, that I am kinda doing this for the hell of it, so if no one uses it I wonā€™t really mind to much.

Another idea (And Iā€™m biased cause I love Kotlin) is to make a DSL accessible from Kotlinscript using the Kotlin script engine. Iā€™m fairly sure itā€™s possible, though I havenā€™t tried it. If FoxLang is purely just a toy project to learn compiler/interpreter architecture, thisā€™d be a way to get started much quicker.

Just an idea :slight_smile:

Yeah, we discussed just using Kotlin or similar, but in the end I decided that I already know enough about compiler/interpreters, that it would be more interesting to do a new project; hence why this is going to be an independent language that compiles down to the JVM, much like Java and Kotlin.

Sounds very interesting.

For simplicity Iā€™d say use inferred, weakly typed variables. You canā€™t expect the average server admin to understand the concept of data-types.
And while I think a BASIC-type language would be better in terms or readability, but a C-like language would make for better one-liners. Since everyone should be used to NBT-tags use curly brackets Iā€™d go for C-likeā€¦

So you more/less translate the script into java to compile it? I know thereā€™s stuff like Javassist to generate bytecode at runtime. (funny storry, I used this once to generate custom blocks in forge from configs at runtime, but for the classes to load properly the client had to restart)
Or do you want to compile directly into Java bytecode?

region1 = FG.regions[1] #index starting at 1, I'm evil :smiley:
region.block[all].type={ :stone, :dirt, :grass }[random]; #how about magic indices?

It will be compiling directly into bytecode. I thought about just turning it into Java first, then compiling that, however that means that either I need to write/include my own Java compiler, or the server needs to have the JDK installed, neither of which option I like. Also it would be slow af.

As far as Fox and I had discussed, we also thought that inferred weakly typed variables was the way to go, although we might add in something much like JavaScriptā€™s ā€˜strictā€™ setting. Otherwise in potentially very large scripts, inferred typing could become messy and slow.

And as far as JAssist goesā€¦ Nah, whatā€™s the fun in that :stuck_out_tongue: I would rather write my in compiler from scratch. Other note, one based indexs will be decided after it is in a semi usable state. For this language it could make sense, since itā€™s math basedā€¦ But the programmer inside me says hell no.

Weakly typed would only mean Object references, wouldnā€™t it?
And inferred variables could be freed by only holding them in a script/method/code-block context that gets released for gc after execution Yea, some stuff needs to persist

Just throwing this out there for the sake of myself and other Skript lovers, even though it seems the entire script-coding/programming universe hates Skript and everything it can do, Iā€™d really like to see a plugin that works just like Skript in terms of what Skript is capable of (custom commands, list variables, random number generators, etc) while making the syntax as simple as:
on walking on stone:
set {randNum} to a random integer between 1 and 3
if {randNum} is 1:
message ā€œRNG rolled 1!ā€ to the player
Etc, etc.

Many server owners/maintainers like myself have made our servers heavily dependent on Skript and weā€™re desperately looking for something we can use to replace it. I actually have a forum post on here I think in the plugin development section offering $100.00 (price is negotiable) USD to anyone who can send me Skript working on Sponge through any means necessary. Could I learn Java and just code my own version of Skript? Why, yes it sounds possible. However, I do not have the time or patience to make an 8th attempt to do so. Iā€™d much rather pay someone who already knows what they are doing for the fastest solution. Not to mention the other server owners out there trying to move to Sponge from CraftBukkit who, like me, would pay for such a plugin as powerful and simple to use as Skript.

@ryan96t

So ā€¦

FoxLang is meant to be able to be used as a super simple language. We want server owners to be able to use it easily without needing a while bunch of programming knowledge. However, we also want people to be able to use some really advanced features, as well as be able to interface directly with actual Java code (such as the Minecraft and sponge code).

This is in part why I created this post. Iā€™m looking for people who have ideas on syntax, and what a regular server inner might want. I obviously cannot guarantee that any and all suggestions will be implemented, however at least it gives me an idea of what people would like to see.

How I had originally planned on doing the same thing as your example code:

bind(event playermovement) {
    randnum = random(1,3);
    event:player.message("RNG rolled $randnum");
}

The way this kind of thing would be handled has been changed multiple times in my head, so its still likely to change.
Do you think that this is easy enough for the regular server owner to use?

Iā€™d rather not make it a fully sentence (English) based language, because then it loses a lot of power for the people who want to actually use it to program. My end goal is that people could write things as simple as one or two line, in-game scripts, OR they could write an entire plugin in it.


@DosMike
Yeah, basically things can be weakly typed, and stuff, during initial compilation, but then I either have to make variables that change into Objects in the bytecode, or I need to do some other really hacky stuff. I might make it inferred types, but strongly typed, but idk. As far as GCing goes, since I am compiling to the JVM I get all the optimizations of JITā€¦ If i program this carefully, it should be able to be GCā€™d just the same as if you wrote it in Java.

How would this be applied on a map? Like, would this trigger every time a player moved? Or is there a way to bind it to a type of block at specific coordinates?

Hmmm good question, right now that would fire every single time any player moves (regardless of where they are).

Now that you mention i, it would probably be useful to have some sort of filter option.

One potential way to do it would be like this:

bind(event playermovement) | within(event:player:position, [x,y,z,x2,y2,z2]) {
    randnum = random(1,3);
    event:player.message("RNG rolled $randnum");
}

Or some other syntax. the original plan was just to have the user to write their own filter, to only listen to things they want.

bind(event playermovement) {
    if (event:player.x > 100) complete;

    randnum = random(1,3);
    event:player.message("RNG rolled $randnum");
}

In which, if the playerā€™s x position is greaterthan 100, it just skips the rest of the code in that block

The reason that I will not be handling filtering (at least not entirely) internally, is because these scripts will be able to have listeners registered directly with Sponge.

The other thing to note, is that these scripts (while they can), are not really planned ot take over for writing a plugin, they are more meant to enhance gameplay:

  • you want a mountain generated, that has a certain level of randomness in it, you can write a script to do itā€¦
  • You want to (in regards to FoxGuard), find the region that the player is looking at, and check if a certain flag is true, and if so add another flag, then it can be done.

Scripts arenā€™t really meant to be overly long running or listening tasks, hence why I think it is a bit different than Skript. Thatā€™s not to say it CANā€™T do those things, its just that I am not (at least for now), waste a bunch of time trying to implement things that would only be used in running a full lifecycle program.

I think part of the biggest difference between what this proposes, and what many other scripting plugins do, is that this compiles into the same bytecode that other java programs do. This means that my scripts should run WAY faster than any other scripting plugin out thereā€¦ at the cost of the fact that once the script has been compiled, I wonā€™t be able to just pick and choose what happens. Think of it this way, all that I am really doing here, is writing a version of Java + its compiler, specifically for a Minecraft and plugin based environment.

TL;DR
The aim of scripts in this plugin are to only be run to do a specific something, then complete, not run as long as the server is running. Because of that, I am not going to focus to much on adding in filters for events and such, as things that use events are probably going to fall into the latter categoryā€¦

We used Skript to make improvements to our server. The scripts we wrote werenā€™t running constantly, but were able to. For example, we used the on walking on event trigger to apply coding to green stained clay that was placed in random bits in areas and, when stepped on, it ran code for triggering a Pokemon spawn (if youā€™re familiar with the Pokemon games, we recreated the grass spawns). However, the first line in the code was a condition that the code that followed it (the spawn code) only had a 3% chance of executing. Itā€™s really only the 'on walking on ', ā€˜on right click on a signā€™, and custom commands parts of Skript that we need for our server. Everything else can be replaced through other means. XD

I donā€™t know if this math is right, but this was kind of the point of the scripts:

generateTreeTrunk(10,70);

fun generateTreeTrunk(var width, var height) {

    var pos = user:cursor:ray(100):first:coords;

    for (var y1 = 0; y1 < height; y1++){
        var PI = 3.1415926535;
        var i, x1, z1;

        for(i = 0; i < 360; i += 0.1)
        {
            angle = i;
            x1 = r * cos(angle * PI / 180);
            z1 = r * sin(angle * PI / 180);

            world:block(pos:x + x1, pos:y + y1, pos:z + z1) {
                type = [[log:1]]; // Oak log
            }
        }
    }
    user:chat.message("Tree trunk created at $pos");
}

Because of the way that I am writing this, it will be able to do pretty much anything Java can doā€¦ But that doesnā€™t mean I am going to go out of my way to do things that donā€™t serve its purpose. What your proposing is that I make FoxLang more or less a super basic scripting language, specifically for server owners who donā€™t know how to code, to make basic plugins or such. At least it seems this way to me.

However, because of the way I am writing the compiler, its going to be pretty abstractā€¦ if someone else wants to make the language a little bit more like that, then i welcome them wholeheartedly.

I feel like I made a mistake when I said this was a scripting language at the start, its a programming languageā€¦ One that is a bit Object Oriented, and a bit Functional.

It IS NOT really meant to replace an existing system, cause it is really targeting a specific use-case, I just decided that since I am doing all this work, I might as well make it be able to do all the things.
It is meant for quick bits of code, and potentially much longer more complex ones; if you want it to be more complex, youā€™re going to have to know some programming theory either way.


I feel after writing this, that I am shooting your idea to scraps, which isnā€™t really the purpose, and if I seem a bit short I apologize, its been a long IRL day. My point is simply that what you do with the system, is entirely up to you, and you could use it and abuse it as much as you want. I am really only looking for features regarding its initial purpose at the moment though.

In other news, I should have an initial binary released sometime in the very near future, if people would like to take a look at it.

1 Like

Iā€™ll definitely mention it to the guy who runs our server nowadays. Heā€™s a little familiar with Java so perhaps he could make use of your work. Thanks for your time!