postsvg 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -0
  3. data/CLAUDE.md +173 -0
  4. data/Gemfile +2 -3
  5. data/README.adoc +456 -179
  6. data/Rakefile +100 -0
  7. data/TODO.roadmap/00-architecture.md +139 -0
  8. data/TODO.roadmap/01-autoload-migration.md +39 -0
  9. data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
  10. data/TODO.roadmap/03-domain-model.md +66 -0
  11. data/TODO.roadmap/04-lexer.md +40 -0
  12. data/TODO.roadmap/05-parser.md +43 -0
  13. data/TODO.roadmap/06-graphics-state.md +45 -0
  14. data/TODO.roadmap/07-matrix-and-color.md +37 -0
  15. data/TODO.roadmap/08-svg-builder.md +51 -0
  16. data/TODO.roadmap/09-renderer.md +52 -0
  17. data/TODO.roadmap/10-visitor.md +58 -0
  18. data/TODO.roadmap/11-operator-coverage.md +103 -0
  19. data/TODO.roadmap/12-svg-domain.md +62 -0
  20. data/TODO.roadmap/13-translation-handlers.md +69 -0
  21. data/TODO.roadmap/14-ps-serializer.md +49 -0
  22. data/TODO.roadmap/15-cli-and-public-api.md +47 -0
  23. data/TODO.roadmap/16-specs.md +84 -0
  24. data/TODO.roadmap/17-docs-sync.md +47 -0
  25. data/TODO.roadmap/18-performance-and-determinism.md +47 -0
  26. data/TODO.roadmap/19-error-model.md +45 -0
  27. data/TODO.roadmap/20-font-and-text.md +46 -0
  28. data/TODO.roadmap/21-images.md +45 -0
  29. data/TODO.roadmap/22-forms-and-resources.md +25 -0
  30. data/TODO.roadmap/23-level2-level3.md +52 -0
  31. data/TODO.roadmap/24-ci-and-release.md +42 -0
  32. data/TODO.roadmap/README.md +77 -0
  33. data/docs/.gitignore +29 -0
  34. data/docs/CHANGELOG.md +114 -0
  35. data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
  36. data/docs/DEPLOYMENT.md +456 -0
  37. data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
  38. data/docs/DOCUMENTATION_PLAN.md +425 -0
  39. data/docs/FINAL_SUMMARY.md +657 -0
  40. data/docs/Gemfile +15 -0
  41. data/docs/README.md +327 -0
  42. data/docs/_config.yml +99 -0
  43. data/docs/advanced-topics.adoc +370 -0
  44. data/docs/api-reference/colors.adoc +705 -0
  45. data/docs/api-reference/converter.adoc +699 -0
  46. data/docs/api-reference/execution-context.adoc +1210 -0
  47. data/docs/api-reference/graphics-state.adoc +1070 -0
  48. data/docs/api-reference/interpreter.adoc +810 -0
  49. data/docs/api-reference/matrix.adoc +1179 -0
  50. data/docs/api-reference/path-builder.adoc +1284 -0
  51. data/docs/api-reference/postsvg-module.adoc +388 -0
  52. data/docs/api-reference/svg-generator.adoc +891 -0
  53. data/docs/api-reference/tokenizer.adoc +925 -0
  54. data/docs/api-reference.adoc +221 -0
  55. data/docs/architecture/command-registry.adoc +1191 -0
  56. data/docs/architecture/conversion-pipeline.adoc +746 -0
  57. data/docs/architecture/design-decisions.adoc +999 -0
  58. data/docs/architecture/generator-stage.adoc +1115 -0
  59. data/docs/architecture/graphics-state-model.adoc +1089 -0
  60. data/docs/architecture/interpreter-stage.adoc +1125 -0
  61. data/docs/architecture/parser-stage.adoc +1051 -0
  62. data/docs/architecture.adoc +354 -0
  63. data/docs/cli-reference/batch-command.adoc +616 -0
  64. data/docs/cli-reference/check-command.adoc +677 -0
  65. data/docs/cli-reference/cli-options.adoc +802 -0
  66. data/docs/cli-reference/convert-command.adoc +462 -0
  67. data/docs/cli-reference/version-command.adoc +296 -0
  68. data/docs/cli-reference.adoc +317 -0
  69. data/docs/concepts/conversion-pipeline.adoc +903 -0
  70. data/docs/concepts/coordinate-systems.adoc +836 -0
  71. data/docs/concepts/graphics-state.adoc +861 -0
  72. data/docs/concepts/path-operations.adoc +1076 -0
  73. data/docs/concepts/postscript-language.adoc +859 -0
  74. data/docs/concepts/svg-generation.adoc +937 -0
  75. data/docs/concepts.adoc +198 -0
  76. data/docs/contributing.adoc +443 -0
  77. data/docs/development.adoc +420 -0
  78. data/docs/faq.adoc +493 -0
  79. data/docs/getting-started/basic-usage.adoc +538 -0
  80. data/docs/getting-started/common-workflows.adoc +577 -0
  81. data/docs/getting-started/first-conversion.adoc +492 -0
  82. data/docs/getting-started/installation.adoc +534 -0
  83. data/docs/getting-started.adoc +94 -0
  84. data/docs/index.adoc +248 -0
  85. data/docs/optimization.adoc +196 -0
  86. data/docs/ps2svg_compatibility.adoc +149 -0
  87. data/docs/quick-reference.adoc +453 -0
  88. data/docs/sitemap.adoc +337 -0
  89. data/docs/troubleshooting.adoc +486 -0
  90. data/docs/validation.adoc +772 -0
  91. data/exe/postsvg +1 -0
  92. data/lib/postsvg/cli.rb +104 -57
  93. data/lib/postsvg/color.rb +132 -0
  94. data/lib/postsvg/errors.rb +68 -3
  95. data/lib/postsvg/format_number.rb +22 -0
  96. data/lib/postsvg/graphics_context.rb +80 -0
  97. data/lib/postsvg/graphics_stack.rb +43 -0
  98. data/lib/postsvg/model/literals/array.rb +41 -0
  99. data/lib/postsvg/model/literals/dictionary.rb +34 -0
  100. data/lib/postsvg/model/literals/hex.rb +37 -0
  101. data/lib/postsvg/model/literals/name.rb +40 -0
  102. data/lib/postsvg/model/literals/number.rb +36 -0
  103. data/lib/postsvg/model/literals/procedure.rb +41 -0
  104. data/lib/postsvg/model/literals/string.rb +30 -0
  105. data/lib/postsvg/model/literals.rb +19 -0
  106. data/lib/postsvg/model/operator.rb +58 -0
  107. data/lib/postsvg/model/operators/arithmetic.rb +264 -0
  108. data/lib/postsvg/model/operators/boolean.rb +182 -0
  109. data/lib/postsvg/model/operators/color.rb +74 -0
  110. data/lib/postsvg/model/operators/container.rb +186 -0
  111. data/lib/postsvg/model/operators/control_flow.rb +119 -0
  112. data/lib/postsvg/model/operators/device.rb +21 -0
  113. data/lib/postsvg/model/operators/dictionary.rb +118 -0
  114. data/lib/postsvg/model/operators/font.rb +121 -0
  115. data/lib/postsvg/model/operators/graphics_state.rb +84 -0
  116. data/lib/postsvg/model/operators/painting.rb +29 -0
  117. data/lib/postsvg/model/operators/path.rb +169 -0
  118. data/lib/postsvg/model/operators/stack.rb +72 -0
  119. data/lib/postsvg/model/operators/transformations.rb +103 -0
  120. data/lib/postsvg/model/operators.rb +89 -0
  121. data/lib/postsvg/model/program.rb +68 -0
  122. data/lib/postsvg/model/token.rb +43 -0
  123. data/lib/postsvg/model.rb +17 -0
  124. data/lib/postsvg/options.rb +29 -0
  125. data/lib/postsvg/renderer.rb +85 -0
  126. data/lib/postsvg/serializer.rb +325 -0
  127. data/lib/postsvg/source/ast_builder.rb +308 -0
  128. data/lib/postsvg/source/lexer.rb +322 -0
  129. data/lib/postsvg/source/operand_stack.rb +55 -0
  130. data/lib/postsvg/source.rb +21 -0
  131. data/lib/postsvg/svg/attribute_parser.rb +45 -0
  132. data/lib/postsvg/svg/clip_path_registry.rb +44 -0
  133. data/lib/postsvg/svg/document.rb +22 -0
  134. data/lib/postsvg/svg/element.rb +84 -0
  135. data/lib/postsvg/svg/elements/circle.rb +36 -0
  136. data/lib/postsvg/svg/elements/clip_path.rb +26 -0
  137. data/lib/postsvg/svg/elements/defs.rb +24 -0
  138. data/lib/postsvg/svg/elements/ellipse.rb +38 -0
  139. data/lib/postsvg/svg/elements/group.rb +37 -0
  140. data/lib/postsvg/svg/elements/image.rb +35 -0
  141. data/lib/postsvg/svg/elements/line.rb +36 -0
  142. data/lib/postsvg/svg/elements/path.rb +32 -0
  143. data/lib/postsvg/svg/elements/polygon.rb +12 -0
  144. data/lib/postsvg/svg/elements/polyline.rb +32 -0
  145. data/lib/postsvg/svg/elements/rect.rb +44 -0
  146. data/lib/postsvg/svg/elements/svg.rb +39 -0
  147. data/lib/postsvg/svg/elements/text.rb +42 -0
  148. data/lib/postsvg/svg/elements.rb +31 -0
  149. data/lib/postsvg/svg/paint.rb +34 -0
  150. data/lib/postsvg/svg/parser.rb +39 -0
  151. data/lib/postsvg/svg/path_data/command.rb +27 -0
  152. data/lib/postsvg/svg/path_data/parser.rb +82 -0
  153. data/lib/postsvg/svg/path_data.rb +17 -0
  154. data/lib/postsvg/svg/stroke.rb +31 -0
  155. data/lib/postsvg/svg/transform_list.rb +59 -0
  156. data/lib/postsvg/svg.rb +22 -0
  157. data/lib/postsvg/svg_builder.rb +249 -0
  158. data/lib/postsvg/translation/arc_converter.rb +86 -0
  159. data/lib/postsvg/translation/bounding_box.rb +59 -0
  160. data/lib/postsvg/translation/context.rb +34 -0
  161. data/lib/postsvg/translation/handler_registry.rb +38 -0
  162. data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
  163. data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
  164. data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
  165. data/lib/postsvg/translation/handlers/ellipse_handler.rb +31 -0
  166. data/lib/postsvg/translation/handlers/group_handler.rb +21 -0
  167. data/lib/postsvg/translation/handlers/image_handler.rb +20 -0
  168. data/lib/postsvg/translation/handlers/line_handler.rb +23 -0
  169. data/lib/postsvg/translation/handlers/open_handler.rb +18 -0
  170. data/lib/postsvg/translation/handlers/path_handler.rb +356 -0
  171. data/lib/postsvg/translation/handlers/polygon_handler.rb +33 -0
  172. data/lib/postsvg/translation/handlers/polyline_handler.rb +31 -0
  173. data/lib/postsvg/translation/handlers/rect_handler.rb +27 -0
  174. data/lib/postsvg/translation/handlers/shared.rb +110 -0
  175. data/lib/postsvg/translation/handlers/svg_handler.rb +25 -0
  176. data/lib/postsvg/translation/handlers/text_handler.rb +56 -0
  177. data/lib/postsvg/translation/handlers.rb +25 -0
  178. data/lib/postsvg/translation/ps_renderer.rb +105 -0
  179. data/lib/postsvg/translation/record_emitter.rb +35 -0
  180. data/lib/postsvg/translation.rb +17 -0
  181. data/lib/postsvg/version.rb +1 -1
  182. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
  183. data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
  184. data/lib/postsvg/visitors/ps_visitor/color.rb +53 -0
  185. data/lib/postsvg/visitors/ps_visitor/common.rb +66 -0
  186. data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
  187. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
  188. data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
  189. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +89 -0
  190. data/lib/postsvg/visitors/ps_visitor/font.rb +93 -0
  191. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
  192. data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
  193. data/lib/postsvg/visitors/ps_visitor/path.rb +112 -0
  194. data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
  195. data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
  196. data/lib/postsvg/visitors/ps_visitor.rb +208 -0
  197. data/lib/postsvg/visitors.rb +9 -0
  198. data/lib/postsvg.rb +93 -59
  199. data/lychee.toml +86 -0
  200. metadata +216 -11
  201. data/postsvg.gemspec +0 -38
@@ -0,0 +1,1210 @@
1
+ = ExecutionContext Class
2
+ :page-nav_order: 4
3
+ :page-parent: API Reference
4
+
5
+ == Purpose
6
+
7
+ The [`ExecutionContext`](../../lib/postsvg/execution_context.rb:9) class encapsulates all mutable state during PostScript execution, including the operand stack, dictionary stack, graphics state, and SVG output. It serves as the runtime environment for the interpreter.
8
+
9
+ == References
10
+
11
+ * link:../index.adoc[Documentation Home]
12
+ * link:../api-reference.adoc[API Reference Overview]
13
+ * link:interpreter.adoc[Interpreter Class]
14
+ * link:graphics-state.adoc[GraphicsState Class]
15
+ * link:../architecture.adoc[Architecture Overview]
16
+
17
+ == Concepts
18
+
19
+ **Operand Stack**:: A LIFO (Last-In-First-Out) stack holding operands for PostScript operators.
20
+
21
+ **Dictionary Stack**:: A stack of dictionaries providing scoped name-to-value mappings.
22
+
23
+ **Graphics State**:: The current drawing parameters including color, line width, transformation matrix, clip paths, etc.
24
+
25
+ **Graphics State Stack**:: A stack for saving and restoring graphics states via `gsave`/`grestore`.
26
+
27
+ **Current Transformation Matrix (CTM)**:: A 2D affine transformation matrix mapping user space to device space.
28
+
29
+ **Path Builder**:: An object that accumulates path commands (moveto, lineto, curveto) before rendering.
30
+
31
+ == Class Overview
32
+
33
+ The [`ExecutionContext`](../../lib/postsvg/execution_context.rb:9) class is defined in [`lib/postsvg/execution_context.rb`](../../lib/postsvg/execution_context.rb:1).
34
+
35
+ **Responsibilities:**
36
+
37
+ * Manage operand stack operations
38
+ * Maintain dictionary stack for name resolution
39
+ * Track graphics state and state stack
40
+ * Build and manage current path
41
+ * Generate SVG output elements
42
+ * Handle coordinate transformations
43
+ * Manage clip paths and patterns
44
+ * Provide utility functions for SVG generation
45
+
46
+ **Key Components:**
47
+
48
+ * Operand stack - General-purpose data stack
49
+ * Dictionary stack - Name/value lookup
50
+ * Graphics state - Drawing parameters
51
+ * Path builder - Path accumulation
52
+ * SVG output - Generated elements
53
+
54
+ **Design Pattern:**
55
+
56
+ The ExecutionContext follows the **Context Object** pattern, encapsulating all runtime state in a single mutable object that's passed to command implementations.
57
+
58
+ == Class Methods
59
+
60
+ === new
61
+
62
+ Create a new ExecutionContext with initialized state.
63
+
64
+ **Syntax:**
65
+
66
+ [source,ruby]
67
+ ----
68
+ context = Postsvg::ExecutionContext.new <1>
69
+ ----
70
+ <1> Initialize context with default state
71
+
72
+ **Returns:**
73
+
74
+ New `ExecutionContext` instance with:
75
+
76
+ * Empty operand stack
77
+ * Global dictionary on dictionary stack
78
+ * Default graphics state
79
+ * Empty path
80
+ * Empty SVG output
81
+
82
+ **Source:**
83
+
84
+ [`lib/postsvg/execution_context.rb:14-30`](../../lib/postsvg/execution_context.rb:14)
85
+
86
+ **Initialization:**
87
+
88
+ [source,ruby]
89
+ ----
90
+ # Operand stack
91
+ @stack = []
92
+
93
+ # Graphics state with defaults
94
+ @graphics_state = {
95
+ ctm: Matrix.new, # Identity matrix
96
+ fill: "black",
97
+ stroke: "black",
98
+ stroke_width: 1,
99
+ line_cap: "butt",
100
+ line_join: "miter",
101
+ font: "Arial, sans-serif",
102
+ font_size: 12,
103
+ clip_stack: [],
104
+ # ... other properties
105
+ }
106
+
107
+ # Dictionary stack with global dict
108
+ @dict_stack = [@global_dict]
109
+
110
+ # SVG output containers
111
+ @svg_output = { defs: [], paths: [], text: [] }
112
+ ----
113
+
114
+ .Create execution context
115
+ [example]
116
+ ====
117
+ [source,ruby]
118
+ ----
119
+ require 'postsvg'
120
+
121
+ context = Postsvg::ExecutionContext.new
122
+
123
+ # Context is ready for use
124
+ puts "Stack size: #{context.stack.length}" # 0
125
+ puts "Fill color: #{context.graphics_state[:fill]}" # "black"
126
+ puts "Line width: #{context.graphics_state[:stroke_width]}" # 1
127
+ ----
128
+ ====
129
+
130
+ == Attributes
131
+
132
+ === stack (read-only)
133
+
134
+ Access the operand stack.
135
+
136
+ **Returns:**
137
+
138
+ Array containing stack values (bottom to top)
139
+
140
+ **Source:**
141
+
142
+ [`lib/postsvg/execution_context.rb:10`](../../lib/postsvg/execution_context.rb:10)
143
+
144
+ .Inspect stack
145
+ [example]
146
+ ====
147
+ [source,ruby]
148
+ ----
149
+ context.push(10)
150
+ context.push(20)
151
+ context.push(30)
152
+
153
+ puts context.stack.inspect # [10, 20, 30]
154
+ puts "Stack depth: #{context.stack.length}" # 3
155
+ puts "Top element: #{context.stack.last}" # 30
156
+ ----
157
+ ====
158
+
159
+ === graphics_state (read-only)
160
+
161
+ Access the current graphics state hash.
162
+
163
+ **Returns:**
164
+
165
+ Hash containing graphics state properties
166
+
167
+ **Source:**
168
+
169
+ [`lib/postsvg/execution_context.rb:10`](../../lib/postsvg/execution_context.rb:10)
170
+
171
+ **Graphics State Properties:**
172
+
173
+ [cols="1,2,1"]
174
+ |===
175
+ | Property | Description | Default
176
+
177
+ | `:ctm`
178
+ | Current transformation matrix
179
+ | `Matrix.new` (identity)
180
+
181
+ | `:fill`
182
+ | Fill color
183
+ | `"black"`
184
+
185
+ | `:stroke`
186
+ | Stroke color
187
+ | `"black"`
188
+
189
+ | `:stroke_width`
190
+ | Line width
191
+ | `1`
192
+
193
+ | `:line_cap`
194
+ | Line cap style
195
+ | `"butt"`
196
+
197
+ | `:line_join`
198
+ | Line join style
199
+ | `"miter"`
200
+
201
+ | `:font`
202
+ | Font family
203
+ | `"Arial, sans-serif"`
204
+
205
+ | `:font_size`
206
+ | Font size in points
207
+ | `12`
208
+
209
+ | `:clip_stack`
210
+ | Array of clip paths
211
+ | `[]`
212
+
213
+ | `:dash`
214
+ | Dash pattern
215
+ | `nil`
216
+
217
+ | `:pattern`
218
+ | Pattern reference
219
+ | `nil`
220
+
221
+ | `:blend_mode`
222
+ | Blend mode
223
+ | `:normal`
224
+
225
+ | `:opacity_alpha`
226
+ | Opacity value
227
+ | `1.0`
228
+ |===
229
+
230
+ .Access graphics state
231
+ [example]
232
+ ====
233
+ [source,ruby]
234
+ ----
235
+ context = Postsvg::ExecutionContext.new
236
+
237
+ # Read properties
238
+ puts context.graphics_state[:fill] # "black"
239
+ puts context.graphics_state[:stroke_width] # 1
240
+
241
+ # Modify properties
242
+ context.graphics_state[:fill] = "red"
243
+ context.graphics_state[:stroke_width] = 2.5
244
+
245
+ # Access transformation matrix
246
+ ctm = context.graphics_state[:ctm]
247
+ puts "Matrix: a=#{ctm.a}, e=#{ctm.e}, f=#{ctm.f}"
248
+ ----
249
+ ====
250
+
251
+ === svg_output (read-only)
252
+
253
+ Access the SVG output container.
254
+
255
+ **Returns:**
256
+
257
+ Hash with three arrays:
258
+
259
+ * `:defs` - SVG definitions (patterns, gradients, clip paths)
260
+ * `:paths` - SVG path elements
261
+ * `:text` - SVG text elements
262
+
263
+ **Source:**
264
+
265
+ [`lib/postsvg/execution_context.rb:10`](../../lib/postsvg/execution_context.rb:10)
266
+
267
+ .Access SVG output
268
+ [example]
269
+ ====
270
+ [source,ruby]
271
+ ----
272
+ context = Postsvg::ExecutionContext.new
273
+
274
+ # Add elements during interpretation...
275
+ # (normally done by command implementations)
276
+
277
+ # Inspect results
278
+ output = context.svg_output
279
+ puts "Definitions: #{output[:defs].length}"
280
+ puts "Paths: #{output[:paths].length}"
281
+ puts "Text elements: #{output[:text].length}"
282
+
283
+ # Access individual elements
284
+ output[:paths].each_with_index do |path, i|
285
+ puts "Path #{i}: #{path[0..50]}..."
286
+ end
287
+ ----
288
+ ====
289
+
290
+ === current_x, current_y (read/write)
291
+
292
+ Current point coordinates in user space.
293
+
294
+ **Returns:**
295
+
296
+ Numeric values representing current position
297
+
298
+ **Source:**
299
+
300
+ [`lib/postsvg/execution_context.rb:12`](../../lib/postsvg/execution_context.rb:12)
301
+
302
+ .Track current point
303
+ [example]
304
+ ====
305
+ [source,ruby]
306
+ ----
307
+ context = Postsvg::ExecutionContext.new
308
+
309
+ # Set current point
310
+ context.current_x = 100
311
+ context.current_y = 200
312
+
313
+ puts "Current point: (#{context.current_x}, #{context.current_y})"
314
+
315
+ # Update current point (usually done by path commands)
316
+ context.update_current_point(150, 250)
317
+ puts "New point: (#{context.current_x}, #{context.current_y})"
318
+ ----
319
+ ====
320
+
321
+ == Stack Operations
322
+
323
+ === push
324
+
325
+ Push a value onto the operand stack.
326
+
327
+ **Syntax:**
328
+
329
+ [source,ruby]
330
+ ----
331
+ context.push(value) <1>
332
+ ----
333
+ <1> Push value onto top of stack
334
+
335
+ **Where:**
336
+
337
+ `value`:: Any Ruby object (Number, String, Array, Hash, etc.)
338
+
339
+ **Source:**
340
+
341
+ [`lib/postsvg/execution_context.rb:33-35`](../../lib/postsvg/execution_context.rb:33)
342
+
343
+ .Stack push examples
344
+ [example]
345
+ ====
346
+ [source,ruby]
347
+ ----
348
+ context = Postsvg::ExecutionContext.new
349
+
350
+ # Push numbers
351
+ context.push(42)
352
+ context.push(3.14)
353
+
354
+ # Push strings
355
+ context.push("hello")
356
+
357
+ # Push arrays
358
+ context.push([1, 2, 3])
359
+
360
+ # Push procedures
361
+ context.push({ type: "procedure", body: [...] })
362
+
363
+ puts context.stack.length # 5
364
+ ----
365
+ ====
366
+
367
+ === pop
368
+
369
+ Pop and return the top value from the stack.
370
+
371
+ **Syntax:**
372
+
373
+ [source,ruby]
374
+ ----
375
+ value = context.pop <1>
376
+ ----
377
+ <1> Pop and return top value
378
+
379
+ **Returns:**
380
+
381
+ The top value from stack, or `nil` if stack is empty
382
+
383
+ **Source:**
384
+
385
+ [`lib/postsvg/execution_context.rb:37-39`](../../lib/postsvg/execution_context.rb:37)
386
+
387
+ .Stack pop examples
388
+ [example]
389
+ ====
390
+ [source,ruby]
391
+ ----
392
+ context.push(10)
393
+ context.push(20)
394
+ context.push(30)
395
+
396
+ val3 = context.pop # 30
397
+ val2 = context.pop # 20
398
+ val1 = context.pop # 10
399
+
400
+ puts "Popped: #{val3}, #{val2}, #{val1}"
401
+ puts "Stack empty: #{context.stack.empty?}" # true
402
+ ----
403
+ ====
404
+
405
+ === pop_number
406
+
407
+ Pop a numeric value, with default fallback.
408
+
409
+ **Syntax:**
410
+
411
+ [source,ruby]
412
+ ----
413
+ num = context.pop_number(default = 0) <1>
414
+ ----
415
+ <1> Pop number with fallback to default
416
+
417
+ **Where:**
418
+
419
+ `default`:: (Optional) Value to return if pop fails or value is not numeric (default: 0)
420
+
421
+ **Returns:**
422
+
423
+ Numeric value or default
424
+
425
+ **Source:**
426
+
427
+ [`lib/postsvg/execution_context.rb:41-47`](../../lib/postsvg/execution_context.rb:41)
428
+
429
+ .Safe number popping
430
+ [example]
431
+ ====
432
+ [source,ruby]
433
+ ----
434
+ context.push(42)
435
+ context.push("not a number")
436
+ context.push(3.14)
437
+
438
+ num1 = context.pop_number # 3.14 (numeric)
439
+ num2 = context.pop_number # 0 (string, uses default)
440
+ num3 = context.pop_number(100) # 42 (numeric)
441
+ num4 = context.pop_number(100) # 100 (empty stack, uses default)
442
+
443
+ puts "Numbers: #{num1}, #{num2}, #{num3}, #{num4}"
444
+ ----
445
+ ====
446
+
447
+ === peek
448
+
449
+ Look at the top value without removing it.
450
+
451
+ **Syntax:**
452
+
453
+ [source,ruby]
454
+ ----
455
+ value = context.peek <1>
456
+ ----
457
+ <1> Return top value without popping
458
+
459
+ **Returns:**
460
+
461
+ The top value from stack, or `nil` if stack is empty
462
+
463
+ **Source:**
464
+
465
+ [`lib/postsvg/execution_context.rb:49-51`](../../lib/postsvg/execution_context.rb:49)
466
+
467
+ .Peek at stack
468
+ [example]
469
+ ====
470
+ [source,ruby]
471
+ ----
472
+ context.push(100)
473
+
474
+ top = context.peek
475
+ puts "Top value: #{top}" # 100
476
+ puts "Stack size: #{context.stack.length}" # 1 (still there)
477
+
478
+ context.pop
479
+ puts "Stack size: #{context.stack.length}" # 0 (now removed)
480
+ ----
481
+ ====
482
+
483
+ == Graphics State Operations
484
+
485
+ === save_graphics_state
486
+
487
+ Save current graphics state (gsave).
488
+
489
+ **Syntax:**
490
+
491
+ [source,ruby]
492
+ ----
493
+ context.save_graphics_state <1>
494
+ ----
495
+ <1> Push current state onto graphics state stack
496
+
497
+ **Source:**
498
+
499
+ [`lib/postsvg/execution_context.rb:54-66`](../../lib/postsvg/execution_context.rb:54)
500
+
501
+ **Saved State:**
502
+
503
+ * Complete graphics state (deep copy)
504
+ * Current point coordinates
505
+ * Current CTM
506
+ * Path builder state
507
+
508
+ .Save and modify state
509
+ [example]
510
+ ====
511
+ [source,ruby]
512
+ ----
513
+ context = Postsvg::ExecutionContext.new
514
+
515
+ # Set initial state
516
+ context.graphics_state[:fill] = "red"
517
+ context.graphics_state[:stroke_width] = 2
518
+
519
+ # Save state
520
+ context.save_graphics_state
521
+
522
+ # Modify state
523
+ context.graphics_state[:fill] = "blue"
524
+ context.graphics_state[:stroke_width] = 5
525
+
526
+ puts "Current fill: #{context.graphics_state[:fill]}" # "blue"
527
+
528
+ # Restore state
529
+ context.restore_graphics_state
530
+
531
+ puts "Restored fill: #{context.graphics_state[:fill]}" # "red"
532
+ puts "Restored width: #{context.graphics_state[:stroke_width]}" # 2
533
+ ----
534
+ ====
535
+
536
+ === restore_graphics_state
537
+
538
+ Restore previously saved graphics state (grestore).
539
+
540
+ **Syntax:**
541
+
542
+ [source,ruby]
543
+ ----
544
+ context.restore_graphics_state <1>
545
+ ----
546
+ <1> Pop and restore state from graphics state stack
547
+
548
+ **Source:**
549
+
550
+ [`lib/postsvg/execution_context.rb:68-77`](../../lib/postsvg/execution_context.rb:68)
551
+
552
+ **Restored State:**
553
+
554
+ * Graphics state properties
555
+ * Current point
556
+ * CTM
557
+ * Path builder
558
+
559
+ .Nested save/restore
560
+ [example]
561
+ ====
562
+ [source,ruby]
563
+ ----
564
+ context = Postsvg::ExecutionContext.new
565
+
566
+ context.graphics_state[:fill] = "red"
567
+ context.save_graphics_state # Save "red"
568
+
569
+ context.graphics_state[:fill] = "green"
570
+ context.save_graphics_state # Save "green"
571
+
572
+ context.graphics_state[:fill] = "blue"
573
+ # Current: "blue"
574
+
575
+ context.restore_graphics_state
576
+ # Restored: "green"
577
+
578
+ context.restore_graphics_state
579
+ # Restored: "red"
580
+
581
+ puts context.graphics_state[:fill] # "red"
582
+ ----
583
+ ====
584
+
585
+ == Dictionary Operations
586
+
587
+ === define
588
+
589
+ Define a name in the current dictionary.
590
+
591
+ **Syntax:**
592
+
593
+ [source,ruby]
594
+ ----
595
+ context.define(key, value) <1>
596
+ ----
597
+ <1> Store key-value pair in current dictionary
598
+
599
+ **Where:**
600
+
601
+ `key`:: Name to define (converted to string)
602
+ `value`:: Value to associate with name
603
+
604
+ **Source:**
605
+
606
+ [`lib/postsvg/execution_context.rb:92-94`](../../lib/postsvg/execution_context.rb:92)
607
+
608
+ .Define variables
609
+ [example]
610
+ ====
611
+ [source,ruby]
612
+ ----
613
+ context = Postsvg::ExecutionContext.new
614
+
615
+ # Define variables
616
+ context.define("x", 100)
617
+ context.define("y", 200)
618
+ context.define("radius", 50)
619
+
620
+ # Define procedures
621
+ context.define("myproc", {
622
+ type: "procedure",
623
+ body: [...]
624
+ })
625
+
626
+ # Look up later
627
+ x = context.lookup("x")
628
+ puts "x = #{x}" # 100
629
+ ----
630
+ ====
631
+
632
+ === lookup
633
+
634
+ Look up a name in the dictionary stack.
635
+
636
+ **Syntax:**
637
+
638
+ [source,ruby]
639
+ ----
640
+ value = context.lookup(name) <1>
641
+ ----
642
+ <1> Search dictionary stack for name
643
+
644
+ **Where:**
645
+
646
+ `name`:: Name to look up (string)
647
+
648
+ **Returns:**
649
+
650
+ Value if found, `nil` otherwise
651
+
652
+ **Source:**
653
+
654
+ [`lib/postsvg/execution_context.rb:96-101`](../../lib/postsvg/execution_context.rb:96)
655
+
656
+ **Lookup Order:**
657
+
658
+ Searches from top to bottom of dictionary stack (most recent first).
659
+
660
+ .Dictionary lookup
661
+ [example]
662
+ ====
663
+ [source,ruby]
664
+ ----
665
+ context = Postsvg::ExecutionContext.new
666
+
667
+ # Define in global scope
668
+ context.define("global_var", 100)
669
+
670
+ # Create new dictionary scope
671
+ context.push_dict({})
672
+ context.define("local_var", 200)
673
+
674
+ # Both accessible
675
+ puts context.lookup("global_var") # 100
676
+ puts context.lookup("local_var") # 200
677
+
678
+ # Pop dictionary
679
+ context.pop_dict
680
+
681
+ # Only global accessible
682
+ puts context.lookup("global_var") # 100
683
+ puts context.lookup("local_var") # nil
684
+ ----
685
+ ====
686
+
687
+ === push_dict
688
+
689
+ Push a new dictionary onto the dictionary stack.
690
+
691
+ **Syntax:**
692
+
693
+ [source,ruby]
694
+ ----
695
+ context.push_dict(dict) <1>
696
+ ----
697
+ <1> Add dictionary to stack
698
+
699
+ **Where:**
700
+
701
+ `dict`:: Hash to push (creates empty hash if not a Hash)
702
+
703
+ **Source:**
704
+
705
+ [`lib/postsvg/execution_context.rb:84-86`](../../lib/postsvg/execution_context.rb:84)
706
+
707
+ === pop_dict
708
+
709
+ Pop a dictionary from the dictionary stack.
710
+
711
+ **Syntax:**
712
+
713
+ [source,ruby]
714
+ ----
715
+ context.pop_dict <1>
716
+ ----
717
+ <1> Remove top dictionary (preserves at least one)
718
+
719
+ **Source:**
720
+
721
+ [`lib/postsvg/execution_context.rb:88-90`](../../lib/postsvg/execution_context.rb:88)
722
+
723
+ == Path Operations
724
+
725
+ === update_current_point
726
+
727
+ Update the current point coordinates.
728
+
729
+ **Syntax:**
730
+
731
+ [source,ruby]
732
+ ----
733
+ context.update_current_point(x, y) <1>
734
+ ----
735
+ <1> Set current point and last text position
736
+
737
+ **Where:**
738
+
739
+ `x`:: X coordinate
740
+ `y`:: Y coordinate
741
+
742
+ **Source:**
743
+
744
+ [`lib/postsvg/execution_context.rb:104-108`](../../lib/postsvg/execution_context.rb:104)
745
+
746
+ === reset_path
747
+
748
+ Reset the path builder to empty state.
749
+
750
+ **Syntax:**
751
+
752
+ [source,ruby]
753
+ ----
754
+ context.reset_path <1>
755
+ ----
756
+ <1> Clear current path
757
+
758
+ **Source:**
759
+
760
+ [`lib/postsvg/execution_context.rb:110-112`](../../lib/postsvg/execution_context.rb:110)
761
+
762
+ === new_path
763
+
764
+ Alias for reset_path (PostScript `newpath` operator).
765
+
766
+ **Syntax:**
767
+
768
+ [source,ruby]
769
+ ----
770
+ context.new_path <1>
771
+ ----
772
+ <1> Start new path
773
+
774
+ **Source:**
775
+
776
+ [`lib/postsvg/execution_context.rb:114-116`](../../lib/postsvg/execution_context.rb:114)
777
+
778
+ === path_to_svg
779
+
780
+ Convert current path to SVG path data string.
781
+
782
+ **Syntax:**
783
+
784
+ [source,ruby]
785
+ ----
786
+ path_data = context.path_to_svg <1>
787
+ ----
788
+ <1> Generate SVG `d` attribute value
789
+
790
+ **Returns:**
791
+
792
+ String containing SVG path data (e.g., `"M 10,20 L 30,40"`)
793
+
794
+ **Source:**
795
+
796
+ [`lib/postsvg/execution_context.rb:122-124`](../../lib/postsvg/execution_context.rb:122)
797
+
798
+ .Path generation
799
+ [example]
800
+ ====
801
+ [source,ruby]
802
+ ----
803
+ context = Postsvg::ExecutionContext.new
804
+
805
+ # Build path using path_builder
806
+ context.path_builder.move_to(10, 20)
807
+ context.path_builder.line_to(30, 40)
808
+ context.path_builder.line_to(50, 30)
809
+ context.path_builder.close_path
810
+
811
+ # Convert to SVG
812
+ svg_path = context.path_to_svg
813
+ puts svg_path # "M 10,20 L 30,40 L 50,30 Z"
814
+ ----
815
+ ====
816
+
817
+ == SVG Output Operations
818
+
819
+ === flush_path
820
+
821
+ Render current path to SVG and add to output.
822
+
823
+ **Syntax:**
824
+
825
+ [source,ruby]
826
+ ----
827
+ context.flush_path(mode, fill_id = nil, bbox = nil) <1>
828
+ ----
829
+ <1> Generate SVG path element and clear path
830
+
831
+ **Where:**
832
+
833
+ `mode`:: Hash specifying render mode
834
+ * `:fill` - Boolean, whether to fill
835
+ * `:stroke` - Boolean, whether to stroke
836
+
837
+ `fill_id`:: (Optional) Pattern or gradient ID for fill
838
+
839
+ `bbox`:: (Optional) Bounding box for clipping
840
+
841
+ **Source:**
842
+
843
+ [`lib/postsvg/execution_context.rb:305-320`](../../lib/postsvg/execution_context.rb:305)
844
+
845
+ .Flush path examples
846
+ [example]
847
+ ====
848
+ [source,ruby]
849
+ ----
850
+ # Build a path
851
+ context.path_builder.move_to(10, 10)
852
+ context.path_builder.line_to(90, 10)
853
+ context.path_builder.line_to(90, 90)
854
+ context.path_builder.close_path
855
+
856
+ # Render with fill only
857
+ context.flush_path({ fill: true, stroke: false })
858
+
859
+ # Result added to svg_output[:paths]
860
+ puts context.svg_output[:paths].last
861
+ # <path d="M 10,10 L 90,10 L 90,90 Z" fill="black" stroke="none" />
862
+ ----
863
+ ====
864
+
865
+ === emit_svg_path
866
+
867
+ Generate SVG path element string.
868
+
869
+ **Syntax:**
870
+
871
+ [source,ruby]
872
+ ----
873
+ path_element = context.emit_svg_path(d, mode, fill_id = nil, bbox = nil) <1>
874
+ ----
875
+ <1> Create SVG path element with current graphics state
876
+
877
+ **Where:**
878
+
879
+ `d`:: SVG path data string
880
+ `mode`:: Hash with `:fill` and `:stroke` booleans
881
+ `fill_id`:: (Optional) Pattern/gradient reference
882
+ `bbox`:: (Optional) Bounding box
883
+
884
+ **Returns:**
885
+
886
+ String containing complete SVG path element
887
+
888
+ **Source:**
889
+
890
+ [`lib/postsvg/execution_context.rb:246-303`](../../lib/postsvg/execution_context.rb:246)
891
+
892
+ === add_def
893
+
894
+ Add a definition element to SVG defs.
895
+
896
+ **Syntax:**
897
+
898
+ [source,ruby]
899
+ ----
900
+ context.add_def(def_element) <1>
901
+ ----
902
+ <1> Add to SVG definitions section
903
+
904
+ **Where:**
905
+
906
+ `def_element`:: String containing SVG definition (pattern, gradient, clipPath, etc.)
907
+
908
+ **Source:**
909
+
910
+ [`lib/postsvg/execution_context.rb:215-217`](../../lib/postsvg/execution_context.rb:215)
911
+
912
+ .Add definitions
913
+ [example]
914
+ ====
915
+ [source,ruby]
916
+ ----
917
+ context = Postsvg::ExecutionContext.new
918
+
919
+ # Add gradient definition
920
+ gradient = <<~SVG
921
+ <linearGradient id="grad1">
922
+ <stop offset="0%" stop-color="red"/>
923
+ <stop offset="100%" stop-color="blue"/>
924
+ </linearGradient>
925
+ SVG
926
+
927
+ context.add_def(gradient.strip)
928
+
929
+ # Add clip path
930
+ clip = '<clipPath id="clip1"><path d="..."/></clipPath>'
931
+ context.add_def(clip)
932
+
933
+ # Definitions will be included in final SVG
934
+ puts context.svg_output[:defs].length # 2
935
+ ----
936
+ ====
937
+
938
+ == Utility Methods
939
+
940
+ === num_fmt
941
+
942
+ Format a number for SVG output.
943
+
944
+ **Syntax:**
945
+
946
+ [source,ruby]
947
+ ----
948
+ formatted = context.num_fmt(number) <1>
949
+ ----
950
+ <1> Format number to minimal string representation
951
+
952
+ **Where:**
953
+
954
+ `number`:: Numeric value to format
955
+
956
+ **Returns:**
957
+
958
+ String representation with:
959
+
960
+ * Integers as plain numbers: `10`
961
+ * Floats with up to 6 decimals, trailing zeros removed: `3.14`
962
+ * Special values as `"0"`: NaN, Infinity, nil
963
+
964
+ **Source:**
965
+
966
+ [`lib/postsvg/execution_context.rb:220-235`](../../lib/postsvg/execution_context.rb:220)
967
+
968
+ .Number formatting
969
+ [example]
970
+ ====
971
+ [source,ruby]
972
+ ----
973
+ context = Postsvg::ExecutionContext.new
974
+
975
+ puts context.num_fmt(10) # "10"
976
+ puts context.num_fmt(10.0) # "10"
977
+ puts context.num_fmt(10.5) # "10.5"
978
+ puts context.num_fmt(3.14159) # "3.14159"
979
+ puts context.num_fmt(1.00000) # "1"
980
+ puts context.num_fmt(0.1 + 0.2) # "0.3"
981
+ puts context.num_fmt(nil) # "0"
982
+ puts context.num_fmt(Float::NAN) # "0"
983
+ ----
984
+ ====
985
+
986
+ === escape_xml
987
+
988
+ Escape string for XML/SVG output.
989
+
990
+ **Syntax:**
991
+
992
+ [source,ruby]
993
+ ----
994
+ escaped = context.escape_xml(string) <1>
995
+ ----
996
+ <1> Escape XML special characters
997
+
998
+ **Where:**
999
+
1000
+ `string`:: String to escape
1001
+
1002
+ **Returns:**
1003
+
1004
+ String with XML entities:
1005
+
1006
+ * `&` → `&amp;`
1007
+ * `<` → `&lt;`
1008
+ * `>` → `&gt;`
1009
+ * `"` → `&quot;`
1010
+ * `'` → `&#39;`
1011
+
1012
+ **Source:**
1013
+
1014
+ [`lib/postsvg/execution_context.rb:237-244`](../../lib/postsvg/execution_context.rb:237)
1015
+
1016
+ .XML escaping
1017
+ [example]
1018
+ ====
1019
+ [source,ruby]
1020
+ ----
1021
+ context = Postsvg::ExecutionContext.new
1022
+
1023
+ text = "Text with <tags> & \"quotes\""
1024
+ escaped = context.escape_xml(text)
1025
+
1026
+ puts escaped
1027
+ # "Text with &lt;tags&gt; &amp; &quot;quotes&quot;"
1028
+
1029
+ # Safe for use in SVG
1030
+ svg_text = "<text>#{escaped}</text>"
1031
+ ----
1032
+ ====
1033
+
1034
+ == ID Generation
1035
+
1036
+ === next_clippath_id
1037
+
1038
+ Generate unique clipPath ID.
1039
+
1040
+ **Syntax:**
1041
+
1042
+ [source,ruby]
1043
+ ----
1044
+ id = context.next_clippath_id <1>
1045
+ ----
1046
+ <1> Get next clipPath ID (auto-increments)
1047
+
1048
+ **Returns:**
1049
+
1050
+ Integer ID value
1051
+
1052
+ **Source:**
1053
+
1054
+ [`lib/postsvg/execution_context.rb:197-201`](../../lib/postsvg/execution_context.rb:197)
1055
+
1056
+ === next_path_id
1057
+
1058
+ Generate unique path ID.
1059
+
1060
+ **Syntax:**
1061
+
1062
+ [source,ruby]
1063
+ ----
1064
+ id = context.next_path_id <1>
1065
+ ----
1066
+ <1> Get next path ID (auto-increments)
1067
+
1068
+ **Returns:**
1069
+
1070
+ Integer ID value
1071
+
1072
+ **Source:**
1073
+
1074
+ [`lib/postsvg/execution_context.rb:203-207`](../../lib/postsvg/execution_context.rb:203)
1075
+
1076
+ === next_id
1077
+
1078
+ Generate generic unique ID.
1079
+
1080
+ **Syntax:**
1081
+
1082
+ [source,ruby]
1083
+ ----
1084
+ id = context.next_id <1>
1085
+ ----
1086
+ <1> Get next general-purpose ID (auto-increments)
1087
+
1088
+ **Returns:**
1089
+
1090
+ Integer ID value
1091
+
1092
+ **Source:**
1093
+
1094
+ [`lib/postsvg/execution_context.rb:209-213`](../../lib/postsvg/execution_context.rb:209)
1095
+
1096
+ .ID generation
1097
+ [example]
1098
+ ====
1099
+ [source,ruby]
1100
+ ----
1101
+ context = Postsvg::ExecutionContext.new
1102
+
1103
+ clip_id1 = context.next_clippath_id # 2
1104
+ clip_id2 = context.next_clippath_id # 4
1105
+ path_id1 = context.next_path_id # 2
1106
+ path_id2 = context.next_path_id # 4
1107
+ id1 = context.next_id # 0
1108
+ id2 = context.next_id # 1
1109
+
1110
+ # Use in SVG
1111
+ clip_def = "<clipPath id=\"clipPath#{clip_id1}\">...</clipPath>"
1112
+ path = "<path id=\"path#{path_id1}\" .../>"
1113
+ ----
1114
+ ====
1115
+
1116
+ ## Thread Safety
1117
+
1118
+ The `ExecutionContext` class is **not thread-safe**. Each execution thread must have its own context instance.
1119
+
1120
+ .Multi-threaded usage
1121
+ [example]
1122
+ ====
1123
+ [source,ruby]
1124
+ ----
1125
+ # Bad: Sharing context
1126
+ context = Postsvg::ExecutionContext.new
1127
+ threads = 5.times.map do
1128
+ Thread.new { execute_with(context) } # NOT SAFE
1129
+ end
1130
+
1131
+ # Good: Each thread has own context
1132
+ threads = 5.times.map do
1133
+ Thread.new do
1134
+ context = Postsvg::ExecutionContext.new
1135
+ execute_with(context)
1136
+ end
1137
+ end
1138
+ ----
1139
+ ====
1140
+
1141
+ == Best Practices
1142
+
1143
+ === State Management
1144
+
1145
+ **Always save before modifying:**
1146
+
1147
+ [source,ruby]
1148
+ ----
1149
+ # Save state
1150
+ context.save_graphics_state
1151
+
1152
+ # Modify
1153
+ context.graphics_state[:fill] = "red"
1154
+ # ... draw things ...
1155
+
1156
+ # Restore
1157
+ context.restore_graphics_state
1158
+ ----
1159
+
1160
+ **Use dictionary scopes:**
1161
+
1162
+ [source,ruby]
1163
+ ----
1164
+ # Create local scope
1165
+ context.push_dict({})
1166
+ context.define("local_var", value)
1167
+
1168
+ # Use local definitions
1169
+ # ...
1170
+
1171
+ # Clean up
1172
+ context.pop_dict
1173
+ ----
1174
+
1175
+ === Error Handling
1176
+
1177
+ **Check stack before popping:**
1178
+
1179
+ [source,ruby]
1180
+ ----
1181
+ if context.stack.length >= 2
1182
+ y = context.pop
1183
+ x = context.pop
1184
+ else
1185
+ raise "Insufficient operands"
1186
+ end
1187
+ ----
1188
+
1189
+ **Use pop_number for safety:**
1190
+
1191
+ [source,ruby]
1192
+ ----
1193
+ # Safe number retrieval
1194
+ value = context.pop_number(0) # Default to 0 if not numeric
1195
+ ----
1196
+
1197
+ == Next Steps
1198
+
1199
+ * Review link:interpreter.adoc[Interpreter Class] for execution flow
1200
+ * Learn about link:graphics-state.adoc[GraphicsState] for state details
1201
+ * See link:../architecture.adoc[Architecture] for system design
1202
+ * Check link:converter.adoc[Converter Class] for high-level API
1203
+
1204
+ == Bibliography
1205
+
1206
+ * link:interpreter.adoc[Interpreter Class Documentation]
1207
+ * link:graphics-state.adoc[GraphicsState Documentation]
1208
+ * link:converter.adoc[Converter Class Documentation]
1209
+ * link:../architecture.adoc[Architecture Overview]
1210
+ * link:https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf[PostScript Language Reference Manual]