or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-types.mdcode-generation.mdcode-specifications.mdfile-management.mdindex.mdtype-system.md

code-generation.mddocs/

0

# Code Generation

1

2

Template-based code generation system and utilities for generating method bodies, initializers, and managing identifier names. This system provides safe string-based code generation with proper escaping and formatting.

3

4

## Capabilities

5

6

### CodeBlock

7

8

Template-based code generation using format strings with type-safe placeholders. Handles proper Java syntax, escaping, and formatting automatically.

9

10

```java { .api }

11

/**

12

* Template-based code generation with type-safe placeholders

13

*/

14

public final class CodeBlock {

15

// Static factory methods

16

public static CodeBlock of(String format, Object... args);

17

public static CodeBlock join(Iterable<CodeBlock> codeBlocks, String separator);

18

public static Collector<CodeBlock, ?, CodeBlock> joining(String separator);

19

public static Collector<CodeBlock, ?, CodeBlock> joining(String separator, String prefix, String suffix);

20

public static Builder builder();

21

22

// Instance methods

23

public boolean isEmpty();

24

public Builder toBuilder();

25

public boolean equals(Object o);

26

public int hashCode();

27

public String toString();

28

}

29

```

30

31

**Template Placeholders:**

32

33

- `$L` - **Literals** - Direct substitution without escaping

34

- `$S` - **Strings** - Adds quotes and escapes special characters

35

- `$T` - **Types** - Type references with automatic import management

36

- `$N` - **Names** - References to other generated elements

37

38

**Usage Examples:**

39

40

```java

41

// Literal substitution ($L)

42

CodeBlock literals = CodeBlock.of("int count = $L", 42);

43

// Result: int count = 42

44

45

CodeBlock booleanLiteral = CodeBlock.of("boolean flag = $L", true);

46

// Result: boolean flag = true

47

48

// String substitution ($S)

49

CodeBlock strings = CodeBlock.of("String message = $S", "Hello, World!");

50

// Result: String message = "Hello, World!"

51

52

CodeBlock escapedString = CodeBlock.of("String path = $S", "C:\\Users\\Name");

53

// Result: String path = "C:\\Users\\Name"

54

55

// Type substitution ($T)

56

CodeBlock types = CodeBlock.of("$T list = new $T<>()", List.class, ArrayList.class);

57

// Result: List list = new ArrayList<>();

58

// Automatically adds imports for List and ArrayList

59

60

// Name substitution ($N)

61

MethodSpec helper = MethodSpec.methodBuilder("helperMethod").build();

62

CodeBlock names = CodeBlock.of("$N()", helper);

63

// Result: helperMethod()

64

65

// Combined usage

66

CodeBlock combined = CodeBlock.of(

67

"$T.out.println($S + $N() + $L)",

68

System.class, "Result: ", helper, 42

69

);

70

// Result: System.out.println("Result: " + helperMethod() + 42)

71

```

72

73

### CodeBlock.Builder

74

75

Builder for constructing complex code blocks with multiple statements and control flow.

76

77

```java { .api }

78

/**

79

* Builder for constructing complex code blocks

80

*/

81

public static final class Builder {

82

// Adding code

83

public Builder add(String format, Object... args);

84

public Builder addNamed(String format, Map<String, ?> arguments);

85

public Builder add(CodeBlock codeBlock);

86

87

// Statements and control flow

88

public Builder addStatement(String format, Object... args);

89

public Builder beginControlFlow(String controlFlow, Object... args);

90

public Builder nextControlFlow(String controlFlow, Object... args);

91

public Builder endControlFlow();

92

public Builder endControlFlow(String controlFlow, Object... args);

93

94

// Indentation

95

public Builder indent();

96

public Builder unindent();

97

98

// Building

99

public CodeBlock build();

100

}

101

```

102

103

**Usage Examples:**

104

105

```java

106

// Simple statements

107

CodeBlock statements = CodeBlock.builder()

108

.addStatement("int x = $L", 10)

109

.addStatement("int y = x * $L", 2)

110

.addStatement("$T.out.println($S + y)", System.class, "Result: ")

111

.build();

112

113

// Control flow - if/else

114

CodeBlock ifElse = CodeBlock.builder()

115

.beginControlFlow("if ($N != null)", someVariable)

116

.addStatement("return $N.toString()", someVariable)

117

.nextControlFlow("else")

118

.addStatement("return $S", "null")

119

.endControlFlow()

120

.build();

121

122

// Loops

123

CodeBlock forLoop = CodeBlock.builder()

124

.addStatement("$T<$T> result = new $T<>()", List.class, String.class, ArrayList.class)

125

.beginControlFlow("for (int i = 0; i < $N.size(); i++)", items)

126

.addStatement("$T item = $N.get(i)", String.class, items)

127

.beginControlFlow("if (item != null)")

128

.addStatement("result.add(item.toUpperCase())")

129

.endControlFlow()

130

.endControlFlow()

131

.addStatement("return result")

132

.build();

133

134

// Try-catch blocks

135

CodeBlock tryCatch = CodeBlock.builder()

136

.beginControlFlow("try")

137

.addStatement("return processData(input)")

138

.nextControlFlow("catch ($T e)", IOException.class)

139

.addStatement("$T.error($S, e)", Logger.class, "Failed to process data")

140

.addStatement("throw new $T($S, e)", RuntimeException.class, "Processing failed")

141

.endControlFlow()

142

.build();

143

144

// Switch statements

145

CodeBlock switchBlock = CodeBlock.builder()

146

.beginControlFlow("switch (type)")

147

.add("case $S:\n", "STRING")

148

.indent()

149

.addStatement("return processString(value)")

150

.unindent()

151

.add("case $S:\n", "INTEGER")

152

.indent()

153

.addStatement("return processInteger(value)")

154

.unindent()

155

.add("default:\n")

156

.indent()

157

.addStatement("throw new $T($S + type)", IllegalArgumentException.class, "Unknown type: ")

158

.unindent()

159

.endControlFlow()

160

.build();

161

```

162

163

### Advanced CodeBlock Patterns

164

165

#### Named Arguments

166

167

For complex templates with many parameters:

168

169

```java

170

Map<String, Object> args = new HashMap<>();

171

args.put("className", "UserService");

172

args.put("fieldName", "userRepository");

173

args.put("methodName", "findUser");

174

args.put("paramType", Long.class);

175

176

CodeBlock namedTemplate = CodeBlock.builder()

177

.addNamed("public class $className:T {\n", args)

178

.addNamed(" private final $fieldType:T $fieldName:L;\n",

179

Map.of("fieldType", UserRepository.class, "fieldName", "userRepository"))

180

.addNamed(" \n")

181

.addNamed(" public $returnType:T $methodName:L($paramType:T id) {\n",

182

Map.of("returnType", User.class, "methodName", "findUser", "paramType", Long.class))

183

.addNamed(" return $fieldName:L.findById(id);\n", args)

184

.addNamed(" }\n")

185

.addNamed("}\n")

186

.build();

187

```

188

189

#### Positional Arguments

190

191

For reusing arguments in different positions:

192

193

```java

194

CodeBlock positional = CodeBlock.builder()

195

.add("$2T $1L = new $2T($3S)", "message", String.class, "Hello")

196

.build();

197

// Result: String message = new String("Hello")

198

```

199

200

#### Joining Code Blocks

201

202

```java

203

List<CodeBlock> statements = Arrays.asList(

204

CodeBlock.of("first()"),

205

CodeBlock.of("second()"),

206

CodeBlock.of("third()")

207

);

208

209

// Join with comma separator

210

CodeBlock joined = CodeBlock.join(statements, ", ");

211

// Result: first(), second(), third()

212

213

// Using stream collectors

214

CodeBlock streamJoined = statements.stream()

215

.collect(CodeBlock.joining(", ", "Arrays.asList(", ")"));

216

// Result: Arrays.asList(first(), second(), third())

217

```

218

219

### NameAllocator

220

221

Utility for generating unique, valid Java identifiers and managing name conflicts.

222

223

```java { .api }

224

/**

225

* Utility for allocating unique Java identifier names

226

*/

227

public final class NameAllocator implements Cloneable {

228

// Constructor

229

public NameAllocator();

230

231

// Name allocation

232

public String newName(String suggestion);

233

public String newName(String suggestion, Object tag);

234

public String get(Object tag);

235

236

// Static utility

237

public static String toJavaIdentifier(String suggestion);

238

239

// Cloning

240

public NameAllocator clone();

241

}

242

```

243

244

**Usage Examples:**

245

246

```java

247

// Basic name allocation

248

NameAllocator nameAllocator = new NameAllocator();

249

250

String name1 = nameAllocator.newName("count"); // "count"

251

String name2 = nameAllocator.newName("count"); // "count_"

252

String name3 = nameAllocator.newName("count"); // "count__"

253

254

// Tagged name allocation

255

nameAllocator.newName("value", "field");

256

nameAllocator.newName("value", "parameter"); // Different tag, same name allowed

257

258

String fieldName = nameAllocator.get("field"); // "value"

259

String paramName = nameAllocator.get("parameter"); // "value_"

260

261

// Java identifier conversion

262

String validName1 = NameAllocator.toJavaIdentifier("class"); // "class_"

263

String validName2 = NameAllocator.toJavaIdentifier("2invalid"); // "_2invalid"

264

String validName3 = NameAllocator.toJavaIdentifier("with-dash"); // "with_dash"

265

String validName4 = NameAllocator.toJavaIdentifier("with space"); // "with_space"

266

267

// Practical usage in code generation

268

NameAllocator allocator = new NameAllocator();

269

270

// Reserve Java keywords

271

allocator.newName("class", "reserved");

272

allocator.newName("interface", "reserved");

273

274

// Generate method parameters

275

String userParam = allocator.newName("user", "param");

276

String contextParam = allocator.newName("context", "param");

277

278

// Generate local variables

279

String resultVar = allocator.newName("result", "local");

280

String tempVar = allocator.newName("temp", "local");

281

282

MethodSpec method = MethodSpec.methodBuilder("processUser")

283

.addParameter(User.class, userParam)

284

.addParameter(Context.class, contextParam)

285

.addStatement("$T $N = new $T()", ProcessResult.class, resultVar, ProcessResult.class)

286

.addStatement("$T $N", Object.class, tempVar)

287

.addStatement("// Use allocated names: $N, $N, $N, $N",

288

userParam, contextParam, resultVar, tempVar)

289

.build();

290

```

291

292

### Code Generation Best Practices

293

294

#### Safe String Building

295

296

```java

297

// Avoid direct string concatenation

298

// BAD: "return " + expression + ";"

299

// GOOD: Use CodeBlock templates

300

CodeBlock safeReturn = CodeBlock.of("return $L", expression);

301

302

// Proper escaping for strings

303

CodeBlock properString = CodeBlock.of("String message = $S", userInput);

304

// Automatically handles quotes and escaping

305

```

306

307

#### Type-Safe Templates

308

309

```java

310

// Type references ensure proper imports

311

CodeBlock typeSafe = CodeBlock.of(

312

"$T<$T> list = $T.asList($L, $L, $L)",

313

List.class, String.class, Arrays.class,

314

"first", "second", "third"

315

);

316

317

// Generates proper imports and code:

318

// import java.util.List;

319

// import java.util.Arrays;

320

// List<String> list = Arrays.asList("first", "second", "third");

321

```

322

323

#### Complex Code Generation

324

325

```java

326

// Building a complete method with complex logic

327

public MethodSpec generateProcessorMethod(List<String> operations) {

328

NameAllocator names = new NameAllocator();

329

String inputParam = names.newName("input", "param");

330

String resultVar = names.newName("result", "local");

331

332

CodeBlock.Builder body = CodeBlock.builder()

333

.addStatement("$T $N = new $T()", ProcessResult.class, resultVar, ProcessResult.class);

334

335

for (String operation : operations) {

336

String operationVar = names.newName(operation.toLowerCase(), "operation");

337

body.addStatement("$T $N = perform$L($N)",

338

Object.class, operationVar,

339

operation.substring(0, 1).toUpperCase() + operation.substring(1),

340

inputParam);

341

body.addStatement("$N.add($N)", resultVar, operationVar);

342

}

343

344

body.addStatement("return $N", resultVar);

345

346

return MethodSpec.methodBuilder("process")

347

.addModifiers(Modifier.PUBLIC)

348

.addParameter(Object.class, inputParam)

349

.returns(ProcessResult.class)

350

.addCode(body.build())

351

.build();

352

}

353

```

354

355

#### Error Handling in Code Generation

356

357

```java

358

// Generate proper exception handling

359

CodeBlock errorHandling = CodeBlock.builder()

360

.beginControlFlow("try")

361

.addStatement("return riskyOperation()")

362

.nextControlFlow("catch ($T e)", IOException.class)

363

.addStatement("$T.error($S, e)", Logger.class, "Operation failed")

364

.addStatement("throw new $T(e.getMessage(), e)", ProcessingException.class)

365

.nextControlFlow("finally")

366

.addStatement("cleanup()")

367

.endControlFlow()

368

.build();

369

```