• 🏆 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!

What Does Everyone Want In A Compiler?

Status
Not open for further replies.
Level 31
Joined
Jul 10, 2007
Messages
6,306
I need to collect some feedback from the general community about what features people want. I was originally going to focus on doing vJASS, but I decided to save it for later since it's such a mess and just do what I call xJASS, known as extended JASS. Keep in mind that I will add vJASS later on. For now I'd rather have a clean language that follows the JASS paradigm.


If we look at the JASS syntax, there are only a few things. I propose to take the original syntax and extend it without deforming it.

JASS:
// comments

type typeName [extends typeName]?

[local]? [constant]? typeName [array]? variableName

exitwhen expression
return expression

set variableName = expression

call functionName(...)

[constant]? function functionName takes ... returns ...
endfunction

if expression then
endif

loop
endloop

globals
endglobals

function main...
function config...

The first extension I propose is the addition of the scope, much like in vJASS. However, scopes may require other scopes. Requirements define the order of initialization.

JASS:
scope [name]? [requires ...]?
endscope

The next point is that all variables within scopes are by default public. To access variables, the resolution operator "." is used

JASS:
scope MyScope
    integer thisIsPublic
endscope

set MyScope.thisIsPublic = 6


A major point of contention is whether to use the public/protected/private/internal scheme or the nothing/local scheme. JASS uses the nothing/local scheme. It's essentially either public or it's protected. If we are to follow JASS syntax as closely as possible, even though we are losing some possible encapsulation features, I think that the nothing/local thing should be used.

JASS:
scope MyScope
    integer thisIsPublic
    local integer thisIsLocal = 7
endscope

set MyScope.thisIsPublic = 6
set MyScope.thisIsLocal = 9 //error!

The next point of contention is the globals block. In JASS, there may only ever be one globals block and this block contains all global variables. I propose to simply do away with it and hide it in the background, much like main and config. The alternative would be opening up main and config to the user like in c++, doing away with requirements, and having the user define everything in their map. Let's not do that.


The next point is how to handle structs from vJASS. I propose to use the type syntax that JASS provides. A type can be declared, but how are fields added to it?

Something like the following would be nice. However, JASS types are by default 1 liners.

JASS:
type myType extends integer
endtype

I propose then that a new scope syntax should be introduced to work with types.

JASS:
type myType extends integer

// the scope is no longer static
scope this.myType
    function this.functionName takes nothing returns nothing
    endfunction
endscope

It would also valid to do this. You would no longer be able to do this.functionName as the scope would be static.

JASS:
type myType extends integer

scope myType
    function functionName2 takes nothing returns nothing
    endfunction
endscope

scope this.myType
    function functionName takes nothing returns nothing
        call functionName2()
    endfunction
endscope

The next point is the order of initialization for merged scopes. I propose a secondary id. The secondary id is defined to be the same as the first id when it's not used. The secondary id is what is actually used for requirements.

When two scopes happen to have the same secondary id, the order of initialization for them can't be defined.

JASS:
// runs either first or second
scope MainScope
    function functionName2 takes nothing returns nothing
    endfunction
endscope

// runs either first or second
scope MainScope
    function functionName3 takes nothing returns nothing
    endfunction
endscope

// runs third
scope MainScope as UniqueScopeName requires MainScope
    // just showing local keyword on a function
    local function functionName takes nothing returns nothing
        call functionName2()
        call functionName3()
    endfunction
endscope

My next proposition is to define initialized code as code that's not in a function. The code runs down the scope in order.

A new Hello World example

call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Hello World!")

Next I propose code reordering based on usage.

JASS:
function A takes nothing returns nothing
    call B() //B is put ahead of A because A uses it
endfunction

function B takes nothing returns nothing
endfunction

Initialized code can't access each other, so their order is defined solely by scope requirements. If you don't care about initialization order, then you don't need to ever use scope requirements.

Next, I propose operator overloading in the following manner. Operators can be local and can be scoped as well.

I also propose getters and setters.

JASS:
// order doesn't matter
operator function + takes integer i, string s returns string
    return I2S(i) + s
endfunction

// careful
operator function this.+ takes string s returns string
endfunction

operator function [] takes integer i returns integer
endfunction

// dynamic
operator function[][][,][][][,,] takes ... returns integer
endfunction

operator function this.[][][][][,,] takes ... returns integer
endfunction

getter function i takes nothing returns integer
    return someVar
endfunctoin

setter function i takes integer m returns nothing
    set someVar = m
endfunction

// create
operator function this.new takes nothing returns someType
endfunction

// allocate
operator function this takes nothing returns someType
endfunction

// destroy
operator function this.delete takes nothing returns nothing
endfunction

set i = 5
string s = i + "moo"

I also propose typecasting

(type)myVar


The next point I'd like to address is polymorphism. JASS types are not polymorphic. You can't remove a widget, or a handle. You must remove the specific type. As such, I propose to add a new polymorphic keyword.

polymorphic type myType extends integer

Everything extending from a polymorphic type must be polymorphic. The base type need not be polymorphic. However, destroying the base type will not destroy the polymorphic type correctly.

Next, I propose the inline keyword

JASS:
inline function hello takes nothing returns nothing
endfunction

I propose the following. It would use a boolexpr array and give each function used like this a unique id that corresponds to the array. I also propose that we allow calling all executable variables like a regular function.

JASS:
function myFunction takes nothing returns nothing
endfunction

function ohNo takes functionid func returns nothing
    call func()
endfunction

call ohNo(myFunction)

I propose function overloading and variable shadowing. I propose that the "." operator, when used by itself, accesses the outer scope.


The next point to cover is preprocessing.

I believe that # should execute preprocessor code and that $ should execute preprocessor code and then dump the result to the script. From the preprocessor side, $ should evaluate a script expression and dump it to the preprocessor. From the string side, $ execute script code and dump it to the string. A $$ would evaluate preprocessor code in a string. I propose that the preprocessor syntax be the same as the xJASS syntax and that xJASS scopes exist both in the preprocessor and in xJASS. Any constant expressions in xJASS also exist in the preprocessor and can be accessed with the $ operator. The # also interpolates.

I also propose preprocessor scopes.

JASS:
constant integer i = 3
#integer m = 2

#scope //preprocessor
    if (true)
        //dumped to script
        #scope //script
        endscope
    else
        //not dumped to script
        #scope //script
        endscope
    endscope

    print($i) //prints 3
endscope

#set m = 9
print($m) //prints 9
print("$i") //prints 3
print("$$m") //prints 9
print("\$i") //prints $i

I propose the break statement, the while loop, the for loop, and the do while loop. I also propose that the preprocessor has access to the map archive objects and what not.

I propose that xJASS have an import keyword. Things may be imported publicly or locally.

I propose an include keyword in the preprocessor, which would include files. The files can be imported as many times as one likes. I propose an import count variable, which counts how many times a given file has been imported.

JASS:
#if (FILE_IMPORT != 1) then
    return
endif

// script

I propose that preprocessor functions be able to tell what scope they are currently running inside of, both by primary and secondary id. This will allow us to implement modules.

I propose lambda expressions

JASS:
functionid c = function() endfunction




I believe that this language is much cleaner than vJASS and follows the JASS paradigm closely. If anyone would recommend any changes, additions, or deletions, please let me know.

I'll eventually put together a manual with the community consensus on what the language should look like.


Now, keep in mind... I love public/protected/private/internal. I really like that fine control over encapsulation. I personally want them, but I know that JASS just uses local. We could possibly say that local is protected internal (translated over) and then add the other stuff : O.


edit
I propose a special preprocessor variable of type script. Script variables can be added to or set. Their contents are dynamically placed in the script.

JASS:
#script i

$i

#set i = i + "hi"
#set i = "o"

// everywhere i is used will be "o", even if it was used before it was changed
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
Unorganized list of thoughts:

This is a bit wordy and probably unnecessary, but it might be more in the spirit of vJass to include "loop" in front of loops, such as this:

JASS:
loop for x from 1 to 10
  ...
endloop

do/while is a rare enough case that the standard syntax

JASS:
loop
  ..
  exitwhen ..
endloop

is probably fine. "loop for" and "loop while" probably make sense though.

I strongly oppose operator overloading in all its forms, but that's neither here nor there.

Whether or not you liked the OOP aspect of vJass (I personally didn't), it makes some degree of sense to treat structs specially. It feels weird to use this bizarre set of confusing keywords just to dance around the fact that you're doing something useful.

JASS:
struct foo
  integer bar
  boolean baz
endstruct

as per vJass/C/etc is probably fine. I agree that methods etc are unnecessary.

Lambdas feel weird in a language trying to be as much like vJass as possible. Perhaps have a function type which you can call with arguments, though, which basically just hides away the gross code or string stuff that you have to do on the back-end to make this work.

Removing declaration before use would be nice.

I have no real opinion on preprocessor stuff since I've always found it wasn't all that useful for the kind of stuff I wanted to do in War3.

Typecasting feels unnecessary if you aren't doing OOP stuff.

Getters/setters feel OOP which confuses me given you claim to not like it, and also are probably unnecessary. Your compiler should be able to figure them out as well as figure out the inline keyword without too much work (one-liners which don't use any of their parameters more than once).

Your scope setup seems fine in terms of actual scoping, although once again I disagree with the declaration before use and weird quasi-OOP stuff.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
The only thing is that in Java and what not, all types are Objects. They all rely on the same typing system. There aren't any exceptions. This is rather clean. I wanted to do this in xJASS too. JASS uses types =). Structs would start introducing special exceptions to the rules.

The idea of the for loop is pretty interesting =).


The inline keyword is just there to force inlining
 
Level 6
Joined
Jul 30, 2013
Messages
282
  • not gonna say that vjass is the best language ever but if adopting your new language is painful then nobody will use it. (not to mention certain projects are allready WAY too fragile) meaning i will probably never use this. (bit sad here)
  • preprocessor language == reeal language; * gonna go get u some waffles for this one :) *
  • type myType extends integer

    // the scope is no longer static
    scope this.myType
    function this.functionName takes nothing returns nothing
    endfunction
    endscope
    .. hmm
    well as a JS dev this kind of feels familiar.. so i dont like hate it..
    but essentially its a class definition and maybe should read more like it (btw JS is getting a class construct in an upcoming ECMA standard.. guess why)
  • make function first class citizen pls, no code[] is one of the things i hate most bout jass :(.
  • for... hmm cohadars vjass had one of those if i recall correctly, might be a good idea to just /steal/ that for consistency :)
  • getters/setters +1!.
  • an efficcient switch-case would be useful.. just to make it easier to do some things more efficiently (just for the sake of if-chain can be really crappy performance.. + readability)
  • everything subtype of object.. is bloody enticing! well if it worked efficiently. but i got a feeling you'll end up with something really ugly so *shiver*
  • operator function[][][,][][][,,] got no idea what you mean by this.. so ehm.. yeah.
  • My next proposition is to define initialized code as code that's not in a function. The code runs down the scope in order. +1!
  • also while you do that.. you could make like function definitions in to statements also..
    eg
    function a takes nothing returns nothing
    ...
    endfunction
    would be equivalent to..
    var a = function(){...} //JS example
    would like allow functions to be nested etc nasty stuff :p (with a bit of code to do lexical scoping that would be awesome..)
    hmm.. also this is kind of removes need for explicit lambda if u tolerate a tad more verbosity..

hmm tho in java there ARE non-object types
int, bool, long, byte are a few examples.

hmm.. what else would i ask of Santa..
self hosting + evil dynamic things eg eval and friends, runtime modifiable classes etc #veryevilwaffles #muhaha!
multiple inheritance?
  • of those eval is the big issue rly..(prolly not worth it?)
  • runtime modification of types? hmm.. well it could be done if u got function ptr, ull likely have some overhead everywhere tho.
  • multiple inheritance (unless u do like runtime modification of types.. .. you probably won't cuz.. well u love speed so much :p) should be relatively simple if u just got a good rule of how to deal with member conflicts.
  • include/require seem a bit duplicating somehow. eg if i say require if like to specify what resource i want and that should be like enuff to go out and include it so i wouldnt have to add a separate line that says the same thing.
  • relating to previous one.. not really a lanugage feature but.. package manager.. pretty please! (#luvpip)
  • array literals! please please pleaseeeeeeee!
  • if not haz_array_literallz goto array_literals pretty please!
  • hashtable/dict should be a native type, (optional with arbitrary keys? 1 key type but compiletime configurable?)
  • dict-literals maybe :)
  • inline kw? id rather have like some sort of generic compile time decorators eg so u could tell the compiler other stuff. eg @pure @cache("lru", 100) @cache("all") @precompute([1,2,3]) @inline and so on.
    @template([str, int]) // generate 2 functions from this
    function f takes T returns T
    ...
    function
  • not language feature but.. need a good IDE. or well at least autocomplete for user defined functions (Worldedit wtf! <2 paragraphs of profanities removed here> happened here?!)
  • also not language feature but.. converter script for legacy resources? would be kinda nice tho it would have to support quite a big mess to rly be useful so its ok if it wont come soon..
  • a good standard library .. and i mean like intuitive #1 cuz BigInt surely isnt for one. having to mess with bases etc is not user friendly at all, spec if u just want to do operations on big numbers.
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Well, my thoughts for functions as first-class members would be to give each function used this way a unique id in the background that points to a boolexpr. Now, the reason I do functionid is because breaking the "code" type would break JASS. Things like timers wouldn't work well. Timers require the specific code type. If I made all functions like that, timers won't work.

Multiple inheritance is planned. You have one allocator representing the instance and the others sorta like delegates from vJASS.

I was just going to use the World Editor IDE, but you can easily run the exe as well from something like notepad++.

There were some other features in the wish list, like compilation of libraries.

Hashtable type can just as easily be a user library.


I could do Integer objects and so on, allowing you to pass by reference and stuff. However, we have an instance limit of only 8191 if arrays are used, and we have a major impact on performance if hashtables are used.

So far, nobody seems to like my ideas for types. I don't really like it either. I take advantage of the fact that the language allows you to merge scopes together and that JASS has the type syntax.

Are there any suggestions for a way that involves using the type syntax from JASS? You can't do an endtype as that would break JASS syntax. It should be as minimal as possible =).

JASS:
//I don't really like this way either. It makes sense, but it adds a new concept of scopes that
//are linked to a type, like declaring a type somewhere and declaring the scope for that type somewhere else
type myType extends integer

scope this.myType
    function this.functionName takes nothing returns nothing
    endfunction
endscope


inline kw? id rather have like some sort of generic compile time decorators eg so u could tell the compiler other stuff. eg @pure @cache("lru", 100) @cache("all") @precompute([1,2,3]) @inline and so on.
@template([str, int]) // generate 2 functions from this
function f takes T returns T
...
function

I don't know how readable that is. I never really agreed with precompiler stuff as that stuff can just be in the prepreocessor. In fact, we can actually drop the inline keyword and just do a preprocessor function. I would actually recommend just dropping inline altogether and doing it like this instead.

I also recommend interpolate blocks. They would be like scopes, except that they don't generate a scope. Otherwise you'd have to make some anonymous scope. Name up for debate. Just a way to interpolate a block of code without making anything new.

JASS:
#function hello takes integer m returns nothing
    #interpolate
        set m = 3
    endinterpolate
endfunction

integer o = 9
call $hello(o) //translates to "set o = 3"
call print(o) //3

So yea, I call for dropping the inline keyword.

edit
My bad, the above code makes no sense.

First, I propose the ref keyword for references.

Next, we have these examples, using the script type in the preprocessor. I also propose that the script type output its contents when it goes out of scope.

JASS:
#function hello takes script m returns nothing
    #interpolate
        set $m = 3
    endinterpolate
endfunction

#function hello2 takes ref script m returns nothing
    #interpolate
        set $m = 3
    endinterpolate
endfunction

#function hello3 takes nothing returns integer
    return 5
endfunction

integer o = 9
#script s = "o"

call #hello(o) //translates to "set o = 3"
#call hello(s) //translates to "set o = 3"
call #hello2(#s) //translates to "set ohg = 3" //syntax error
$call hello3() //5 is dumped to script

#set s = "ohg"

call print(o) //3

Returning script variables would make things really interesting.
 
Last edited:
Level 6
Joined
Jul 30, 2013
Messages
282
i.. dont really get what you want #interpolate to do seems as functional as a comment at a glance..
does it like provede block scoping or sth? so its like a scope except can be used inside functions?

hmm macros? yes/no/different? u never said anything bout em..
i guess a preprocessor is basicalyl a superset so u could have a compiletime preprocessor command just dump that stuff in there with vars prefixed or sth..

i know hashtable could be user lib but..
local Hashtable h = {a:b, c:d}
beats
local Hashtabole h = Hashtable.create()
set h["a"] = b
set h["c"] = d
could even do a bit of type enference
eg
set h = {} -> local Hashtable h is generated automatically
this would make the code a lot more readable.
well this does kind of focus on use of hashtable as a quick throwaway object to storte a handful of values in ..
perhaps theres solutions that are more reasonable..
tho for quick prototyping the short syntax is rly useful..

preprocessor functions could be reasonable..
tho i don't know how easy making generic decorator like stuff would be with them. ill hold off my verdict till its too late (i will nag on you after u implemented it :p )
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
i.. dont really get what you want #interpolate to do seems as functional as a comment at a glance..
does it like provede block scoping or sth? so its like a scope except can be used inside functions?

It just interpolates a block of code between the preprocessor and script. I was previously just using #scope, but that would end up creating an anonymous scope each time. You don't necessarily always want that. The interpolate thing would just do the interpolation, nothing created.

hmm macros? yes/no/different? u never said anything bout em..
i guess a preprocessor is basicalyl a superset so u could have a compiletime preprocessor command just dump that stuff in there with vars prefixed or sth..

Yup, the preprocessor functions are essentially macros in the eyes of the script.

local Hashtable h = {a:b, c:d}

Hmmm. Seems worth it ; ).



Also, rather than supporting vJASS syntax, I could do a vJASS -> xJASS translator ^_-. However, things like keywords aren't supported in xJASS. Keywords essentially make every instance of a given symbol (even internally) internal to a specific scope. This is very bad practice.

JASS:
scope a
    private keyword m

    scope b
        integer m = 5 //it's public! but it's really private to scope a
    endscope
endscope


What we might do is go with public/private/internal/protected and just do local for private variables with a finite lifespan.

JASS:
scope
    integer a //can't be accessed due to no name, but continues to persist
    local integer b //illegal, doesn't have finite lifespan
endscope

function s takes nothing returns nothing
    integer m = 6 //illegal, functions only have finite lifespans
    local integer d = 9
endfunction
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Hi again Ruke. This is the same project as before, just improved some stuffs.

vJASS has a lot of core design flaws. Static ifs, keywords, keys, structs, struct extends array, methods, method operators, and modules to name just a few. There is no way to even salvage it without breaking tons of scripts. Someone mentioned doing a translator from vJASS to xJASS, which I think is a fantastic idea.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
How about capability to remove handle leaks automatically? The compiler will detect when possible leak occurs, then put leak removal at the end of the code block.

E.g. the compiler detects a leak:

JASS:
function a takes nothing returns nothing
    local unit u = GetTriggerUnit()

    return
endfunction
// Leak removal is not detected

Then it would be compiled:

JASS:
function a takes nothing returns nothing
    local unit u = GetTriggerUnit()
    
    set u = null // Handle/agent reference leak detected
    return
endfunction

?
 
Level 6
Joined
Jul 30, 2013
Messages
282
+1 for automatic leak removal (tho optimisers allready do that ...) if your gonna make a better languagre might as well fix the big bugs of the old one :)

the interpolate syntax is still puzzling tho. its like a whole different language.. so -1 for that (at least the syntax).
now that i look at it closer it just looks like

#function hello takes integer m returns nothing
#interpolate
set m = 3
endinterpolate
endfunction
is equivalent to..
define hello(s) = {
set m = s
}

and i definitely prefer the cjass version here. (even tho its not jass-like syntax at all it still looks way more intuitive,)
there's ofc a //! runtextmacro equivalent but youd need be a genious to make something that looks even more awful, not to mention lack of being able to call other macros inside..

i kind of like the fact that you try to make the macro look like jass.. but its NOT jass rly face it, you have already failed.
you have made a compiletime only construct that uses compiletime only features etc.
-1 for #interpolate
-1 for there's "#interpolate" but "endinterpolate" they are not visually matching tags. use # for both start and end if you do....
+1 for being able to specify type constraints..
+1 for u can make functions that work BOTH compiletime AND runtime (unless u use interpolate..)

id propose a replacement
eg
function hello takes integer m returns nothing
call emit ("set m = 3")
endfunction
or..

function hello takes integer m returns nothing
emit set m = 3
endfunction
or..
function hello takes integer m returns jass
return JASS([set("m",3)])
endfunction

emit hello(3)

or
@macro
function hello takes m returns nothing
set m = 3
endfunction

hello(3) // macro decorator makes the function dump its contents in steal of eval?
(seems i rly miss decorators.. they so useful :'( )

perhaps id try to avoid making a macro system at all..
and in stead id make an extended language that can be used.
and ud like run the entire map script in this new extended language
and you'd use the result and save it as the real map script.

(python influence obviously again.. why i like wurst i guess.. tho i do agree keeping a jass-like syntax would be preferred. its a bad idea to have 10 independent languages mixing in a project unless its like REALLY massive and some conditions apply..)

also if u new to python this is what i mean by decorators: http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
i know other languages have it too but this is the experience i have in mind when i talk bout em..
 
Level 6
Joined
Jul 30, 2013
Messages
282
-1 for i++ and ++1 ppl always abuse them cuz they so short and then they do shitty ass stuff that fucks up their code cuz they dont fully comprehend what it does. (most ppl dont even know difference of i++ vs ++i or why it was ever invented..)

+10 for being able to take/return arrays tho, would be super useful! :)
hmm
zinc? i think we actually have like 1 spell that uses that lol, but 99% of resources are in vjass so thats what should be #1 in terms of compatibility..
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
so no preprocessor language and no types then? no interpolation whatsoever either?

Interpolation is jumping between the preprocessor and the script.

not sure how to accomplish things like static ifs, modules, and so on without making the language a mess then >.<

no way to return arrays unless they are hashtables :/. Huge performance impact.

Automatic leak removal is an optimization feature. I'm saving all of that for last because I must finish a lot of this by May 1st.

Can do preprocessor, but that'd make it difficult to access vars. There'd be no differentiation between execution and execute/dump either.

For any syntax that is added, I think it should be as flexible as possible to keep the language as small as possible.

Printing strings to a script is a bad idea as there is no highlighting or autocomplete. Printing huge things is also tough.

I'd rathet not do something like set(). What about all of the other operations? Inlining huge blocks of code? You'd have to add a bunch of stuff to the language.

The preprocessor functions aren't macros. They are functions with the capability of outputting to script. Any preprocessor code can output to script. Since we aren't doing those, we need something else just as powerful that is intuitive ; ).

Need something to allow users to inject script anywhere. My idea was the script variable.

Need something to allow modules.

Need OO stuff that is compatible with JASS : )


Plenty of people have already said they don't like type/scope stuff, so let's not do it that way. It also seems that interpolation is confusing, so let's figure out another way. The idea is to do a lot with a little. Assume each little thing that is added has an enormous cost, so it better be worth it. A complex language is no good ; ).

edit

#interpolate scope
endscope

???
 
Last edited:
Level 6
Joined
Jul 30, 2013
Messages
282
well i got nothing against types really. just the alternate examples i provided used cjass and that does plain text substitution always without regards for types. if u do use types thats ok.

not sure how to accomplish things like static ifs, modules, and so on without making the language a mess then >.<
well modules etc are ok as a preprocessor language..
eg
module
endmodule
is OK imo.

but static ifs.. why?!
statif if... then
endif
is just horrible..

in stead do like
// ifs outside functions make no sense in jass, thus is easy to tell apart, also adds 0 new syntax
if debug then
function...
endfunction
endif

also can use compiletime functions to do some stuff
eg
function static_if takes boolean cnd, script code returns nothing

endfunction
static_if (DEBUG, script(
...
...
)
)
alternative would be to use constant keyword
eg
constant integer DEBUG= 0
if DEBUG then
constant expression should be evaluated at compile time, thus we can decide even without the special annotation
endif

alternate
constant integer A=1
constant integer B=3
// u can use expressions based on A and B and if would be static magically
constant integer C=A+B (make it bit more explicit)

also...
constant boolean SPECIAL = false

...
SPECIAL = true // dont rly like this particular idea but.. constant as in runtime constant not compiletime constant
then special can be use like a real variable but result in static-if semantics in expressions (eg all conditions static if unless spoiled by code that cant be proven runtime constant)

also
forEach doesnt need to be a new construct (issues with who likes what for one tho i would like the enhanced readability)
can be a compiletime function in stead
forEach (iterable, script) would do imo
alternately
Iterable.each(script) sounds nice :)

no way to return arrays unless they are hashtables :/. Huge performance impact.
unless u make concessions that it..
if they are statically sized (eg int[3] for point coords)
then u can just put save em in a real array and return pointer to first one.
(or u can make dynamic arrays if u make first element hold size in stead...)
if you need return more than 2 items from a function at a time then youll be stuffing stuff in to global variables anyway at points so it shouldn't be too unreasonable that u need allocate an array object.(vjass like objject in a sense..)


Automatic leak removal is an optimization feature. I'm saving all of that for last because I must finish a lot of this by May 1st.
agreed :)

For any syntax that is added, I think it should be as flexible as possible to keep the language as small as possible.
yeah.. avoid adding syntax if possible, only do it when rly needed and gives great gains!

Printing strings to a script is a bad idea as there is no highlighting or autocomplete. Printing huge things is also tough.
hmm..
how bout like a script-literal ?

eg in stead of "abc" do `set abc` and just have the highlighter ignore the special quotes so it highlights it as it would otherwise.
u can have `
lots
of
lines
too!
`
if u got like
return `
do this
then that
then 3rd
`
it doesnt look too bad anymore tho it adds a bit of syntax... :(

imo
u need write a jass interpreter, then execute script in that interpreter and use output as the map script.
this gives a nice elegant result.
true stuff like events make no sense in compile time code but you wouldnt use those at comoile time anyway so shouldnt be a real issue..

script typed variables? hmm they kind of like strings really.. tho might be useful.. (sb with better insight pls reply! :) )

The idea is to do a lot with a little +1! :)

hmm
#interpolate scope
endscope
marginally better
why not make it like
print then
or
function f takes .. returns script
return scope
call something()
set var = something2()
endscope
endfunction

print(call f()) // turns in to "
// call something()
// set var = something2()
// "

// print call may or may not be a good thing.. but i think that the function f should compose the code..
// and the caller should decide what to do with it, wheter to print it or pass to another compiletime function
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
The problem is that scopes define a private space. I was thinking of interpolate on there to say "don't make this scope." We'd need some other space then that isn't a scope. Something to state that this is an interpolation space or that this is a chunk of code that has no scope, but is still organized in a chunk.


The return idea isn't so great. Consider loops, multiple sets of dumps that may be in ifs, and so on. Return would only return one thing.


You are mixing up a lot of preprocessor code and regular code. How can you tell that an if-statement is part of the preprocessor or not? If-statements aren't necessarily just for debug. How do you access preprocessor variables vs script variables?


What if we did something like this

JASS:
chunk
    //a chunk of code
endchunk

Chunks in regular script essentially don't do anything. Well, I guess they do! You could require chunks o_O.

If we do both chunks and scopes and then something like

JASS:
#function hi takes script m returns nothing
    #chunk
        set $m = 3
    endchunk
endfunction

Would that look better then? You first interpolate into the preprocessor function, then you interpolate into a script chunk, then you set an interpolated variable to a value. The variable is the script type, which is like a special string that only ever dumps its contents when it goes out of scope. This means that $m is not dumped until the function ends. This could actually be bad with loops >.<. Might need to take a string instead, heh.

JASS:
chunk
    //a chunk of code
endchunk

Chunks in regular script essentially don't do anything. Well, I guess they do! You could require chunks o_O.

If we do both chunks and scopes and then something like

JASS:
#function hi takes string m returns nothing
    #chunk
        set $m = 3
    endchunk
endfunction

integer o = 3
call #hi(o) //would input 3! Uh oh

I guess we could pass in an actual string, like "o," but I think support for names should also be done or something, like o.name.



Want to make sure that people that have only ever written in vanilla JASS can easily go into xJASS without any trouble ; ).
 
Level 6
Joined
Jul 30, 2013
Messages
282
go steal some pypy ideas :p

ull see what i mean.
(essentially PyPy is written in a language called rpython with is a limited strongly typed (via inference tho not annotation) language, but the macro-language for rpython is python itself) which is a bit mind bending at first i guess.. but it works rly well :)

(rpython gets translated to C by a script called translate.py which is itself written in full fledged python again so lots of stuff happening there..)

(im not really hinting anymore am i..
go steal some ideas from em! :D )
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I don't understand.

How do you differentiate between rpython and python, unless you are saying run a certain script on another script to do translation? This would go to a functional implementation, like a library, which is something I really don't want to do. At that point, you would no longer have a target scripting language.



What's wrong with just doing a preprocessor language? I don't understand what's so bad about it. PHP does it. PHP is literally an HTML preprocessor.

They go with a string approach rather than code and stuff, which means that highlighting and stuff is lost.

PHP:
<?php echo '<p>Hello World</p>'; ?>

You essentially can interpolate to PHP, but you can't interpolate back to HTML. What I really want to be able to do with this language is interpolate back and forth.


The big thing that you don't seem to like right now is interpolating back to a block of script without generating a scope. How do you do general multiline interpolation? My idea was that # and $ interpolates the next thing. If it interpolates a scope, then that scope gets interpolated. It's sort of cheated multiline interpolation. With the idea of a chunk (or some other name), you can define areas of code that may require each other that have no privacy. They exist in the global scope, but they can still require each other. This isn't particularly useful, but when it comes to interpolation, it is very useful.

The word "chunk" comes from Lua. I would actually prefer to call it a block since block is the proper term -> http://en.wikipedia.org/wiki/Block_(programming)

However, in technicality, a block is a scope and a scope is a block scope. I would like to tweak the definitions slightly to state that a scope is a block + scope and a block is just a block ^)^.

JASS:
block
endblock

scope
endscope

#function hello takes postscript m returns nothing
    #block
        set $m = 6
    endblock

    set m = "o"
endfunction

#function hello2 takes script m returns nothing
    #block
        set $m = 6
    endblock

    set m = "o"
endfunction

integer i = 5

call #hello(i) //set o = 6
call #hello2(i) //set i = 6

Also, rather than introducing the script type, we can have a string and a poststring or something like that. Post refers to an ending remark.

JASS:
#function hello takes poststring m returns nothing
    #block
        set $m = 6
    endblock

    set m = "o"
endfunction

#function hello2 takes string m returns nothing
    #block
        set $m = 6
    endblock

    set m = "o"
endfunction

integer i = 5

call #hello("i") //set o = 6
call #hello2("i") //set i = 6

Now, I don't really want to do it this way because I want to avoid strings like the plague, so I think script variable would be worth it.

Another thing we can do to make it seem less confusing is \# to go to script and # to go to preprocess, but I'd personally rather it just be a generic interpolate operator. Another thing we can do is # \#, but then we would lose the nice stuff like #call and #hello and what not.

JASS:
#
function hello takes poststring m returns nothing
    \#
        set $m = 6
    #

    set m = "o"
endfunction

function hello2 takes string m returns nothing
    \#
        set $m = 6
    #

    set m = "o"
endfunction
\#

integer i = 5

call #hello("i")\# //set o = 6
call #hello2("i")\# //set i = 6
 
Last edited:
Level 6
Joined
Jul 30, 2013
Messages
282
valid php:
<? if (true){ ?>
some html here..
<? } else { ?>
....
<? } ?>
just so u know..

also how to tell rpython apart from python?
well essentially .. you cant theres literally a magic comment in the beginning of the docstring :D

but really i think theres a lot to learn from PyPy if your in to making a custom language.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Yea, then we shouldn't use PyPy. We need to be able to mix the code up freely.

So PHP does something like the # /#. I think we should just do the #.


I personally think this is about as clean as it can get

We could also name them regions! That would be cool. Or section.

The idea is to do what PHP does in a JASS way since PHP affords you the most freedom and ease of use with mixing preprocessor script and regular script ^)^.

JASS:
#function hello takes postscript m returns nothing
    #region
        set $m = 6
    endregion

    set m = "o"
endfunction

#function hello2 takes script m returns nothing
    #region
        set $m = 6
    endregion

    set m = "o"
endfunction

integer i = 5

call #hello(i) //set o = 6
call #hello2(i) //set i = 6


I still can't think of another way that is both very JASS and lets you mix code
 
Level 6
Joined
Jul 30, 2013
Messages
282
lol then why not just use php as a preprocessor..
i mean really, it could totally work out
my_script.j.php :D

note: im rather tempted to link to some html precursors that got potentially preferable style for our application.. but i cant find a good link atm :(

EDIT: also i think that last example you gave.. u sure u didnt get the comments swapped? (cuz if u didnt then im afraid im simply incapable of parsing your code atm.. (cry) )
 
Level 6
Joined
Jul 30, 2013
Messages
282
you'r right bout php not being jass ofc.. would be rather surprising to ppl + couldnt reuse compiletime and runtime code.

k.. i finally chewed through your example..
i do find it really confusing that such drastic change is caused by the variable type tho.
u read 2 scripts that look identical and they do such different things just because the variable type of 1 is different and that somehow causes the preprocessord to to a completely different thing.. (i wouldnt expect the preprocessor to magically change what it does for 1 variable type over the other i would expect all variables to be handled as containers for data.., i do agree that there might be some use case that might cater for.. but i'd urge you to find an alternative way to express this..)

i still find it really confusing tho, anything more complex and i think only you'd be able to understand it in a reasonable amount of time (being the script author..)
 
Level 6
Joined
Jul 30, 2013
Messages
282
i wish i wish i wish we had a working JASS interpreter.. so we could do unit testing without all the pain of firing up war3.. (at least for some resources..)
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Is it possible that your compiler will allow multiple constructors for one struct/class with same method name but with different parameters/arguments? Just like in java:

JASS:
// Constructor 1
static method newColor takes integer r, integer g, integer b returns thistype

// Constructor 2
static method newColor takes integer r, integer g, integer b, integer alpha returns thistype

// Constructor 3
static method newColor takes string hex returns thistype

// Exactly same method names but with different parameters
JASS:
// At somewhere I use this constructor
local Color c = Color.newColor(255, 255, 255)
// Then the compiler will paste constructor 1 here
// =>
// local integer c = Color_newColor_1(255, 255, 255)

// At somewhere else I use this constructor
local Color c = Color.newColor("FFFFFF")
// Then the compiler will paste constructor 3 here
// =>
// local integer c = Color_newColor_3("FFFFFF")

// Just examples btw

The compiler will detect the number and type of passed arguments and will determine used constructor for that lane. If no one matched => throw syntax error.

It can be achieved by somehow the compiler should rename the method to something else like: (if same methods are detected)
- newColor_1
- newColor_2
- newColor_3

Or is it supported already?
 
Level 6
Joined
Jul 30, 2013
Messages
282
+1 for method overloading by arity
+1 for variable overloading by arg types

in addition would be useful in some cases if you allowed:
variable arity
keyword arguments
 
Level 6
Joined
Jul 30, 2013
Messages
282
if a language cant do recursion then i consider it to be EXCEPTIONALLY broken. i guess it's a given for most as to why nobody has mentioned it before..
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
It would also be awesome if we could do function/method recursion

Well, there is recursion:


JASS:
function Factorial takes integer n returns integer
	if n < 2 then
		return 1
	endif
	return n*Factorial(n - 1) // Recursive call
endfunction

scope RecursionTest initializer onInit
	private function onInit takes nothing returns nothing
		call BJDebugMsg("3! = " + I2S(Factorial(3)))
		call BJDebugMsg("4! = " + I2S(Factorial(4)))
		call BJDebugMsg("5! = " + I2S(Factorial(5)))
	endfunction
endscope


There is of course the problem of two different functions calling each other mutually recursive, but Wurst Script has found a quite nice solution for that problem too.

Bribe said:
Unable to pass an array as a variable

Hm, that should be doable with a compiler I think? Something like


JASS:
function foo takes integer array arr returns nothing
	call BJDebugMsg(I2S(arr[0]))
endfunction

function bar takes nothing returns nothing
	local integer array arr
	set arr[0] = 1
	call foo(arr)
endfunction

could be compiled to

JASS:
globals
	integer array arr_foo // Hidden for the user
endglobals

function Init_arr_foo takes nothing returns nothing // Hidden for the user
	local integer i = 0
	loop
		exitwhen i >= JASS_MAX_ARRAY_SIZE
		set arr_foo[i] = 0
		set i = i + 1
	endloop
endfunction

function foo takes nothing returns nothing
	call BJDebugMsg(I2S(arr_foo[0]))
endfunction

function bar takes nothing returns nothing
	call Init_arr_foo()
	set arr_foo[0] = 1
	call foo()
endfunction

where array would be treated as a reference type (just like structs).



Nestharus said:
Yea, then we shouldn't use PyPy. We need to be able to mix the code up freely.

So PHP does something like the # /#. I think we should just do the #.


I personally think this is about as clean as it can get


JASS:
#function hello takes postscript m returns nothing
    #region
        set $m = 6
    endregion

    set m = "o"
endfunction

#function hello2 takes script m returns nothing
    #region
        set $m = 6
    endregion

    set m = "o"
endfunction

integer i = 5

call #hello(i) //set o = 6
call #hello2(i) //set i = 6

Tbh I don't really understand that code sample respectively what would be the benefits of this. For me it looks very complicated and confusing. Maybe you can give a simple "real-world" example which shows the advantages of such compiler mechanisms?
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Unable to use code arrays

Can't do this otherwise it will break timers

JASS:
globals
    integer array arr_foo // Hidden for the user
endglobals

function Init_arr_foo takes nothing returns nothing // Hidden for the user
    local integer i = 0
    loop
        exitwhen i >= JASS_MAX_ARRAY_SIZE
        set arr_foo[i] = 0
        set i = i + 1
    endloop
endfunction

function foo takes nothing returns nothing
    call BJDebugMsg(I2S(arr_foo[0]))
endfunction

function bar takes nothing returns nothing
    call Init_arr_foo()
    set arr_foo[0] = 1
    call foo()
endfunction

The above won't work. We are talking passing any array around. A single global array will end up being overwritten by other arrays.

call foo(array1)
call foo(array2)

etc

If you are talking about copying one array to another array, and then copying back, you would also have to do a local copy or you would break recursion.

8192 superficial array limit - the size should be allocated by the user

Not possible unless we use ugly binary if-statements or a hashtable.

OP limit for thread crashing

Do you mean an easier way to split functions up into chunks?

Something maybe like this?

JASS:
function Hello takes nothing returns nothing
    opchunk
    endopchunk
endfunction

0 second timer not 0 seconds.

No way to fix this. If the 0 second timer were changed into a regular function call, that would break a slew of systems as well.

Tbh I don't really understand that code sample respectively what would be the benefits of this. For me it looks very complicated and confusing. Maybe you can give a simple "real-world" example which shows the advantages of such compiler mechanisms?

I needed those features in DDS and Unit Indexer : ).
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
The above won't work. We are talking passing any array around. A single global array will end up being overwritten by other arrays.

call foo(array1)
call foo(array2)

etc

If you are talking about copying one array to another array, and then copying back, you would also have to do a local copy or you would break recursion.

Yes right, you would have to make two copys... a bit expensive but it still would be doable and potentially helpfull.

I needed those features in DDS and Unit Indexer : ).

Well, with example I meant something a bit more concrete ;)
Can you show some sample code or say where/why you need that in DDS/UnitIndexer?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
I agree that the interpolation syntax is not so great. It's simple, but it's inherently difficult to read.

What if we had

#preprocess
#endpreprocess

#script
#endscript

This adds extra stuff to the language, but it makes it easier to read.

However, # technically takes an expression, so it can technically work on functions and so on too...

I guess one could write comments to show where someone currently is, but the other poor thing is that if you delete some code somewhere, it breaks code somewhere else because that code is no longer in the same stage of execution.

We could also do the following

!# for script
# for preprocessor

However, now we are getting into symbolic things

Another alternative is to say that # doesn't denote an expression, but then you lose the nice #if. We can also make # a single line unless you do #preprocess

JASS:
#if (true) then
    //script
#endif

//vs

#if (true) then
    //preprocess script
endif

//script


My thoughts are that # should only apply to a single line. If it is applied to a block, that doesn't mean that the contents of that block are part of the preprocessor. The only way to change what language you are in is with a #preprocessor, or something like that.

This syntax could be expanded to be completely generic, supporting island grammars like vJASS

What if you don't know what script you are currently in? We should still support the #script, which would just go back to whatever script it was in. The preprocessing language is going to either be xJASS or Lua. I don't like the idea of mixing xJASS with Lua. I do like this feature

JASS:
scope A
    #private integer b //local to A
endscope

However, the above feature is very dangerous and can get confusing. I think that the two languages should be completely separated. A scope from the target script does not denote a scope from the preprocessor script. At this point, I think just using Lua for the preprocessing language would be the best way to go. A common Lua library, with registration and requirements, would be how code initialization would be achieved. It places users in complete control. It also lets users work with the map archive stuff from grim001 pretty easily.


Thus, we come to this

JASS:
#xjass
    // xJASS
#end

#vjass
    // vJASS
#end

#zinc
    // Zinc
#end

#wurst
    // Wurst
#end

#preprocess
     // Lua
#end

#script
    // xJASS
#end

#if (...) then
    //script
#end

#while (...) do
#end

#function hi(...)
#end

// etc


If we make the preprocessor be a completely different language, it should be obvious what language you are currently working with, even if you are in the depths of a block.

If we say that # from the preprocessor always refers to the script and that # from the script always refers to the preprocessor, then you don't have several stages of interpolation. You could, but it would all be in one line rather than be spread out across several lines.


I believe that these things will solve the issue of code readability. Yes, these things aren't needed, but we don't want an inherently unreadable language here.



The other cool thing we could do is this, on top of the above

JASS:
#preprocess function hi()
     // Lua

    #script function hi takes nothing returns nothing
    endfunction
end

But this would mean that script/preprocessor could optionally take any expression, which includes a block of code. I don't know if this ruins readability at all. You'll have to let me know.

We could say that # doesn't spread across lines, but make the script/preprocess things regular decorators

JASS:
preprocess function hi()
     // Lua

    script function hi takes nothing returns nothing
        // xJASS
    endfunction
end

//xJASS

With this, we can have several decorators like so

JASS:
preprocess function hi()
     // Lua

    vjass function hi takes nothing returns nothing
        // vJASS
    endfunction

    xjass function hi takes nothing returns nothing
        // xJASS
    endfunction
end

//xJASS

We don't necessarily want to use these keywords inside of expressions as things would get pretty ugly rather fast

Lua:
m = xjass i + 4*xjass a

-- vs

m = $i + 4*$a -- which language do i and a come from? Do they come from the script or preprocessor?


I can do it any which way. What would everyone prefer?



Also, how about this =)

It's essentially stating that type A is expanded out into a scope.
JASS:
scope type A extends integer
endtype
 
Level 6
Joined
Jul 30, 2013
Messages
282
+1 for augmented assignment

passing arrays..
hmm cant we at least pass tuples? (i mean for args i can use many params but returning more than 1 value at a time would be REALLY helpful, say a function that produces a value and a status code err/fail etc, currently ud be forced to use some global to pass it or a separate struct type which is clumsy.. )

u will still need to copy stuff like 2 times or so but a small handfull of items shouldnt be too evil...
so pretty please allow passing constant length tuples or stuff.

Since this is a compile time thing..(your prolly gonna compile this to a handful of globals right..?) maybe also pretty unpacking syntax eg:
JASS:
a, b, c = f(33)
translating in to sth like

function f..
    tmp_a= some value 1
    tmp_b= some value 2
    tmp_c= some value 3
endfunction

function caller..
local a
local b
local c
call f(33) 
set a = tmp_a
set b = tmp_b
set c = tmp_c
endfunction
:)


+1 for the idea of being able to easily mix languages..
but the JNGP is already way fragile.. just adding more of em wont do..
it could work if u presented some way to make them work together in a elegant/robust way..

i still dont rly like the amount of pound-signs in your examples tho @Nestharus
it would work i guess but i kinda find it unneccesarily complicating stuff..


JASS:
// notice lots of special precompiler syntax.. completely unnecessary imo
  #if (true) then
      //script
  #endif
  
  //vs
  
  #if (true) then
      //preprocess script
  endif

  //script
I propose the following:

Notice this is a regular if-statement
It is in the global scope, not inside a function --> it can only be a compiletime construct!
Map script is evaluated at compile time.
Evaluated expressions values are emitted to output.
The value of a function definition is the function definition itself
Same with struct/class other variable defs.

If a variable unused at runtime it will be removed by optimiser
value of if-statement is the value of the taken branch
if *if* statement is in a place that needs be evaluated at compiletime and condition cannot be resolved at compiletime emit compile error

JASS:
if DEBUG then
    //some code here...
    function print takes Object o returns nothing
        local string oname = object.name
        local integer oid = object
        call DisplaytimedTextTo... (.. some more info.. )
    endfunction
else
    //some code here...
    function print takes Object o returns nothing
        local string oname = object.name

        call DisplaytimedTextTo... (.. less info ..)
    endfunction
endif

function onlyUseThisAtCompileTime takes boolean b1 returns string
    // this could be more elegant if we had pretty multiline literals :)
    local string code = ""
    if b1 then
       code += "function f takes nothing returns nothing\n"
                     "    call BJDebugMessage(\"value of b1 was " + B2S(b1)+ "\")\n"
                     "endfunction"
    else
       code += "function f takes nothing returns nothing\n"
                     "    call DisplayTimedTextToPlayer(\"We just killed all your units, muhaha!\")"
                     "endfunction"
    endif
   return code
endfuncttion

// compiles to function f that displays "value of b1 was true" to all players
// if the function is not used at runtime it will be removed by optimiser
// thus u dont declare a function as compiletime as its a valid runtime function as well, u just dont use it at runtime if u dont need it. (this func wouldnt be much use at runtime, but it would work!)
onlyUseThisAtCompileTime(true)

//as an added bonus u could use at compiletime stuff that doesnt exist at runtime (eg code arrays)
// it would still be syntatically valid jass, just that if those cant be removed by runtime it would be compile error

essentially i'm saying: please implement a jass interpreter with a few tweaks and u can have a much more powerful system with 0 (i mean NONE) syntactic changes!


function silly takes nothing returns nothing
    // if can result is compiletime constant, essentially this is a static if
    // look mommy, no new syntax!
    if DEBUG then
        BJDebugMsg("debug")
    else
        DisplaytimedMessageToPlayer(GetLocalPlayer(),0,0,20,"not debug")
    endif
endfunction

the whole concept of static-ifs goes away, and we lose nothing.
the compiler will simply try to evaluate as much as it can at runtime and ifs whose outcome can be determined compiletime will be reduced to the winning branches contents. no functionality lost. excess keyword creep avoided. no new syntax to learn. noob friendly!

same if u got compiletime functions and way to emit their results to the map script.. you dont need macros either..
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
That breaks run time code outsidd of functions and introduces ambiguity between the runtime environment and the compile time environment : /.

One core feature of xJASS was no initializer functions. Code that runs at map init is just code not inside of a function.

Also, I don't think the compile time script should share the same syntax. This introduces ambiguity. The compile type script also doesn't need type declarations. It is much more flexible.

We already discussed code output in strings being a bad idea. You lose highlighting.

In the code inside the ifs, you make no distinction on whether it is dumped to the script or not. No distinction between them changes their behavior based on how they are used. This leads to code that is inherently difficult to understand.

I'm trying my hardest to come up with good preprocessor syntax. People told me it was too ambiguous. I agree. The # and other things are there to promote readable code : ).
 
Level 6
Joined
Jul 30, 2013
Messages
282
hmm
ok i get that u dont like string building.. (prolly could use a better syntax..)

and that perhaps it not a good idea that function calls just emit code.. (prolly a bit of extra syntax would be useful here.. eg emit keyword in stead of call or sth)

but if's?

comon whats hard to understanc about
JASS:
if something then
   statements1
else
   statements2
endif
if u forget all about static ifs..
then it does EXACTLY what you think it would..

and basically what im asking is the compiler should be smart enuff to optimise away the if-else without u having to type hints like
JASS:
static if

its not about how much you can add..
but how much you can take away.. (well at least syntatically)


oh.. speaking of wishlist..
would be kinda neat if it compiled to JASS2 .. and also to galaxy script..
tho im not sure how portable stuff would be (eg different id's for stuff etc..)
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
What is the different between this

JASS:
if (expression) then
    // runtime code
endif

and this

JASS:
if (expression) then
    // compile time code
endif


How would a compiler be smart enough to differentiate between the two? Neither of them are in functions. They are absolutely identical.


Also, static ifs are flawed. They can't generate code with an endif in them.

JASS:
// syntax error

static if expression then
    if (expression)
endif

static if expression then
    endif
endif


I am not trying to just outright say no to everything everyone says, but it's like people aren't thinking : |

edit
and my bad, I never mentioned that code outside of a function is code that is automatically run >.<.
 
Level 6
Joined
Jul 30, 2013
Messages
282
What is the different between this

JASS:
if (expression) then
    // runtime code
endif

and this

JASS:
if (expression) then
    // compile time code
endif

the difference is the content of the expression.
if the expression can be evaluated at compile time (constant expression) then it acts like a static if else its a normal one.

an expression is constant if any of these hold:
  • The expression consists of evaluating a literal of some sort
  • The expression consists of evaluating a compiletime constant (e.g DEBUG or LIBRARY_MyLib..)
  • The expression consists of evaluating a variable that's immutable (e.g variable declared constant with a value and can never change)
  • The expression is a call to a constant/perfect function (maybe an annotation or something to distinguish those) and all parameters are themselves constant expressions
  • .. if it can be otherwise proven that an expressions value can't change at runtime (read: if the compiler is powerful enough to prove its a constant expression, its a constant expression)
  • The expression is composed of 2 or more sub-expressions all of which are constant expressions.

if the compiler cant prove that the expression is a constant expression then it is NOT a constant expression, thus the if will be a regular if.
if the IF is not allowed to be a regular one in that position but must be static a compile error is thrown. this can be detected by the simple algorithm of: if the if statement contains code that must be global (outside any other block, eg function defs, globals etc) then it must be STATIC and if it cant be proven static u throw an error.

notice that often times a static if is used as an optimisation tool to just bring the evaluation of the condition to compile time and save runtime performance (eg decide if should print debug statements) in these positions a static if and regular one are semantically equivalent. and it doesnt really make any difference if its static or not to program semantics.


also note that in those if-s the //runtime code and //compiletime code..
there's literally NO difference. its just code.
if u run it at compiletime or runtime depends on the context entirely. e.g is it inside a function or is it outside?

note: all these proposals ofc work better if init remains a function or seperate block..

tho i think the issue there is larger. if all code outside functions is an init function.. well there where do you put the meta-code that generates ur super special functions at compile time?!
if all code outside is essentially the insides of an init block.. then all that code that generates your functions at compile also falls in to the init block. if you can tell the difference there then telling between static/runtime if becomes (well not quite trivial but..) completely reasonable.



btw whats ur thinking on how your gonna implement this thing?

EDIT: (some more ideas)
ability do define own blocks. ex:
JASS:
// handler for block types
// takes context: ptr to context in which the block is in
// AST: .. of the code contained in the block

function handle_myblock takes scope context, AST code returns AST
    // do some transformations on the AST..
    // possibly modify enclosing scope for some exotic goods
endfunction

define_block("myblock","endmyblock", function handle_myblock )


myblock
    some code
    some other code
    ...
endmyblock
// gets transformed in to
// handle_myblock(current_scope, ["some code","some other code", "..." ,...])
thus implementing stuff like init/endinit will be quite simple.
also blocks like class for instance would become trivial to implement, and it could be made by the user, be used as comfortable as a built-in

all you need do is emit a function for the on-init code and add a call statement to the end of current_scope.main (or global_scope.main? )
so if u sacrefice the implicit init-ness of floating code u wont rly lose much.
because its simple to define your own block to do that. (might be part of the stdlib but not language spec)

also if u put code inside a block that wont mess with highlighting :p (could use this to like define custom string types.. )

actually.. if you just give the function the current scope as a parameter..
you can mutate it at will and do all sorts of funny stuff.. so you dont need to emit code.. u can just tweak the AST if you want ;)

hmm i guess i should elaborate a bit
an ast.. what would it contain then..?
JASS:
// here on alternating one possible proposal of the code and how it effects the AST..

// scope == {}
integer a = 3
// scope == {a:{type:int, value:3, constant:false }}

//
function f takes integer a returns integer
   s1
   s2
endfunction
// scope == {
//    a:{type:int, value:3, constant:false },
//    f:{args:[{name:"a",type:int}], statements:[s1,s2], rtype: int}
//  }

something else that may be useful..
being able to pass raw args to a block
eg
class(classname, superclass) // on second thought it might be more elegant to omit the parens...
....
endclass
or
library([requirement1, requirement2], {syntax:vjass, flags:[...], sthelse:...})

endlibrary
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
the difference is the content of the expression.
if the expression can be evaluated at compile time (constant expression) then it acts like a static if else its a normal one.

I don't think this is a good idea - a compiletime if (like #if in C++) works very differently than a standard if, even if the condition of the if is completly constant.

For example

JASS:
#define MY_FALSE 0
#if MY_FALSE
	§$&+^^....
#endif

will compile completly fine, while

JASS:
#define MY_FALSE 0
if (MY_FALSE) {
	§$&+^^....
}

wont. Its even possible to use non-existing identifiers in a #if, while in a standard if, all identifiers have to be known and be convertible to bool. The semantics of #if and if are extremly different, so choosing one based on the context is very dangerous.


@Nestharus: What is this going to be exactly? A preprocessor only, a new Compiler (for "xJass") or both?

Regardless of that, I wouldn't add support for all ever existing Wc3 modding languages like in you huge language list (jass, vjass, "xjass", wurst, zinc, preproccesor, etc). Why would anyone use all those languages in a map? It just makes everything extremly complicated.

If you want to make a new language, then it should stand for itself, right? C# is also not backwards compatible with C and thats a very good thing. C++ is just backwards compatible to one single language and thats already the cause of a lot of problems...
 
Level 6
Joined
Jul 30, 2013
Messages
282
I don't think this is a good idea - a compiletime if (like #if in C++) works very differently than a standard if, even if the condition of the if is completly constant.

For example

JASS:
#define MY_FALSE 0
#if MY_FALSE
	§$&+^^....
#endif

will compile completly fine, while

JASS:
#define MY_FALSE 0
if (MY_FALSE) {
	§$&+^^....
}

wont. Its even possible to use non-existing identifiers in a #if, while in a standard if, all identifiers have to be known and be convertible to bool. The semantics of #if and if are extremly different, so choosing one based on the context is very dangerous.


@Nestharus: What is this going to be exactly? A preprocessor only, a new Compiler (for "xJass") or both?

Regardless of that, I wouldn't add support for all ever existing Wc3 modding languages like in you huge language list (jass, vjass, "xjass", wurst, zinc, preproccesor, etc). Why would anyone use all those languages in a map? It just makes everything extremly complicated.

If you want to make a new language, then it should stand for itself, right? C# is also not backwards compatible with C and thats a very good thing. C++ is just backwards compatible to one single language and thats already the cause of a lot of problems...

i cant really see the difference between the static and non-static ifs there. i really cant.
in python eg this is valid..

[/code]
if False:
complete junk that wouldnt ever compile in a static language
else:
somethinguseful()
[/code]
and it will run 100% of time without any issues.
as long as u dont break the syntax too bad (in case of python the indent must be reasonable so u can tell the blocks apart, a very lax requirement imo) u can delay compiling the inner block untill you know the condition.

now if that condition were to be known only at runtime its an issue.. but if it can be computed at compiletime then it will work fine..

you can ofc complain about it being inconvenient to use if/endif inside *static* if.. but hold that thought for a moment. Nes' just said like 3 times in this thread that he does NOT want macros that just do string substitution, but wants to work with logical chunks if possible.. now how would you do that if u had a random "if" or "else" keyword floating around in the code..
i argue this shortcoming is an illusion, in production code you wouldn't use such constructs anyway)



hmm i think your issue is that you haven't got enuff experience with dynamic languages (for pre-compile time its reasonable we want a dynamic language so we can tweak the resulting code more easily) and thus get bogged down by limitations of the languages that you are used to.

(C is from a time when often times you had so little memory you had to write stuff in assembly because you didn't have enough memory to run a high level compiler, it is not surprising that it lacks features that would need more work on the compilers part, that however does not mean such things are impossible)
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
i cant really see the difference between the static and non-static ifs there. i really cant.

The difference is that they do completly different things??

Maybe something like that is valid in Python (actually, its not), but thats not the point. The point is that

JASS:
if false then
    complete junk
else
    call BJDebugMsg("Valid code")
endif

is not valid Jass code, no matter how constant the literal false is. I still don't know if Nes wants to build a preprocessor only or a new language (the thread is a bit confusing). But in both cases such a fundamental thing like a simple if should work like expected.

hmm i think your issue is that you haven't got enuff experience with dynamic languages (for pre-compile time its reasonable we want a dynamic language so we can tweak the resulting code more easily) and thus get bogged down by limitations of the languages that you are used to.

Thats your assumption (and its wrong). Matlab for example is also a dynamic language and doesn't allow invalid code in statements that are never reached. That has nothing todo with language limitations but with semantics.

(C is from a time when often times you had so little memory you had to write stuff in assembly because you didn't have enough memory to run a high level compiler, it is not surprising that it lacks features that would need more work on the compilers part, that however does not mean such things are impossible)

I don't talk about C. What I said is also true for modern languages like C#.
 
Last edited:
Status
Not open for further replies.
Top