## Automated HSpeak tests. See documentation in hspeaktest.py
## Run these tests with "scons hspeaktest"

## Including just this is faster than all of plotscr.hsd
include, hamsterspeak.hsd

globalvariable(1,globalvar)
defineconstant(1,constant)

define function, begin
  1,noop4,4,0,0,0,0
  @obsolete, 2,obsoletecmd,0
  @obsolete(replacement,"Message"), 3,obsoletecmd2,0
  @obsolete(error), 4,removedcmd,0
  5,globalvar,0          # ERROR
  6,constant,0           # ERROR
  @obsolete(), 100,__obsolete,0      # OK
end

script, div, a, b ()

defineoperator(100, eqstr, stringcompare)
defineoperator(100, div, div)
defineoperator(100, oper, constant)  # ERROR
defineoperator(100, oper, globalvar) # ERROR  (known failure)
## Could only allow scripts and commands that take at least two args
##defineoperator(100, oper, a script)               # OK
##defineoperator(100, oper, a plotscript)           # ERROR
##defineoperator(100, oper, noop)                   # ERROR


## Check for errors given extra commas, and for operators in illegal positions
script, comma and operator tests, begin
  variable(endsin:,xx)
  +,                     # ERROR
  + ,                    # ERROR
  <<,                    # ERROR
  << ,                   # ERROR
  ,<<1                   # ERROR
  , <<2                  # ERROR
  ,<3                    # ERROR
  , <4                   # ERROR
  1,-2                   # WARN
  ,-2                    # WARN
  -2,                    # WARN
  noop4(1,-2)            # OK
  noop4(endsin:,endsin:) # OK
  1,:=2                  # ERROR
  1,--2                  # ERROR
  2--1                   # WARN
  ## FIXME: This is major lexer bug
  2-1                    # ERROR  (known failure)
  1, div, 2              # OK
  1, eqstr, 2            # OK
  1, eqstr, 2 + 3        # OK
  (1) eqstr (2 + 3)      # OK
  (1) div (2 + 3)        # OK
  noop4(1,mod,2)         # OK
  #if,(xx) then()         # WARN
  if(xx), then()         # OK
  #if(xx) then,()         # WARN
  noop4((1), (2))        # OK
  noop4(-2)              # OK
  noop4((2) -- (1))      # OK
  ## These error checks aren't implemented; they're hard to catch
  noop(),                # ERROR  (known failure)
  noop,()                # ERROR  (known failure)
  noop4(noop,())         # ERROR  (known failure)
  ## This fails because parsed as noop(0), but noop takes no args
  ## Let's say this should be a warning, because the behaviour would have changed
  noop4(noop,(0))        # WARN   (known failure)
  noop4( --2)            # ERROR
  noop4(,--2)            # ERROR
  noop4( ,  , 0)         # ERROR
  noop4( , 0)            # ERROR
  ## These probably don't particularly need to be disallowed
  noop4(0 ,)             # OK
  variable(,yy)          # ERROR  (explict check for this)
  variable(yy,)          # OK  (??)
  variable()             # OK  (??)
  ## $ is treated as a unary operator
  $,0=""                 # ERROR
  $0,=""                 # ERROR
  $0=,""                 # ERROR
  noop4($0="")           # OK
  noop4(1,$0="")         # OK
  noop4(,$0="")          # ERROR
  ## Warnings for logical errors
  if (xx == 2||3||4) then()      # WARN   (known failure)
end

end                      # ERROR
begin                    # ERROR
script, foo, end         # ERROR
()                       # ERROR

script, string tests, begin
  $0="", 232             # WARN
  $0="" 232              # ERROR   (known failure)
  "asdasd"               # ERROR
end

script, number tests, x, begin
  x := 000 0000              # OK
  x := - 14                  # OK
  ## tab characters
  x := -	1	4    # OK
  x := 14a                   # ERROR
  x := - 14a                 # ERROR
  x := 0x14a                 # OK
  x := - 0x 14a              # OK
  x := -	0x	14a  # OK
  x := 0x                    # ERROR
  x := 0o                    # ERROR
  x := 0b                    # ERROR
  ## Space after the 0 not supported... but we don't care one way or the other
  ##x := 0 x1
  ## - is not a valid token, and identifiers can't start with -
  x := -                     # ERROR
  variable(-)                # ERROR
  variable(-y)               # ERROR
  x := -x                    # ERROR
  x := -(1+2)                # ERROR
  ## Numbers which aren't 32 bit
  x := 0x100000000           # ERROR
  x := 0o1                   # OK
  x := 0o8                   # ERROR
  x := 0oa                   # ERROR
  x := 0b0                   # OK
  x := 0xa                   # OK
  x := 0xf                   # OK
  x := 0bf                   # ERROR
  x := 0XF                   # OK
  x := -0x111                # OK
  ## special rules for non-decimals: silently overflow large unsigned 32bit ints
  x := 0xffffffff            # OK
  x := -0xffffffff           # OK
  x := -2147483648           # OK
  x := -2147483649           # ERROR
  x := 1.                    # ERROR
  x := 1.0                   # ERROR
  x := .0                    # ERROR
end

script, math warnings, x, begin
  x := random ()             # ERROR
  x := random (1)            # ERROR
  x := random (1, 0)         # WARNING  (known failure)
  x := random (1, 1)         # OK
  ## The following test optimisations
  x := 1 / 0                 # ERROR
  x := 1, mod, 0             # ERROR
  x := 1^0                   # OK
  x := 0^-1                  # ERROR
  ## Negative exponents evaluate to 0, but will probably change in future
  x := 1^-1                  # OK
  x := sqrt(0)               # OK
  x := sqrt(-1)              # ERROR
end

script, include tests, begin
  include                    # ERROR
  include,                   # ERROR
  include, "foo"  bar        # ERROR
## "Found unexpected text"
  include, "foo.hss  bar     # ERROR
## "Expected " at end of line"
end

script, flow tests, dummy, begin
  (dummy)                # WARN
  ()                     # ERROR

  if(dummy) then() else()
  else()                 # ERROR
  then()                 # ERROR
  break                  # ERROR  (known failure)
  continue               # ERROR  (known failure)
  return                 # ERROR
  return()               # ERROR
  exitreturning          # ERROR
  exitreturning(1,2)     # ERROR
  exit(1,2)              # ERROR

  if () then()           # ERROR
  if(dummy,dummy) then() # ERROR
  if(dummy) if(dummy) then() # ERROR
  if(dummy) else()           # OK
  if(dummy) else() then()    # ERROR
  dummy := variable(foo)     # ERROR
  (if(dummy) else())         # ERROR   (known failure)
  if(if(1)then(1))then()     # ERROR
  dummy := if(1)then(1)      # ERROR
  if(assert(1))then()        # ERROR
  if($1="")then()            # OK
  if() then                  # ERROR
  if(then())                 # ERROR
  if(dummy) variable(x) then()  # ERROR
  if(dummy) then(variable(x))   # OK

  ## In case of of a missing bracket, ideally hspeak would throw an error here
  ## instead of complaining the next script/declaration appears inside this script.
  ## (This test fails because the error gets thrown on a different line.)
  if (key is pressed(key:M) then (pick hero())  # ERROR   (known failure)

end

############################### Namespace tests ###############################
## Testing whether various types of names are properly disallowed

globalvariable(one,global)       # ERROR
globalvariable(two,globalvar2)   # OK
globalvariable(2,globalvar)      # ERROR
globalvariable(1,globalvar2)     # ERROR
globalvariable(2,one)            # ERROR
globalvariable(8,G2,9,G3)        # OK
globalvariable(8,G2,9,G2)        # ERROR
globalvariable(8)                # ERROR
globalvariable(8,G2,9)           # ERROR
globalvariable(9,begin)          # ERROR
globalvariable(9,+)              # ERROR
globalvariable(9,add)            # ERROR
globalvariable(9,mod)            # ERROR
globalvariable(9,eqstr)          # ERROR
globalvariable(9,div)            # ERROR
globalvariable(-1,ok)            # ERROR
globalvariable(9,script)         # ERROR
## (subscript isn't a trigger type like script/plotscript are)
globalvariable(9,subscript)      # ERROR
globalvariable(9,return)         # ERROR
globalvariable(9,exitreturning)  # ERROR
globalvariable(9,exit)           # ERROR
globalvariable(9,flowtests)      # ERROR

defineconstant(1,begin)          # ERROR

script, namespace tests, arg, begin
  variable(noop)         # ERROR
  variable(script)       # ERROR
  variable(variable)     # ERROR
  variable(globalvariable) # ERROR
  variable(globalvar)    # ERROR
  variable(constant)     # ERROR
  variable(flow tests)   # ERROR
  variable(arg)          # ERROR
  variable(1)            # ERROR
  variable(a.)           # ERROR
  variable(add)          # ERROR
  variable(mod)          # ERROR
  variable(eqstr)        # ERROR
  variable(div)        # ERROR
  variable(:=)           # ERROR
  variable(x:=y)         # ERROR
  variable($)            # ERROR
  variable($+)           # ERROR
  variable(v)
  variable(@v)           # ERROR  (known failure)
  variable(@obsolete)    # ERROR

  ## subscript args and variables can shadow outer locals, but not globals or other names
  subscript, sub ()                               # OK
  subscript, sub, globalvar ()                    # ERROR
  subscript, sub, constant ()                     # ERROR
  subscript, sub, NO OP ()                        # ERROR
  subscript, sub, namespace tests ()              # ERROR
  subscript, sub, sub ()                          # ERROR
  subscript, sub, arg ()                          # OK
  subscript, sub, v ()                            # OK
  subscript, namespace tests, arg ()              # ERROR
  subscript, sub, (subscript, sub2 ())            # OK
  subscript, sub, (subscript, SUB ())             # ERROR
  subscript, sub(), subscript, sub()              # ERROR
  subscript, sub, (subscript, namespace tests ()) # ERROR
  subscript, sub, W (subscript, sub2, w ())       # OK
  subscript, sub, W (), subscript, sub2, w ()     # OK
  subscript, sub, W (subscript, sub2, w (), subscript, sub3, w ())  # OK
  v := subscript, sub ()                          # ERROR
  @obsolete("message") subscript, sub ()          # OK
  @obsolete, @obsolete(blarg), subscript, sub ()  # OK
  ## Should shadowing scripts/locals in an outer scope be allowed? (Currently not.) Seems useful.
  ## Scripts named div and ascript have been declared, but hspeak
  ## hasn't parsed ascript yet, so fails to report an error.
  subscript, div ()                               # ERROR (?)
  subscript, a script ()                          # ERROR (?) (known failure)
  variable(sub), subscript, sub ()                # ERROR
  subscript, sub (), variable(sub)                # ERROR
  subscript, sub (), subscript, foo (subscript, sub ())  # ERROR (?)
  subscript, foo (subscript, sub ()), subscript, sub ()  # ERROR (?) (known failure)
  subscript, sub (), subscript, foo (variable (sub))     # ERROR (?)
  subscript, foo (variable (sub)), subscript, sub ()     # ERROR (?)
  ## Operators (builtin or from defineoperator above)
  subscript, add ()                               # ERROR
  subscript, sub, add ()                          # ERROR
  subscript, mod ()                               # ERROR
  subscript, sub, mod ()                          # ERROR
  subscript, eqstr ()                             # ERROR
  subscript, sub, eqstr ()                        # ERROR
  subscript, div ()                               # ERROR
  subscript, sub, div ()                          # ERROR

  ## Testing @obsolete warnings and errors
  obsoletecmd            # WARN
  obsoletecmd2           # WARN
  removedcmd             # ERROR
  obsoletescript         # WARN
end

definescript(1, missing script, 0)                # ERROR
## Don't care whether definescript after the script itself is allowed (currently is)
#definescript(1, flow tests, 1, 0)                # OK
## Even plotscripts can use definescript to fix an ID
definescript(1, a plotscript, 0)                  # OK
## OK to give defaults for more arguments in definescript than in the definition
definescript(1, a script, 3, 0, 56, 42)           # OK
definescript(1, a script, 3, 0, 56, 0)            # ERROR (elsewhere)
definescript(autonumber, a script, 3, 0, 0, 42)   # OK
## Only functions can have variable numbers of args
definescript(1, a script, -1)                     # ERROR

plotscript, a plotscript ()
script, a script, x, y, z = 42 ()
@obsolete, script, obsolete script ()
