from .t import T as Template

class T(Template):
    def __init__(self): super().__init__("Lua")

    def _NUMBER(s):                                                                 return str(s.n[1])
    def _STRING(s):                                                                 return f"\"{s.n[1]}\""
    def _RSTRING(s):                                                                return f"[[{s.n[1]}]]"
    def _TRUE(s):                                                                   return "true"
    def _FALSE(s):                                                                  return "false"
    def _NONE(s):                                                                   return "nil"
    def _COMMENT(s):                                                                return f"-- {s.n[1]}"
    def _ellipsis(s):                                                               return f"..."
    def _output(s):                                                                 return f"print({s.wt(s.n[1])})"
    def _break(s):                                                                  return f"break"
    def _local_set(s):                      s.dollar = s.jwt(s.n[1], ", ");         return f"local {s.dollar} = {s.jwt(s.n[2], ", ")}"
    def _assert(s):                                                                 return f"assert({s.wt(s.n[1])})"
    def _raise(s):                                                                  return f"error({s.wt(s.n[1])})"
    def _func(s):                                                                   return f"{s.wt(s.n[1])}({s.jwt(s.n[2], ", ")})"
    def _func_self(s):                                                              return f"{s.wt(s.n[1])}:{s.wt(s.n[2])}({s.jwt(s.n[3], ", ")})"
    def _tuple(s):                                                                  return "{"+f"{s.jwt(s.n[1], ", ")}{"," if len(s.n[1]) == 1 else ""}"+"}"
    def _list(s):                                                                   return s._tuple()
    def _dict(s):                                                                   return "{"+(", ".join(f"{s.wt(k)}={s.wt(v)}" for k, v in s.n[1]))+"}"
    def _arg(s):                                                                    return f"*{s.n[1]}"
    def _default_arg(s):                                                            return f"{s.n[1]} = {s.wt(s.n[2])}"
    def _set(s):                            s.dollar = s.jwt(s.n[1], ", ");         return f"{s.dollar} = {s.jwt(s.n[2], ", ")}"
    def _set_add(s):                        s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} + {s.wt(s.n[2])}"
    def _set_subtract(s):                   s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} - {s.wt(s.n[2])}"
    def _set_multiply(s):                   s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} * {s.wt(s.n[2])}"
    def _set_divide(s):                     s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} / {s.wt(s.n[2])}"
    def _set_dot(s):                        s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar}.{s.wt(s.n[2])}"
    def _set_power(s):                      s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = math.pow({s.dollar}, {s.wt(s.n[2])})"
    def _set_floor_divide(s):               s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = math.floor({s.dollar} / {s.wt(s.n[2])})"
    def _set_modulo(s):                     s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} % {s.wt(s.n[2])}"
    def _set_strjoin(s):                    s.dollar = s.wt(s.n[1]);                return f"{s.dollar} = {s.dollar} .. {s.wt(s.n[2])}"
    def _add(s):                                                                    return f"{s.wt(s.n[1])} + {s.wt(s.n[2])}"
    def _subtract(s):                                                               return f"{s.wt(s.n[1])} - {s.wt(s.n[2])}"
    def _multiply(s):                                                               return f"{s.wt(s.n[1])} * {s.wt(s.n[2])}"
    def _divide(s):                                                                 return f"{s.wt(s.n[1])} / {s.wt(s.n[2])}"
    def _unary_minus(s):                                                            return f"-{s.wt(s.n[1])}"
    def _power(s):                                                                  return f"math.pow({s.wt(s.n[1])}, {s.wt(s.n[2])})"
    def _floor_divide(s):                                                           return f"math.floor({s.wt(s.n[1])} / {s.wt(s.n[2])})"
    def _modulo(s):                                                                 return f"{s.wt(s.n[1])} % {s.wt(s.n[2])}"
    def _strjoin(s):                                                                return f"{s.wt(s.n[1])} .. {s.wt(s.n[2])}"
    def _cmp_e(s):                                                                  return f"{s.wt(s.n[1])} == {s.wt(s.n[2])}"
    def _cmp_g(s):                                                                  return f"{s.wt(s.n[1])} > {s.wt(s.n[2])}"
    def _cmp_l(s):                                                                  return f"{s.wt(s.n[1])} < {s.wt(s.n[2])}"
    def _cmp_le(s):                                                                 return f"{s.wt(s.n[1])} <= {s.wt(s.n[2])}"
    def _cmp_ge(s):                                                                 return f"{s.wt(s.n[1])} >= {s.wt(s.n[2])}"
    def _cmp_ne(s):                                                                 return f"{s.wt(s.n[1])} ~= {s.wt(s.n[2])}"
    def _between(s):                                                                return f"({s.wt(s.n[1])} >= {s.wt(s.n[2])} and {s.wt(s.n[1])} <= {s.wt(s.n[3])})"
    def _index(s):                                                                  return f"{s.wt(s.n[1])}[{s.wt(s.n[2])}]"
    def _index_from(s):                                                             return f"string.sub({s.wt(s.n[1])}, {s.wt(s.n[2])})"
    def _index_to(s):                                                               return f"string.sub({s.wt(s.n[1])}, 1, {s.wt(s.n[2])})"
    def _index_from_to(s):                                                          return f"string.sub({s.wt(s.n[1])}, {s.wt(s.n[2])}, {s.wt(s.n[3])})"
    def _list_remove(s):                                                            return f"{s.wt(s.n[2])} = table.remove({s.wt(s.n[1])})"
    def _list_append(s):                                                            return f"table.insert({s.wt(s.n[1])}, {s.wt(s.n[2])})"
    def _member(s):                                                                 return f"{s.wt(s.n[1])}.{s.wt(s.n[2])}"
    def _string_upper(s):                                                           return f"string.upper({s.wt(s.n[1])})"
    def _string_lower(s):                                                           return f"string.lower({s.wt(s.n[1])})"
    def _length(s):                                                                 return f"#{s.wt(s.n[1])}"
    def _get_type(s):                                                               return f"type({s.wt(s.n[1])})"
    def _use(s):                                                                    return f"local {s.wt(s.n[1])} = require(\"{s.wt(s.n[1])}\")"
    def _use_as(s):                                                                 return f"local {s.wt(s.n[2])} = require(\"{s.wt(s.n[1])}\")"
    def _use_from(s):                                                               return f"local {s.wt(s.n[1])} = require(\"{s.wt(s.n[2])}\").{s.wt(s.n[1])}"
    def _use_as_from(s):                                                            return f"local {s.wt(s.n[2])} = require(\"{s.wt(s.n[3])}\").{s.wt(s.n[1])}"
    def _while(s):                          s.indent += 4;                          return f"while {s.wt(s.n[1])} do{s.body(s.wt(s.n[2]))}\n{" "*(s.indent-4)}end"
    def _for(s):                            s.indent += 4;                          return f"for {s.jwt(s.n[1], ", ")} in {s.wt(s.n[2])} do{s.body(s.wt(s.n[3]))}\n{" "*(s.indent-4)}end"
    def _for_to(s):                         s.indent += 4;                          return f"for {s.wt(s.n[1])} = 1, {s.wt(s.n[2])} do{s.body(s.wt(s.n[3]))}\n{" "*(s.indent-4)}end"
    def _for_from_to(s):                    s.indent += 4;                          return f"for {s.wt(s.n[1])} = {s.wt(s.n[2])}, {s.wt(s.n[3])} do{s.body(s.wt(s.n[4]))}\n{" "*(s.indent-4)}end"
    def _times(s):                          s.indent += 4;                          return f"for _ = 1, {s.wt(s.n[1])} do\n{" " * s.indent}_ = nil{s.body(s.wt(s.n[2]))}\n{" "*(s.indent-4)}end"
    def _if(s):                             s.indent += 4;                          return f"if {s.wt(s.n[1])} then{s.body(s.wt(s.n[2]))}\n{" "*(s.indent-4)}end"
    def _if_else(s):                        s.indent += 4;                          return f"if {s.wt(s.n[1])} then{s.body(s.wt(s.n[2]))}\n{" "*(s.indent-4)}else{s.body(s.wt(s.n[3]))}\n{" "*(s.indent-4)}end"
    def _if_elif(s):                        s.indent += 4;                          return f"if {s.wt(s.n[1])} then{s.body(s.wt(s.n[2]))}{s.body(list((" "*(s.indent-4))+f"elseif {s.wt(cond)} then{s.body(s.wt(prog))}" for cond, prog in s.n[3]))}\n{" "*(s.indent-4)}end"
    def _if_elif_else(s):                   s.indent += 4;                          return f"if {s.wt(s.n[1])} then{s.body(s.wt(s.n[2]))}{s.body(list((" "*(s.indent-4))+f"elseif {s.wt(cond)} then{s.body(s.wt(prog))}" for cond, prog in s.n[3]))}\n{" "*(s.indent-4)}else{s.body(s.wt(s.n[4]))}\n{" "*(s.indent-4)}end"
    def _func_def_untyped(s):               s.indent += 4;                          return f"function {s.wt(s.n[1])}({s.jwt(s.n[2], ", ")}){s.body(s.wt(s.n[3]))}\n{" "*(s.indent-4)}end"
    def _func_def_local_untyped(s):                                                 return f"local {s._func_def_untyped()}"
    def _func_def_anon_untyped(s):          s.indent += 4;                          return f"function({s.jwt(s.n[1], ", ")}){s.body(s.wt(s.n[2]))}\n{" "*(s.indent-4)}end"
    def _return(s):                                                                 return f"return {s.wt(s.n[1])}"
    def _del(s):                                                                    return f"{s.wt(s.n[1])} = nil"
    def _and(s):                                                                    return f"{s.wt(s.n[1])} and {s.wt(s.n[2])}"
    def _or(s):                                                                     return f"{s.wt(s.n[1])} or {s.wt(s.n[2])}"
    def _not(s):                                                                    return f"not {s.wt(s.n[1])}"
    def _lambda(s):                                                                 return f"function({s.jwt(s.n[2], ", ")}) return {s.wt(s.n[1])} end"