- Joined
- Sep 26, 2009
- Messages
- 9,534
Edit August 2023 - Please see GitHub - wurstscript/WurstScript: Programming language that compiles to Jass and Lua (the language to create Warcraft III Maps). for the actual parser that should be used if you prefer this type of syntax.
old stuff, will not be done:
I'm going to be writing an entirely new compiler. It will be like Jass Shop Pro where it doesn't interface directly with World Editor or Jass NewGen Pack, so it will work on Mac OS X systems as well as PC's. It will have its own GUI with syntax highlighting, very beginner-friendly syntax checking that displays proper error messages, and of course it compiles as well. In fact, you won't even have to have WarCraft III installed on the computer in order to open, edit and save a project.
It will work with a map that was already saved with World Editor or Jass NewGen Pack so backwards compatibility will already be there by default.
Unlike Jass Shop Pro, the war3map.j contents will be invisible while editing, so you have an interface more like the trigger editor where each library can have its own frame, making it so you don't have to throw all of the script together yourself.
As you can see based on this script, I am using Python-style comments and block comments for personality's sake. JASS comments and vJass block comments will not parse.
More like JASS, the "local" keyword is required to declare local variables. However, you can also declare local functions and local static variables, making it very easy to name your variables (without risking conflict with other systems).
The normal solution is to include things in different "scopes", but it is more logical to associate it directly with the only function that uses it.
Please post requests, comments and/or constructive criticism.
Alternate discussion: http://www.thehelper.net/forums/showthread.php/163961-JassHelper-Update
old stuff, will not be done:
I'm going to be writing an entirely new compiler. It will be like Jass Shop Pro where it doesn't interface directly with World Editor or Jass NewGen Pack, so it will work on Mac OS X systems as well as PC's. It will have its own GUI with syntax highlighting, very beginner-friendly syntax checking that displays proper error messages, and of course it compiles as well. In fact, you won't even have to have WarCraft III installed on the computer in order to open, edit and save a project.
It will work with a map that was already saved with World Editor or Jass NewGen Pack so backwards compatibility will already be there by default.
Unlike Jass Shop Pro, the war3map.j contents will be invisible while editing, so you have an interface more like the trigger editor where each library can have its own frame, making it so you don't have to throw all of the script together yourself.
To finish by end-of-June:
- Getting the right API for Luck
- Writing the parser for Luck (keywords, operators, optimization, procedures, writing it to war3map.j, etc.)
- Enabling the parser to write to MPQ
- Compiling the parser
- Syntax Highlighting plugin (I will release a Notepad++ UDL so you WILL have syntax highlighting, just not built-in with the program itself just yet)
- Compiler to turn vJass scripts into Luck scripts
- Adding more functionality to procedures
Code:
library Fraction:
"""
Fraction, based on the fraction module from Python, allows you to do math
without floating points & automatically simplifies ((3, 12) becomes (1, 4)).
"""
real struct: # adds its members to the real struct to allow syntax like bj_DEGTORAD.round()
public integer round():
return R2I(this + real.tertiaryOp(this > 0, 0.50, -0.50))
public boolean rational(integer p=3):
p = R2I(10 ** p)
return this * p == R2I(this) * p
integer struct:
public integer length(): return I2S(this).length()
# Greatest-common-denominator for a fraction to be simplified into.
public integer getGCD(integer(num, den)):
while den > 0:
integer pnum = num
num = den
den = pnum % den
return num
struct fraction:
readonly integer num, den
# f.set(1, 2) sets the numerator & denominator to whatever you want.
public:
fraction set(integer(a, b)):
local integer d = integer.getGCD(a, b)
if d != 0:
this.num = a / d
this.den = b / d
else:
this.num = 0
this.den = 1
return this
static fraction create(integer(num, den)): return fraction.allocate().set(num, den)
# Ease-of-use API:
static fraction fromInt(integer i):
local fraction this = fraction.allocate()
this.num = i; this.den = 1
return this
static fraction fromFloat(real f, integer p):
p = R2I(10 ** p)
return fraction.create(R2I(f * p), p)
real product(): return num / I2R(den)
fraction copy(): return fraction.create(num, den)
nothing display(real duration):
print(duration, "Fraction(" + num + ", " + den + ")")
# Math API
fraction add(fraction f): return this.set(this.num * f.den + this.den * f.num, this.den * f.den)
fraction sub(fraction f): return this.set(this.num * f.den - this.den * f.num, this.den * f.den)
fraction mul(fraction f): return this.set(this.num * f.num, this.den * f.den)
fraction div(fraction f): return this.set(this.num * f.den, this.den * f.num)
# Comparison API
boolean eq(fraction f): return this.num == f.num and this.den == f.den
boolean gt(fraction f): return this.num * f.den > f.num * this.den
boolean lt(fraction f): return this.num * f.den < f.num * this.den
# Returns a this-destroying fraction instance.
public fraction Fraction(integer num, integer den):
local static:
timer clock = CreateTimer()
fraction list[]
integer size
local fraction this = fraction.create(num, den)
list[size] = this
size++
clock.start(0, false, lambda nothing:
integer i = size - 1
size = 0
while i >= 0:
list[i].destroy()
i--
)
return this
More like JASS, the "local" keyword is required to declare local variables. However, you can also declare local functions and local static variables, making it very easy to name your variables (without risking conflict with other systems).
JASS:
globals
private integer i = 0
endglobals
function foo takes nothing returns nothing
call BJDebugMsg(I2S(i))
endfunction
globals
private integer i = 1 //Conflict!
endglobals
function bar takes nothing returns nothing
call BJDebugMsg(I2S(i))
endfunction
Code:
nothing spam():
local static integer i = 0
print(i)
nothing eggs():
local static integer i = 1 # No conflict
print(i)
- Primary language will be Luck. vJass backwards-compatibility will be added after the initial release. Zinc will not be supported. For now I have no plans for a c-like build.
- hooks restructured to allow hooking either before or after. I will include the option to fully overwrite the function as well, but the function can only be overwritten once (syntax error for duplicate overwrite attempts).
Code:# Overwrite hook hook: nothing PauseUnit(unit u, boolean flag): if u.shouldBePaused: u.pause(flag) debug else: print("Tried to pause a unit that should not be paused!") # Hook after hook.after: nothing CreateItem(item i): data++ i.userData = data # Hook before is the current incarnation of vJass hooks hook.before: boolean UnitDamageTarget(unit u, unit t, real f, boolean ranged, boolean attack, attacktype a, damagetype d, weapontype w): u.scriptedAttack = true
- Concatenating an integer or real directly will automatically add I2S or R2S wrappers to soften the workload for you.
Code:print("JASS max array size is: " + JASS_MAX_ARRAY_SIZE) # is the same as: print("JASS max array size is: " + I2S(JASS_MAX_ARRAY_SIZE)) # You can also do: print(JASS_MAX_ARRAY_SIZE.varName) # This produces a string of the variable name itself.
- You can design a function to have optional parameters.
JASS:public unit NewUnit(player p=Player(0), integer id='hfoo', real(x=0, y=0, face=0)): return CreateUnit(p, id, x, y, face)
JASS:unit u = NewUnit() unit u = NewUnit('ewsp') unit u = NewUnit(face=180) # Use this flavor to skip to a specific param in case there are multiple entries of the same type.
- Anonymous functions are pretty easy to make:
Code:onInit: local trigger t = trigger.create() t.addCondition(Filter(lambda boolean: return true)) t.addAction(lambda nothing: print("I am awesome") ) if t.evaluate(): t.execute()
- Textmacros totally redefined as procedures to give maximum functionality. You can basically define your own compile-time rules now.
Code:# Old: //! textmacro macro call DoNothing() //! endtextmacro # Call via: //! runtextmacro macro() # New: define process(): write("DoNothing()") # Call via: #! process()
- Modules are deleted in favor of merging them into procedures.
Code:define module(): write(true, "readonly static real x, y") # Only this procedure can set these write("onInit: x = 10; y = 10") # Works.
- Procedures can have variables of their own and use "define" objects as "globals".
Code:define GLOBAL = 0 define process(name, type): GLOBAL++ local wrapper = "" if type.type == 'handle': wrapper = '.id' elif type.type != 'integer': throw "'type' must be an integer or a handle!" local i = 10 while i > 0: write("""\ integer GetData""" + GLOBAL + i + (" + type + """ myVar): return data.get(myVar""" + wrapper + ")" ) i--
- Procedures can be nested and taking into account multi-layered writing:
Code:define A(): return "DoNothing()" define B(): write(A())
"A" returns "DoNothing()", "B" writes what A returns, so "B" writes "DoNothing()" - You also have the bookmark keyword to specify where to write to.
Code:define duo(): write(myBookmark, """\ t.addAction(lambda nothing: DoNothing() ) """) #! duo() onInit: local trigger t = trigger.create() #! bookmark myBookmark # 't' automatically sets to null at the end because t.type is a handle.
- Strings can be indicated either by '' or "". Single and quadruple-length ''-type strings will be treated as integer rawcodes if passed as an integer value, otherwise they will be treated as a string. The advantage is ''-type strings are taken literally so they avoid the need to escape quotes or escape backslashes.
Current:string s = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdx"
New:string s = 'Abilities\Weapons\FarseerMissile\FarseerMissile.mdx'
This also makes it so a straight copy-paste of the model path is now possible without having to change everything to double-backslash, making your script a lot faster to tinker around with. - Multi-line strings are marked with triple-quotes, like in Python.
Code:""" this spans multiple lines """ ''' so does this '''
- Writing "static if" is going to throw a syntax error. Normal if's should intelligently sort out which if's will be static and which will be dynamic.
- All functions, variables and methods are treated as "internal" by default. The "public" keyword needs to be injected to indicate the object can be accessed outside of the library, though "private" and "protected" will be available and the "internal" keyword can be injected for clarity if you wish.
- Script optimization is done automatically. Functions, variables, etc. that are not referenced are deleted during compilation. Shortening names is done as well.
- Structs are a mix between array structs and normal structs but have more syntax potential. Allocate and deallocate can be overwritten and, as mentioned earlier, things that are not referenced are destroyed during optimization. Another thing, "onDestroy" will not use a trigger evaluation unless the struct is also extended. This should make it easier for users who don't want to bother with both overriding "destroy" and calling "deallocate" from it, while still preserving speed.
- I will not include support for custom-defined arrays. Use of the Dictionary library is more clear and much more dynamic.
- The new "throw" keyword allows you to define your own syntax errors.
JASS:if myStruct.onDestroy.exists: this.onDestroy() else: throw 'Error: "onDestroy" not found!'
- Readonly library variables
- All initializers inside of a library will run before all initializers in a library that requires it. This eliminates the need to hack the initialization process by abusing module initializers, as well as restore struct & library initializers as useful creatures. The initialization process inside of each library will be "priority->struct->library". "onInit.priority" is just something you can hardcode to make it initialize before other things.
Please post requests, comments and/or constructive criticism.
Alternate discussion: http://www.thehelper.net/forums/showthread.php/163961-JassHelper-Update
Last edited: