Made this post on another forum, gonna post it here too for posterity.
Well, it's been well over five years since I first started getting into game engine programming, and I guess it's finally official:
I didn't just pull off the "make your own game engine" meme. I didn't just pull off the "make your own game logic scripting language" meme. I made an insane high-level programming language with support for runtime procedural metaprogramming and a simple game engine around it.
I took two stabs at making the language before, but both old versions were a lot worse than what I have now.
So, here it is:
https://github.com/wareya/gammakithttps://github.com/wareya/magmakithttps://streamable.com/p7xrdGammakit is a ridiculous toy programming language that supports runtime code generation, lambdas, generators, first-class primitive data structures (arrays, dicts, maps), and coherent integration into the parent application (magmakit)'s design philosophy with custom types.
It has support for GameMaker-like objects and wrapping the current scope with that of a given instance (i.e. with()), and also implicitly looping over all extant instances of a given object (i.e. GameMaker's specific with()).
Scope looks just like lexical scope, but nested functions don't close over the scope they're defined in. Functions can be passed around in variables.
Global variables are supported but have to be prefixed with "global."; global functions exist and don't need to be prefixed.
There are "subroutine"-like functions which execute as though they were code written inline where they were called (i.e. they can access the parent stack frame).
Primitive collections stored in variables can be modified with method-like function bindings, like myarray->remove(5).
The language doesn't have a concept of references, except for the manually-managed IDs of instances. Yes, really. Gammakit is implemented without anything resembling a garbage collector, and without doing any analysis of what variables or values belong to what code. Everything is managed at runtime.
The language's grammar has a declarative specification. The parser is a PEG-like recursive descent parser with support for backtracking. The compiler compiles to bytecode, which is executed in an ad-hoc virtual machine. There are built-in binding functions like "print", but the parent application doesn't have to provide them to the interpreter.
Code can be generated at runtime using parsing and compilation bindings, resulting in a function-like value that you can store in a variable and pass around cheaply and call however many times you want.
Did I mention that it supports generators? You know, semicoroutines? Those things that are super useful for AI scripts, visual novels, and virtual machines?
And it's not JUST a toy. I have a proof-of-concept of the very beginnings of a game written in Magmakit, a toy game engine that adds bindings for things like sprite loading, drawing, and input, and has a mainloop. Let me link that streamable again.
https://streamable.com/p7xrdTHIS is what you get when you go "I don't like this. I want to make my own." instead of just making a game in an existing game engine. A dev art sprite jumping around on tiles.