Rasagar/Library/PackageCache/com.unity.visualscripting/Runtime/VisualScripting.Flow/Dependencies/NCalc/NCalc.g

304 lines
9.0 KiB
Plaintext
Raw Normal View History

2024-08-26 13:07:20 -07:00
grammar NCalc;
options
{
output=AST;
ASTLabelType=CommonTree;
language=CSharp;
}
@header {
using System.Text;
using System.Globalization;
using System.Collections.Generic;
using NCalc.Domain;
}
@members {
private const char BS = '\\';
private static NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
private string extractString(string text) {
StringBuilder sb = new StringBuilder(text);
int startIndex = 1; // Skip initial quote
int slashIndex = -1;
while ((slashIndex = sb.ToString().IndexOf(BS, startIndex)) != -1)
{
char escapeType = sb[slashIndex + 1];
switch (escapeType)
{
case 'u':
string hcode = String.Concat(sb[slashIndex+4], sb[slashIndex+5]);
string lcode = String.Concat(sb[slashIndex+2], sb[slashIndex+3]);
char unicodeChar = Encoding.Unicode.GetChars(new byte[] { System.Convert.ToByte(hcode, 16), System.Convert.ToByte(lcode, 16)} )[0];
sb.Remove(slashIndex, 6).Insert(slashIndex, unicodeChar);
break;
case 'n': sb.Remove(slashIndex, 2).Insert(slashIndex, '\n'); break;
case 'r': sb.Remove(slashIndex, 2).Insert(slashIndex, '\r'); break;
case 't': sb.Remove(slashIndex, 2).Insert(slashIndex, '\t'); break;
case '\'': sb.Remove(slashIndex, 2).Insert(slashIndex, '\''); break;
case '\\': sb.Remove(slashIndex, 2).Insert(slashIndex, '\\'); break;
default: throw new RecognitionException("Unvalid escape sequence: \\" + escapeType);
}
startIndex = slashIndex + 1;
}
sb.Remove(0, 1);
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
public List<string> Errors { get; private set; }
public override void DisplayRecognitionError(String[] tokenNames, RecognitionException e) {
base.DisplayRecognitionError(tokenNames, e);
if(Errors == null)
{
Errors = new List<string>();
}
String hdr = GetErrorHeader(e);
String msg = GetErrorMessage(e, tokenNames);
Errors.Add(msg + " at " + hdr);
}
}
@init {
numberFormatInfo.NumberDecimalSeparator = ".";
}
ncalcExpression returns [LogicalExpression value]
: logicalExpression EOF! {$value = $logicalExpression.value; }
;
logicalExpression returns [LogicalExpression value]
: left=conditionalExpression { $value = $left.value; } ( '?' middle=conditionalExpression ':' right=conditionalExpression { $value = new TernaryExpression($left.value, $middle.value, $right.value); })?
;
conditionalExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=booleanAndExpression { $value = $left.value; } (
('||' | 'or') { type = BinaryExpressionType.Or; }
right=conditionalExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
booleanAndExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=bitwiseOrExpression { $value = $left.value; } (
('&&' | 'and') { type = BinaryExpressionType.And; }
right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
bitwiseOrExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=bitwiseXOrExpression { $value = $left.value; } (
'|' { type = BinaryExpressionType.BitwiseOr; }
right=bitwiseOrExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
bitwiseXOrExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=bitwiseAndExpression { $value = $left.value; } (
'^' { type = BinaryExpressionType.BitwiseXOr; }
right=bitwiseAndExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
bitwiseAndExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=equalityExpression { $value = $left.value; } (
'&' { type = BinaryExpressionType.BitwiseAnd; }
right=equalityExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
equalityExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=relationalExpression { $value = $left.value; } (
( ('==' | '=' ) { type = BinaryExpressionType.Equal; }
| ('!=' | '<>' ) { type = BinaryExpressionType.NotEqual; } )
right=relationalExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
relationalExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=shiftExpression { $value = $left.value; } (
( '<' { type = BinaryExpressionType.Lesser; }
| '<=' { type = BinaryExpressionType.LesserOrEqual; }
| '>' { type = BinaryExpressionType.Greater; }
| '>=' { type = BinaryExpressionType.GreaterOrEqual; } )
right=shiftExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
shiftExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=additiveExpression { $value = $left.value; } (
( '<<' { type = BinaryExpressionType.LeftShift; }
| '>>' { type = BinaryExpressionType.RightShift; } )
right=additiveExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
additiveExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=multiplicativeExpression { $value = $left.value; } (
( '+' { type = BinaryExpressionType.Plus; }
| '-' { type = BinaryExpressionType.Minus; } )
right=multiplicativeExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
multiplicativeExpression returns [LogicalExpression value]
@init {
BinaryExpressionType type = BinaryExpressionType.Unknown;
}
: left=unaryExpression { $value = $left.value); } (
( '*' { type = BinaryExpressionType.Times; }
| '/' { type = BinaryExpressionType.Div; }
| '%' { type = BinaryExpressionType.Modulo; } )
right=unaryExpression { $value = new BinaryExpression(type, $value, $right.value); }
)*
;
unaryExpression returns [LogicalExpression value]
: primaryExpression { $value = $primaryExpression.value; }
| ('!' | 'not') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Not, $primaryExpression.value); }
| ('~') primaryExpression { $value = new UnaryExpression(UnaryExpressionType.BitwiseNot, $primaryExpression.value); }
| '-' primaryExpression { $value = new UnaryExpression(UnaryExpressionType.Negate, $primaryExpression.value); }
;
primaryExpression returns [LogicalExpression value]
: '(' logicalExpression ')' { $value = $logicalExpression.value; }
| expr=value { $value = $expr.value; }
| identifier {$value = (LogicalExpression) $identifier.value; } (arguments {$value = new Function($identifier.value, ($arguments.value).ToArray()); })?
;
value returns [ValueExpression value]
: INTEGER { try { $value = new ValueExpression(int.Parse($INTEGER.text)); } catch(System.OverflowException) { $value = new ValueExpression(long.Parse($INTEGER.text)); } }
| FLOAT { $value = new ValueExpression(double.Parse($FLOAT.text, NumberStyles.Float, numberFormatInfo)); }
| STRING { $value = new ValueExpression(extractString($STRING.text)); }
| DATETIME { $value = new ValueExpression(DateTime.Parse($DATETIME.text.Substring(1, $DATETIME.text.Length-2))); }
| TRUE { $value = new ValueExpression(true); }
| FALSE { $value = new ValueExpression(false); }
;
identifier returns[Identifier value]
: ID { $value = new Identifier($ID.text); }
| NAME { $value = new Identifier($NAME.text.Substring(1, $NAME.text.Length-2)); }
;
expressionList returns [List<LogicalExpression> value]
@init {
List<LogicalExpression> expressions = new List<LogicalExpression>();
}
: first=logicalExpression {expressions.Add($first.value);} ( ',' follow=logicalExpression {expressions.Add($follow.value);})*
{ $value = expressions; }
;
arguments returns [List<LogicalExpression> value]
@init {
$value = new List<LogicalExpression>();
}
: '(' ( expressionList {$value = $expressionList.value;} )? ')'
;
TRUE
: 'true'
;
FALSE
: 'false'
;
ID
: LETTER (LETTER | DIGIT)*
;
INTEGER
: DIGIT+
;
FLOAT
: DIGIT* '.' DIGIT+ E?
| DIGIT+ E
;
STRING
: '\'' ( EscapeSequence | (options {greedy=false;} : ~('\u0000'..'\u001f' | '\\' | '\'' ) ) )* '\''
;
DATETIME
: '#' (options {greedy=false;} : ~('#')*) '#'
;
NAME : '[' (options {greedy=false;} : ~(']')*) ']'
;
E : ('E'|'e') ('+'|'-')? DIGIT+
;
fragment LETTER
: 'a'..'z'
| 'A'..'Z'
| '_'
;
fragment DIGIT
: '0'..'9'
;
fragment EscapeSequence
: '\\'
(
'n'
| 'r'
| 't'
| '\''
| '\\'
| UnicodeEscape
)
;
fragment HexDigit
: ('0'..'9'|'a'..'f'|'A'..'F') ;
fragment UnicodeEscape
: 'u' HexDigit HexDigit HexDigit HexDigit
;
/* Ignore white spaces */
WS : (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
;