• 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.

Repl

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
Repl - a REPL written in vJass

Code:
1. Required tools
    1.1 jasshelper (vJass)
    1.2 LeP's updated pjass for the "//# +nosemanticerror" annotations: https://www.hiveworkshop.com/threads/pjass-updates.258738/

2. Required external libraries
    1.1 leandrotp's Typecast and Memory libraries: https://www.hiveworkshop.com/threads/accessing-memory-from-the-script-its-time-of-the-revolution.279262/
    1.2 Lord of theDing's StringFromId: https://www.hiveworkshop.com/threads/jasm-lets-dive-into-bytecode.293369/
    1.3 LeP's Jass parsing library: https://www.hiveworkshop.com/threads/jass%C2%B2-a-jass-parser-written-in-vjass.294283/

3. Configuration
    Repl comes with the common-j-native-wrappers.j and common-ai-native-wrappers.j that
    wrap all the natives in jass functions which helps with type checking.
    The natives are divided into groups, only native functions from a group that is enabled
    can be called from the REPL.

4. Supported statements/commands

    4.1 Global variable declaration
        syntax: global <type> <variable-name> [= <expr>]

        <type> can be any of:
            code, integer, real, string, handle, boolean,
            integer array, real array, string array, handle array, boolean array

        examples:
            global integer foo
            global integer bar = 1
            global string array bazs
            global handle hero = CreateUnit(Player(0), 'Hpal', 0.0, 0.0, 270.0)

    4.2 Variable assignment
        syntax: set <var> = <expr>

        examples:
            set foo = 2
            set bazs[bar] = "baz1"
            set foo = IntegerTertiaryOp(foo > 1 and not false, 1 + 2 - 3, 4 * 5 / 6)

    4.3 Function call in void context
        syntax: call <function-name>([args])

        examples:
            call BJDebugMsg(bazs[bar])

    4.4 Printing variable/function information
        syntax: x <name>

        examples:
        x foo
        x bazs
        x BJDebugMsg

Update: 2017.09.09
- now uses the Memory library's 'module Bytecode' to execute bytecode
- no longer requires //! inject config (fix by leandrotp)
 

Attachments

  • common-j-native-wrappers.j
    138.1 KB · Views: 64
  • common-ai-native-wrappers.j
    18.8 KB · Views: 61
  • repl.j
    69.7 KB · Views: 62
  • string-table-id-from-handle.j
    1.4 KB · Views: 44
  • get-array-struct.j
    990 bytes · Views: 47
Last edited:

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
543
Nice. Havent tested it yet but im a fan of repls and repl driven development.

I assume this is abusing the JASS bytecode manipulation exploit? If so then users should be aware that it might not be future proof as Blizzard might fix such security exploits in future patches.

One could always write a jass interpreter in jass and use that instead. And then parse the war3map.j to have access to the functions and globals. Would be a lot more work though.
 
Level 6
Joined
Jul 30, 2013
Messages
282
i once had a project to translate jass to python.. and i even got quite far with it.
it wasnt really useful tho because i never too the time to implement all the natives (and that would mean like emulating warcraft 3 internals to an extent... ) would still be useful for stuff like unit-testing jass2 math libraries n stuff tho.

btw if anybody IS interested in that.. ping me!
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
If you can translate to JS, I am interested :p

I made a simple translator at some point, but it didn't actually parse anything, just replaced keywords and used eval, since Jass and JS are very similar.

I always thought of implementing at least a part of the Jass natives in the 3D viewer, just as a fun side project.
 
Last edited:
Level 6
Joined
Jul 30, 2013
Messages
282
i could with very little effort actually.(emit any kind of language you want)
if you are interested in writing some native impls tho.. i basically got a hello world and 200 stubs or sth like that lol

uses python 3.4+ in case youn want to tinker.
repo at: Waffle_est / jass2_interpreter — Bitbucket

you can contact me via
email: [email protected]
or skype (if ppl still use it?): joonas.liik

i personally use pycharm for development (by JetBrains, really nice tool, if you are a student you can get the pro-grade stuff for free which is also cute but community edition is totally useable too)

also.. i got unit tests .. a lot of em :)
 
Level 6
Joined
Jul 30, 2013
Messages
282
Also the intent was to expand the grammar/provide alternate grammars so that you could parse eg vJASS or cJASS also.

hmm..
also if we are to emit alternate langages..
we will want to code as much as possible in JASS. that means we should implement the as much as possible in jass so that we would have to implement less in the target language.

edit: also there are implementations of python you can embed in javascript.
PyPyJS being exceptionally compliant to true python. it might be a valid solution to just embed the python solution in JS and then call it from js.
 
Last edited:
Level 6
Joined
Jul 30, 2013
Messages
282
actually.. its not such a big difference like you think it is.

python has a runtime, so has javascript.
and they both have a repl.

so basically you just need to be able to load code later on, which isnt that difficult at all.

emulating war3 natives is most of the work really, the translation aint too difficult.
rly add me on skype or sth tho so we can have a longer talk if you are interested.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
I can already support probably most of the unit/doodad/etc-related natives, and most of the rest can be simple one-liner wrappers, that's not really my issue.
Rather, I don't want to evaluate code at run time, so Jass->JS by itself isn't quite enough. Like I said, I can actually do that with some simple string replacements, since the languages are so close.
 
Level 6
Joined
Jul 30, 2013
Messages
282
then what is it that you need?

i mean you GOT a VM if you use JS or Python or any a number of many other languages..
i fail to see what is missing.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
A Jass VM written in JS, rather than eval().

eval() is really easy (replace types with var, remove types from arguments, change scopes to {}, etc.), but it assumes the code is perfect. No type checking, and any syntax errors will obviously be in JS.

It would be pretty surreal to have a VM and just implement the natives.
 
Level 6
Joined
Jul 30, 2013
Messages
282
i got a full parses with a grammar for jass2 tho.
if its broke then it wont parse and then u dont feed it to eval but rather throw an error at the user..
also VM doesnt need to be explicit bytecode u know, python already has a bytecode vm.
just need to plug into it suitably.

alternatively could just have a dict with all the globals and functions... the ones that got past validation.
you really should stop listings things you presume you need and in stead list your goals, then we can see how to optimally achieve them and wether or not my project may or may not be of any help.

also.. we totally hijacked this thread.. sorry!
 
Level 6
Joined
Jul 30, 2013
Messages
282
that's basically what my lil utility does.

the repl is in need of some work tho, and the native impls are mostly missing.
but it translates jass2 to valid python3 (last i checked.. but i got bunch of unit tests to convince myself) and can run it.

you want to implement your natives in javascript tho? is that an important constraint or just preference?
 
Level 9
Joined
Jul 30, 2012
Messages
156
I made some slight modifications to your REPL library, actually I didn't touch anything in your code, I just cleaned somethings up and ported it to work with my new libraries. I suppose it will only make it easier for you to mantain it, as you no longer need to worry about the whole "get array address" thing.

I also used a better trick to obtain the address of main function, so the whole //!inject config macro is not needed anymore. I have attached a TestMap with all the stuff together.

Btw, you did an amazing job! REPL is a very useful tool, and it will certainly help a lot of people.
 

Attachments

  • REPL.w3x
    205.9 KB · Views: 41
  • Like
Reactions: pyf
Level 13
Joined
Nov 7, 2014
Messages
571
Btw, you did an amazing job! REPL is a very useful tool, and it will certainly help a lot of people.

If it wasn't for 'someone else' to figure all the intricacies of blizzard's jass parser and VM and document them, and another 'someone else' to write a jass parser in vJass, this would've been, well... impossible.

PS: the old silly instruction counting thing I had broke in debug mode
JASS:
private function bc_init takes nothing returns nothing
    // Note: the order of these declarations/statements is important
    //
    local integer bc_init_addr = C2I(function bc_init) // 6 instructions
    set bc[8190] = 0 // 5 instructions
    set code_value = null // 2 instructions
    set integer_value = 0 // 2 instructions
    set real_value = 0.0 // 2 instructions
    set string_value = "" // 2 instructions
    set handle_value = null // 2 instructions
    set boolean_value = false // 2 instructions

    set bc_stid = Memory[bc_init_addr/4 + 6*8/4 + (4*8+4)/4]
    set bc_code = I2C(Memory[get_array_struct_from_stid(bc_stid)/4 + 12/4])

    set code_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + (8+4)/4]
    set integer_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + (8+4)/4]
    set real_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + 2*8/4 + (8+4)/4]

    set string_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + (8+4)/4]
    set empty_string_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + (4)/4]

    set handle_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + (8+4)/4]
    set boolean_value_stid = Memory[bc_init_addr/4 + 6*8/4 + 5*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + 2*8/4 + (8+4)/4]
endfunction
because set bc[8190] = 0 is no longer an array set but a function call.

Now I simple call the stid_from_handle function instead: set code_value_stid = stid_from_handle(SCOPE_PRIVATE + "code_value")
 
Status
Not open for further replies.
Top