# ANTLR4 Runtime for Dart

Notice: Dart target may generate code incompatible with Dart 2.9 sound null safety. Please set the minimum SDK constraint to 2.8.4 or lower if such violation is found. Contributions are welcomed.

### First steps

#### 1. Install ANTLR4

[The getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md) 
should get you started.

#### 2. Install the Dart ANTLR runtime

Each target language for ANTLR has a runtime package for running parser 
generated by ANTLR4. The runtime provides a common set of tools for using your parser.

Install the runtime with the same version as the main ANTLR tool:

Add this to your package's pubspec.yaml file:
```yaml
...
dependencies:
  antlr4: <ANTLR version>
...
```

#### 3. Generate your parser

You use the ANTLR4 "tool" to generate a parser. These will reference the ANTLR 
runtime, installed above.

Suppose you're using a UNIX system and have set up an alias for the ANTLR4 tool 
as described in [the getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md). 
To generate your Dart parser, run the following command:

```shell script
antlr4 -Dlanguage=Dart MyGrammar.g4
```

For a full list of antlr4 tool options, please visit the 
[tool documentation page](https://github.com/antlr/antlr4/blob/master/doc/tool-options.md).

### Complete example

Suppose you're using the JSON grammar from https://github.com/antlr/grammars-v4/tree/master/json.

Then, invoke `antlr4 -Dlanguage=Dart JSON.g4`. The result of this is a 
collection of `.dart` including:

* JsonLexer.dart
* JsonParser.dart
* JsonBaseListener.dart
* JsonListener.dart (if you have not activated the -no-listener option)
* JsonVisitor.dart (if you have activated the -visitor option)

We'll write a small main func to call the generated parser/lexer 
(assuming they are separate). This one writes out the encountered 
`ParseTreeContext`'s:

```dart
import 'package:antlr4/antlr4.dart';
import 'package:my_project/JSONParser.dart';
import 'package:my_project/JSONLexer.dart';

class TreeShapeListener implements ParseTreeListener {
  @override
  void enterEveryRule(ParserRuleContext ctx) {
    print(ctx.text);
  }

  @override
  void exitEveryRule(ParserRuleContext node) {
  }

  @override
  void visitErrorNode(ErrorNode node) {
  }

  @override
  void visitTerminal(TerminalNode node) {
  }
}

void main(List<String> args) async {
  JSONLexer.checkVersion();
  JSONParser.checkVersion();
  final input = await InputStream.fromPath(args[0]);
  final lexer = JSONLexer(input);
  final tokens = CommonTokenStream(lexer);
  final parser = JSONParser(tokens);
  parser.addErrorListener(DiagnosticErrorListener());
  parser.buildParseTree = true;
  final tree = parser.json();
  ParseTreeWalker.DEFAULT.walk(TreeShapeListener(), tree);
}
```

Create a `example.json` file:
```json
{"a":1}
```

Parse the input file:

```shell script
dart bin/main.dart example.json
```

The expected output is:

```
{"a":1}
{"a":1}
{"a":1}
"a":1
1
```