• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.autofuzz;
16 
17 import java.util.Stack;
18 import java.util.stream.Collectors;
19 
20 public class AutofuzzCodegenVisitor {
21   private final Stack<Group> groups = new Stack<>();
22   private int variableCounter = 0;
23 
AutofuzzCodegenVisitor()24   AutofuzzCodegenVisitor() {
25     init();
26   }
27 
init()28   private void init() {
29     pushGroup("", "", "");
30   }
31 
pushGroup(String prefix, String delimiter, String suffix)32   public void pushGroup(String prefix, String delimiter, String suffix) {
33     groups.push(new Group(prefix, delimiter, suffix));
34   }
35 
pushElement(String element)36   public void pushElement(String element) {
37     groups.peek().push(element);
38   }
39 
popElement()40   public void popElement() {
41     groups.peek().pop();
42   }
43 
popGroup()44   public void popGroup() {
45     if (groups.size() == 1) {
46       throw new AutofuzzError(
47           "popGroup must be called exactly once for every pushGroup: " + toDebugString());
48     }
49     pushElement(groups.pop().toString());
50   }
51 
generate()52   public String generate() {
53     if (groups.size() != 1) {
54       throw new AutofuzzError(
55           "popGroup must be called exactly once for every pushGroup: " + toDebugString());
56     }
57     return groups.pop().toString();
58   }
59 
addCharLiteral(char c)60   public void addCharLiteral(char c) {
61     pushElement("'" + escapeForLiteral(Character.toString(c)) + "'");
62   }
63 
addStringLiteral(String string)64   public void addStringLiteral(String string) {
65     pushElement('"' + escapeForLiteral(string) + '"');
66   }
67 
uniqueVariableName()68   public String uniqueVariableName() {
69     return String.format("autofuzzVariable%s", variableCounter++);
70   }
71 
escapeForLiteral(String string)72   private String escapeForLiteral(String string) {
73     // The list of escape sequences is taken from:
74     // https://docs.oracle.com/javase/tutorial/java/data/characters.html
75     return string.replace("\t", "\\t")
76         .replace("\b", "\\b")
77         .replace("\n", "\\n")
78         .replace("\r", "\\r")
79         .replace("\f", "\\f")
80         .replace("\f", "\\f")
81         .replace("\"", "\\\"")
82         .replace("'", "\\'")
83         .replace("\\", "\\\\");
84   }
85 
toDebugString()86   private String toDebugString() {
87     return groups.stream()
88         .map(group -> group.elements.stream().collect(Collectors.joining(", ", "[", "]")))
89         .collect(Collectors.joining(", ", "[", "]"));
90   }
91 
92   private static class Group {
93     private final String prefix;
94     private final String delimiter;
95     private final String suffix;
96     private final Stack<String> elements = new Stack<>();
97 
Group(String prefix, String delimiter, String suffix)98     Group(String prefix, String delimiter, String suffix) {
99       this.prefix = prefix;
100       this.delimiter = delimiter;
101       this.suffix = suffix;
102     }
103 
push(String element)104     public void push(String element) {
105       elements.push(element);
106     }
107 
pop()108     public void pop() {
109       elements.pop();
110     }
111 
112     @Override
toString()113     public String toString() {
114       return elements.stream().collect(Collectors.joining(delimiter, prefix, suffix));
115     }
116   }
117 }
118