start: program

program: top_stmt*

top_stmt: non_block
        | block

non_block: stmt*
block: "{" stmt* "}"

stmt: buttom_stmt ";"
    | decoreted_stmt
    | func_def
    | ctrl_flow
    | module_stmt

buttom_stmt: expression
           | cli_stmt
           | vars_stmt

cli_stmt: write_stmt
        | read_stmt

write_stmt: "tuliskan" expression
read_stmt: "bacalah" VAR_NAME

vars_stmt: alias_decl
         | final_decl
         | var_decl
         | def_decl
         | redecl
         | setobj

redecl: ID "=" expression
alias_decl: "alias" "[" ID "]" "sebagai" ID
final_decl: "final" "[" type_ann "]" ID "=" expression
def_decl: "def" "[" type_ann "]" ID
var_decl: "var" "[" type_ann "]" ID "=" expression
setobj: ID getobj+ "=" expression

decoreted_stmt: "#" "[" ID postfix* "]" ";" /\n/ func_def
func_def: "fungsi" "[" type_ann "]" ID params block_func
block_func: "{" stmt* "}"

ctrl_flow: if_ctrl
         | while_ctrl
         | for_ctrl
         | try_ctrl
         | switch_ctrl

if_ctrl: if_stmt elif_stmt* else_stmt?
if_stmt: "jika" "(" expression ")" "maka" block
elif_stmt: "namun" "jika" "(" expression ")" "maka" block
else_stmt: "namun" "tidak" block

while_ctrl: while_stmt
while_stmt: "selama" "(" expression ")" "lakukan" block

for_ctrl: for_stmt
for_stmt: "untuk" "(" for_expr ")" "lakukan" block
for_expr: def_decl "didalam" expression

try_ctrl: try_stmt catch_stmt finnaly_stmt?
try_stmt: "coba" block
catch_stmt: "tangkap" "(" ID ")" block
finnaly_stmt: "akhiri" block

switch_ctrl: switch_stmt
switch_stmt: "pilah" "(" expression ")" block_switch
block_switch: "{" body_switch "}"
body_switch: case_stmt+ default_stmt?
case_stmt: "kalau" case_expr ":" body_case
default_stmt: "kalau" "tidak" ":" body_case
case_expr: expression ("," expression)* 
body_case: stmt+

module_stmt: export_stmt
           | import_stmt

export_stmt: "ekspor" "{" exp_params "}"
exp_params: exp_arg ("," exp_arg)*
exp_arg: VAR_NAME ("sebagai" ID)?

import_stmt: "impor" "{" imp_params? "}" "dari" path_stmt
imp_params: imp_arg ("," imp_arg)*
imp_arg: ID ("sebagai" ID)?

path_stmt: path_params
path_params: path_args (":" path_args)*
path_args: parent_path | path_arg
path_arg: ID ("." ID)*
parent_path: once_dot | two_dot
once_dot: "."
two_dot: ".."

expression: equal

equal: not_equal ("==" not_equal)*
not_equal: great_equal ("!=" great_equal)*

great_equal: great_than (">=" great_than)*
great_than: less_equal (">" less_equal)*
less_equal: less_than ("<=" less_than)*
less_than: not_bool ("<" not_bool)*

not_bool: /tidak/ or_bool
        | or_bool
or_bool: and_bool ("atau" and_bool)*
and_bool: in_bool ("dan" in_bool)*

in_bool: not_in ("dalam" not_in)?
not_in: add ("tidak" "didalam" add)?

add: minus ("+" minus)*
minus: multi ("-" multi)*
multi: divide ("*" divide)*
divide: modular ("/" modular)*
modular: pow ("%" pow)*
pow: term ("**" term)*

term: prefix postfix*
    | lambda_func
    | return_stmt
    | throw_stmt
    | continue_stmt
    | break_stmt
    | type_of
    | pointer
    | unpointer
    | crement

prefix: "(" expression ")"
      | expression
      | literal
      | is_stmt
      | VAR_NAME

postfix: getobj
       | call_params

lambda_func: "lambda" params "{" expression "}"
return_stmt: "kembalikan" "{" expression "}"
throw_stmt: "kegalatan" "<" ID ">" "{" expression "}"
continue_stmt: "lanjutkan!"
break_stmt: "berhentikan!"
type_of: "tipe" "dari" VAR_NAME
pointer: "&" ID
unpointer: "*" ID

is_stmt: is_bool
       | is_not_bool

is_bool: ID "adalah" ID
is_not_bool: ID "bukanlah" ID

getobj: getattr | getindex
getattr: "." ID
getindex: "[" expression+ "]"

crement: (increment | decrement) VAR_NAME
increment: "++"
decrement: "--"

call_params: "(" call_args? ")"
call_args: call_arg ("," call_arg)*
call_arg: (ID "=")? expression

type_ann: basic_type
        | object_type

basic_type: /teks|angka|desimal|boolean|kekosongan|apapun/
object_type: dict_type
           | array_type
           | func_type
           | union_type
           | literal_type
           | optional_type

dict_type: "kamus" "<" integer ">" "{" type_ann ":" type_ann "}"
array_type: "daftar" "<" integer ">" "[" type_ann "]"
func_type: "fungsi" "[" "{" (type_ann ("," type_ann)* )? "}" "," type_ann "]"
union_type: "[" type_ann ("," type_ann)* "]"
literal_type: "[" literal ("," literal)* "]"
optional_type: "?" type_ann


literal: basic_literal
       | object_literal

basic_literal: string
             | integer
             | float
             | boolean

object_literal: array
              | dictinary

array: "[" ( array_body ("," array_body)* )? "]"
array_body: expression | unpack

dictinary: dict_body
dict_body: "{" ( dict_bodies ("," dict_bodies)* )? "}"
dict_bodies: VAR_NAME | dict_items | unpack
dict_items: key_params ":" value_params
key_params: basic_literal
          | "[" VAR_NAME "]"
          | ID

value_params: expression

unpack: "..." (literal | VAR_NAME)

%import common.SIGNED_INT
%import common.DECIMAL
%import common.ESCAPED_STRING

string: ESCAPED_STRING
integer: SIGNED_INT
float: DECIMAL

boolean: /benar|salah/

VAR_NAME: ID+
ID: /[a-zA-Z_][a-zA-Z0-9_]*/


params: "(" param? ")"
param: args ( "," args)*
args: type_ann ID ("=" expression)?

%import common.CPP_COMMENT
%import common.C_COMMENT
%import common.WS

%ignore CPP_COMMENT
%ignore C_COMMENT
%ignore WS

