https://github.com/bridge-core/molang
Fast MoLang parser for JavaScript/TypeScript applications
https://github.com/bridge-core/molang
hacktoberfest interpreter javascript molang molang-parser parser typescript
Last synced: about 1 year ago
JSON representation
Fast MoLang parser for JavaScript/TypeScript applications
- Host: GitHub
- URL: https://github.com/bridge-core/molang
- Owner: bridge-core
- License: mit
- Created: 2019-12-25T14:30:01.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-08-02T00:19:25.000Z (almost 2 years ago)
- Last Synced: 2025-04-11T21:03:49.382Z (about 1 year ago)
- Topics: hacktoberfest, interpreter, javascript, molang, molang-parser, parser, typescript
- Language: TypeScript
- Homepage:
- Size: 1020 KB
- Stars: 18
- Watchers: 2
- Forks: 5
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Molang
A fast Molang parser used and developed by the bridge. team. This library has full support for all of Minecraft's Molang features.
## About
> Molang is a simple expression-based language designed for fast calculation of values at run-time. Its focus is solely to enable script-like capabilities in high-performance systems where JavaScript is not performant at scale. We need scripting capabilities in these low-level systems to support end-user modding capabilities, custom entities, rendering, and animations.
\- From the Minecraft documentation
## Installation
- `npm i molang`
**or**
- Download the `dist/main.web.js` file and add the script to your HTML page (library access via global `Molang` object).
## Basic Usage
To execute a basic Molang statement, first construct a new instance of the `Molang` class. The first constructor argument is the environment your Molang script will have access to and the second argument configures the Molang interpreter. Take a look at the `IParserConfig` interface [for a list of all available options](https://github.com/bridge-core/Molang/blob/master/lib/main.ts).
`molang.execute(...)` simply executes a Molang script and returns the value it evaluates to.
```javascript
import { Molang } from 'molang'
const molang = new Molang(
{
query: {
x: 0,
get(val) {
return val + 4
},
},
},
{ useCache: true }
)
molang.execute('query.x + query.get(3) == 7')
```
### Setting up nested environments
For the context switching operator "->", you can set up nested environments like this:
```javascript
import { Molang, Context } from 'molang'
const molang = new Molang({
query: {
test: 1,
},
context: {
other: new Context({
query: { test: 2 },
}),
},
})
molang.execute('query.test') // Returns 1
molang.execute('context.other->query.test') // Returns 2
```
## Using Custom Molang Functions
Custom Molang functions were designed to support `.molang` files within bridge.
```javascript
import { CustomMolang } from 'molang'
const customMolang = new CustomMolang({})
const molangFunctions = ... // Somehow load Molang input that defines custom functions
// Make custom functions known to Molang parser
customMolang.parse(molangFunctions)
const molangSource = ... // Somehow load Molang source from JSON files
const transformedSource = customMolang.transform(molangSource)
... // Write the transformed source string back to the JSON file or do further processing
```
A custom Molang function is defined like this:
```javascript
function('sq', 'base', {
return math.pow(a.base, 2);
});
function('pow', 'base', 'exp', {
return a.exp == 0 ? 1 : a.base * f.pow(a.base, a.exp - 1);
});
```
- The first argument always defines the function name
- All following arguments except the last one define input arguments
- The last argument is the function body
- Temporary variables get scoped to the current function body automatically
- Basic recursion is supported as long as the interpreter can stop the recursive calls at compile-time
- To call a function inside of Molang scripts, simply do `f.sq(2)` or `f.pow(3, 2)`
## Using AST Scripts
You can write abitrary scripts to traverse the abstract syntax tree this library builds.
```javascript
import { Molang, expressions } from 'molang'
const molang = new Molang()
let ast = molang.parse(`context.other->query.something + 1`)
const { NumberExpression } = expressions
// This increments all numbers within a Molang script
ast = ast.walk((expr) => {
if (expr instanceof NumberExpression)
return new NumberExpression(expr.eval() + 1)
})
const output = ast.toString() // 'context.other->query.something+2'
```
## Performance
**Disclaimer:** Both bridge.'s Molang library and Blockbench's library are usually fast enough. However, bridge.'s Molang interpreter shines when it comes to executing a wide variety of different scripts (ineffective cache) where it is up to 10x faster at interpreting a vanilla Molang script.
### Vanilla Script
The following script gets executed 100,000 times for the first test:
`variable.hand_bob = query.life_time < 0.01 ? 0.0 : variable.hand_bob + ((query.is_on_ground && query.is_alive ? math.clamp(math.sqrt(math.pow(query.position_delta(0), 2.0) + math.pow(query.position_delta(2), 2.0)), 0.0, 0.1) : 0.0) - variable.hand_bob) * 0.02;`
### Molang
Used by bridge.
| Test | Average Time |
| -------------------------- | ------------ |
| Parse & Execute (uncached) | 1253.332ms |
| Parse & Execute (cached) | 90.036ms |
### MolangJS
Used by Blockbench & Snowstorm
| Test | Average Time |
| -------------------------- | ------------ |
| Parse & Execute (uncached) | 11872ms |
| Parse & Execute (cached) | 185.299ms |
### Early Return
The same script as above, except that we now insert a "return 1;" in front of it. bridge.'s interpreter is smart enough to figure out that the whole expression is static after it parsed `return 1;`. These kinds of optimizations can be found throughout our library.
### Molang
Used by bridge.
| Test | Average Time |
| -------------------------- | ------------ |
| Parse & Execute (uncached) | 103.61ms |
| Parse & Execute (cached) | 8.835ms |
### MolangJS
Used by Blockbench & Snowstorm
| Test | Average Time |
| -------------------------- | ------------ |
| Parse & Execute (uncached) | 13230.682ms |
| Parse & Execute (cached) | 147.786ms |
## Molang Playground
We have built a very basic Molang playground with this interpreter. You can use it at [bridge-core.github.io/molang-playground](https://bridge-core.github.io/molang-playground).