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

Intoroduce parameterizing rules with conditional statement #418

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

ydah
Copy link
Collaborator

@ydah ydah commented May 9, 2024

I would like to propose a new grammar in this PR.
I believe that more parameterizing rules can handle more abstract rules if we can switch between rules and actions that are expanded by conditions in order to make rules common.

Syntax is as follows:

%rule defined_rule(X, condition): /* empty */
                                | X { $$ = $1; } %if(condition)
                                ;

%%

r_true        : defined_rule(number, %true)
              ;

r_false       : defined_rule(number, %false)
              ;

It's like a postfix if in Ruby. If condition is false, it is equivalent to missing this line.

❯ exe/lrama --trace=rules spec/fixtures/parameterizing_rules/user_defined/if.y
Grammar rules:
$accept -> r_true YYEOF
defined_rule_number_true -> ε
defined_rule_number_true -> number
r_true -> defined_rule_number_true
defined_rule_number_false -> ε
r_false -> defined_rule_number_false
Old design

DesignDoc: https://gist.github.com/ydah/62008655a6f6c3118ab01134dc91da6f

Syntax is as follows:

%rule defined_rule(X, condition): /* empty */
                                | X { $$ = $1; } %if(condition) /* 1 */
                                | %if(condition) X %endif X { $$ = $1; } /* 2 */
                                ;

%%

r_true        : defined_rule(number, %true)
              ;

r_false       : defined_rule(number, %false)
              ;
  1. It's like a postfix if in Ruby. If condition is false, it is equivalent to missing this line.
  2. If statementIf condition is false, it is equivalent to missing RHS between %if and% endif.
❯ exe/lrama --trace=rules spec/fixtures/parameterizing_rules/user_defined/if.y
Grammar rules:
$accept -> r_true YYEOF
defined_rule_number_true -> ε
defined_rule_number_true -> number
defined_rule_number_true -> number number
r_true -> defined_rule_number_true
defined_rule_number_false -> ε
defined_rule_number_false -> number
r_false -> defined_rule_number_false

Motivation

I believe it will solve the problem mentioned in the article below with the tight coupling with Lexer "to disable certain generation rules under certain conditions" and I would like to propose this feature to solve this problem.
https://yui-knk.hatenablog.com/entry/2023/04/04/190413

We can trace the RHS to f_args > args_tail > args_forward, where f_args is the RHS of both the lambda argument (f_larglist) and the method definition argument (f_arglist).
So if we can switch between RHS and actions by passing parameters, we can break up the Lexer/Parser coupling here.

@ydah ydah marked this pull request as draft May 9, 2024 12:20
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch from 2cb042d to c15c765 Compare May 9, 2024 13:46
@ydah ydah changed the title [WIP] [PoC] Intoroduce parameterizing rules with conditonal [PoC] Intoroduce parameterizing rules with conditonal May 9, 2024
@ydah ydah marked this pull request as ready for review May 9, 2024 13:46
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch 2 times, most recently from 9a48181 to 6ba14f2 Compare May 13, 2024 02:51
@ydah ydah changed the title [PoC] Intoroduce parameterizing rules with conditonal [PoC] Intoroduce parameterizing rules with conditional statement May 13, 2024
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch from 6ba14f2 to b90290f Compare June 9, 2024 05:18
@ydah ydah changed the title [PoC] Intoroduce parameterizing rules with conditional statement Intoroduce parameterizing rules with conditional statement Jun 9, 2024
@ydah ydah requested a review from yui-knk June 9, 2024 05:25
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch from b90290f to a044fe0 Compare June 11, 2024 15:21
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch from a044fe0 to dd5808c Compare June 27, 2024 12:21
ydah added 4 commits July 2, 2024 15:20
I would like to propose a new grammar in this PR.
I believe that more parameterizing rules can handle more abstract rules if we can switch between rules and actions that are expanded by conditions in order to make rules common.

Syntax is as follows:
```
%rule defined_rule(X, condition): /* empty */
                                | X { $$ = $1; } %if(condition) /* 1 */
                                | %if(condition) X %endif X { $$ = $1; } /* 2 */
                                ;

%%

r_true        : defined_rule(number, %true)
              ;

r_false       : defined_rule(number, %false)
              ;
```

1. It's like a postfix if in Ruby. If condition is false, it is equivalent to missing this line.
2. If statementIf condition is false, it is equivalent to missing RHS between `%if` and`% endif`.

I believe it will solve the problem mentioned in the article below with the tight coupling with Lexer "to disable certain generation rules under certain conditions" and I would like to propose this feature to solve this problem.
https://yui-knk.hatenablog.com/entry/2023/04/04/190413

We can trace the RHS to [f_args](https://github.com/ruby/ruby/blob/2f916812a9b818b432ee7c299e021ec62d4727fb/parse.y#L5523-L5575) > [args_tail](https://github.com/ruby/ruby/blob/2f916812a9b818b432ee7c299e021ec62d4727fb/parse.y#L5487-L5503) > [args_forward](https://github.com/ruby/ruby/blob/2f916812a9b818b432ee7c299e021ec62d4727fb/parse.y#L5586-L5597), where f_args is the RHS of both the lambda argument (f_larglist) and the method definition argument (f_arglist).
So if we can switch between RHS and actions by passing parameters, we can break up the Lexer/Parser coupling here.
```
%rule defined_rule(X, condition): X { $$ = $1; } %if(condition)
                                ;
```
@ydah ydah force-pushed the parameterizing-rules-meets-conditonal branch from dd5808c to 77218fe Compare July 2, 2024 06:21
parser.y Outdated
{
builder = val[2]
builder.symbols << val[3] if val[3]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

builder (is the instance of Grammar::ParameterizingRule::Rhs) has one or zero if_clause. Then I think it's reasonable for builder has attribute for if_clause than holding if_clause on symbols.

@yui-knk
Copy link
Collaborator

yui-knk commented Jul 28, 2024

I agree to the feature.
What I concern is the syntax. There are 3 points for discussion:

  1. Modifier style (%if(condition)) makes senes for me
  2. The syntax for parameters (defined_rule(X, condition)) is a point of concern. Parameters for rule (X) are different from parameters for condition (condition). If so I want to make the difference clear from the syntax. For example, in Ruby optional parameter is clear from its syntax (a = 1) and we can set the constrain on the order of parameters if condition parameter has different syntax from rule parameter. One example is adding some prefix to condition parameter like defined_rule(X, @condition).
  3. The syntax for condition argument is another point of concern. I think the meaning of rule argument and condition argument are different. Condition argument might be a kind of expression. If so it might be better to introduce different syntax like defined_rule(number, %{true}) or defined_rule(number, {true}) and so on.

Sorry for the late response.

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

Successfully merging this pull request may close these issues.

2 participants