Repository: facebookresearch/hydra

Issue:
[Bug] Hydra's override grammar allows quoted resolver args, but OmegaConf does not recognize them
# 🐛 Bug

## Description

Best explained with an example (assume a basic `my_app.py` that prints the resolved config):

```bash
python my_app.py +port='${env:PORT}'     # works, may crash if PORT is not defined
python my_app.py +port='${env:PORT,80}'  # crashes: not recognized by Hydra's grammar
python my_app.py +port='${env:PORT,"80"}'  # accepted by Hydra but OmegaConf does not resolve it
```

This is because in the current version of OmegaConf, quotes are not allowed inside interpolations.

## Checklist
- [x] I checked on the latest version of Hydra
- [x] I created a minimal repro

## To reproduce

** Minimal Code/Config snippet to reproduce **

```python
from omegaconf import DictConfig, OmegaConf
import hydra

@hydra.main()
def my_app(cfg: DictConfig) -> None:
    print(OmegaConf.to_yaml(cfg, resolve=True))

if __name__ == "__main__":
    my_app()
```

Then try the examples above.

** Stack trace/error message **

Just showing the last example:
```
port: ${env:PORT,"80"}
```

## Expected Behavior
Hydra should allow the same characters as OmegaConf.

## System information
- **Hydra Version** :  current master (7afee097)
- **Python version** : 3.8.3
- **Virtual environment type and version** : conda 4.8.3
- **Operating system** : MacOS



Discussion:

Resolving patch:
diff --git a/hydra/core/override_parser/overrides_parser.py b/hydra/core/override_parser/overrides_parser.py
--- a/hydra/core/override_parser/overrides_parser.py
+++ b/hydra/core/override_parser/overrides_parser.py
@@ -54,8 +54,8 @@ def parse_rule(self, s: str, rule_name: str) -> Any:
         lexer.addErrorListener(error_listener)
 
         # Set the lexer in the correct mode to parse the desired rule.
-        lexer_mode = "KEY" if rule_name in KEY_RULES else "VALUE"
-        lexer.mode(getattr(OverrideLexer, lexer_mode))
+        if rule_name not in KEY_RULES:
+            lexer.mode(OverrideLexer.VALUE_MODE)
 
         stream = CommonTokenStream(lexer)
         parser = OverrideParser(stream)


Test patch:
diff --git a/tests/test_overrides_parser.py b/tests/test_overrides_parser.py
--- a/tests/test_overrides_parser.py
+++ b/tests/test_overrides_parser.py
@@ -306,6 +306,11 @@ def test_choice_sweep(value: str, expected: Any) -> None:
         pytest.param(
             "a , b", ChoiceSweep(list=["a", "b"], simple_form=True), id="a , b",
         ),
+        pytest.param(
+            "${a},${b}",
+            ChoiceSweep(list=["${a}", "${b}"], simple_form=True),
+            id="${a},${a}",
+        ),
     ],
 )
 def test_simple_choice_sweep(value: str, expected: Any) -> None:
@@ -613,6 +618,12 @@ def test_key(value: str, expected: Any) -> None:
             QuotedString(text="false", quote=Quote.single),
             id="value:bool:quoted",
         ),
+        # interpolations:
+        pytest.param("${a}", "${a}", id="primitive:interpolation"),
+        pytest.param("${a.b.c}", "${a.b.c}", id="primitive:interpolation"),
+        pytest.param("${foo:a}", "${foo:a}", id="primitive:interpolation"),
+        pytest.param("${foo:1,2,3}", "${foo:1,2,3}", id="primitive:interpolation"),
+        pytest.param("${foo:[1,2,3]}", "${foo:[1,2,3]}", id="primitive:interpolation"),
     ],
 )
 def test_primitive(value: str, expected: Any) -> None: