program = importDeclaration* , (typeDefinition | functionDeclaration)* , mainFunction;

importDeclaration = "import" , identifier , ";";

typeDefinition = "type" , identifier , gomType , ";";

functionDeclaration = "fn" , identifier , "(" , argumentItem* , ")" , functionReturnType? ,
	"{" , statement+ , "}";

mainFunction = "fn" , "main" , "(" , argumentItem* , ")" , functionReturnType? , 
	"{" , statement+ , "}";

statement = ifStatement
	| forStatement
	| returnStatement
	| letStatement
	| expressionStatement;
	
forStatement = "for" , "(" , expr , ";" , expr , ";" , ")" , "{" , statement* , "}";

returnStatement = "return" , expr , ";";

letStatement = "let" , identifier , "=" , expr , ";";

expressionStatement = expr , ";";

gomType = primitiveType | compositeType , primitiveType?;

argumentItem = identifier , ":" , gomType , ","?;

functionReturnType = ":" , gomType;

expr = access
	| call
	| "(" , expr , ")"
	| comparison;
	
access = identifier , ("." , (identifier | call))+;

call = identifier , "(" , term* , ")";
	
comparison = sum , "<" , sum
	| sum , ">" , sum
	| sum , "<=" , sum
	| sum , ">=" , sum
	| sum , "==" , sum
	| sum;
	
sum = quot , "+" , quot
	| quot , "-" , quot
	| quot;
	
quot = expo , "/" , expo
	| expo , "*" , expo
	| term;
	
term = identifier | numLiteral | stringLiteral;

identifier = letter , (letter | digit)*;

numLiteral = digit+;

stringLiteral = '"' , (letter | digit)* , '"';

primitiveType = "i8" | "i16" | "f16" | "str";

compositeType = identifier;

letter = "A" | "B" | "C" | "D" | "E" | "F" | "G"
       | "H" | "I" | "J" | "K" | "L" | "M" | "N"
       | "O" | "P" | "Q" | "R" | "S" | "T" | "U"
       | "V" | "W" | "X" | "Y" | "Z" | "a" | "b"
       | "c" | "d" | "e" | "f" | "g" | "h" | "i"
       | "j" | "k" | "l" | "m" | "n" | "o" | "p"
       | "q" | "r" | "s" | "t" | "u" | "v" | "w"
       | "x" | "y" | "z" ;

digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

S = (#x20 | #x9 | #xD | #xA)+