/*
 [The "BSD licence"]
 Copyright (c) 2005-2008 Terence Parr
 All rights reserved.

 Grammar conversion to ANTLR v3 and C#:
 Copyright (c) 2008 Sam Harwell, Pixel Mine, Inc.
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
 3. The name of the author may not be used to endorse or promote products
    derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

lexer grammar ActionTranslator;

options
{
	language=CSharp3;
	// try all non-fragment rules in order specified
	filter=true;
}

@lexer::namespace{Antlr3.Grammars}
@ctorModifier{private}

/**	$x.y	x is enclosing rule, y is a return value, parameter, or
 * 			predefined property.
 *
 * 			r[int i] returns [int j]
 * 				:	{$r.i, $r.j, $r.start, $r.stop, $r.st, $r.tree}
 * 				;
 */
SET_ENCLOSING_RULE_SCOPE_ATTR
	:	'$' x=ID '.' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';' {CanMatchSetEnclosingRuleScopeAttribute($x.text, $y.text)}?
		{HandleSetEnclosingRuleScopeAttribute($x.text, $y.text, $expr.text);}
	;

ENCLOSING_RULE_SCOPE_ATTR
	:	'$' x=ID '.' y=ID	{CanMatchEnclosingRuleScopeAttribute($x.text, $y.text)}?
		{HandleEnclosingRuleScopeAttribute($x.text, $y.text);}
	;

/** Setting $tokenlabel.attr or $tokenref.attr where attr is predefined property of a token is an error. */
SET_TOKEN_SCOPE_ATTR
	:	'$' x=ID '.' y=ID WS? '=' {CanMatchSetTokenScopeAttribute($x.text, $y.text)}?
		{HandleSetTokenScopeAttribute($x.text, $y.text);}
	;

/** $tokenlabel.attr or $tokenref.attr where attr is predefined property of a token.
 *  If in lexer grammar, only translate for strings and tokens (rule refs)
 */
TOKEN_SCOPE_ATTR
	:	'$' x=ID '.' y=ID	{CanMatchTokenScopeAttribute($x.text, $y.text)}?
		{HandleTokenScopeAttribute($x.text, $y.text);}
	;

/** Setting $rulelabel.attr or $ruleref.attr where attr is a predefined property is an error
 *  This must also fail, if we try to access a local attribute's field, like $tree.scope = localObject
 *  That must be handled by LOCAL_ATTR below. ANTLR only concerns itself with the top-level scope
 *  attributes declared in scope {} or parameters, return values and the like.
 */
SET_RULE_SCOPE_ATTR
	:	'$' x=ID '.' y=ID WS? '=' {CanMatchSetRuleScopeAttribute($x.text, $y.text)}?
		{HandleSetRuleScopeAttribute($x.text, $y.text);}
	;

/** $rulelabel.attr or $ruleref.attr where attr is a predefined property*/
RULE_SCOPE_ATTR
	:	'$' x=ID '.' y=ID {CanMatchRuleScopeAttribute($x.text, $y.text)}?
		{HandleRuleScopeAttribute($x.text, $y.text);}
	;


/** $label	either a token label or token/rule list label like label+=expr */
LABEL_REF
	:	'$' ID {CanMatchLabelReference($ID.text)}?
		{HandleLabelReference($ID.text);}
	;

/** $tokenref in a non-lexer grammar */
ISOLATED_TOKEN_REF
	:	'$' ID	{CanMatchIsolatedTokenReference($ID.text)}?
		{HandleIsolatedTokenReference($ID.text);}
	;

/** $lexerruleref from within the lexer */
ISOLATED_LEXER_RULE_REF
	:	'$' ID	{CanMatchIsolatedLexerRuleReference($ID.text)}?
		{HandleIsolatedLexerRuleReference($ID.text);}
	;

/**  $y 	return value, parameter, predefined rule property, or token/rule
 *          reference within enclosing rule's outermost alt.
 *          y must be a "local" reference; i.e., it must be referring to
 *          something defined within the enclosing rule.
 *
 * 			r[int i] returns [int j]
 * 				:	{$i, $j, $start, $stop, $st, $tree}
 *              ;
 *
 *	TODO: this might get the dynamic scope's elements too.!!!!!!!!!
 */
SET_LOCAL_ATTR
	:	'$' ID WS? '=' expr=ATTR_VALUE_EXPR ';' {CanMatchSetLocalAttribute($ID.text)}?
		{HandleSetLocalAttribute($ID.text, $expr.text);}
	;

LOCAL_ATTR
	:	'$' ID {CanMatchLocalAttribute($ID.text)}?
		{HandleLocalAttribute($ID.text);}
	;

/**	$x::y	the only way to access the attributes within a dynamic scope
 * 			regardless of whether or not you are in the defining rule.
 *
 * 			scope Symbols { List&lt;object&gt; names; }
 * 			r
 * 			scope {int i;}
 * 			scope Symbols;
 * 				:	{$r::i=3;} s {$Symbols::names;}
 * 				;
 * 			s	:	{$r::i; $Symbols::names;}
 * 				;
 */
SET_DYNAMIC_SCOPE_ATTR
	:	'$' x=ID '::' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';' {CanMatchSetDynamicScopeAttribute($x.text, $y.text)}?
		{HandleSetDynamicScopeAttribute($x.text, $y.text, $expr.text);}
	;

DYNAMIC_SCOPE_ATTR
	:	'$' x=ID '::' y=ID {CanMatchDynamicScopeAttribute($x.text, $y.text)}?
		{HandleDynamicScopeAttribute($x.text, $y.text);}
	;

ERROR_SCOPED_XY
	:	'$' x=ID '::' y=ID
		{HandleErrorScopedXY($x.text, $y.text);}
	;

/**		To access deeper (than top of stack) scopes, use the notation:
 *
 * 		$x[-1]::y previous (just under top of stack)
 * 		$x[-i]::y top of stack - i where the '-' MUST BE PRESENT;
 * 				  i.e., i cannot simply be negative without the '-' sign!
 * 		$x[i]::y  absolute index i (0..size-1)
 * 		$x[0]::y  is the absolute 0 indexed element (bottom of the stack)
 */
DYNAMIC_NEGATIVE_INDEXED_SCOPE_ATTR
	:	'$' x=ID '[' '-' expr=SCOPE_INDEX_EXPR ']' '::' y=ID
		{HandleDynamicNegativeIndexedScopeAttribute($x.text, $y.text, $expr.text);}
	;

DYNAMIC_ABSOLUTE_INDEXED_SCOPE_ATTR
	:	'$' x=ID '[' expr=SCOPE_INDEX_EXPR ']' '::' y=ID 
		{HandleDynamicAbsoluteIndexedScopeAttribute($x.text, $y.text, $expr.text);}
	;

fragment
SCOPE_INDEX_EXPR
	:	(~']')+
	;
	
/** $r		y is a rule's dynamic scope or a global shared scope.
 * 			Isolated $rulename is not allowed unless it has a dynamic scope *and*
 * 			there is no reference to rulename in the enclosing alternative,
 * 			which would be ambiguous.  See TestAttributes.testAmbiguousRuleRef()
 */
ISOLATED_DYNAMIC_SCOPE
	:	'$' ID {CanMatchIsolatedDynamicScope($ID.text)}?
		{HandleIsolatedDynamicScope($ID.text);}
	;
	
// antlr.g then codegen.g does these first two currently.
// don't want to duplicate that code.

/** %foo(a={},b={},...) ctor */
TEMPLATE_INSTANCE
	:	'%' ID '(' ( WS? ARG (',' WS? ARG)* WS? )? ')'
		{HandleTemplateInstance($text);}
	;

/** %({name-expr})(a={},...) indirect template ctor reference */
INDIRECT_TEMPLATE_INSTANCE
	:	'%' '(' ACTION ')' '(' ( WS? ARG (',' WS? ARG)* WS? )? ')'
		{HandleIndirectTemplateInstance($text);}
	;

fragment
ARG	:	ID '=' ACTION
	;

/**	%{expr}.y = z; template attribute y of StringTemplate-typed expr to z */
SET_EXPR_ATTRIBUTE
	:	'%' a=ACTION '.' ID WS? '=' expr=ATTR_VALUE_EXPR ';'
		{HandleSetExpressionAttribute($a.text, $ID.text, $expr.text);}
	;
	
/*    %x.y = z; set template attribute y of x (always set never get attr)
 *              to z [languages like python without ';' must still use the
 *              ';' which the code generator is free to remove during code gen]
 */
SET_ATTRIBUTE
	:	'%' x=ID '.' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
		{HandleSetAttribute($x.text, $y.text, $expr.text);}
	;

/** Don't allow an = as first char to prevent $x == 3; kind of stuff. */
fragment
ATTR_VALUE_EXPR
	:	~'=' (~';')*
	;
	
/** %{string-expr} anonymous template from string expr */
TEMPLATE_EXPR
	:	'%' ACTION
		{HandleTemplateExpression($ACTION.text);}
	;
	
fragment
ACTION
	:	'{' (options {greedy=false;}:.)* '}'
	;
	
ESC
	:	'\\' c=. {HandleEscape((char)$c);}
	;

ERROR_XY
	:	'$' x=ID '.' y=ID
		{HandleErrorXY($x.text, $y.text);}
	;
	
ERROR_X
	:	'$' x=ID
		{HandleErrorX($x.text);}
	;
	
UNKNOWN_SYNTAX
	:	'$'
		{HandleUnknownAttributeSyntax();}
	|	'%' (ID|'.'|'('|')'|','|'{'|'}'|'"')*
		{HandleUnknownTemplateSyntax();}
	;

TEXT
	:	~('$'|'%'|'\\')+ {HandleText();}
	;
	
fragment
ID
	:	'@'? ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
	;

fragment
INT
	:	'0'..'9'+
	;

fragment
WS
	:	(' '|'\t'|'\n'|'\r')+
	;
