Year: 2022

Abstract:
Code completion is usually cast as a language modelling problem, i.e., continuing an input in a left-to-right fashion. However, in practice, some parts of the completion (e.g., string literals) may be very hard to predict, whereas subsequent parts directly follow from the context. To handle this, we instead consider the scenario of generating code completions with “holes” inserted in places where a model is uncertain. We develop GRAMMFORMER, a Transformer-based model that guides code generation by the programming language grammar, and compare it to a variety of more standard sequence models. We train the models on code completion for C# and Python given partial code context. To evaluate models, we consider both ROUGE as well as a new metric REGEXACC that measures success of generating completions matching long outputs with as few holes as possible. In our experiments, GRAMMFORMER generates 10-50% more accurate completions compared to traditional generative models and 37-50% longer sketches compared to sketch-generating baselines trained with similar techniques.

heading: 1 INTRODUCTION
text: Recent high-capacity language models (LM) have shown that machine learning models are able to generate coherent, realistic text, but it is often hard to guide them towards a specific goal, especially when describing the intent is complex or more costly than manually generating the target output.
One such scenario are LMs of source code (LMC). Since Hindle et al. (2012) increasingly sophisticated LMCs have been built, including transformer-based ones, such as those of Svyatkovskiy et al. (2020); Feng et al. (2020); Chen et al. (2021) and various similar unpublished models such as TabNine and SourceAI. These models generate full sequences of code tokens left-to-right with any prefix acting as the (partial) user intent. While LMs generate realistic-looking outputs, they are known to occasionally “hallucinate” (Puduppully et al., 2019; Malmi et al., 2019; Maynez et al., 2020; Liu et al., 2021), i.e. generate plausible but incorrect content. This is particularly problematic in generating source code, where small mistakes can lead to erroneous code that is very hard to debug or introduces vulnerabilities (Pearce et al., 2021).
In this work, we investigate models that can decline to make predictions in places where there is high uncertainty (e.g., where the user should choose a name), but continue generating around these “holes”. For example, in Fig. 1(left) a developer has typed some code and is about to type the next line. A likely completion is to consume more command line arguments, but their name is unclear
Code Context: 1 import sys 2 target = sys.argv[1] 3 I
Ground-Truth: ID = sys.argv[2]
Suggested Code Completions: L→ R target = target.replace("\\", "/") L→ R +⦸ target = L→ R + print(target) Copilot (No suggestion) GRAMMFORMER = sys.argv[2]
Figure 1: A sample snippet (left; abbreviated from Fig. 12 in Appx. A). A developer has just typed the code and their cursor (in blue) is at line 3. Code completions provided by a number of models are shown on the right, where L→ R is a standard LMC and GRAMMFORMER is our new model.
from the context. A traditional generative model (e.g. Fig. 1; top right) may choose to provide a completion that exists in the training data, but is not clearly called for here. On the other hand, a model able to explicitly mark where it is uncertain (Fig. 1; bottom right) makes it clear to a user where further input is required.
However, creating such models is not trivial. A simple first attempt may be to use a standard LMC, but output a “hole token” whenever the model is uncertain about the next output token. However, continuing after the “ ” then becomes infeasible, as the LMC was not trained on such data. Hence, a suitable training dataset and objective need to devised. As no large datasets with holes exist, we instead choose to use a reinforcement learning approach in which our reward function encourages the model to make “long” predictions with as few “ ” tokens as possible, but to avoid making incorrect predictions. We found that standard left-to-right sequence models perform poorly on this task. Hence, we developed GRAMMFORMER, a model that construct suggestions by generating a (partial) syntax tree, but which has the option of leaving non-terminals in its output.
Contributions (1) We present GRAMMFORMER, a transformer-based model that generates code based on the programming language grammar and can predict hole tokens rather than output it is uncertain about. (2) We develop REGEXACC, a metric that evaluates the quality of predictions with holes. (3) We evaluate GRAMMFORMER on Python and C# code and show that GRAMMFORMER makes longer and more precise statement-level sketch completions compared to baselines.

heading: 2 METHOD
text: Our aim is to predict code completions as sketches, a mix of actual tokens and “holes” , which are meant to signify that the model is unable to make a useful prediction within the given context and further user input is required. Formally, we consider models that take a context sequence x of tokens as input and have to produce an output sequence y; intuitively, x is what the user typed so far, and y is the suggestion presented to the user. In our setting, y is a sketch, a mix of tokens from the programming language and the special token signifying a “hole” that could be filled by an arbitrary sequence of tokens. For example, t = foo( ) is a sketch corresponding to assigning the return value of function foo to variable t, but leaves the arguments of the function call undetermined.
Metric A good sketch is one that (a) can be completed into the correct output and (b) is as precise as possible. To measure how successful a method is in doing so, we define a new metric REGEXACC. For (a), we use toRegex(ŷ) to turn a predicted code sketch ŷ into a regular expression by replacing all holes with the wildcard matching any non-empty sequence (“.+” in Perl Compatible Regular Expression syntax). If the regex matches the ground truth, matches(⋅, ⋅) returns a score of 1 otherwise it returns 0. To implement (b), we scale this result by the proportion of terminal tokens predicted, by defining nTokens(ŷ) as the function that returns the number of non-hole symbols in ŷ. More formally, assume an output sketch ŷ and a ground-truth sequence y∗, where y∗ does not contain any tokens. REGEXACC is then defined as
REGEXACC(ŷ,y∗) ≜ matches(toRegex(ŷ),y∗) ⋅ nTokens(ŷ) nTokens(y∗) .
Beyond REGEXACC, we also consider ROUGE (Lin, 2004), since a sketch can be thought as a form of a “summary” of the target text. For this, we use a helper function ERASEHOLES(ŷ) that simply
drops all tokens, and then consider ROUGEF1(ERASEHOLES(ŷ),y∗). ROUGE is more lenient to errors than REGEXACC and gives partial credit to non-matching but plausible sketches.

heading: 2.1 LINEAR CODE SKETCH GENERATION
text: First, we consider the idea of generating code sketches using a standard generative model for language. To this end, we simply extend the vocabulary with the special “ ” token. An obvious problem is that while we have plenty of training data for a standard generative model, we do not have training data for outputs y that contain the token. Consequently, we cannot train the model in a fully supervised fashion, and instead turn to reinforcement learning. Concretely, we devise a reward function r(⋅) that averages REGEXACC and ROUGE, i.e. for a predicted output sketch ŷ and a ground truth output (without tokens) y∗, we define
r(ŷ,y∗) = 1 2 (REGEXACC(ŷ,y∗) + ROUGEF1(ERASEHOLES(ŷ,y∗)) . (1)
Using the combination of ROUGE (which does not consider holes) and REGEXACC is crucial here, as ROUGE is much “smoother” compared to REGEXACC, which is 0 for all but very few predictions, allowing us to measure partial improvement. We use our reward function from Eq. 1 to evaluate the quality of the output of the full model and compute a loss. Inspired by Paulus et al. (2017) we use self-critical policy gradient training (Rennie et al., 2017) and for a prediction ŷ we minimise
L(x,y∗) = (r(ŷ,y∗) − r̃(x)) ⋅ Lgen (x, ŷ) (2) Here, r̃(x) is the reward achieved by the prediction from the snapshots of the model that achieved the best score so far and Lgen is the loss of the generative model. Intuitively, this objective rewards models that improve upon the previous best policy with respect to r.
To model this in practice, we use a standard encoder/decoder Transformer model Vaswani et al. (2017); Radford et al. (2019), “translating” the context x into the output y using separate encoder and decoder models. We additionally also consider the language modelling case, i.e., a model that conditioned on x predicts token y0, conditioned on x,y0 predicts token y1, etc..
Pretraining In practice, we found that directly training a sequence model to maximise Eq. 1, is very slow and does not converge to a useful model. Instead, we heuristically generate a dataset suitable for supervised pretraining. We replace random AST non-terminals of the target output by and generate target sequences. These contain terminals and zero or more . We then pretrain the model on this dataset to convergence, and then fine-tune it using the reward of Eq. 1.

heading: 2.2 GRAMMAR-BASED CODE SKETCH GENERATION
text: In experiments, we found the simple extended sequence model from above to not perform well, in particular, tokens would not replace semantically meaningful subsequences (e.g. “szconv. )”
Algorithm 1 GRAMMFORMER generative process, given an input sequence x(0). for t = 0, 1, 2, ... do
i (t) ∼ Ps (i ∣ x(t), N(x(t))) ▷ sample non-terminal position from N(x(t)) to expand if i(t) = ⦸ then ▷ if x(t) does not contain non-terminals or none was selected by Ps break ▷ stop generation u (t) ⊚i(t) ∼ Pe (u ∣ x(t), i(t)) ▷ sample expansion of non-terminal at position i(t) x (t+1)
← x (t) <i(t) ∶∶ u (t) ⊚i(t) ∶∶ x (t) >i(t) ▷ create x (t+1) by replacing non-terminal at i(t) by u(t) ⊚i(t)
return NONTERMINALSTOHOLES(x(t))▷ convert remaining non-terminals to holes and return
does not contain a left parenthesis and requires the user to fill it in.). To resolve this, we developed GRAMMFORMER, a grammar-guided model. It generates code by following the structure of the context-free grammar (CFG) defining the programming language syntax, iteratively expanding nonterminal symbols. Crucially, it can choose to not expand some non-terminal symbols, which can then be presented as to users. In traditional grammar-based generation of text (Cohen et al., 2012) or code (Maddison & Tarlow, 2014; Yin & Neubig, 2017; Allamanis & Sutton, 2014; Bielik et al., 2016), the CFG is followed by sequentially expanding the left-most, bottom-most non-terminal symbol, using one of the production rules of the grammar. GRAMMFORMER changes this and instead selects the non-terminal symbol to expand, if any. An example generation is shown in Fig. 2.
Probabilistic Model A CFG is defined as a tuple (Σ,N , S,R) where Σ is a set of terminal symbols, N is a set of non-terminal symbols, S ∈ N is the root symbol andR is a set of production rules. We denote non-terminals as ⟨NonTerminalName⟩. GRAMMFORMER can be viewed as a sequenceto-sequence model transforming x = x0,x1, ...,xn into a new sequence in which one non-terminal symbol xi has been replaced by a new sequence of new symbols, according to a production rule of the grammar. Examples of such sequences and rewrites are shown in Fig. 2.
GRAMMFORMER does this rewriting in two steps. First, a non-terminal selector model Ps selects a non-terminal in x to expand and then the non-terminal expansion model Pe determines how to expand it. To define Ps, letN(x) = {i ∣ xi ∈ N }∪{⦸} denote the set of non-terminal positions in x and a special “stop expansion” ⦸ symbol. Conditioned on x, Ps produces a probability distribution over N(x). In turn, Pe is conditioned on x and a position i ∈ N(x) and models a probability distribution over expansion sequences u ∈ (Σ ∪ N )∗. Note that factorising GRAMMFORMER into two models Ps and Pe is an important modelling decision: how to best expand a non-terminal is entirely separated from predicting whether a hole should be introduced. These two concepts are intermixed in standard (sequence) decoders. In practice, we define both models using neural architectures with partially shared parameters, as discussed below.
Alg. 1 shows a high-level description of GRAMMFORMER, in which Ps and Pe are used repeatedly to select and expand non-terminals (not necessarily the left-most one), until none are left or the Ps indicates that expansion should stop. Here, NONTERMINALSTOHOLES(⋅) replaces all remaining non-terminal symbols with a hole . Note that GRAMMFORMER is not context-free, taking into account the whole input sequence when expanding a non-terminal. Second, in contrast to many grammar-based methods (Yin & Neubig, 2017; Bielik et al., 2016), any non-terminal can be expanded at each step. Finally, Pe is not directly constrained to follow the production rule set R, but can generate any sequence. In practice, it learns to follow to the rules of R from the data, but this flexibility is important for handling string literals and argument tuples of variable length.
Neural Model To implement Ps and Pe, we use a shared encoder module that computes a representation of the input sequence x = x0, . . . ,xn as vectors e0, . . . , en, ei ∈ R
D, where D is a hyperparameter. Our encoder module is a Transformer (Vaswani et al., 2017), given the impressive results of transformer-based models in NLP and code (Feng et al., 2020). Other architectures (RNNs, 1D-CNNs, Transformer variants) would be suitable, but we leave their study for future work.
Ps is implemented similar to a pointer network on top of this encoder module, i.e.
Ps(i ∣ x) = softmax i∈N(x) (f(ei)) ,
where f is a learnable feed-forward neural network. For our purposes, we define e⦸ as the representation of the special start symbol [CLS] used in our Transformer encoder.
The expansion model Pe follows a standard autoregressive decoder formulation, i.e.
Pe(u ∣ x, i) = m
∏ j=1 Pdec(uj ∣ e0, . . . , en, i,u<j).
We implement Pdec as a (causal) relational Transformer decoder, similar to Wang et al. (2019). Relational transformers augment the attention mechanism by incorporating predefined relationships among elements; attention scores are then biased by learnable weights for each relation. In GRAMMFORMER, we only use a single relation, connecting each token to the expanded non-terminal token xi, to help the model focus on the token it needs to generate an expansion for.
Objective Due to the lack of supervised data, we employ reinforcement learning to train GRAMMFORMER. We use our reward function from Eq. 1 to evaluate the quality of the output of the full model. We use self-critical policy gradient training as in Eq. 2 and minimise
L(x,y∗) = (r(ŷ,y∗) − r̃(x)) ⋅ T
∑ t=0 (− logPs (i(t) ∣ x(t)) − I (i(t) ≠ ⦸) ⋅ logPe ((u (t) ⊚i(t) )∗ ∣ x(t), i(t))) .
(3) Here, r̃(x) is the reward achieved by the snapshots of Ps and Pe that achieved the best score so far. The rest of the objective follows the iterations of the loop in Alg. 1, where t is the iteration index, ŷ is the predicted sketch, y∗ is the ground-truth sequence of terminals, and I(⋅) is the indicator function.
Pretraining As in the sequence model, directly training with the RL objective Eq. 3 is computationally intensive due to the sampling requirement. We again use a pretraining strategy. First, we train Pe to expand every non-terminal, independently of the expansion order learned by Ps. To do this, we use the input training examples and follow Alg. 1, but instead of sampling from Ps(⋅), we sample i(t) from a uniform distribution over the non-terminals in x(t), Ñ(x(t)) = {i ∣ xi ∈ N }. This yields sequences of intermediate sketches x(t) for each example. Furthermore, for each x(t), we compute the ground-truth expansion (u(t)⊚i )
∗ for all non-terminals i ∈ Ñ(x(t)). We can then pretrain Pe using the supervised objective
Lpre, e (x(t), (u (t) ⊚i ) ∗ i∈Ñ(x(t))) =
1
∣Ñ(x(t))∣ ⋅ ∑ i∈Ñ(x(t)) − logPe ((u (t) ⊚i(t) )∗ ∣ x(t), i) ,
i.e. the negative log-likelihood of the correct expansion for all non-terminals in x(t). This computation is more computationally efficient compared to the one in Eq. 3 since the cost of encoding x(t) is amortised across all potential expansions and no sampling is required. Once Pe is pretrained, we pretrain Ps. For this, we fix the weights of the shared encoder module, and optimise only the remaining parameters of Ps through Eq. 3. Once we have a pretrained both models, we then fine-tune all model weights end-to-end, using Eq. 3.
Optimisation: Grammar Flattening Following the formal grammar of a programming language commonly introduces tedious expansions. For example, the Python non-terminal ⟨Call⟩ is always expanded to ⟨Expr⟩(⟨ArgumentList⟩), and the C# non-terminal ⟨NotEqualOp⟩ is always expanded to the terminal !=. We “flatten” the grammar by replacing non-terminals such as ⟨Call⟩ and ⟨NotEqualOp⟩ with all their possible expansions. In Appx. C we provide the list of the flattened non-terminals. Note that if we repeated this process for all non-terminals except from the starting symbol S, GRAMMFORMER would degenerate into a standard encoder-decoder model.
Beam Search At test time, we employ a two-step beam search, and replace sampling from Ps and Pe with their top-ν outputs, keeping a beam of size k. First, for each x
(t) in the beam, we compute Ps and select the top-m non-terminal positions to expand. For each of those m positions, we sample the top-n expansions from Pe using a standard beam search. We compute the likelihood of all k ⋅ n ⋅m results, and then keep only the top-k. This process (detailed in Appx. E) is similar to a standard beam search but takes into account that two submodels are used.
Computational Cost GRAMMFORMER’s ability to predict sketches comes with additional computational cost compared to standard transformer encoder-decoders: at each iteration of the loop in Alg. 1 x(t) changes, Ps and Pe must be recomputed. This means that the encoder-decoder runs once on each partial sequence, in contrast to left-to-right causal generation, in which intermediate results can be re-used. Future work may consider selecting more than one element to expand from N(x(t)) at each step, reducing the expansion steps, similar to Welleck et al. (2019); Stern et al. (2019).

heading: 3 EVALUATION
text: To empirically evaluate our model’s ability to predict useful completions, we use REGEXACC and ROUGE. Note that we measure these on the generated sequence, i.e. we ignore the context tokens.
Datasets To collect a dataset, we clone all non-fork repositories with more than 20 stars on GitHub that have C# or Python as their top language. Then, we deduplicate the corpus using the method of Allamanis (2019); Lopes et al. (2017). Finally, we parse all files into a syntax tree using Treesitter, ignoring any files that cannot be parsed using the v0.19.0 grammar definitions. Finally, we split the files into 70-10-20 train-validation-test. To create (pre-)training examples, i.e. inputs to Alg. 1, we search the syntax tree of each file and for each ⟨SimpleStatement⟩ non-terminal create an example. The syntax tree rooted at the ⟨SimpleStatement⟩ non-terminal is then used to get the ground-truth expansions during pre-training and the ground-truth expansion y∗. For our test set, we randomly sample a ⟨SimpleStatement⟩ non-terminal for each file to evaluate and obtain 318K (resp. 362K) examples for C# (resp. Python). For each example, x is the 200 terminal tokens before the ⟨SimpleStatement⟩ non-terminal. More details about the dataset can be found in Appx. B.
Baselines Since we are not aware of any prior model that targets code completion with sketches, we consider two Transformer-based baselines. We consider both the sequence-to-sequence setting using separate encoder and decoder models (Vaswani et al., 2017) as well as the language modelling setting (where there is no distinction between encoder and decoder). We refer to these as “L → R” and “LM”. We use “L → R” to denote a standard Transformer encoder-decoder model (Vaswani et al., 2017) used in sequence-to-sequence tasks. Additionally, we consider “L → R + ⦸” and “LM +⦸”, which are trained to stop generation by inserting a final token that captures any suffix. Note that this models can only generate sketches that are prefixes of the target completion, i.e. it corresponds to a standard token-level generative model with a learnable stopping ability. To train this model, we use self-critical policy gradient training (as in Eq. 2).
Model Training We provide the training details for all experiments. Most of our models use a 6-layer Transformer as encoder and 6-layer Transformer as decoder, each with a hidden dimension of 768 and 12 attention heads, with the exception of the LM model (and its variations), which uses a single 12-layer Transformer, to match the number of parameters of the other models. We set the intermediate dimension of each Transformer layer as 3072 and use 3 fully-connected layers with 3072, 768 and 1 hidden sizes as the feed-forward neural network f in the selector model Ps. The vocabulary is constructed using byte-pair encoding (Sennrich et al., 2015) and the vocabulary size is 25 000. We set max length of input and output sequences as 512 and 64, respectively. We train the model with Adam optimiser using a learning rate of 2e-5 and batch size 4 096. We used automatic mix precision. Training used 64 NVIDIA Tesla P100 with 16GB memory for 10 days. For beam search we use k = 5, n = 1 and m =∞, i.e. we consider all non-terminals in each x(t). We selected these during early experiments as a reasonable trade-off between speed and predictive performance.
Results Tbl. 1 shows the results for all considered models. For both Python and C#, GRAMMFORMER outperforms the baseline methods in terms of REGEXACC, showing that the grammarbased generation can create better sketches compared to simpler methods. Note that althoughL→ R has a comparable or better ROUGE score, it does substantially worse than GRAMMFORMER with respect to REGEXACC, meaning that the predictions are “similar” but the sketches contain errors (i.e. do not match the ground-truth). This means that if a code completion system suggested the full output of L → R, the user would have to pause and correct the suggestion more frequently. On the other hand, L→ R+⦸ improves over L→ R in terms of REGEXACC but has a worse ROUGE and generates significantly shorter suggestions (5.3 vs. 7.5 tokens-long for C#). This is expected since
L→ R+⦸ is trained to be more “conservative” (i.e. avoid incorrect suggestions) but is also unable to introduce holes beyond the last generated token. Finally, we can see that while GRAMMFORMER already performs well after our pre-training procedure, we can further improve its performance with our fine-tuning technique. We believe that this is because when Ps and Pe are trained jointly, they co-adapt: some of the capacity of the shared encoder module that is used to make predictions for hard-to-expand non-terminals is “freed” since Ps learns to not expand them.
Fig. 3 shows how the length of the generated code sketch relates to the length of the ground truth expression. While the differences between models are small for short target sequences, GRAMMFORMER generates substantially longer suggestions than other models when more complex suggestions are required. In particular, the L → R + ⦸ model generates very short suggestions, as it is trained to stop generation whenever it reaches a point at which it is uncertain about the next token.
Fig. 4 in turn shows how often the suggested sketch was correct dependent on the length of the ground truth token sequence. Here, L→ R+⦸ does best because it generates the shortest (i.e., least determined) predictions, which is exactly the trade-off captured by our REGEXACC metric. Of the models that generate longer suggestions, GRAMMFORMER clearly does best, with the improvement becoming more pronounced with the length of the target sequence. Note that the performance of the models on C# is generally better compared to the performance in Python. We believe that this has to do with the grammar of each language and the patterns it induces within the developer’s code. Casalnuovo et al. (2019); Karampatsis et al. (2020) have observed a similar phenomenon on the perplexity across (standard left-to-right) language models for different programming languages.
Ablations Next, we look into ablations of GRAMMFORMER and reason about how its components perform. To this end, Tbl. 2 shows the performance of different model variants on the C# dataset. First, we analyse the effect of the selector model Ps. To this end, we consider two ablations. The first is the “random expansion” model, in which the non-terminal token to expand is sampled uniformly at random from the full set of non-terminal symbols, and which hence does not stop expansion as long as any holes are remaining. This is effectively GRAMMFORMER after our pre-training procedure for Pe. This model achieves the best ROUGE score, but a relatively bad REGEXACC, as it is forced to generate a prediction even when it is very uncertain. The second ablation, a “fixed threshold”
model is similar to our first ablation, but stops expansion when the probability of the generated x (t) falls below a threshold. We choose this threshold on the validation set. This model makes shorter, but more accurate sketch predictions compared to the “random expansion”, but is worse than GRAMMFORMER. These two ablations demonstrate that our learned Ps is useful.
Second, we consider the effect of using different reward functions r(⋅) in the training of GRAMMFORMER. Concretely, whereas we use the mean of REGEXACC and ROUGE in GRAMMFORMER, we now consider using only a single of these two metrics. As expected, the results on the corresponding metric improve, with a substantial cost in the other metric. Concretely, using only REGEXACC leads to significantly shorter predictions with a low ROUGE score. We believe that this is because REGEXACC is a strict metric, returning 0 if the sketch does not match, which leads to sparse rewards and makes the resulting model more conservative at expanding non-terminals.
Finally, to evaluate the benefit of the grammar-guided decoder, we consider a variant of GRAMMFORMER that does not allow the introduction of and instead has continue expansion until no non-terminals exist anymore. This variant can be compared to L → R, which also cannot stop or introduce tokens. Our ablation shows that there is substantial benefit in using grammar-guided decoding, leading both to longer predictions as well as more correct ones.

heading: 3.1 QUALITATIVE EVALUATION
text: Having observed the quantitative results, we now turn our attention to a qualitative look at the results and show some cherry-picked examples that illustrate desired and undesired behaviours of GRAMMFORMER and the baselines, where we also include the suggestions of the GitHub Copilot system GitHub (2021). Fig. 1 shows an example and eleven more are shown in Appx. A. Fig. 1 illustrates the importance of generating sketches instead of concrete sequences of terminal tokens: oftentimes, the code context does not provide sufficient information about the user’s intent. Sketchgenerating models can offer more informative suggestions given the partial intent.
Of course, GRAMMFORMER also makes mistakes. For example, GRAMMFORMER and L→ R+⦸ are sometimes “too” conservative (e.g. Fig. 15 in Appx. A) generating holes where L→ R generates fully concrete completions. This suggests future research opportunities for better calibration of Ps.
Finally, a pure language modelling approach to code completion will always be insufficient. For example, user-defined types and rare APIs cannot be predicted by a language model, since‘’ the APIs cannot be known during training (Fig. 7 and Fig. 17 in Appx. A). Researching methods to scalably introduce information from static analyses and additional context may alleviate this.

heading: 4 RELATED WORK
text: One of the successful applications of LMCs is code completion (Svyatkovskiy et al., 2019; Karampatsis et al., 2020). Transformer LMs have shown exceptional performance at the task being able to predict relatively long code sequences (Svyatkovskiy et al., 2020; Chen et al., 2021). Grammarbased code completion and generation has been researched with neural (Maddison & Tarlow, 2014; Yin & Neubig, 2017; Kim et al., 2021) and non-neural models (Bielik et al., 2016), always expanding the left-most, bottom-most non-terminal. In contrast to GRAMMFORMERs, all these models target the generation of complete code without the ability to create sketches. R3NN (Parisotto et al., 2017) generates only complete programs of a simple string transformation DSL but expands the non-terminal with the highest confidence, instead of the left-most, bottom-most one, similar to GRAMMFORMER. In contrast to the aforementioned models, GRAMMFORMER does not maintain an explicit tree representation but instead uses the sequences of leaves in the generation tree.
Sketch-like ideas appear in NLP such as the coarse-to-fine semantic parsing of Dong & Lapata (2018) and chat-bots of Shum et al. (2019). However, sketches are extracted deterministically to create a supervised dataset. Similarly, SketchAdapt (Nye et al., 2019) uses a sequence model to generate sketches for small functional programs of a simple DSL towards speeding-up enumerative program synthesis from input-output examples. SketchAdapt is also trained as a supervised sketch generator. A supervised corpus is created by enumerating all possible sketches and selecting the one with the highest-probability and within a heuristically computed time budget. In GRAMMFORMER domain, enumerating all sketches is computationally intractable due to the complexity of generalpurpose programming languages while no similar heuristic exists for code completion.
Recently, sequence generation approaches beyond the left-to-right paradigm have been proposed (Welleck et al., 2019; Stern et al., 2019; Gu et al., 2019; Ford et al., 2018; Lee et al., 2018; Shah et al., 2018), usually by considering generation as an procedure that iteratively changes or extends a sequence. These models often aim in speeding-up inference or allowing models to figure a better order for full sentence generation. However, since these models focus on natural language and since its grammar is not defined a priori, these methods do not follow a grammar that limits the space for sketch generation. Additionally, these generate full utterances of text, rather than sketches.
A related concept is learning to abstain (Ziyin et al., 2019) where a model learns to predict a “don’t know”. This resembles the stop symbol “⦸” with the difference that GRAMMFORMER employs RL to learn Ps for a sequential problem rather than learning to abstain for a single-step classification.

heading: 5 DISCUSSION & CONCLUSIONS
text: In this work, we presented GRAMMFORMER, a generative model of code that goes beyond standard left-to-right generation and is able to generate sketches, i.e. snippets of code with holes. Designing generative machine learning models with such abilities is important towards facilitating better collaboration between machine learning models and their human users.
While we showed that GRAMMFORMER performs better than alternatives in sketch generation, there are still many research opportunities. First, larger transformers will most probably yield better results, as shown in the literature. Second, although we used REGEXACC as an evaluation metric, human studies to evaluate it are needed. Such studies, similar to those in machine translation and summarization, can yield more informed r(⋅) and improved user experiences. Second, although we focused on programming languages, modelling natural language also seems possible. Finally, we treated programming languages as a sequence of terminals and non-terminals, ignoring the structure imposed by code’s semantics, e.g. data and control flow. Explicitly providing x‘the code’s structure, e.g. with relational transformers (Hellendoorn et al., 2019) may further improve GRAMMFORMER.

heading: ACKNOWLEDGMENTS
text: The authors would like to thank Alex Polozov for useful discussions. We also thank Patrick Fernandes, Szymon Malik, and Guilherme Ilunga for working on earlier modeling ideas on sketch generation. Although those were unsuccessful, they provided the inspiration for this work.

heading: A GENERATED SAMPLES
text: Fig. 5 and Fig. 6 show two examples from our dataset along with the ground-truth and the sequence of expansions performed by GRAMMFORMER. Fig. 7-13 show example generations by GRAMMFORMER and the baseline models L → R and L → R + ⦸. The parentheses in red indicate the REGEXACC score for each suggestion. For the L → R + ⦸ baseline the special non-terminal <suffix> is added to indicate that a hole is introduced at the end of the left-to-right generation. Finally Fig. 15-17 show example generations where GRAMMFORMER make mistakes. A discussion for each of those sample is found at the caption of each figure.

heading: B DATASET STATISTICS
text: Some statistics about the datasets used throughout this work are shown in Tbl. 3

heading: C FLATTENED NON-TERMINALS
text: The non-terminals in Tbl. 4 are always expanded and are not considered as non-terminals. Most of these non-terminals have always the same children (terminals or non-terminals), representing a single CFG rule. By flattening those non-terminals the depth of tree is reduced (and hence the number of loops needed in Alg. 1).

heading: D UNDERSTANDING REGEXACC
text: Since REGEXACC is a new metric, we include two deterministic ways of introducing sketches in Tbl. 5. First, if all literals (strings, numeric) are replaced with a hole, we see that a high REGEXACC
is achieved. In contrast, replacing both identifiers and literals (leaving “just” parentheses, brackets, dots, etc.) we get an easy “lower-bound”. Note how C# — which is syntactically more verbose — achieves a better score, compared to Python. In Tbl. 6, we show some example sketches and their associated REGEXACC score.

heading: E BEAM SEARCH
text: Alg. 2 presents the beam search used in GRAMMFORMER.
Algorithm 2 GRAMMFORMER beam search, given an input sequence x0. b← {(x0, 0,false)} ▷ Initialize Beam (state, logprob, isDone) while ∃(x, p, isDone) ∈ b with isDone = false do ▷ While beam contains incomplete generations
b ′ ← {} for (x, p, isDone) ∈ b do ▷ For each sample in beam if isDone then ▷ If suggestion is complete
b ′ ← b ′ ∪ {(x, p, isDone)} ▷ No operation, beam is complete continue for i ∈ TOPM(Ps(i∣x, N(x))) do ▷ Get top-m non-terminal positions ps ← logPs(i∣x, N(x)) if i = ⦸ then
b ′ ← b ′ ∪ {(x, p + ps,true)} ▷ Stop Expansion else
for y ∈ TOPN(Pe(y∣x, i)) do ▷ Beam search on y yields n candidates pe ← Pe(y∣x, i) b ′ ← b
′ ∪ {(x<i ∶∶ y ∶∶ x>i), p + ps + pe,false)} ▷ Expand xi b← TOPK(b′) ▷ Prune Candidates and keep top k
return b

Review summaries:
This work proposes, GRAMMAFORMER, a transformer model for generating code with "holes" inserted in places where a model is uncertain. GRAMMAFORMER is trained on code completion task for C# and Python. The model generates 10-50% more accurate completions and 37-50% longer sketches.

The paper presents a new model for code completion which allows the model to completions with “holes” that are inserted in places where the model is uncertain. The idea of generating “holes” to enable skipping over “hard parts” of the prediction is novel and interesting. To realize this idea, the authors present a model that generates partial syntax trees where some of the non-terminals may be left without further expansion.  The model is evaluated on C# and Python programs and is shown to outperform existing techniques. The also paper presents a thorough ablation study.