Skip to content

Instantly share code, notes, and snippets.

@ccbristo
Created May 24, 2023 16:03
Show Gist options
  • Save ccbristo/ea0eb96691d47b85f1e7699ecec39061 to your computer and use it in GitHub Desktop.
Save ccbristo/ea0eb96691d47b85f1e7699ecec39061 to your computer and use it in GitHub Desktop.
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