• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

PJass updates

Status
Not open for further replies.
Level 9
Joined
Jul 20, 2018
Messages
176
Hm, I am still getting a lot of errors.

1618304929173.png
 
Level 13
Joined
Nov 7, 2014
Messages
571
shameless plug...

@Prometheus3375

Although it's unlikely that you will get better error messages from JiffyJass' check mode than pjass, you could try, maybe?
There's a script attached to this post that you can use to convert your 'common.j' to something that can be used by JiffyJass for the type checking.

Code:
> ls
common.j mapscript.j phonyup.j
> jj run phonyup.j -- common.j
processing file 'common.j'... done (3.14159 seconds)
> ls
common.j mapscript.j phonyup.j phony_common.j
> jj check mapscript.j phony_common.j
mapscript.j:2:10: error: undeclared function 'BJDebugMsg'
 

Attachments

  • phonyup.j
    15.1 KB · Views: 39
Level 9
Joined
Jul 20, 2018
Messages
176
@Aniki, that problem is not very important. Basically, I noticed this huge amount of errors only when one person reported JassHelper freezing during printing errors. We solved this, and the problem was not in pjass.exe.
 
Last edited:
Level 13
Joined
Nov 7, 2014
Messages
571
@LeP

The 'code' type is rather strange. One can assign to a variable of type 'code' a function that returns anything (any type) and nothing (void type). pjass doesn't seem to complain (ignoring the '+filter' flag and the ('Filter', 'Condition') natives) and the game is probably fine with this "loophole" in the type system?

Code:
function f1 takes nothing returns nothing
    return
endfunction
function f2 takes nothing returns integer
    return 0
endfunction
function f3 takes nothing returns real
    return 0.0
endfunction
function f4 takes nothing returns boolean
    return false
endfunction
function f5 takes nothing returns string
    return ""
endfunction
function f6 takes nothing returns code
    return null
endfunction
function f7 takes nothing returns handle
    return null
endfunction
function main takes nothing returns nothing
    local code x1 = function f1
    local code x2 = function f2
    local code x3 = function f3
    local code x4 = function f4
    local code x5 = function f5
    local code x6 = function f6
    local code x7 = function f7
endfunction
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
We solved this, and the problem was in in pjass.exe.
+ not in pjass.exe

The 'code' type is rather strange
Yes it is.

One can assign to a variable of type 'code' a function that returns anything (any type) and nothing (void type). pjass doesn't seem to complain (ignoring the '+filter' flag and the ('Filter', 'Condition') natives) and the game is probably fine with this "loophole" in the type system?

Code:
function f1 takes nothing returns nothing
    return
endfunction
function f2 takes nothing returns integer
    return 0
endfunction
function f3 takes nothing returns real
    return 0.0
endfunction
function f4 takes nothing returns boolean
    return false
endfunction
function f5 takes nothing returns string
    return ""
endfunction
function f6 takes nothing returns code
    return null
endfunction
function f7 takes nothing returns handle
    return null
endfunction
function main takes nothing returns nothing
    local code x1 = function f1
    local code x2 = function f2
    local code x3 = function f3
    local code x4 = function f4
    local code x5 = function f5
    local code x6 = function f6
    local code x7 = function f7
endfunction
If pjass says it's correct and it doesn't work ingame that's a bug. I assume it works though? Can't really test it, so feel free to report it :)
 
Level 13
Joined
Nov 7, 2014
Messages
571
It seems the game thinks that (tested on version 1.31):
  • returning nothing is false (probably because of the implicit return 0 in the bytecode)
  • returning integer 1 is true, 0 is false
  • returning real 1.0 is true, 0.0 is false
  • returning boolean true is true, false is false :^)
  • returning string "" is true, null is false ("" has a non-zero id in the string table?)
  • returning code function DoNothing is true, null is false (note: "return null" in a function that returns code doesn't compile?)
  • returning handle Location(0, 0) is true, null is false

Makes sense... I suppose.
I can't think of a way that makes these "bad booleans" problematic.

Code:
function writeln takes string s returns nothing
    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 10.0, s)
endfunction

function unitNew takes integer id returns unit
    return CreateUnit(Player(0), id, 0.0, 0.0, 270.0)
endfunction

function f1 takes nothing returns nothing
    call writeln("f1")
    // return
    // there is an implicit return 0 (in the bytecode)
endfunction
function f2 takes nothing returns integer
    call writeln("f2")
    return 1
    // return 0
endfunction
function f3 takes nothing returns real
    call writeln("f3")
    return 1.0
    // return 0.0
endfunction
function f4 takes nothing returns boolean
    call writeln("f4")
    return true
    // return false
endfunction
function f5 takes nothing returns string
    call writeln("f5")
    return ""
    // return null
endfunction
function f6 takes nothing returns code
    local code codeNil = null
    call writeln("f6")
    return function DoNothing
    // return codeNil // why can't we just return null?
endfunction
function f7 takes nothing returns handle
    call writeln("f7")
    return Location(0.0, 0.0)
    // return null
endfunction

function testCondition takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerAddCondition(t, Condition(function f7))
    if TriggerEvaluate(t) then
        call writeln("true")
    else
        call writeln("false")
    endif
endfunction

function testFilter takes nothing returns nothing
    local group g
    local unit u

    set g = CreateGroup()
    call GroupAddUnit(g,unitNew('hpea'))
    call GroupAddUnit(g,unitNew('hfoo'))
    call GroupAddUnit(g,unitNew('hrif'))
    call GroupAddUnit(g,unitNew('hkni'))
    call GroupEnumUnitsInRect(g, GetWorldBounds(), Filter(function f7))

    call writeln("g.size: "+I2S(BlzGroupGetSize(g)))
    loop
        set u = FirstOfGroup(g)
        exitwhen null == u
        call GroupRemoveUnit(g, u)
        call writeln(GetUnitName(u))
    endloop
endfunction
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
returning code function DoNothing is true, null is false (note: "return null" in a function that returns code doesn't compile?)
return null used to work for a function returning code but it was changed in one of the recent patches. I think i was hestiant to change pjass but if it's still forbidden i might need to add a flag to let the user chose if it is allowed or not depending on their patch :/
 
Level 9
Joined
Jul 20, 2018
Messages
176
+ not in pjass.exe
Fixed.

Can't really test it, so feel free to report it
Yes it works as @Aniki said. You can pass any function with no arguments and with any return type to TriggerAddAction, Filter, Condition, etc. Basically, this is why vJass works. Inside vJass all functions for calling methods/funcs before their declaration return true and then they passed to TriggerAddAction and TriggerAddCondition for .execute() and .evaluate(). These funcs return boolean because original pjass complains when you pass a function with not a boolean return to Filter or Condition. Actually, this is not required at all. I intentionally pass void functions to Filter since all necessary actions a filter function does and no true return is required.

vJASS:
function Y takes nothing returns nothing
    local A a = A.create.evaluate(1)
    call a.m.evaluate(2)
endfunction

struct A
    readonly integer info

    static method create takes integer b returns thistype
        local thistype this = allocate()
        set info = b
        return this
    endmethod

    method m takes integer a returns real
        set info = info + a
        return I2R(info)
    endmethod

    method onDestroy takes nothing returns nothing
        set info = 1
    endmethod

endstruct

JASS:
globals
//JASSHelper struct globals:
constant integer si__A=1
integer si__A_F=0
integer si__A_I=0
integer array si__A_V
integer array s__A_info
trigger st__A_create
trigger st__A_m
trigger st__A_onDestroy
trigger array st___prototype2
integer f__result_integer
integer f__arg_integer1
integer f__arg_this
real f__result_real
endglobals


//Generated method caller for A.create
function sc__A_create takes integer b returns integer
    set f__arg_integer1=b
    call TriggerEvaluate(st__A_create)
return f__result_integer
endfunction

//Generated method caller for A.m
function sc__A_m takes integer this,integer a returns real
        set s__A_info[this]=s__A_info[this] + a
        return I2R(s__A_info[this])
endfunction

//Generated method caller for A.onDestroy
function sc__A_onDestroy takes integer this returns nothing
        set s__A_info[this]=1
endfunction

//Generated allocator of A
function s__A__allocate takes nothing returns integer
local integer this=si__A_F
    if (this!=0) then
        set si__A_F=si__A_V[this]
    else
        set si__A_I=si__A_I+1
        set this=si__A_I
    endif
    if (this>8190) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Unable to allocate id for an object of type: A")
        return 0
    endif

    set si__A_V[this]=-1
return this
endfunction

//Generated destructor of A
function sc__A_deallocate takes integer this returns nothing
    if this==null then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
        return
    elseif (si__A_V[this]!=-1) then
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
        return
    endif
    set f__arg_this=this
    call TriggerEvaluate(st__A_onDestroy)
    set si__A_V[this]=si__A_F
    set si__A_F=this
endfunction
function sc___prototype2_execute takes integer i,integer a1 returns nothing
    set f__arg_integer1=a1

    call TriggerExecute(st___prototype2[i])
endfunction
function sc___prototype2_evaluate takes integer i,integer a1 returns integer
    set f__arg_integer1=a1

    call TriggerEvaluate(st___prototype2[i])
return f__result_integer
endfunction


function Y takes nothing returns nothing
    local integer a= sc__A_create(1)
    call sc__A_m(a,2)
endfunction


    function s__A_create takes integer b returns integer
        local integer this= s__A__allocate()
        set s__A_info[this]=b
        return this
    endfunction

    function s__A_m takes integer this,integer a returns real
        set s__A_info[this]=s__A_info[this] + a
        return I2R(s__A_info[this])
    endfunction

    function s__A_onDestroy takes integer this returns nothing
        set s__A_info[this]=1
    endfunction

//Generated destructor of A
function s__A_deallocate takes integer this returns nothing
    if this==null then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Attempt to destroy a null struct of type: A")
        return
    elseif (si__A_V[this]!=-1) then
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1000.,"Double free of type: A")
        return
    endif
    call s__A_onDestroy(this)
    set si__A_V[this]=si__A_F
    set si__A_F=this
endfunction

//Struct method generated initializers/callers:
function sa__A_create takes nothing returns boolean
local integer b=f__arg_integer1
        local integer this= s__A__allocate()
        set s__A_info[this]=b
set f__result_integer= this
   return true
endfunction
function sa__A_m takes nothing returns boolean
local integer this=f__arg_this
local integer a=f__arg_integer1
        set s__A_info[this]=s__A_info[this] + a
set f__result_real= I2R(s__A_info[this])
   return true
endfunction
function sa__A_onDestroy takes nothing returns boolean
local integer this=f__arg_this
        set s__A_info[this]=1
   return true
endfunction
function sa___prototype2_s__A_create takes nothing returns boolean
local integer b=f__arg_integer1

        local integer this= s__A__allocate()
        set s__A_info[this]=b
    set f__result_integer= this
    return true
endfunction

function jasshelper__initstructs13218656 takes nothing returns nothing
    set st__A_create=CreateTrigger()
    call TriggerAddCondition(st__A_create,Condition( function sa__A_create))
    set st__A_m=CreateTrigger()
    call TriggerAddCondition(st__A_m,Condition( function sa__A_m))
    set st__A_onDestroy=CreateTrigger()
    call TriggerAddCondition(st__A_onDestroy,Condition( function sa__A_onDestroy))
    set st___prototype2[1]=CreateTrigger()
    call TriggerAddAction(st___prototype2[1],function sa___prototype2_s__A_create)
    call TriggerAddCondition(st___prototype2[1],Condition(function sa___prototype2_s__A_create))
endfunction

Pay attention to jasshelper__initstructs13218656 and sa___prototype2_s__A_create.


  • returning nothing is false (probably because of the implicit return 0 in the bytecode)
  • returning integer 1 is true, 0 is false
  • returning real 1.0 is true, 0.0 is false
  • returning boolean true is true, false is false :^)
  • returning string "" is true, null is false ("" has a non-zero id in the string table?)
  • returning code function DoNothing is true, null is false (note: "return null" in a function that returns code doesn't compile?)
  • returning handle Location(0, 0) is true, null is false
False is returned only when all bits of a return value are 0. Such values are false, 0, 0., null. Any other value is not 32 zeros; so, they are true. Also, maybe -0. is also true because the first bit is 1.
 
Last edited:
Level 5
Joined
Mar 6, 2017
Messages
190
I want to report a bug, line 17 got error but pjass did not recognize the error @LeP

edit: I used ENG VI keyboard, when u press number or shift-number it will generate some strange characters. It cause no error in pjass syntax checker but unplayable
 

Attachments

  • war3map.j
    4.8 KB · Views: 42
Last edited:

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
I want to report a bug, line 17 got error but pjass did not recognize the error @LeP

edit: I used ENG VI keyboard, when u press number or shift-number it will generate some strange characters. It cause no error in pjass syntax checker but unplayable
Yeah that's stuff in the Lexer that has been there forever.
 

Attachments

  • pjass-git-6f64950.zip
    44.7 KB · Views: 320
  • pjass-git-6f64950-src.zip
    63.5 KB · Views: 96

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
Thanks for testing. Indeed the fix is very easy but it's not pjass' domain to do so.
Here is a fresh pjass version which reports this.

Code:
$ cat tests/should-fail/native-as-code.j
native TriggerSyncStart takes nothing returns nothing

function foo takes nothing returns nothing
    local code bla = function TriggerSyncStart
endfunction

$ ./pjass tests/should-fail/native-as-code.j
tests/should-fail/native-as-code.j:4: Cannot use native 'TriggerSyncStart' as code
tests/should-fail/native-as-code.j failed with 1 error
Parse failed: 1 error total
Since i've been doing work on jhcr recently pjass threw this at me as i heavily make usage of function literals.
Can anyone confirm or deny that you can or cannot use natives as code literals in the latest patch? Maybe try different configurations like assigning to variable in contrast to returning it, etc. Make sure to actually call those functions. You have to ignore pjass errors of course. Thanks in advance.

JASS:
function A takes nothing returns code
    return function TriggerSyncStart
endfunction

function B takes nothing returns nothing
    local code c = function TriggerSyncStart
endfunction

Also can anybody test if using null still fails? It used to work in older patches (~1.29) but then stopped working at some point. Maybe patches changed again.
JASS:
function C takes nothing returns code
    return null
endfunction
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
Hi,
is it possible to show the columns in addition to the lines for syntax errors?
No. As for adding them: when i looked into it prior it didn't seem very straightforward. Which doesn't have to mean that it's difficult to do. But in the end it was too much work for too little gain to me. YMMV
 
Level 9
Joined
Jul 20, 2018
Messages
176
Also can anybody test if using null still fails?
This works on 1.26. When I tried to launch map on the latest patch, lobby reported an error.

Can anyone confirm or deny that you can or cannot use natives as code literals in the latest patch?
Map crashes without printing anything right after loading on both 1.26 and the latest.
 

Attachments

  • native-as-code.w3x
    8 KB · Views: 15
  • null-code.w3x
    7.4 KB · Views: 16

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
537
This works on 1.26. When I tried to launch map on the latest patch, lobby reported an error.


Map crashes without printing anything right after loading on both 1.26 and the latest.
Thank you very much. It still feels very bad to work on pjass w/o having a recent wc3 setup. I might have set it up again...
 
Status
Not open for further replies.
Top