EngineScript (Scripting Language)

I have been working with my team, 2Pablos Games. We are currently working on a Scratch game with its game engine, and we are also working on a Roblox framework on the side. In order to introduce various new ideas, I have been working on designing a scripting language called EngineScript, a high-level table-oriented (every object is a table) multi-paradigm language.

The language is still in development, and there's no interpreter yet. Please tell me what you think, and I can respond to questions. To see more examples, check the website, as I will eventually update it to further explain the syntax and semantics.

-- Hello, world!
console.print("Hello, world!")

-- Factorial
local fact = [n]{
	-- not(order(n, 0)); not n > 0; n <= 0
	-- *(number, fact(-(number, 1)))) == n * fact(n - 1)
	check(not(order(n, 0)), 1, *(n, fact(-(n, 1))))
}; console.print(fact(5))

-- Fibonacci
local fib = [n]{
	-- +(fib(-(n, 1)), fib(-(n, 2))) == fib(n - 1) + fib(n - 2)
	check(order(2, n), n, +(fib(-(n, 1)), fib(-(n, 2))))
}; fib(10)

-- FizzBuzz
local loop = [num, out]{
	local fizz = equal(%(num, 3), 0) -- n % 3 == 0
	local buzz = equal(%(num, 5), 0) -- n % 5 == 0
	out.insert(check(fizz, check(buzz, "FizzBuzz", "Fizz"), check(buzz, "Buzz", num)))
	check(order(100, num), loop(+(num, 1)), out)
}; console.print:loop(1)

What do table-oriented mean?

A table-oriented language uses tables to represent data. To explain this, let's define then use a function (variable as a lambda object).

local foo = {}

When this program runs, it sets foo.self to the lambda object, which is used when we use it as a function. But, because foo is a table, we can define items with the variable.

foo.bar = 42
foo(), foo.bar -- both legal

This is because foo is ["self" = {}, "bar" = [self = 42], ...]. This can be useful because instead of defining two items in a table like items = [main = {}, sub = {}] to main = [self = {}, sub = {}].

uh, I can't figure out how to test it out, so, can you tell me?

It's still on its design stage, there's no interpreter. You can write them in Snap instead for now.

oh, ok. You could say that it's still in the design process, I thought it was done.

Understand the confusion, I will edit the post for some clarity.


I believe that "order" is a bound on the absolute value of a number, not the number itself.

order() doesn't covert numbers to their absolute value. You write one (check(order(0, x), *(x, -1)), x meaning if 0 < x then x * -1 else x) or use math.absolute(). It returns true if the arguments are ordered from greatest to smallest. It's a way to conserve tokens when passing the program, so that's why +(a, b) is used instead of a + b.

I understand how you're using it. What I mean is that I don't think that's what the word means, outside of your language.

The reason why it's called order because your are checking the order of the arguments from the biggest to the smallest. Do you have any suggestions on what it should be called instead?

Sure: ≤.

Thanks for your suggestion. Does the symbol is for something like a ≤ b ≤ c, because it doesn't include equality, so it would look like a > b > c or c < b < a. In the logic module, fairOrder() checks equality and inequality, so something like fairOrder(3, 2, 2, 1) means 3 ≥ 2 ≥ 2 ≥ 1.

I prefer to easily type the functions names than to look up characters. Fortunately, you can define a variable with your preferred name attached to a specific function.

local >, !, & = order, not, all
>(9, 7, 5, 3, 1) -- order(9, 7, 5, 3, 1)
!(true, false) -- not(true, false)
&(true, false, true) -- all(true, false, true)