|
1 | 1 | #lang racket/base |
2 | | - |
3 | | -(require "lexer.rkt" |
4 | | - "huffparser.rkt" |
5 | | - "utils.rkt" |
6 | | - threading |
7 | | - racket/list |
8 | | - racket/match |
9 | | - racket/file |
10 | | - racket/path) |
11 | | - |
12 | | -;; some structs, for convenience getter/setter methods |
13 | | -;; program-data will contain all the data required to compile a contract |
| 2 | +;;; analysis.rkt - Parse tree analysis for Huff code |
| 3 | +;;; |
| 4 | +;;; This file contains the code for analyzing the parsed Huff AST |
| 5 | +;;; and extracting program data such as macros, functions, constants, |
| 6 | +;;; and other definitions. It builds a comprehensive data structure |
| 7 | +;;; that represents all the components of a Huff program, which is then |
| 8 | +;;; used by the compiler to generate bytecode. |
| 9 | + |
| 10 | +(require "lexer.rkt" ; Tokenizer |
| 11 | + "huffparser.rkt" ; Parser |
| 12 | + "utils.rkt" ; Common utilities |
| 13 | + threading ; Threading macros (~>) |
| 14 | + racket/list ; List operations |
| 15 | + racket/match ; Pattern matching |
| 16 | + racket/file ; File operations |
| 17 | + racket/path) ; Path operations |
| 18 | + |
| 19 | +;; program-data: Structure containing all necessary data for compiling a Huff contract |
| 20 | +;; |
| 21 | +;; Fields: |
| 22 | +;; - labels: Hash map of jump labels to their positions |
| 23 | +;; - macros: Hash map of macro names to their definitions (args, takes, returns, body) |
| 24 | +;; - functions: Hash map of function names to their definitions |
| 25 | +;; - fndecls: Hash map of function declarations (used for function signatures) |
| 26 | +;; - eventdefs: Hash map of event definitions |
| 27 | +;; - errordefs: Hash map of error definitions |
| 28 | +;; - constants: Hash map of constant names to their values |
| 29 | +;; - errors: Hash map for error tracking |
| 30 | +;; - includes: List of included file paths |
| 31 | +;; - ctx: Context hash map (e.g., current filename for resolving includes) |
14 | 32 | (struct program-data (labels |
15 | 33 | macros |
16 | 34 | functions |
|
22 | 40 | includes |
23 | 41 | ctx) #:mutable) |
24 | 42 |
|
25 | | -;; no-arg constructor |
| 43 | +;; make-program-data: -> program-data |
| 44 | +;; Creates a new empty program-data structure with initialized hash maps |
26 | 45 | (define (make-program-data) |
27 | | - (program-data (make-hash) ;; labels |
28 | | - (make-hash) ;; macros |
29 | | - (make-hash) ;; functions |
30 | | - (make-hash) ;; fndecls |
31 | | - (make-hash) ;; eventdefs |
32 | | - (make-hash) ;; errordefs |
33 | | - (make-hash) ;; constants |
34 | | - (make-hash) ;; errors |
35 | | - (list) ;; includes |
36 | | - (make-hash)));; ctx |
37 | | - |
38 | | -;; analyze all top-level nodes, outputting into the same data object |
| 46 | + (program-data (make-hash) ;; labels - Jump labels used in the code |
| 47 | + (make-hash) ;; macros - Macro definitions |
| 48 | + (make-hash) ;; functions - Function definitions |
| 49 | + (make-hash) ;; fndecls - Function declarations |
| 50 | + (make-hash) ;; eventdefs - Event definitions |
| 51 | + (make-hash) ;; errordefs - Error definitions |
| 52 | + (make-hash) ;; constants - Constant definitions |
| 53 | + (make-hash) ;; errors - Error tracking |
| 54 | + (list) ;; includes - List of included files |
| 55 | + (make-hash)));; ctx - Context for file resolution |
| 56 | + |
| 57 | +;; analyze-program: (list 'program node ...) program-data -> void |
| 58 | +;; Analyzes all top-level nodes in a program, updating the program-data |
| 59 | +;; structure with the results |
39 | 60 | (define (analyze-program program data) |
40 | 61 | (for-each (lambda (n) (analyze-node n data)) (rest program))) |
41 | 62 |
|
42 | | -;; save each macro body in the data object |
| 63 | +;; analyze-defmacro: (list 'defmacro identifier args takes returns body ...) program-data -> void |
| 64 | +;; Extracts and stores a macro definition in the program-data |
| 65 | +;; |
| 66 | +;; Format of macro entry: (list args takes returns body) |
| 67 | +;; - args: Macro arguments |
| 68 | +;; - takes: Stack inputs |
| 69 | +;; - returns: Stack outputs |
| 70 | +;; - body: Macro implementation |
43 | 71 | (define (analyze-defmacro defmacro data) |
44 | 72 | (match defmacro |
45 | | - [(list 'defmacro identifier args takes returns body ...) (hash-set! (program-data-macros data) identifier (list args takes returns body))] |
| 73 | + [(list 'defmacro identifier args takes returns body ...) |
| 74 | + (hash-set! (program-data-macros data) identifier (list args takes returns body))] |
46 | 75 | [_ (error "Invalid defmacro")])) |
47 | 76 |
|
48 | | -;; save each function body in the data object |
| 77 | +;; analyze-defn: (list 'defn identifier args takes returns body) program-data -> void |
| 78 | +;; Extracts and stores a function definition in the program-data |
| 79 | +;; |
| 80 | +;; Format of function entry: (list args takes returns body) |
| 81 | +;; - args: Function arguments |
| 82 | +;; - takes: Stack inputs |
| 83 | +;; - returns: Stack outputs |
| 84 | +;; - body: Function implementation |
49 | 85 | (define (analyze-defn defn data) |
50 | 86 | (match defn |
51 | | - [(list 'defn identifier args takes returns body) (hash-set! (program-data-functions data) identifier (list args takes returns body))] |
| 87 | + [(list 'defn identifier args takes returns body) |
| 88 | + (hash-set! (program-data-functions data) identifier (list args takes returns body))] |
52 | 89 | [_ (error "Invalid defn")])) |
53 | 90 |
|
54 | | -;; save each constant value in the data object |
| 91 | +;; analyze-defconst: (list 'defconst identifier value) program-data -> void |
| 92 | +;; Extracts and stores a constant definition in the program-data |
55 | 93 | (define (analyze-defconst defconst data) |
56 | 94 | (match defconst |
57 | | - [(list 'defconst identifier value) (hash-set! (program-data-constants data) identifier value)] |
| 95 | + [(list 'defconst identifier value) |
| 96 | + (hash-set! (program-data-constants data) identifier value)] |
58 | 97 | [_ (error "Invalid defconst")])) |
59 | 98 |
|
| 99 | +;; analyze-declfn: (list 'declfn identifier args vis returns) program-data -> void |
| 100 | +;; Extracts and stores a function declaration in the program-data |
| 101 | +;; Used primarily for generating function signatures |
60 | 102 | (define (analyze-declfn declfn data) |
61 | 103 | (match declfn |
62 | 104 | [(list 'declfn identifier args vis returns) |
63 | 105 | (hash-set! (program-data-fndecls data) identifier args)] |
64 | 106 | [_ (error "Invalid declfn")])) |
65 | 107 |
|
| 108 | +;; analyze-deferror: (list 'deferror identifier args) program-data -> void |
| 109 | +;; Extracts and stores an error definition in the program-data |
66 | 110 | (define (analyze-deferror deferror data) |
67 | 111 | (match deferror |
68 | | - [(list 'deferror identifier args) (hash-set! (program-data-errordefs data) identifier args)] |
| 112 | + [(list 'deferror identifier args) |
| 113 | + (hash-set! (program-data-errordefs data) identifier args)] |
69 | 114 | [_ (error "Invalid deferror")])) |
70 | 115 |
|
| 116 | +;; analyze-defevent: (list 'defevent identifier args) program-data -> void |
| 117 | +;; Extracts and stores an event definition in the program-data |
71 | 118 | (define (analyze-defevent defevent data) |
72 | 119 | (match defevent |
73 | | - [(list 'defevent identifier args) (hash-set! (program-data-eventdefs data) identifier args)] |
| 120 | + [(list 'defevent identifier args) |
| 121 | + (hash-set! (program-data-eventdefs data) identifier args)] |
74 | 122 | [_ (error "Invalid defevent")])) |
75 | 123 |
|
76 | 124 |
|
77 | | -#| IMPORT HANDLING |# |
78 | | -;; macro to save the current context and restore it after the analysis |
79 | | -;; this is used for includes, which need to know the current file's directory |
80 | | -;; so we temporarily set the context to one with the include's filename |
| 125 | +;;; IMPORT HANDLING ;;; |
| 126 | + |
| 127 | +;; with-temp-context: program-data hash-map expr ... -> any |
| 128 | +;; Temporarily changes the context of program-data for executing expressions |
| 129 | +;; This is used for include handling to track the current file path |
| 130 | +;; Restores the original context after execution |
81 | 131 | (define-syntax with-temp-context |
82 | 132 | (syntax-rules () |
83 | 133 | [(_ data ctx body ...) |
|
87 | 137 | body ... |
88 | 138 | (set-program-data-ctx! data old-ctx)))])) |
89 | 139 |
|
| 140 | +;; analyze-filename: string program-data -> void |
| 141 | +;; Reads a file, lexes it, parses it, and analyzes the parse tree |
| 142 | +;; Used for processing included files |
90 | 143 | (define (analyze-filename filename data) |
91 | 144 | (let ([parse-tree (~> filename |
92 | | - file->string |
93 | | - lex |
94 | | - parse |
95 | | - syntax->datum)]) |
| 145 | + file->string ; Read file to string |
| 146 | + lex ; Convert to tokens |
| 147 | + parse ; Parse tokens to AST |
| 148 | + syntax->datum)]) ; Convert to plain data |
96 | 149 | (with-temp-context data (hash 'filename filename) |
97 | 150 | (analyze-node parse-tree data)))) |
98 | 151 |
|
| 152 | +;; analyze-include: (list 'include filename) program-data -> void |
| 153 | +;; Processes an include directive by resolving the file path |
| 154 | +;; and analyzing the included file's content |
99 | 155 | (define (analyze-include inc data) |
100 | 156 | (let* ([current-file (hash-ref (program-data-ctx data) 'filename)] |
101 | 157 | [current-dir (path->string (path-only (path->complete-path current-file)))]) |
102 | 158 | (parameterize ([current-directory current-dir]) |
103 | 159 | (match inc |
104 | | - [(list 'include filename) (let* ([filename (string-append current-dir (format-filename filename))]) |
105 | | - (set-program-data-includes! data (cons filename (program-data-includes data))) |
106 | | - (analyze-filename filename data))] |
| 160 | + [(list 'include filename) |
| 161 | + (let* ([filename (string-append current-dir (format-filename filename))]) |
| 162 | + ; Add to the list of included files |
| 163 | + (set-program-data-includes! data (cons filename (program-data-includes data))) |
| 164 | + ; Analyze the included file |
| 165 | + (analyze-filename filename data))] |
107 | 166 | [_ (error "Invalid include")])))) |
108 | | -#| END IMPORT HANDLING |# |
109 | 167 |
|
110 | | -;; top-level node-handler function |
| 168 | +;;; END IMPORT HANDLING ;;; |
| 169 | + |
| 170 | +;; analyze-node: any [program-data] [hash-map] -> program-data |
| 171 | +;; Top-level node analysis dispatcher function |
| 172 | +;; Analyzes a node from the parse tree and updates the program-data accordingly |
| 173 | +;; |
| 174 | +;; Parameters: |
| 175 | +;; - node: The AST node to analyze |
| 176 | +;; - data: Optional program-data to update (creates new if not provided) |
| 177 | +;; - ctx: Optional context hash-map for resolving includes |
| 178 | +;; |
| 179 | +;; Returns: |
| 180 | +;; - The updated program-data structure |
111 | 181 | (define (analyze-node node [data #f] [ctx #f]) |
112 | 182 | (let ([data (or data (make-program-data))]) |
113 | 183 | (when ctx (set-program-data-ctx! data ctx)) |
| 184 | + ; Dispatch based on the node type |
114 | 185 | (match (first node) |
115 | | - ['program (analyze-program node data)] |
116 | | - ['defmacro (analyze-defmacro node data)] |
117 | | - ['include (analyze-include node data)] |
118 | | - ['defconst (analyze-defconst node data)] |
119 | | - ['defn (analyze-defn node data)] |
120 | | - ['deferror (analyze-deferror node data)] |
121 | | - ['defevent (analyze-defevent node data)] |
122 | | - ['declfn (analyze-declfn node data)]) |
| 186 | + ['program (analyze-program node data)] ; Program (top-level) |
| 187 | + ['defmacro (analyze-defmacro node data)] ; Macro definition |
| 188 | + ['include (analyze-include node data)] ; Include directive |
| 189 | + ['defconst (analyze-defconst node data)] ; Constant definition |
| 190 | + ['defn (analyze-defn node data)] ; Function definition |
| 191 | + ['deferror (analyze-deferror node data)] ; Error definition |
| 192 | + ['defevent (analyze-defevent node data)] ; Event definition |
| 193 | + ['declfn (analyze-declfn node data)]) ; Function declaration |
123 | 194 | data)) |
124 | 195 |
|
125 | | -(provide (struct-out program-data) |
126 | | - make-program-data |
127 | | - analyze-node) |
| 196 | +;; Export the program-data struct with accessors/mutators |
| 197 | +;; and the functions for creating and analyzing program data |
| 198 | +(provide (struct-out program-data) ; Export program-data structure definition |
| 199 | + make-program-data ; Export constructor |
| 200 | + analyze-node) ; Export analysis entry point |
0 commit comments