AntlrDenter 0.1.0
dotnet add package AntlrDenter --version 0.1.0
NuGet\Install-Package AntlrDenter -Version 0.1.0
<PackageReference Include="AntlrDenter" Version="0.1.0" />
paket add AntlrDenter --version 0.1.0
#r "nuget: AntlrDenter, 0.1.0"
// Install AntlrDenter as a Cake Addin #addin nuget:?package=AntlrDenter&version=0.1.0 // Install AntlrDenter as a Cake Tool #tool nuget:?package=AntlrDenter&version=0.1.0
ANTLR-Denter: Python-like indentation tokens for ANTLR4 C# Hosts
This project adds INDENT
and DEDENT
tokens for autogenerated ANTLR4 parsers for Python-like scopes. This defines a DenterHelper
that can be added to an ANTLR4 grammar.
This repository is a fork of yshavit's ANTLR-Denter project since the original repo is no longer maintained. This fork aims to maintain a C#-specific library using the official Antlr4.Runtime.Standard and support work with RenDisco.
Overview
This is a plugin that is spliced into an ANTLR grammar's lexer, and allows that lexer to make use of INDENT
and DEDENT
to represent Python-like scope entry and termination.
Features
Using INDENT
and DEDENT
tokens in a parser
When DenterHelper
injects DEDENT
tokens, it will prefix any string of them with a single NL
. A single NL
is also inserted before the EOF token if there are no DEDENT
s to insert (that is, if the last line of the source file is not indented). A NL
is not inserted before an INDENT
, since indents always imply a newline before them (and thus make the newline token meaningless).
For example, given this input;
hello
world
universe
dolly
Would be parsed as;
"hello"
INDENT
"world"
INDENT
"universe"
NL
DEDENT
DEDENT
"dolly"
NL
<eof>
This approach lets you define expressions, single-line statements, and block statements naturally.
- Expressions in your parser grammar should not end in newlines. This makes compound expressions work naturally.
- Single-line statements in your grammar should end in newlines. For example, an assignment expression might be
identifier '=' expression NL
. - Blocks are bookended by INDENT and DEDENT, without mentioning extra newlines:
block: INDENT statement+ DEDENT
.- You should not include a newline before the INDENT
- An
if
would be something likeif expression ':' block
. (Note the lack ofNL
after the:
.)
In the example above, universe
and dolly
represent simple expressions, and you can imagine that the grammar would contain something like statement: expression NL | helloBlock;
.
Handling and asserting indentation
The DenterHelper
processor asserts correct indentation on DEDENT. Take the following example:
someStatement()
if foo():
if bar():
fooAndBar()
bogusLine()
bogusLine()
does not dedent to the indentation of any valid scope - lacking indentation to qualify as part of the if foo():
's scope and too indented to share a scope with someStatement()
. In Python this is expressed as an IndentationError
.
The DenterHelper
processor handles this by inserting two tokens: a DEDENT
followed immediately by an INDENT
(the total sequence here would actually be two DEDENT
s followed by an INDENT
, since bogusLine()
is twice-dedented from fooAndBar()
). The rationale is that the line has dedented to its parent, and then indented.
As a consequence, the DenterHelper
processor will also assert correct indentation for all lines where an INDENT
is not expected. Take the following example in a Python-like grammar of two method calls:
someStatement()
bogusLine()
This would be illegal due to no INDENT
s being expected after someStatement()
.
Usage
In an ANTLR grammar definition MyGrammar.g4
, use the following.
tokens { INDENT, DEDENT }
@lexer::header {
using AntlrDenter.DenterHelper;
}
@lexer::members {
private DenterHelper denter;
public override IToken NextToken()
{
if (denter == null)
{
denter = DenterHelper.Builder()
.Nl(NL)
.Indent(MyGrammarParser.INDENT)
.Dedent(MyGrammarParser.DEDENT)
.PullToken(base.NextToken);
}
return denter.NextToken();
}
}
NL: ('\r'? '\n' ' '*); #For tabs just switch out ' '* with '\t'*
Note the injected code is dedented with respect to the @lexer::members
block. This is so that it has the proper formatting in the resulting C# Lexer file.
Acknowledgements
Many thanks to yshavit for developing the original ANTLR-Denter, and tejacques for their Deque implementation.
Related Work
- The original ANTLR-Denter.
- ANTLR4, the language toolkit.
- kaby76's Antlr4BuildTasks, which has been used for further reading on C# and .NET with ANTLR.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Antlr4.Runtime.Standard (>= 4.13.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.0 | 56 | 12/15/2024 |