• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

JassHelper Remake: A Modern C++20 Compiler Reimplementation Project for vJASS/Zinc

Level 3
Joined
Mar 14, 2019
Messages
8
Recently, I’ve been working on a long-term refactoring project: JassHelper Remake.

The performance of the legacy JassHelper is honestly quite poor. Even without using T, compiling my roughly 7 million characters / 150,000 lines of JASS code with the old JassHelper takes about 2–3 minutes per build.

I searched extensively but couldn’t find any modern replacement JassHelper compiler, and I didn’t dig into the original JassHelper source code either. Of course, Lua can be used for map scripting—and it’s not necessarily harder than JASS—but I’ve already built too many existing libraries around JASS, so migrating away from it isn’t realistic for me.

The goal of this project is to reimplement the classic JassHelper using modern C++20, compiling vJASS / Zinc into standard JASS (war3map.j), while addressing the old tool’s shortcomings in parallel compilation, maintainability, and static analysis.

Core positioning:
Compatible with both vJASS and Zinc syntax, supporting syntax mode switching within the same file.

Compilation architecture:
Preprocessor → Lexer → Parser → AST → SymbolTable → CodeGen, with a fully modular pipeline.

Performance direction:
File-level multithreaded parsing + multi-phase parallel validation.
At the moment, performance is already very impressive: JassHelper takes 2–3 minutes to compile my project once, while my compiler finishes the same project in about 1 second.

Code generation:
Implements struct-to-array modeling, method dispatch, a function pointer system, and main/config template injection.

Engineering setup:
Built with CMake + MSBuild, directly buildable on Windows and integrable into the map import workflow.

Key feature: Desync static analysis (annotation-driven)

This is a highly practical feature. During development, we generally understand how desync occurs—but it’s nearly impossible to eliminate it completely. Once it happens, tracking down the root cause can take weeks and hundreds of test games. (Of course, this is unlikely to happen with T.)

My approach is based on a taint-propagation algorithm:

  • When you use a dangerous function (e.g., GetLocalPlayer), any variable, branch, assignment, or hashtable entry derived from its return value is marked as “tainted” (unreliable).
  • If a tainted value is later used inside a handle-operation function, or participates in a conditional that leads to a handle operation, the compiler emits a warning.
So you might see annotations like:

JASS:
//@ desync handle-op 3
native GetRandomInt takes integer lowBound, integer highBound returns integer
native GetRandomReal takes real lowBound, real highBound returns real

JASS:
//@ desync danger 17
constant native GetCameraBoundMinX          takes nothing returns real
constant native GetCameraBoundMinY          takes nothing returns real
constant native GetCameraBoundMaxX          takes nothing returns real
constant native GetCameraBoundMaxY          takes nothing returns real
constant native GetCameraField              takes camerafield whichField returns real
constant native GetCameraTargetPositionX    takes nothing returns real
constant native GetCameraTargetPositionY    takes nothing returns real
constant native GetCameraTargetPositionZ    takes nothing returns real

If you believe the compiler warning is a false positive, you can write:

//@ desync safe

This causes the next line to skip desync detection.

The compiler also supports set null detection. As we all know, in JASS, if you don’t set a handle variable to null at the end of a function, that handle will never be properly released.

Additionally, several modern language features are supported, such as:

  • Ternary expressions
  • Removing the restriction that variables must be declared at the top of a function
  • Default parameter values
  • A complete for loop syntax
The project has now entered a “usable + continuously optimizing” phase. Recent focus areas include improving desync analysis accuracy (cross-function propagation, call graph construction, false-positive mitigation) and compatibility with large-scale map scripts.

If you’re working on Warcraft 3 map development or JASS/vJASS toolchains, feel free to share test cases and edge-case syntax scenarios—let’s refine this compiler together and make it more robust.

PS: The compiler currently does not support anything related to T—not even map regions, camera objects, global variables, or JASS written directly in the editor. I may not plan to support T compatibility in the future either.
 
The performance of the legacy JassHelper is honestly quite poor. Even without using T, compiling my roughly 7 million characters / 150,000 lines of JASS code with the old JassHelper takes about 2–3 minutes per build.

I searched extensively but couldn’t find any modern replacement JassHelper compiler, and I didn’t dig into the original JassHelper source code either. Of course, Lua can be used for map scripting—and it’s not necessarily harder than JASS—but I’ve already built too many existing libraries around JASS, so migrating away from it isn’t realistic for me.

If I'm not mistaken, the YDWE PK fast map saving plugin does this.
I don't have too much code, so it would be nice if you tested it.
 
What is T?
Second question, are you sure you'll be able to understand the spaghetti logic of vJass and JassHelper to output equivalent Jass?
Third question, although it's been a standalone thing, but I like to annoy people about completeness: cJass?
Fourth and final question: considering the nuissance of performance, are you sure it's better than profiling and optimizing JassHelper to fix the minute long compiles?

All the other stuff sounds cool.
 
What is T?
Second question, are you sure you'll be able to understand the spaghetti logic of vJass and JassHelper to output equivalent Jass?
Third question, although it's been a standalone thing, but I like to annoy people about completeness: cJass?
Fourth and final question: considering the nuissance of performance, are you sure it's better than profiling and optimizing JassHelper to fix the minute long compiles?

All the other stuff sounds cool.
  1. T refers to GUI.
  2. At the moment, it works equivalently on my 150k-line Zinc codebase. vJass itself isn’t very complex — the main tricky parts are structs and function pointers, but those have already been resolved.
  3. Sorry, it doesn’t support cJass. However, Zinc can be used as an alternative.
  4. I feel that trying to optimize vJass and make it support multithreading would be harder than just rewriting it from scratch. Also, I couldn’t find a GitHub repository for JassHelper.

I think the more important feature would be editor support for desync warnings. That workload is actually more complex and troublesome than building the compiler itself.

At the same time, since we now have traceable and source-trackable algorithms, it might be possible to implement a leak detection system at the compiler level. For example, if CreateGroup is found in the logic but no corresponding RemoveGroup is detected, the compiler could issue a warning.


However, in practice, a few thousand leaks in-game are usually not a serious problem and don’t noticeably affect performance, so I’m still considering whether this feature is worth implementing.
 
vJass itself isn’t very complex
I don't know... I nearly had a brain meltdown trying to accomodate vJass syntax features for Notepad++ highlighting.
Sorry, it doesn’t support cJass. However, Zinc can be used as an alternative.
b-but you said your architecture is modular. Won't it be easy to add a preprocessor or modify the lexer/parser?
it might be possible to implement a leak detection system at the compiler level.
If you don't, I will. This is both a threat and a promise and I hope you'll work on it instead of me, if I ask you nice enough :wgrin:

There exists a hurdle where some natives return null depending on invalid arguments. False positives will be inevitable without a considerable leeway. Very much static analysis territory of trade-offs...
 
I don't know... I nearly had a brain meltdown trying to accomodate vJass syntax features for

b-but you said your architecture is modular. Won't it be easy to add a preprocessor or modify the lexer/parser?

If you don't, I will. This is both a threat and a promise and I hope you'll work on it instead of me, if I ask you nice enough :wgrin:

There exists a hurdle where some natives return null depending on invalid arguments. False positives will be inevitable without a considerable leeway. Very much static analysis territory of trade-offs...
In fact, using VS Code to build a syntax plugin is much easier. I previously made a Zinc syntax highlighting plugin for my own use, and I also implemented automatic parameter passing for closures. That way, I no longer have to manually write that silly hashtable → timer parameter-passing boilerplate every time.


Actually, I added a “unused return value” warning to the compiler. If you call a function that returns a value and don’t handle the return value, the compiler will issue a warning. In C/C++ standards, handling return values is generally required. Of course… this currently results in thousands of warnings in the existing project.


It’s very easy to implement, but I haven’t used cJass before. Supporting an unfamiliar syntax could cause issues, since I don’t have enough real-world code samples to properly test compatibility. Moreover, as far as YDWE is concerned, CJass is no longer recommended, so switching to Zinc would be the better choice.
 
GitHub - LuciferFor/JassForge-Project
Finished writing it — this is the scaffold.

I don't know... I nearly had a brain meltdown trying to accomodate vJass syntax features for Notepad++ highlighting.

b-but you said your architecture is modular. Won't it be easy to add a preprocessor or modify the lexer/parser?

If you don't, I will. This is both a threat and a promise and I hope you'll work on it instead of me, if I ask you nice enough :wgrin:

There exists a hurdle where some natives return null depending on invalid arguments. False positives will be inevitable without a considerable leeway. Very much static analysis territory of trade-offs...
You can try the link above.
 
"Project/Parser.h" not pushed to git:
Code:
...git\JassForge-Project> tree /f /a
Code:
|   .gitignore
|   jassforge.exe
|   JassForge_语言参考.md
|   makefile.common.ps1
|   makefile.ps1
|   makefile1.ps1
|   makefile_run.ps1
|   Map.w3x
|   README.md
|   Storm.dll
|   sync.exe
|
+---.vscode
|       settings.json
|
\---JassFrame
    +---import
    |       blizzard.j
    |       common.j
    |       DzAPI.j
    |       Platformapi_common.j
    |
    +---include
    |       EXJapi.j
    |       main.j
    |
    \---JassCode
        \---Project
            \---Main
                    Main.j
 
Back
Top