// This grammar serves a documentation for the LL(N) parser 
// implemented a recursive descent parser
// Grammar can not be LL(1). Needs more than the next tokens at several places
// Example: let name = $some_var vs 
// let name = $join(@some_array)
// In the same context the string sigil can signal a reference to variable or the call of a method !
// N has to be determined yet.

// Grammar rules derived from the code snippets of the ion online manual.
// Link: https://doc.redox-os.org/ion-manual/introduction.html

// Words beginning with an underscore are non-terminal. Non-terminal are tokens provided by
// the scanner phase

// _Anything is every possible non-terminal
// Rules ending with an equal sign, are elements of the syntax tree. 

// This grammar is not designed to be unambiguous so far.
// !! is checkpoint marker at which the parser can continue after encountering a parser error.

Program -> Statement* ~ EOI


Statement -> HorizontalNoise* 
             ~ ( ( NoCommend ~ Commend? ) | Commend ) 
              

NoCommend -> ( 
                IfBlock 
                | WhileBlock 
                | ForBlock
                | MatchBlock
                | VariableDeclaration 
                | ExportDeclaration 
                | CommandChain 
             ) ~ HorizontalNoise* ~ EndOfStatement ~ !!

EndOfStatement ->  _Semicolon | NewLine | EOI

// Note:
// ( LogicalChainOperator ~ noise*  ~ PipedCommands )*
//                            ^
// `noise*` in the            |
// Supports syntax lie: 
// test $bar = "bar" &&
// echo "foobar was found"
CommandChain -> PipedCommands ~ ( LogicalChainOperator ~ noise*  ~ PipedCommands )* ~ DetachOperator?
PipedCommands -> CommandExpression ~ ( PipeOperator ~ CommandExpression )*
CommandExpression -> Command ~ ( HorizontalNoise* ~ CommandValue )* ~ RedirectToFile*
CommandValue = !PipeOperator ~ Value

LogicalChainOperator -> ( LogicalAnd | LogicalOr )
LogicalAnd -> _AndOperator
LogicalOr -> _OrOperator
PipeOperator -> ( PipeStdOut | PipeStdErr | PipeBoth ) 
RedirectOperator -> ( RedirectInput | RedirectOutOperator ) 
RedirectOutOperator > ( RedirectStdout | RedirectStderr | RedirectBoth ) ~ AppendRedirect?
RedirectToFile -> RedirectOperator ~ File
File -> _Word


HorizontalNoise -> _WhiteSpace | _Tab
Noise -> HorizontalNoise | _NewLine
AppendRedirect -> _ToStdOut
RedirectStdout -> _ToStdOut
RedirectStderr -> _ToStdErr
RedirectBoth -> _ToStdBoth
RedirectInput -> _FileInputOpreator
PipeStdOut -> _PipeStdOut
PipeStdErr -> _PipeStdErr
PipeBoth -> _PipeBoth
DetachOperator -> ( DetachProcessOperator | DisownOperator )
DetachProcessOperator -> _Ampersand 
DisownOperator -> _Disown 
VariableDeclaration -> _Let ~ VariableStatement 
ExportDeclaration -> _Export ~ VariableName

DocString -> _StartDocString ~ ContentOfCommend
Commend -> _Hash ~ ContentOfCommend
ContentOfCommend -> ( !_NewLine ~ _Anything ) 

// _Word can be an executable
Command -> !(IllegalStartForCommand) ~ Value
IllegalStartForCommand -> ( LogicalChainOperator | PipeOperator | RedirectOperator )

// _Word+ for Multiple Assignments
VariableStatement -> VariableName ~ Assignment ~ RightHandExpression

VariableName -> *HorizontalNoise ~ _Word ~ (_Colon ~ _TypeIdent)?
Variable -> _Word


ArrayVariableResolving -> _ArraySigil ~ VariableReference 
StringVariableResolving -> _StringSigil ~ VariableReference
VariableReference -> Variable ~ ( IndexAccess | KeyAccess )?

// JustVariableName does not allow index access within a index access.
// Correct Example: $var[$another] 
// Wrong Example: $var[$another[2]] 
KeyAccess -> _OpenBracets ~ ( _Word | JustVariableName ) ~ _ClosedBracket
JustVariableName -> _StringSigil ~ Variable

IndexAccess= -> _OpenBrackets ~ SliceAccess ~ _ClosedBracket

SliceAccess= -> _Int | ( SliceOperator ~ _Equal? ~ _Int )

// Example:  "7.." in "$foo[7..]" 
SliceOperator= -> _DoublePoint | _TriplePoint 

Str -> ( _Quotation ~ ( !_SingleQuotation ~ _Anything )* ~ _Quotation ) 
       | ( _SingleQuotation ~ ( !_Quotation ~ _Anything )* ~ _SingleQuotation )


Assignment -> _AddAssignment | _MinusAssignment | _PowerAssignment 
                | _MultAssignment | _InterDivAssignment | _DivAssignment 
                | _ConcatAssignment | _Compare | _Equal 

BinaryOperators -> _Add | _Subtract | _Power | _Multiply

ArrayExpression -> _OpenBrackets 
                   ~ ( 
                       FirstArrayValue
                       ~ NextArrayValue* 
                       ~ noise* 
                   )? 
                   ~ _ClosedBracket
FirstArrayValue -> noise* ~ Value
NextArrayValue -> noise+ ~ Value

Value -> Str 
        | ProcessExpansion
        | StringVariableResolving 
        | ArrayVariableResolving 
        | ArrayExpression
        | FnMethodCall 
        | Number 
        | BraceExpansion
        | ArithmeticExpansion
        | WordStartingWithOp
        | Word 
        | WordStartingWithNumber

Word = Number? ~ _Word
// Ion shell allows operators at the start of a word like "--p"
// It also allows operators on their own like "++"
WordStartingWithOp -> ( BinaryOperators | PipeOperator )+ ~ ( Number | _Word )?

// ( Value | BinaryOperators )* : for multiple values of multiple assignments
RightHandExpression -> HorizontalNoise* ~ Value
Number -> _Int | _Float


Sigil -> _StringSigil | _ArraySigil
FnMethodCall -> Sigil ~ _Word ~ OpenParanteseCurlyBracket ~ Value* ~ ClosedParanteseCurlyBracket

ProcessExpansion -> StringProcessExpansion | ArrayProcessExpansion  
StringProcessExpansion -> _StringSigil ~ ProcessExpansionExpression
ArrayProcessExpansion -> _ArraySigil ~ ProcessExpansionExpression
ProcessExpansionExpression -> OpenParanteseCurlyBracket ~ CommandExpression ~ CloseParanteseCurlyBracket


BraceExpansionComponent -> ( BraceExpansion | _Word )
CommaSeparatedWords -> _Word ~ CommaWordComponent* 
CommaWordComponent -> _Comma ~ BraceExpansionComponent 
BraceExpansion -> _OpenCurlyBracket ~ ( SliceAccess | CommaSeparatedWords ) ~ _ClosedCurlyBracket


BlockStatement -> !_End ~ Statement

IfBlock -> IfClause 
           ~ ( !ElseIfClause ~ !_Else ~ BlockStatement)* 
           ~ ElseIfBlock* 
           ~ ElseBlock? 
           ~ _End
           
ElseBlock -> _Else ~ BlockStatement*
ElseIfBlock -> ElseIfClause ~ BlockStatement*

IfClause -> _If ~ Condition 
ElseIfClause -> _ElseIf ~ Condition

WhileClause -> _While ~ CommandChain
WhileBlock -> WhileClause ~ BlockStatement* ~ _End

ForBlock -> _For ~ Variable ~ _In ~ Value ~ BlockStatement* ~ _End
MatchBlock -> _Match ~ Value ~ CaseBlock+ ~ _End
CaseBlock -> CaseCondition ~ (!_Case ~ Statement)*
CaseCondition -> _Case ~ Value ~ IfGuard? ~ EndOfStatement
IfGuard -> If ~ CommandChain

FnBlock ->  _Fn ~ _Word ~ ( _WhiteSpace+ ~ Argument )* ~ Statement* ~ _End
TypeAnnotation -> _Word ~ ( _Colon ~ CertainType )?

CertainType -> ScalarType | ArrayType
ScalarType -> _TypeIdent
ArrayType -> _OpenSquareBracket ~ ScalarType ~ _CloseSquareBracket
ArithmeticExpansion -> _StringSigil 
                      ~ _OpenParanteseCurlyBracket ~ _OpenParanteseCurlyBracket 
                      ~ MathExpression*
                      ~ _ClosedParanteseCurlyBracket ~ _ClosedParanteseCurlyBracket

MathExpression= -> ( NestedMathExpression | MathCalc )
MathValue -> MathValue
NestedMathExpression= -> _OpenParanteseCurlyBracket 
                         ~ HorizontalNoise* 
                         ~ MathEpression 
                         ~ HorizontalNoise* 
                         ~ _ClosedParanteseCurlyBracket

MathCalc -> MathValue ~ ( MathOperator ~ MathValue )?
MathOperator -> HorizontalNoise+ ~ _Operator ~ HorizontalNoise+
MathValue= -> _Int | _Float | _Word

