Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NullReferenceException when using optional term without specifing Ast node type #35

Open
maelmahdy opened this issue Jul 30, 2020 · 3 comments

Comments

@maelmahdy
Copy link

maelmahdy commented Jul 30, 2020

Hi folks,

I've the below grammar:

    public class AutomateGrammar : InterpretedLanguageGrammar
    {
        public AutomateGrammar() : base(false)
        {
            var identifier = new IdentifierTerminal("Identifier", IdOptions.IsNotKeyword);
            var numbers = new NumberLiteral("Number");
            var strings = new StringLiteral("String", "\"", StringOptions.AllowsAllEscapes);
            var trueTerm = ToTerm("true") | "yes";
            var falseTerm = ToTerm("false") | "no";
            var optionalThenTerm = ToTerm("then").Q();

            var booleans = new NonTerminal("Boolean", typeof(BooleanNode));
            var comparisonOperation = new NonTerminal("Comparison", typeof(ComparisonNode));
            var value = new NonTerminal("Value");
            var assignment = new NonTerminal("Assignment", typeof(AssignmentNode));
            var ifStatement = new NonTerminal("If", typeof(IfNode));
            var optionalElseStatement = new NonTerminal("Else");
            var statement = new NonTerminal("Statement");
            var statements = new NonTerminal("Statements");
            var block = new NonTerminal("Block");

            comparisonOperation.Rule = value + (ToTerm("=") | "<>" | ">" | ">=" | "<" | "<=") + value;
            booleans.Rule = trueTerm | falseTerm | comparisonOperation | "(" + booleans + ")";
            value.Rule = numbers | strings | booleans | identifier;
            assignment.Rule = identifier + "=" + value;
            statement.Rule = assignment | ifStatement;
            statements.Rule = MakeStarRule(statements, null, statement);
            block.Rule = statement | ToTerm("begin") + statements + "end";
            optionalElseStatement.Rule = Empty | PreferShiftHere() + "else" + block;
            ifStatement.Rule = ToTerm("if") + booleans + optionalThenTerm + block + optionalElseStatement;

            MarkPunctuation(value);
            MarkPunctuation("=", "if", "then", "else", "begin", "end", "(", ")");
            MarkPunctuation(optionalThenTerm);
            MarkTransient(value, statement);

            Root = ifStatement;

            MarkReservedWords("if", "then", "else", "true", "false", "yes", "no");

            LanguageFlags = LanguageFlags.CreateAst;
        }
    }

When I run grammar explorer and type "if x=true then y=5" it throws NullReferenceException

How to bypass this exception without having to create a class for each terminal or non-terminal ?

@rivantsov
Copy link
Contributor

does it show in call stack where it happens? put grammar directly into samples project and then step thru in debugger, try to find where it happens. sorry, handling these situations is not perfect in Irony, you have to investigate; but in general, you can't 'bypass' it if some node type is missing

@maelmahdy
Copy link
Author

maelmahdy commented Jul 30, 2020

@rivantsov Thanks for your quick response,
I did that already and found it fails in AstBuilder.BuildAst method in this part:

if (config.NodeCreator != null)
      {
        config.NodeCreator(Context, parseNode);
        // We assume that Node creator method creates node and initializes it, so parser does not need to call 
        // IAstNodeInit.Init() method on node object. But we do call AstNodeCreated custom event on term.
      }
      else
      {
        //Invoke the default creator compiled when we verified the data
        parseNode.AstNode = config.DefaultNodeCreator();
        //Initialize node
        var iInit = parseNode.AstNode as IAstNodeInit;
        if (iInit != null)
          iInit.Init(Context, parseNode);
      }

I added this line before this block and the issue is fixed:
if (config.NodeCreator == null && config.DefaultNodeCreator == null) return;

I'm not sure if it has side effects or not, I hope you can check and accept PR #36 if it's OK

Also, Irony is a true master piece so I really hope It'll get your support and development continued :)

@rivantsov
Copy link
Contributor

Hi
thank you for help, and for your compliments. but man, in your pull req/commit, the formatting changed all thru the whole file, like position of opening brace, so github shows all these changes and it's really hard to see the actual change and its possible impact. I will keep this suggestion in todo list when I get back to next fix, hopefully this year.
GraphQL effort with Irony definitely highlighted many shortcoming that need to be fixed
thank you again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants