Created
May 24, 2023 16:03
-
-
Save ccbristo/ea0eb96691d47b85f1e7699ecec39061 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Antlr4.Runtime; | |
using Antlr4.Runtime.Misc; | |
using Parsing.AntlrGen; | |
using Parsing.Syntax; | |
namespace Parsing.Compilation; | |
// CDScript uses '=' for both assignment and comparison | |
// so we need a way to determine what it means based on | |
// the external context | |
internal class CDScriptExpressionVisitor : CDScriptBaseVisitor<CDScriptExpression> | |
{ | |
private readonly EqualMode _mode; | |
private readonly ITokenStream _tokenStream; | |
public CDScriptExpressionVisitor(EqualMode mode, ITokenStream tokenStream) | |
{ | |
_mode = mode; | |
_tokenStream = tokenStream; | |
} | |
public override CDScriptExpression VisitStatement(CDScriptParser.StatementContext context) | |
{ | |
// context.assignmentOrComparison().memberOrIndexer().memberAccess().Identifier().GetText() | |
var assignmentOrComparison = context.assignmentOrComparison(); | |
if (assignmentOrComparison != null) | |
{ | |
var assignmentOrComparisonExpression = VisitAssignmentOrComparison(assignmentOrComparison); | |
return assignmentOrComparisonExpression; | |
} | |
if (context.dateCalculation() != null) | |
{ | |
throw new InvalidOperationException("Implement date calculation here"); | |
} | |
throw new InvalidOperationException("Unrecognized input string"); | |
} | |
public override CDScriptExpression VisitAssignmentOrComparison(CDScriptParser.AssignmentOrComparisonContext context) | |
{ | |
var operatorText = context.AssignmentOrComparisonOperator().GetText(); | |
var restOfLine = VisitRestOfLine(context.restOfLine()); | |
var memberOrIndexer = (MemberAccessExpression)VisitMemberAccess(context.memberAccess()); | |
var result = new AssignmentOrComparisionExpression | |
{ | |
MemberAccess = memberOrIndexer, | |
Operator = GetOperator(operatorText), | |
Value = restOfLine | |
}; | |
return result; | |
} | |
/* | |
* I don't understand why (most likely due to the rule being left recursive) | |
* but something like a.b.c is coming through this method in c b a order. | |
* The stack is being used to reverse this back to a b c order | |
*/ | |
private readonly Stack<MemberAccessExpression> _stackedMembers = new(); | |
public override CDScriptExpression VisitMemberAccess(CDScriptParser.MemberAccessContext context) | |
{ | |
string identifier = context.Identifier().GetText(); | |
var nextMemberOrIndexer = context.memberAccess(); | |
_stackedMembers.TryPop(out var parent); | |
var current = new MemberAccessExpression | |
{ | |
Name = identifier, | |
Inner = parent | |
}; | |
if (nextMemberOrIndexer == null) | |
return current; | |
_stackedMembers.Push(current); | |
var next = VisitMemberAccess(nextMemberOrIndexer); | |
return next; | |
} | |
public override CDScriptExpression VisitRestOfLine(CDScriptParser.RestOfLineContext context) | |
{ | |
var memberAccess = context.memberAccess(); | |
if (memberAccess != null) | |
return VisitMemberAccess(memberAccess); | |
var quotedString = context.QuotedString(); | |
if (quotedString != null) | |
{ | |
var text = quotedString.GetText(); | |
// trim off the leading/trailing single/double quotes | |
// NOT using .Trim because you could have a single/double quote as the first/last character | |
text = text.Substring(1, text.Length - 2); | |
return new ConstantExpression | |
{ | |
Value = text | |
}; | |
} | |
var unquotedString = context.unquotedString(); | |
System.Diagnostics.Debug.Assert(unquotedString != null); | |
return new ConstantExpression | |
{ | |
// for input "something = unquoted text", Value is being set to "unquotedtext" | |
Value = _tokenStream.GetText(unquotedString.SourceInterval) | |
}; | |
} | |
private Operator GetOperator(string operatorText) | |
{ | |
return (_mode, operatorText) switch | |
{ | |
(_, "<") => Operator.LessThan, | |
(_, "<=") => Operator.LessThanOrEqual, | |
(EqualMode.Assignment, "=") => Operator.Assignment, | |
(EqualMode.Equality, "=") => Operator.Equality, | |
(_, "!=") => Operator.NotEqual, | |
(_, ">=") => Operator.GreaterThan, | |
(_, ">") => Operator.GreaterThanOrEqual, | |
_ => throw new ArgumentOutOfRangeException(nameof(operatorText), $"Unrecognized operator {operatorText}") | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment