grammar Piggly
rule start tSpace? block ';'? tSpace? end rule block label_open:tLabelDefinition tSpace blockDeclarations:stmtDeclare* kwBEGIN bodySpace:tSpace bodyStub:stubNode body:statement* blockExceptions? kwEND ( tSpace label_close:tLabel )? tSpace? <Piggly::Parser::Nodes::Block> / blockDeclarations:stmtDeclare* kwBEGIN bodySpace:tSpace bodyStub:stubNode body:statement* blockExceptions? kwEND tSpace? <Piggly::Parser::Nodes::Block> end rule statement inner:( block ';' / stmtAssignment / stmtIf / stmtCase / stmtLoop / stmtWhileLoop / stmtForLoop / stmtForEachLoop / stmtExit / stmtContinue / stmtReturn / stmtRaise / stmtExecSql / stmtNull / stmtGetDiag ) tail:tSpace? <Piggly::Parser::Nodes::Statement> end rule stmtAssignment lval:lValue tSpace? kwASSIGN ws? rval:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Assignment> end rule stmtCase kwCASE tSpace cases:condWhen+ else:stmtElse? kwEND tSpace kwCASE tSpace? ';' <Piggly::Parser::Nodes::Cond> / kwCASE tSpace expr:expressionUntilWhen cases:caseWhen+ else:stmtElse? kwEND tSpace kwCASE tSpace? ';' <Piggly::Parser::Nodes::Case> end rule stmtIf kwIF condSpace:tSpace? condStub:stubNode cond:expressionUntilThen kwTHEN bodySpace:tSpace bodyStub:stubNode body:statement* else:stmtElse? kwEND tSpace kwIF tSpace? ';' <Piggly::Parser::Nodes::If> end rule stmtElse kwELSIF condSpace:tSpace? condStub:stubNode cond:expressionUntilThen kwTHEN bodySpace:tSpace bodyStub:stubNode body:statement* else:stmtElse? <Piggly::Parser::Nodes::If> / kwELSE bodySpace:tSpace bodyStub:stubNode body:statement* <Piggly::Parser::Nodes::Else> end rule stmtLoop label_open:tLabelDefinition tSpace cond:kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )? tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::Loop> / cond:kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::Loop> end rule stmtWhileLoop label_open:tLabelDefinition tSpace kwWHILE condSpace:tSpace? condStub:stubNode cond:expressionUntilLoop kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* kwEND tSpace kwLOOP ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )? tSpace? ';' <Piggly::Parser::Nodes::WhileLoop> / kwWHILE condSpace:tSpace? condStub:stubNode cond:expressionUntilLoop kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* kwEND tSpace kwLOOP tSpace? ';' <Piggly::Parser::Nodes::WhileLoop> end rule stmtForEachLoop label_open:tLabelDefinition tSpace kwFOREACH tSpace tIdentifier tSpace kwIN tSpace kwARRAY condSpace:tSpace cond:expressionUntilLoop kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )? tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForEachLoop> / kwFOREACH tSpace tIdentifier tSpace kwIN tSpace kwARRAY condSpace:tSpace cond:expressionUntilLoop kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForEachLoop> end rule stmtForLoop label_open:tLabelDefinition tSpace kwFOR tSpace identifierList tSpace kwIN condSpace:tSpace cond:( stmtForSql / expressionUntilLoop ) kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP ( tSpace label_close:tLabel <Piggly::Parser::Nodes::TLabel> )? tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForLoop> / kwFOR tSpace identifierList tSpace kwIN condSpace:tSpace cond:( stmtForSql / expressionUntilLoop ) kwLOOP bodySpace:tSpace bodyStub:stubNode body:statement* doneStub:stubNode kwEND tSpace kwLOOP tSpace? ';' exitStub:stubNode <Piggly::Parser::Nodes::ForLoop> end rule stmtForSql sqlKeyword tSpace expressionUntilLoop <Piggly::Parser::Nodes::Sql> end rule stmtExit bodyStub:stubNode body:( kwEXIT (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? ) tSpace? ';' <Piggly::Parser::Nodes::Exit> / body:( kwEXIT (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? ) tSpace kwWHEN condSpace:tSpace condStub:stubNode cond:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::ExitWhen> end rule stmtContinue bodyStub:stubNode body:( kwCONTINUE (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? ) tSpace? ';' <Piggly::Parser::Nodes::Continue> / body:( kwCONTINUE (tSpace label:tLabel <Piggly::Parser::Nodes::TLabel> )? ) tSpace kwWHEN condSpace:tSpace condStub:stubNode cond:expressionUntilSemiColon ';' <Piggly::Parser::Nodes::ContinueWhen> end rule stmtReturn bodyStub:stubNode body:(kwRETURN ( tSpace? &';' / tSpace kwNEXT tSpace expressionUntilSemiColon tSpace? / tSpace kwQUERY tSpace expressionUntilSemiColon / expressionUntilSemiColon )) ';' <Piggly::Parser::Nodes::Return> end rule stmtRaise kwRAISE tSpace level:( kwWARNING / kwNOTICE / kwINFO / kwLOG / kwDEBUG ) ( tSpace expr:expressionUntilSemiColon )? ';' <Piggly::Parser::Nodes::Raise> / bodyStub:stubNode body:(kwRAISE ( tSpace level:kwEXCEPTION tSpace? )? expr:expressionUntilSemiColon) ';' <Piggly::Parser::Nodes::Throw> end rule stmtExecSql sqlKeyword tSpace expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Sql> end rule stmtGetDiag kwGET tSpace ( kwSTACKED tSpace )? kwDIAGNOSTICS tSpace expressionUntilSemiColon ';' <Piggly::Parser::Nodes::Expression> end rule stmtNull kwNULL tSpace? ';' end ############################################################################# rule stmtDeclare kwDECLARE tSpace varDeclaration* end rule varDeclaration name:tIdentifier tSpace ( kwCONSTANT tSpace )? type:tType ( tSpace kwNOT tSpace kwNULL )? ( tSpace? kwASSIGN tSpace? rval:expressionUntilSemiColon )? tSpace? ';' tSpace? end rule identifierList tIdentifier ( tSpace? ',' tSpace? tIdentifier )* end rule blockExceptions kwEXCEPTION tSpace cases:exceptionCase* end rule exceptionCase # cannot provide branch-coverage on cond kwWHEN condSpace:tSpace cond:expressionUntilThen kwTHEN bodySpace:tSpace bodyStub:stubNode body:statement* <Piggly::Parser::Nodes::Catch> end rule caseWhen # cannot provide branch-coverage on cond kwWHEN condSpace:tSpace cond:expressionUntilThen kwTHEN bodySpace:tSpace bodyStub:stubNode body:statement* <Piggly::Parser::Nodes::CaseWhen> end rule condWhen kwWHEN condSpace:tSpace condStub:stubNode cond:expressionUntilThen kwTHEN bodySpace:tSpace bodyStub:stubNode body:statement* <Piggly::Parser::Nodes::CondWhen> end ## EXPRESSIONS ############################################################################# rule expressionUntilSemiColon head:tSpace? expr:( tString / skipWords / tSpace !';' / !tSpace [^;] )* tail:tSpace? &';' <Piggly::Parser::Nodes::Expression> end rule expressionUntilClosingBracket head:tSpace? expr:( tString / skipWords / tSpace !']' / !tSpace [^\]] )+ tail:tSpace? &']' <Piggly::Parser::Nodes::Expression> end rule expressionUntilThen head:tSpace? expr:( tString / skipWords / tSpace !kwTHEN / !tSpace !kwTHEN . )+ tail:tSpace &kwTHEN <Piggly::Parser::Nodes::Expression> end rule expressionUntilWhen head:tSpace? expr:( tString / skipWords / tSpace !kwWHEN / !tSpace !kwWHEN . )+ tail:tSpace &kwWHEN <Piggly::Parser::Nodes::Expression> end rule expressionUntilLoop head:tSpace? expr:( tString / skipWords / tSpace !kwLOOP / !tSpace !kwLOOP . )+ tail:tSpace &kwLOOP <Piggly::Parser::Nodes::Expression> end rule skipWords [a-z0-9_]+ <Piggly::Parser::Nodes::TextNode> end ############################################################################# rule ws [ \t\n\v\f\r]+ <Piggly::Parser::Nodes::TextNode> end rule dollarQuoteMarker '$' tag:( [a-z\200-\377_] [a-z\200-\377_0-9]* )? '$' <Piggly::Parser::Nodes::TDollarQuoteMarker> end rule stubNode '' <Piggly::Parser::Nodes::StubNode> end rule notImplemented '' <Piggly::Parser::Nodes::NotImplemented> end rule lValue tIdentifier ( '[' expressionUntilClosingBracket ']' )* ( [.] lValue )* <Piggly::Parser::Nodes::Assignable> end ## BASIC TOKENS ############################################################################# rule tEOF !. end rule tLabelDefinition '<<' tSpace? tLabel tSpace? '>>' <Piggly::Parser::Nodes::TLabel> end rule tLabel tIdentifier end rule tIdentifier ( '"' [^"]+ '"' )+ <Piggly::Parser::Nodes::TIdentifier> / !keyword ( [a-z\200-\377_] [a-z\200-\377_0-9$]* ) <Piggly::Parser::Nodes::TIdentifier> end # not context sensitive so opening and closing tag might not match rule tString openTag:dollarQuoteMarker content:(!dollarQuoteMarker .)* closeTag:dollarQuoteMarker <Piggly::Parser::Nodes::TString> / "E'" content:("''" / [^'])* "'" <Piggly::Parser::Nodes::TString> / "'" content:("''" / [^'])* "'" <Piggly::Parser::Nodes::TString> end # beware this is quite broad and might match things it shouldn't rule tType [a-z\200-\377_] ( '(' rType ')' / '[' rType ']' / [a-z\200-\377_0-9$%]+ '.'? / ws !( kwAS / kwNOT / kwASSIGN / kwDEFAULT ) )* <Piggly::Parser::Nodes::TDatatype> end rule rType ( '(' rType ')' / '[' rType ']' / [^\(\)\[\]]+ )* end rule tSpace ws !tComment <Piggly::Parser::Nodes::TextNode> / ( ws / tComment )+ end rule tComment '/*' content:(!'*/' .)* '*/' <Piggly::Parser::Nodes::TComment> / '--' content:[^\n]* ("\n" / tEOF) <Piggly::Parser::Nodes::TComment> end ## ############################################################################# rule tBinary "b'" [01]+ "'" end rule tHex "x'" [0123456789abcdef]+ "'" end rule tNumber tBinary / tHex / sign:[+-]? '.' [0-9]+ exponent:('e' [+-]? [0-9]+)? / sign:[+-]? [0-9]+ '.' [0-9]* exponent:('e' [+-]? [0-9]+)? / sign:[+-]? [0-9]+ '.'? exponent:('e' [+-]? [0-9]+)? end rule tLiteral tString (tSpace? '::' tSpace? tType) / tString / tNumber (tSpace? '::' tSpace? tType) / tNumber / 'cast' tSpace? '(' tSpace? tString tSpace kwAS tSpace tType tSpace? ')' / 'cast' tSpace? '(' tSpace? tNumber tSpace kwAS tSpace tType tSpace? ')' end ## KEYWORDS ############################################################################# rule sqlKeyword ( 'insert' / 'select' / 'update' / 'delete' / 'perform' / 'execute' / 'open' / 'close' / 'lock' / 'fetch' / 'move' / 'truncate' / 'create' / 'drop' / 'alter' / 'commit' / 'copy' / 'create' / 'set' / 'start' / 'notify' / 'with' ) ![a-z0-9] <Piggly::Parser::Nodes::TKeyword> end rule keyword # WHEN is checked first as a minor optimization to distinguish # CONTINUE tIdentifier WHEN cond; # EXIT tIdentifier WHEN cond; # # CONTINUE WHEN cond; # EXIT WHEN cond; kwWHEN / kwAS / kwASSIGN / kwALIAS / kwBEGIN / kwBY / kwCASE / kwARRAY / kwCONSTANT / kwCONTINUE / kwCURSOR / kwDEBUG / kwDECLARE / kwDEFAULT / kwDIAGNOSTICS / kwELSE / kwELSIF / kwEND / kwEXCEPTION / kwEXECUTE / kwEXIT / kwFOR / kwFROM / kwGET / kwIF / kwIN / kwINFO / kwINSERT / kwINTO / kwIS / kwLOG / kwLOOP / kwNOT / kwNOTICE / kwNULL / kwFOREACH / kwOR / kwRAISE / kwRENAME / kwRESULTOID / kwRETURN / kwREVERSE / kwROWCOUNT / kwSCROLL / kwSTRICT / kwTHEN / kwTO / kwTYPE / kwWARNING / kwWHILE end # this terminates keywords rule x [^a-z0-9_] end rule kwAS 'as' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwASSIGN ':=' <Piggly::Parser::Nodes::TKeyword> / '=' <Piggly::Parser::Nodes::TKeyword> end rule kwALIAS 'alias' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwARRAY 'array' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwBEGIN 'begin' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwBY 'by' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwCASE 'case' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwCONSTANT 'constant' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwCONTINUE 'continue' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwCURSOR 'cursor' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwDEBUG 'debug' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwDECLARE 'declare' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwDEFAULT 'default' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwDIAGNOSTICS 'diagnostics' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwELSE 'else' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwELSIF ('elsif'/'elseif') ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwEND 'end' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwEXCEPTION 'exception' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwEXECUTE 'execute' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwEXIT 'exit' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwFOR 'for' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwFOREACH 'foreach' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwFROM 'from' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwGET 'get' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwIF 'if' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwIN 'in' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwINFO 'info' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwINSERT 'insert' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwINTO 'into' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwIS 'is' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwLOG 'log' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwLOOP 'loop' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwNEXT 'next' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwNOT 'not' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwNOTICE 'notice' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwNULL 'null' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwOR 'or' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwPERFORM 'perform' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwQUERY 'query' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwRAISE 'raise' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwRENAME 'rename' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwRESULTOID 'result_oid' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwRETURN 'return' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwREVERSE 'reverse' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwROWCOUNT 'row_count' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwSCROLL 'scroll' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwSTACKED 'stacked' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwSTRICT 'strict' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwTHEN 'then' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwTO 'to' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwTYPE 'type' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwWARNING 'warning' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwWHEN 'when' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end rule kwWHILE 'while' ![a-z0-9_] <Piggly::Parser::Nodes::TKeyword> end
end