Nestharus
o-o
- Reaction score
- 84
So I was just looking at notes from a language I was working on and I came across this.
the export keyword exports a symbol or group of symbols from one scope to another scope. In the above example, the symbol "i" is being exported. the "static" means that it's not instanced (like the field of an instance of a class). the "out" keyword means go out to the scope that is using this.
So all in all, the result is that anything that calls ReturnThis will get a symbol of type integer i that is set to a variable n. n has the "out" modifier, meaning that it is located in the calling scope.
function Woah has an integer n and a while loop. Inside of this loop, it continues to call ReturnThis and then prints i, which was exported from ReturnThis. The result is 5, 6, 7, 8, 9, 10 being printed out to the screen.
Here are the notes
Keep in mind that virtual symbols are defined in code block #2
This is an article on embedding languages
JASS:
the export keyword exports a symbol or group of symbols from one scope to another scope. In the above example, the symbol "i" is being exported. the "static" means that it's not instanced (like the field of an instance of a class). the "out" keyword means go out to the scope that is using this.
So all in all, the result is that anything that calls ReturnThis will get a symbol of type integer i that is set to a variable n. n has the "out" modifier, meaning that it is located in the calling scope.
function Woah has an integer n and a while loop. Inside of this loop, it continues to call ReturnThis and then prints i, which was exported from ReturnThis. The result is 5, 6, 7, 8, 9, 10 being printed out to the screen.
Here are the notes
JASS:
/*
* Comment
*
* Comments may be either single line or delimited
*/
//a single line comment
/*
a multi-line comment
*/
/*
* multi-line comments may be nested
*/
/* /* hi */*/
/*
* Statement
*
* Every single line statement must end with either a new line or EOF.
*
* A single line statement may be continued to another line with \.
*
* Delimited statements include
*
* 1. ( )
* 2. " "
* 3. ' '
* 4. { }
*/
/*
* Scope
*
* There are five different types of named scopes
*
* 1. function scope
* 2. property scope
* 3. operator scope
* 4. type scope
* 5. scope
*
* Of these five types, they are split into the following name spaces
*
* 1. function scope A
* 2. property scope B
* 3. operator scope C
* 4. type scope D
* 5. scope D
*
* The reason why type scopes and scopes share the same space is because
* they both utilize the lookup operator (.)
*
*/
set hi.v=5
/*
* When a scope is used, the code inside of it is simply placed into the space of
* that scope. There is no scope declaration, there is only scope setting. This
* means that if two scopes are the same, the code inside of them share the same space.
* However, there can still be differences between the two scopes (more later).
*/
/*
* The scope may be anonymous or named
*/
scope label
end
scope
end
/*
* Any scope of any type may be nested into any other scope of any type
*/
scope
scope rawr
scope foo
end
end
end
/*
* Function Scope
*
* A function scope is a scope with a limited lifetime. There are two special scopes
* under the function scope.
*
* 1. property scope
* 2. operator scope
*
* However, the three scopes do not share the same name space.
*
* A function scope is accessed in the following manner
*
*/
function label takes arguments returnstype
end
/*
* An example of a function
*/
function Hello takesnothingreturnsnothing
end
/*
* Functions may have either an explicit or implicit return type
*/
function Hello takesnothing
end
/*
* The scope signature does not include the return type
*
* If the same scope is accessed in two incompatible ways, the
* scope can't be created. As such, a syntax error will occur.
*/
function Hello takesnothingreturnsstring
return"hi"
end
function Hello takesnothingreturnsinteger
return5
end
/*
* Note that an explicit return type will only accept that return type.
*
* Implicit return types may work with explicit return types so long
* as the implicit return types are compatible with the explicit return types.
*/
//both of these return agents, so the scope is still valid
function Boo takesnothingreturnsagent
returnCreateUnit(Player(0),039;hfoo039;,0,0,270)
end
function Boo takesnothing
returnCreateItem(039;afac039;,0,0)
end
/*
* The function scope is used with the call keyword.
*
* The parameters are passed in between the ( ).
*/
call Boo()
/*
* Please keep in mind JASS syntax for arguments.
*/
/*
* Implicit return types return the compatible type among
* types that the function returns.
*/
function ReturnsWidget takesinteger o
if(o ==5)then
returnCreateUnit(Player(0),039;hfoo039;,0,0,270)
end
returnCreateItem(039;afac039;,0,0)
end
/*
* Unreachable statements are removed from functions
*/
function ReturnsItem takesnothing
if(false)then
returnCreateUnit(Player(0),039;hfoo039;,0,0,270)
end
returnCreateItem(039;afac039;,0,0)
end
/*
* Property Scope
*
* The property scope is a function scope that acts like a variable
*
* It has two forms
*/
//getter, must return something
property label
end
//setter
property label =integer o
end
/*
* Example of properties
*/
internal privateinteger m =0
property i
return m
end
property i =integer o
set m = o
end
set i =4//accessed just like a variable
integer t = i
/*
* The operator scope is a function that uses operator syntax
*
* Keep in mind that any type can be used in the operators.
* integer isn't being used for any particular reason.
*/
//all operators
//
//static or non-static
//
//must return something
operator+integer i
return(thistype)((integer)this+ i)
end
operator-integer i
return(thistype)((integer)this- i)
end
operator/integer i
return(thistype)((integer)this/ i)
end
operator*integer i
return(thistype)((integer)this* i)
end
operator & integer i
return//?
end
operator | integer i
return//?
end
operator ^ integer i
return//?
end
operator ~
return//?
end
operator<<integer i
return//?
end
operator>>integer i
return//?
end
operator>>>integer i
return//?
end
//static or non-static
//
//must return something
operator<integer i
return(integer)this< i
end
operator<=integer i
return(integer)this<= i
end
operator>integer i
return(integer)this> i
end
operator>=integer i
return(integer)this>= i
end
operator==integer i
return(integer)this== i
end
operator !=integer i
return(integer)this != i
end
//all operators
//
//static or non-static
//
//must return something
reference operator=thistype i
setthis= i
returnthis
end
reference operator+=integer i
setthis=(thistype)((integer)this+ i)
returnthis
end
reference operator-=integer i
setthis=(thistype)((integer)this- i)
returnthis
end
reference operator*=integer i
setthis=(thistype)((integer)this* i)
returnthis
end
reference operator/=integer i
setthis=(thistype)((integer)this/ i)
returnthis
end
reference operator &=integer i
//code
end
reference operator |=integer i
//code
end
reference operator ^=integer i
//code
end
reference operator>>=integer i
return(thistype)((integer)this/R2I(Pow(2, i)+.5))
end
reference operatorthistype reference this<<=integer i
return(thistype)((integer)this*R2I(Pow(2, i)+.5))
end
reference operator>>>=integer i
//code
end
//static or non-static
//
//typecast must be of a valid type
//
// operator (integer)
// operator (real)
//
//a typecast operator is required for any type that isn't either
//imported or extended
//
//any type may typecast to any other type that it extends without an operator
//only non-virtual types may typecast to types that extend it
//
//must return the type
//
operator(string)
return"foo"
end
//static or non-static
//
//must return something
reference operatorthis++
setthis=(thistype)((integer)this+ i)
return(thistype)((integer)this-1)
end
reference operator++this
setthis=(thistype)((integer)this+ i)
returnthis
end
reference operator this--
setthis=(thistype)((integer)this- i)
return(thistype)((integer)this+1)
end
reference operator--this
setthis=(thistype)((integer)this- i)
returnthis
end
//static or non-static
//
//any valid expression
//
//similar to properties
//
// operator [integer i]
// operator [integer i, integer i2]
// operator [integer i][integer i2]
// operator [integer i, integer i2][integer i3]
// operator [integer i] = integer v
// operator [integer i, integer i2, integer i3][integer i4][integer i5] = integer v
//static or non-static
//
//must return something
operatorandinteger i
if((integer)this==0or(integer)i ==0)then
returnfalse
end
returntrue
end
operatororinteger i
if((integer)this !=0or(integer)i !=0)then
returntrue
end
returnfalse
end
operatornot
if((integer)this==0)then
returnfalse
end
returntrue
end
//static or non-static
//
//must return something
operator ?
if((integer)this==0)then
returnfalse
end
returntrue
end
//
//can take whatever and be overloaded like a regular function
//if this doesn't use override, it's automatically allocated and so on
//if it does, it isn't
operator new takesnothing
end
override operator new takesinteger i
setthis= allocate()
returnthis
end
//if any form of new is created, the default empty new is lost
operator delete
end
//alternative
//override operator delete
// call deallocate()
//end
/*
* Type Scope
*
* The type scope creates a new variable type.
*
* The primitive/native type it extends from dictates what variable type
* it will work with.
*/
type test extendsinteger
//integer this
type test2 extendsunit
//unit this
type test3 extendswidget
//widget this
/*
* It may have statements (either one or many)
*/
type test2 extendsintegerscope
end
type test2 extendsintegerinteger oh //one-liner with member oh
/*
* The label of a type may not share the same name as the label of a scope
*
* This is because both of them use the same lookup operator
*/
scopeinteger//error
end
/*
* Access Modifier
*
* public
* can be seen from anywhere
*
* protected
* can be seen by extending types
*
* private
* can be seen only within the direct scope
*
* internal
* can be seen within the file or trigger
* may be applied to other access modifiers
*
* friend
* can be seen only within scope (all scopes merging with it too)
*/
publicinteger i
protectedinteger i
privateinteger i
internal integer i
internal publicinteger i
internal protectedinteger i
internal privateinteger i
type a extendsprivateinteger //integer access stops at a
//can be interpreted as integer.
type a extendsprotectedinteger //integer access for children of a
//can only be interpreted as integer by children
type b extendsprivate a //can see integer, but child can't
//can't be interpreted as a
type a extends internal integer //integer access only to other code in same file/trigger.
//can only be interpreted as integer by other code in same file/trigger.
type a extendsinteger //anything can see integer from a
//anything can interpret a as integer
scope
privatescope
integer i
end
set i =5//good
end
set i =4//bad
friend integer i
scope a
end
scope d
end
scope e
end
scope b
//can only be seen by members of a if those
//members decide to merge with b
//nothing else can see it
friend a integer i
//can be seen by a,d,e when merged
friend a,d,e integer i
//can be seen by a,d,e
public friend a,d,e integer i
//friends are useful for things like with what modules used to do
//you may only want the variable to be seen by a certain module
//JASS has no modules, but it has constructs that can be used
//to similar effect
end
/*
* Variable
*
* A variable may be either implicit, global, or local.
*
* A global variable is a variable that exists outside of a function scope.
* A local variable is a variable that exists inside of a function scope.
* An implicit variable exists either globally or locally depending on where it is used.
*/
global integer i //explicitly global variable
localinteger i //explicitly local variable
integer i //may be global or local
//explicit globals block
globals
integer i
end
//explicit locals block
locals
integer i
end
/*
* An example of implicit variables
*/
integer i //i is local to Foo
function Foo takesnothing
set i =4
end
integer m //m is local to the anonymous function in this scope
set m =5
integer o //o is global
set o =3
function Foo takesnothing
set o =4
end
localinteger p
function Foo takesnothing
set p =4//syntax error
end
localinteger z
global integer z //no syntax error
localinteger L
integer L //global, no syntax error
function Foo takesnothing
set L =5
end
function Foo takesinteger i
set L =5
end
/*
* Variable types may also be implicit
*/
var i
set i =4//integer
var o
set o =CreateUnit(...)
set o =CreateItem(...)//widget
/*
* Intelligent Simplification
*
* Code is reordered based on use
* If there is cyclical use, a syntax error will occur
*/
//no errors
function Oh takesnothing
call Foo()
end
function Foo takesnothing
end
//cyclical error
function Boo takesnothing
call Grow()
end
function Grow takesnothing
call Boo()
end
/*
* Symbols that are not used anywhere are not included in code output.
*
* ExecuteFunc and TriggerRegisterVariableEvent symbol use is checked.
*
* Symbol use within strings handles string concatenation and variable use.
* Variables that do not resolve to a known finite set of values will cause all symbols
* that match the expression to be kept.
*
* If only a variable from an unknown source is used, then all symbols will be kept
*/
//kept
function cheese34958493 takesnothing
end
//not kept
function cheese31914 takesnothing
end
//kept
function cheeseqa9a923 takesnothing
end
function oh takesnothing
localstring str =GetEventPlayerChatString()
callExecuteFunc("cheese"+ str +"3")
end
/*
* Both boolean and mathematical expressions are simplified
*/
not a ornot b ->not(a and b)
3*a +4*a ->7*a
392+5->397
3+3*a +3*b ->3*(1+ a + b)
/*
* Lookup Operator (.)
*
* Accesses members of a scope
*/
scope a
scope b
integer o
end
end
set a.b.o=4
type m extendsintegerstaticinteger c
set m.c=5
scope a.b
integer a
end
set a.b.a=5
type m extendsintegerscope
statictype o extendsintegerstaticinteger c
end
set m.o.c=11
/*
* Scope Import, Export, Require
*
* Require is used to make one scope require another scope's code
* before being placed. This is used only for autorun code.
*/
scope
require b
call Print("ran anonymous scope")
end
scope b
call Print("ran b")
end
//
//outputs
//
// ran b
// ran anonymous scope
//
/*
* Import is used to import the symbols of a scope.
*
* Import may either be static or non-static. Static will not
* import virtual symbols. Virtual symbols can't be imported into a
* non-type scope.
*
* Import may also be global. Global will start at the global scope.
*/
scope a
integer p
end
scope b
import a
set p =4
end
type o scope
staticinteger m
end
type z scope
static import o //doesn't have to be static
set m =5
end
scope h
scope a
integer q
end
global static import a
set p =4//imported a from global scope, not local
end
/*
* Export is used to export the symbols from the scope to another scope
*
* Export may be global and or static
*
* Exported symbols may not be seen within the local scope.
*/
scope c
integer o
end
scope d
global static export c
integer q //this q can see the scope it's in, but not the
//scope it's being exported to
//set o = 5 would not work
//set c.o = 5 would work
end
//this scope can't see q
//set q = 4 would not work
//set c.q = 4 would work
end
scope c
require d //just to let people know that we now want d
//this isn't necessary, but it's a good practice
set q =5//success
end
/*
* Symbols from a scope may only be imported into a scope once
* The imported symbols are not copied!
* The imported symbols can be shadowed
*/
integer c =4
integer c =4//syntax error, multiple definitions
scope a
integer c
integer d
end
scope b
integer c
integer e
global static import a
set c =5//b.c
set d =5//a.d
end
/*
* Static
*
* A static member is a member that is linked to a type scope, the an
* instance of a type scope.
*
* A static symbol is a symbol that is not virtual.
*/
type d extendsprivateintegerscope
integer m //not static
staticinteger o //static
end
set d.o=4//linked to scope
set((d)1).m=4//linked to instance of scope
//instances of a scope are also linked to the scope
set((d)1).o=4
//nothing in a type scope is static without the static keyword
type d extendsprivateintegerscope
statictype a extendsprivateinteger
type a2 extendsprivateinteger//this is not static!
end
//example
d test = new d()
d.a test2 = new d.a()//linked to scope
d.a2 test3 = new test.a2()//linked to instance of scope
//if test were to be deleted, test3 would also be deleted
//this is primarily used for closures (more on this later)
/*
* Type Instance
*
* A type is instantiated with the new operator.
*
* The new operator calls the allocate function, which
* returns an instance of the type.
*
* If the new operator is overloaded, the default empty new operator
* is removed.
*
* If either the allocate or deallocate functions or overloaded, the
* default of the other will be removed.
*/
type test extendsprivateintegerscope
override operator new takesinteger i
setthis= allocate()
returnthis
end
override operator delete
call deallocate()
end
privatestaticinteger instanceCount =0
privatestaticintegerarray recycler
privatestaticfunction allocate takesnothing
localinteger instance = recycler[0]
if(instance ==0)then
set instance = instanceCount +1
set instanceCount = instance
else
set recycler[0]= recycler[instance]
end
return instance
end
privatefunction deallocate takesnothing
set recycler[(integer)this]= recycler[0]
set recycler[0]= recycler[(integer)this]
end
end
test t = new test()//error, the default new operator was removed
/*
* If new doesn't override, it will automatically call allocate
*
* If delete doesn't override, it will automatically call deallocate
* When delete doesn't override, the flow looks like this
*
* call HiddenDeleteFunction(this)
* call Delete(this)
*
* The HiddenDeleteFunction will first call delete, then it will
* deallocate.
*
* The new operator works the same way in that it will allocate, call
* the new function, then return the allocated instance
*/
function Delete takesintegerthisreturnsnothing
//user code
endfunction
function Deallocate takesintegerthisreturnsnothing
//user code or default code
endfunction
//what is actually called when delete doesn't override
function HiddenDeleteFunction takesintegerthisreturnsnothing
call Delete(this)
call Deallocate(this)
endfunction
function New takesintegerthisreturnsnothing
//user code
endfunction
function Allocate takesnothingreturnsinteger
//user code or default code
endfunction
//what is actually called
function HiddenNewFunction takesnothingreturnsinteger
localintegerthis= Allocate()
//initialize fields
call New(this)
returnthis
endfunction
/*
* If delete isn't overloaded, Deallocate is called directly.
*
* The new operator is *never* called directly. If it's not overloaded, then
* it's just not called. If allocate isn't overloaded, then initialize fields
* goes into allocate. If nothing is overloaded, allocate is called directly.
*
* Unless override is used on new, the matching signature from the parent is called.
* Unless allocate is overloaded, the allocate relies on parent's allocator.
*
* The override keyword is used to stop the child type from calling the parent.
* All functions in a type go through a dummy function that calls the parent before
* going to the actual user function if a parent signature exists and it does something.
*/
type a extendsprivateintegerscope
integer o =3
function Foo takesnothing
set o =4
set o =6
end
operator new takesnothing
set o =9
set o =10
end
operator delete
set o =9
set o =10
end
end
type b extends a scope
integer c =5
function Foo takesnothing
set o =7
set o =8
end
operator new takesnothing
set o =9
set o =10
end
operator delete
set o =9
set o =10
end
end
//translates to (actual code isn't readable)
globals
integerarray a_o
integerarray b_c
endglobals
function A_Foo takesintegerthisreturnsnothing
set a_o[this]=4
set a_o[this]=6
endfunction
function A_New takesintegerthisreturnsnothing
set a_o[this]=9
set a_o[this]=10
endfunction
function A_Delete takesintegerthisreturnsnothing
set a_o[this]=9
set a_o[this]=10
endfunction
//allocate globals, other allocate code
function A_Allocate takesnothingreturnsinteger
//code
endfunction
function A_Deallocate takesnothingreturnsinteger
//code
endfunction
function A_Hidden_New takesnothingreturnsinteger
localintegerthis= A_Allocate()
set a_o[this]=3
call A_New(this)
returnthis
endfunction
function A_Hidden_Delete takesintegerthisreturnsnothing
call A_Delete(this)
call A_Deallocate(this)
endfunction
function B_Foo takesintegerthisreturnsnothing
set a_o[this]=7
set a_o[this]=8
endfunction
function B_New takesintegerthisreturnsnothing
set a_o[this]=9
set a_o[this]=10
endfunction
function B_Delete takesintegerthisreturnsnothing
set a_o[this]=9
set a_o[this]=10
endfunction
function B_Hidden_New takesnothingreturnsinteger
localintegerthis= A_Hidden_New()
set b_c[this]=5
call B_New(this)
returnthis
endfunction
function B_Hidden_Delete takesintegerthisreturnsnothing
call A_Delete(this)//no way around this chain
call B_Delete(this)
call A_Deallocate(this)
endfunction
/*
* Types can be used as variable types
*/
type o extendsinteger
o test
/*
* They can be created and destroyed
*/
set test = new o()
delete test
/*
* Non-static members can be accessed
*/
type o extendsintegerinteger m
set test = new o()
set test.m=5
type o extendsintegeroperator+ o c
return(integer)this+(integer)c
end
o test2 = new o()
o test3 = test + test2 //dangerous
/*
* Out vs In
*
* Out switches to the scope relating to the current scope
* In switches back to the current scope
*/
out scope
end
in scope
end
in integer i
out integer i
/*
* Example
*/
scope a
function Foo takesnothing
privateinteger i
end
end
scope a
function Foo takesnothing
scope c
call Print("hello")
end
end
end
scope d
privateinteger n
global static export a
out scope//only way to combine with Foo inside of d
function Foo takesnothing
//in refers to d
//out refers to caller of Foo
//in.out refers to Foo
//can't see i, can't see n
in scope
//can see n now, but only because
//n is part of the origin scope
set n =5
end
//this is dangerous
out
set f =6//any calling scope better see an f
call RunMe()//wtf?
end
call Print("what?")
require c
end
end
end
end
scope z
integer f
function RunMe takesnothing
call Print("ran")
end
call a.Foo()
end
scope
integer f
function RunMe takesnothing
call Print("ran again")
end
call a.Foo()
end
/*
* Output
*
* "ran"
* "ran again"
* "hello"
* "what"
*
* Results
*
* z.f = 6
* anon.f = 6 //the anonymous scope
*/
/*
* Keep in mind that for merging scopes, the only fields that may not be
* visible are private an internal.
*
* Private will never be visible.
*
* Internal will only be visible if the merging scope is in the same file or trigger.
*/
//this example is about as whacked as it gets
function foo takesnothing
out set o =5
end
function t takesnothing
integer o
call foo()
call Print(o)//prints 5
end
/*
* One of the strangest examples ever
* A way to return multiple variables
*/
function ReturnThis takesnothing
out static export //no name needed
integer i = out n
end
end
scope
function Woah takesnothing
integer n =4
while(n++<10) do
ReturnThis()
Print(i) //5
//6
//7
//8
//9
//10
end
end
end
/*
* Set
*
* Set is used to explicitly require the = operator
*
*/
set i =5
/*
* It can only ever be used with the = operator
*
* Without set
*/
i =5
i++
++i
i /=5
/*
* Call
*
* Call is just an explicit function call. It may also be
* implicit. As call does not really require anything, it
* becomes an optional keyword.
*/
call Foo()
Foo()
/*
* This fixes the special exceptions found in JASS
*/
set i = Foo()//exception
//should be
set i =call Foo()//correct
//by allowing call to be implicit, it fixes this exception
/*
* Loops
*
* for (integer i = 5, i < 4, ++4) do
* end
*
* while (i++ < 5) do
* end
*
* loop
* while i++ < 5
* exitwhen i++ >= 5
* end
*
* //overload the in operator
* //overload the iterator operator
* for (unit u in group) do
* end
*/
JASS:
//inline
inline function Foo takesnothing//inline is forced
return5
end
//symbols are kept from strings so long as they can be derived from that string statically
//this means only set-once variables that originate from literals
callExecuteFunc("${function Foo}")
callExecuteFunc((string)function Foo)
//runs preprocess code
preprocess
end
//debug only code
debug
end
//used inside of preprocess code to go back to script
script
end
//automatically determine signature of constant code
//anonymous function support
constantcode c =functiontakesnothing
return5
end
var i = c()
//use triggers for non-set once code
set c =functiontakesnothing
end
call c()//trigger
//when no signature is provided, expects takes nothing returns nothing
function hi takesinteger i,integer i2 returnsinteger
return i + i2
end
hi code c = functiontakesinteger m,integer m2 returnsinteger
return m*m2
end
c =function hi
call c(5,6)//11
//virtual keyword may be applied to functions, operators, and properties within a type scope
//anything virtual will run off of triggers
virtual function Foo takesnothingreturnsnothing
end
type a extendsprivateinteger
virtual scope a link type a
virtual function Foo takesnothingreturnsnothing
return"a"
end
end
type b extends a //public
virtual scope b link type b
virtual function Foo takesnothingreturnsnothing
return"b"
end
end
a test1 = new a()
a test2 = new b()
call Print(test1.Foo())//"a"
call Print(test2.Foo())//"b"
//example of how scoping works
type a extendsprivateinteger
virtual scope o link type a
end
scope
//access modifier on a one-liner refers to this scope
//Foo is accessed from the target scope though
private o function Foo takesnothing
end
end
//The $ operator is used to interpolate things one level up
//string -> script -> preprocessor
string name ="hi"
call Print("$name")//prints hi
preprocess string name ="myVar" end
$name ="$$name"//myVar = "myVar"
loops
loop
forloop
whileloop
do whileloop
loop keywords
exitwhen expression
break
continue
//example of some dynamic code with preprocess
preprocess
typemodule
virtual scopemodule link typemodule
privatestatic dictionary<signature> flag = new dictionary<signature>()
protected virtual function createScript takesnothingreturnsnothing
end
staticoperator new takes signature sig
if(flag[sig])thenreturn(module)0
call createScript()
return(module)1
end
end
end
preprocess
type mymodule extendsmodule
virtual scope mymodule link type mymodule
protected virtual function createScript takesnothingreturnsnothing
integer i =0
while(i <10)
script
publicstaticstring str$i ="str$i"
end
end
end
end
end
type test extendsprivateinteger
virtual scope test link type test
preprocess new mymodule(type test) end
//the above creates 10 string variables, str0 through str9
//attempting to run it a second time will do nothing
preprocess new mymodule(type test) end
end
//templates are created with < > and can be applied types, functions, operators, and properties
//< > can accept signatures or labels
//
//the signature type is any signature
//
//template arguments are defined in both the preprocessor and the script and are constant
type<type T> test extendsprivateinteger//type T may also be made more explicit with extends
//for example, type T extends list, meaning that T must be
//a type of list, including list itself
//variable signatures are also accepted, like integer array VAR
virtual scope test link type test<type T>//signature includes the template
T value
end
test<type integer> t = new test<type integer>()
set t.value=5
//The abstract keyword when applied to a type means that the type can't be used except for by other types.
//The sealed keyword when applied to a type means that the type can't be extended.
//The constant keyword when applied to a type means that all members of that type must be static and constant (like enums)
//when constant is applied to something, it can't change and it can only use constant code
//the super keyword is used in types to access the parent type
type a extendsprivateinteger
type b extendsprivate a
virtual scope a link type a
function foo takesnothing
return"a"
end
end
virtual scope b link type b
function foo takesnothing
returnsuper.foo()//"a"
end
end
//signature is a primitive type that holds signatures
//
//signatures include
//
// function
// scope
// type
// property
// operator
//
//signatures can be used in various places
//the label of a signature can be used as a value (signaturetype label)
//the raw signature can also be used
//the signature type can be worked with like any other type
//
//the signature type includes the following functions and operators
//
// (string)
// scope //gets signature of enclosing scope
// .exists //does the signature exist?
//
//the top level scope is called global
//
//an inlined function that is not simple enough to normally do inlining will create local variables
//to hold function calls
//closures
function rake takesnothing
integer k =5
function far takesnothing
set k =6
end
call far()
call Print(k)//prints 6
callTimerStart(CreateTimer(),1,false,
functiontakesnothing
callDestroyTimer(GetExpiredTimer())
call Print(k)//prints 9
end)
set k =9
end
//set takes an expression (it really should be evaluate..)
//
//set i++
//set i--
//integer forms
//
// ascii: 'aaaaaaaaaaaaa'
// hex: 0x5
// octal: 01
// binary: 0b1
//however, global and local variables don't really hold a place anymore
function rake takesnothing
integer k =5//local variable
//this is technically public, but it only exists for the lifetime of rake, so
//it can't really be called outside of this instance of rake
function far takesnothing
//as no variables are copied, this just passes in the original closure
//if there were new variables, it would create a new closure and give it old
//closure + variables
function far2 takesnothing
call Print(k)
end
if(++k <10)then
call far()
end
end
integer i =4
//a closure is created for this instance of rake
//all locals used in far are copied to this closure
//the closer is passed into far
//far then uses the closure to work with the variables
call far()
//closure c = new closure(k)
//call far(c)
// if (++c.k < 10) then call far(c) end
//set k = c.k
//i is not copied because far does not use it
call Print(k)//prints 10
//closures running on a timer or trigger or anything else are copied for those handles
//via a hashtable
callTimerStart(CreateTimer(),1,false,
functiontakesnothing
callDestroyTimer(GetExpiredTimer())
call Print(k)//prints 9
call far()//passes in closure that this function has
//if there were multiple timers, triggers, and so on from this function, they'd
//all share the same closure
end)
set k =9
end
//type nesting is the same way, except that rather than closures, types are passed in
//this is because the type itself can serve as a closure
//as such, a non-static type nested inside of a type must be created a special way
type outside extendsprivateinteger
virtual scope outside link type outisde
type inside extendsprivateinteger
end
outside test = new outside()
outside.inside test2 = new test.inside()
//preprocessor includes object type, which works with objects
//object types include units, items, doodads, etc
unit footman =unit[039;hfoo039;]//access footman object
unit test = new unit(039;hfoo039;)//create a new object based on footman and return id
set test.life=5000//or w/e, properties are based off of object properties
//functions may take references
function hi takes reference integr i
set i =5
end
integer i =4
call hi(i)//i is now 5
// a virtual type is a type that can't be instantiated
//
// type a extends private integer scope
// virtual function oh takes nothing
// call Print("a")
// end
// end
//
// type b extends private integer scope
// import a
//
// virtual function oh takes nothing
// call Print("b")
// end
// end
//
// a test = new a()
// a test2 = new b()
//
// call test.oh() //prints "a"
// call test2.oh() //error, not allocated
//
// polymorpshim for function oh will still work under type b
//
// type c extends private b scope
// virtual function oh takes nothing
// call Print("c")
// end
// end
//
// b test3 = new c()
// call test3.oh() //prints "c"
//
// to use polymorphism, use extends or extensions
//
// import will only import public symbols
// extends and extensions will import public and protected symbols
//
// .exists
// .type
// .signature
// .super
//
// a type may extend off of one non-virtual type
// a type may extend off of many virtual types
// a type may typecast to any type it extends from/to, including virtual types
// a virtual type can't be typecasted to anything
// types and virtual types can typecast to anything that they have an operator for
// once a signature is virtual, it stays virtual
// a signature may go from non-virtual to virtual
// by default, methods will call super.method
// in order to not call super.method, you may use the override keyword
//
Keep in mind that virtual symbols are defined in code block #2
This is an article on embedding languages
//o] is an expression?!
//how about it stops at ] and goes back to jass as ] isn't legal
//vjass either takes an expression or a statement!
//j vj j vj
set i[vjass o] = vjass 4
//this will be some hellish tokenization
//from a tokenizer point of view, when JASS sees vjass, what should the mode look like?
//it depends on where it's at, but the problem is that the tokenizer doesn't know where it's at
//so how about the tokenizer pushes modes whenever it enters a block such as a function?
//it pops modes whenever it hits ]
//this means that the following would tokenize
//j vj j
set o = vjass 5]
//let's conside this then
set i[vjass o]
//jass
//set i
//encounters [, so pushes jass mode
//but this depends on the mode we're in
//[
//push vjass
//vjass o
//pop vjass, now we're in jass
//pop jass, now we're still in jass
//]
//however, this would mean that for any token, it would have to do a look-ahead
//token {check for pops!}
//are there are smarter ways to do this?
//alternative solution is to have a standard set of tokens for all languages
//however, vjass 5] should still pop when it hits ]
//but this will mean that it won't need a look-ahead and ] will still just go to TOKEN__RBRACK
//instead of TOKEN__VJASS__RBRACK
//this would mean that there must be 1 tokens file, not 1 tokens file for each language
//tokens may not be used by a given language though
//whenever any language enters a delimited value, it pushes the current mode in
//whenever any langauge exits a delimited value, it pops
//this is already done for the values themselves, but not for [ ]
//so block statements would push/pop languages
//so should atoms push/pop values? no
//what about a string atom with complex interpolate operator? Still no, the $ operator would do it
//vjass itself won't pop until it sees a terminal or some sort of delimited closer
//j vj j
set i[vjass "foo"]
//the next problem is this
vjass function hi takes nothing returns nothing
endfunctoin
//by what was said previously
//vjass -> push vjass
//function -> push vjass
//endfunction -> pop vjass
//uh oh! this is where the terminal comes in, because remember vjass takes a statement
//\n -> pop vjass
//what about a language like cjass?
cjass void hi()
{
}
//cjass -> push cjass
//{ -> would normally push cjass, but what about the \n?
//we're in cjass atm, so it's expecting a ; terminal
//cjass -> push cjass
//{ -> push cjass
//} -> pop cjass
//uh oh, we're still in cjass!!
//; -> pop cjass
cjass void hi()
{
};
//so we're in cjass until we add a terminal?
//is this ok, or should } pop twice?
//perhaps check to see if it's expecting a terminal or not, then
//} can act as both a terminal and a function ender
//cjass -> push cjass, expecting terminal
//{ -> push cjass, not expecting terminal
//} -> pop cjass, check is expecting terminal, if it is, pop it again!
//this can actually be a loop, keep popping until you're not expecting a terminal
//now we can do this
cjass void hi()
{
}
//or this
//however, this is not good!
set i = cjass o; + 4
//this is smarter
//the ( ) is part of expressions, so it would push cjass and then pop it
//the ) is expectnig a terminal, so pop again
//then we get into the + 4
set i = cjass(o) + 4
//what about this?
cjass (integer i = 3)
//it would fail on the parser side as that's not a valid statement
//fails on the parser side, the [ ] is not valid here
set i = cjass[o] + 4
//this successed
set i = a cjass[o] + 4
//so then what if cjass gives a full terminal and it's expecting a terminal
//it's a terminal token!
set i = cjass (o) + 4
//-> set i = (o) + 4
//as can be seen, it will still produce a syntax error
//while the above won't
set i = cjass o; + 4
//-> set i = o
//+ 4
//this means that a statement can't end in either a language change or a terminal
//it must ALWYAS end in a termina
//if that language change includes a terminal, it will be used
//but what about things like }?
//the } can act as a terminal in cJASS!
//does this mean that we need to output a terminal token to play nice with the parser regardless of where we are with }?
//yes! the } by itself can't have two types, and cjass expects a { } while jass jass wants a \n
//but then wouldn't the following be valid?
cjass void hi() {
} set o = 4 //jass here
//so then perhaps } will pop twice like normal, then you can't put jass on the same line as the }
//so } should not output two tokens, it should not act as either a terminal or a }
//it is simply that cjass does not expect a terminal when it sees a }
//jass still wants its terminal regardless!
//what about something like this then?
set i = cjass o
//we're still in cjass down here, it wants a terminal
+ 5
+ 6;
//good!
//i believe that this offers the most flexibility and is the most logical
//now that we have organized the syntax from the lexer's point of view, it needs to be
//organized from the parer's point of view
//the parser must know where it's at at any given point of a statement, meaning statements
//must be broken up into many rules
//it is either that, or a cjass/vjass/etc token is only allowed at certain points, meaning that
//a statement won't need to be broken into oblivion
//where are these points valid then?
//at the start of any statement or within any expression?
//this means that there are in fact 5 scopes
//scope permanent
//scope global
//scope temporary
//scope action
//scope expression
//scope expression raises some other interesting points though
//set i = (integer b = 5)
//by rules of scoping, b would be visible outside of ( )
//to address scoping, we must ascertain what kind of visibility modifiers there are in JASS
//global anywhere
//local local to the scope
//none accessible through the scope (or anywhere if the scope is anonymous)
//if we follow these rules and apply them at any point, this will work out for JASS
//in cJASS, vJASS, etc, there are different properties
//public = none
//local = private
//protected
//internal
//friend
//this means that at any point in the parser, it must act on a language token depending on
//what type of scope it is in
//vjass doesn't take 1 statement, it takes 1 statement that is legal in the given scope that it wants
//so in reality, there are 5 different vjass things within JASS
//if it's in global, vjass can take a native, a type, or w/e
//if it's in temporary, vjass can only take certain other things
//I believe this ends the organization of both the lexer and the parser
//how do we organize this for
// call vjass foo()
// ????
//need deeper rules!
// temporary scope function
//
// can't have temporary scopes
// can't have globals
// can't have natives/types
//
// permanent scope scope
//
// can't have natives/types
//
// action scope loop, if
//
// can't have temporary scopes
// can't have natives/types
//
// global scope
//
// anything
1 different environment for each language
use the special language construct tto access another environment/syntax
//the o,z,d are all from vjass environment
//everything up to the end of the statement is vjass
//the question is, how to have the terminal also be part of the jass statement
//unless a jass statement can end in either a code environment switch or a terminal
//which is smart
//so vjass should also be counted as a terminal
//jass o + vjass o + z + d
set i = o +
//doesn't allow one-liners
vjass
endvjass
vjass scope hi
endscope
function foo takes nothing returns nothing
vjass function boo takes nothing returns nothing //this shouldn't be allowed
endfunction //part of vjass still
//back to jass
endfunction
//a vjass function
//it's brilliant :O, cuz vjass is like a modifier here
vjass function foo takes nothing returns integer
return 5
endfunction
//another foo
//because each language
function foo takes nothing returns nothing
endfunction
//call foo from vjass
set i = vjass foo()
vjass call foo()
call foo()
//jass cjass jass
set i = o + cjass i; set c = i