Bribe
vJass errors are legion
- Reaction score
- 67
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.
Fraction module (nearly-useless in the JASS environment, I have it here to show off the syntax):
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.
The basics (many more things I don't have time to explain):
Please post requests, comments and/or constructive criticism.
Alternate discussion: http://www.hiveworkshop.com/forums/showthread.php?t=193557/
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.
Fraction module (nearly-useless in the JASS environment, I have it here to show off the syntax):
Code:
lib Fraction:
"""
Fraction, based on the fraction module from Python, allows you to do math
without floating points & automatically simplifies ((3, 12) becomes (1, 4)).
"""
float class: # adds its members to the float class to allow syntax like bj_DEGTORAD.round()
public int round():
return R2I(self + float.tertiaryOp(self > 0, 0.50, -0.50))
public bool rational(int p=3):
p = R2I(10 ** p)
return self * p == R2I(self) * p
int class:
public int length():
return I2S(self).length()
# Greatest-common-denominator for a fraction to be simplified into.
public int getGCD(int num, int den):
while den > 0:
int pnum = num
num = den
den = pnum % den
return num
class fraction:
readonly int num, den
# f.set(1, 2) sets the numerator & denominator to whatever you want.
public:
fraction set(int a, int b):
int d = int.getGCD(a, b)
if d != 0:
self.num = a / d
self.den = b / d
else:
self.num = 0
self.den = 1
return self
static fraction create(int num, int den):
return fraction.allocate().set(num, den)
# Ease-of-use API:
static fraction fromInt(int i):
fraction self = fraction.allocate()
self.num = i
self.den = 1
return self
static fraction fromFloat(float f, int p):
p = R2I(10 ** p)
return fraction.create(R2I(f * p), p)
float product():
return num / I2R(den)
fraction copy():
return fraction.create(num, den)
nothing display(float duration):
print(time=duration, "Fraction(\$num, \$den)")
# Math API
fraction add(fraction f):
return self.set(self.num * f.den + self.den * f.num, self.den * f.den)
fraction sub(fraction f):
return self.set(self.num * f.den - self.den * f.num, self.den * f.den)
fraction mul(fraction f):
return self.set(self.num * f.num, self.den * f.den)
fraction div(fraction f):
return self.set(self.num * f.den, self.den * f.num)
# Comparison API
bool eq(fraction f):
return self.num == f.num and self.den == f.den
bool gt(fraction f):
return self.num * f.den > f.num * self.den
bool lt(fraction f):
return self.num * f.den < f.num * self.den
internal:
timer clock = CreateTimer()
fraction list[]
int size = 0
# Returns a self-destroying fraction instance.
public fraction Fraction(int num, int den):
fraction self = fraction.create(num, den)
list[size] = self
size++
clock.start(0, false, lambda nothing:
int i = size - 1
size = 0
while i >= 0:
list[i].destroy()
i--
)
return self
The basics (many more things I don't have time to explain):
- 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, bool flag): if u.shouldBePaused: u.pause(flag) else: debug print("TRIED TO PAUSE UNIT THAT SHOULD NOT BE PAUSED!") # Hook after hook.after: nothing DestroyGroup(group g): if g == ENUM_GROUP: print("GROUP UTILS ERROR: ATTEMPT TO DESTROY ENUM_GROUP") ENUM_GROUP = CreateGroup() # Hook before is the current incarnation of vJass hooks hook.before: bool UnitDamageTarget(unit u, unit t, float f, bool ranged, bool attack, attacktype a, damagetype d, weapontype w): u.scriptedAttack = true
- Placing a "\$" token within a ""-type string will treat its following segment as an I2S or R2S or basic string with concatenation.
Code:print("JASS max array size is: \$JASS_MAX_ARRAY_SIZE") # is the same as: BJDebugMsg("JASS max array size is: " + I2S(JASS_MAX_ARRAY_SIZE)) # You can also do: print(JASS_MAX_ARRAY_SIZE.name) # This produces a string of the variable name itself. # It tries to be as intelligent as it can, taking into account "." extensions and function calls.
- You can design a function to have optional parameters.
JASS:public unit NewUnit(player p=Player(0), int id=039;hfoo039;, float x=0, float y=0, float face=0): return CreateUnit(p, id, x, y, face)
The above can be written dynamically, with intuitive variations.
- Anonymous functions as so:
Code:onInit: trigger t = trigger.create() t.addCondition(Filter(lambda bool: # return false is added automatically if there are no return statements found. ))
- 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 //! runtextmacro macro() # New: procedure process(): write: DoNothing() luck.process()
- Modules are deleted in favor of merging them into procedures.
Code:procedure module(): include: readonly static float x readonly static float y # Only this procedure can set these include: onInit: x = 10 y = 10 # Works. write: onInit: x = 10 # This works too. You just can't set them outside of the procedure.
- Procedures can have variables of their own and use "config" objects as "globals".
Code:config GLOBAL = 0 procedure process(name, type): GLOBAL++ wrapper = "" if type.type == handle: wrapper = '.getId()' elif type.type != int: throw "'type' must be an int or a handle!" local i = 10 while i > 0: write: int GetData{GLOBAL}{i}({type} myVar): return data.get(myVar{wrapper}) i--
- As you can see, curly brackets are now used instead of "$" tokens.
- Procedures can be nested and taking into account multi-layed writing:
Code:procedure A(): write: DoNothing() procedure B(): write: luck.A()
"A" writes "DoNothing()", "B" writes what A writes, so "B" effectively writes "DoNothing()"
- You also have the bookmark keyword to specify where to write to.
Code:procedure duo(): write(myBookmark): t.addAction(lambda nothing: DoNothing() ) luck.duo() onInit: 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 int rawcodes if passed as an int 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: [ljass]string s = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdx"[/ljass]
New: [ljass]string s = 'Abilities\Weapons\FarseerMissile\FarseerMissile.mdx'[/ljass]
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. - 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.
- Array structs and normal structs are treated very similarly which allows you to have total control. 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. Struct arrays are capped at 8192, nothing more or less.
- The new "throw" keyword allows you to define your own syntax errors.
JASS:if myStruct.onDestroy.exists: self.onDestroy() else: throw 039;Error: "onDestroy" not found!039;
- Notice self is used here. Taking a step back for objectivity, I thought if there was no such thing as vJass or Python and I had to choose between "this" and "self", I chose "self".
- Readonly library variables
- Top-sort for structs instead of letting methods get turned into trigger evaluations if they are located below a method calling them.
- 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 things. The initialization process inside of each library will be "priority->struct->library". "onInit.priority" is essentially the same as a module init.
- "xor" added.
Please post requests, comments and/or constructive criticism.
Alternate discussion: http://www.hiveworkshop.com/forums/showthread.php?t=193557/